/****************************************************************************** NAME vc_gencmd_until SYNOPSIS int vc_gencmd_until(const char *cmd, const char *error_string, int timeout); FUNCTION Sends the command repeatedly, until one of the following situations occurs: The specified response string is found within the gencmd response. The specified error string is found within the gencmd response. The timeout is reached. The timeout is a rough value, do not use it for precise timing. RETURNS 0 if the requested response was detected. 1 if the error string is detected or the timeout is reached. ******************************************************************************/ int vc_gencmd_until( char *cmd, const char *property, char *value, const char *error_string, int timeout) { char response[128]; int length; char *ret_value; int ret = 1; use_gencmd_service(); for (;timeout > 0; timeout -= 10) { vc_gencmd(response, (int)sizeof(response), cmd); if (strstr(response,error_string)) { ret = 1; break; } else if (vc_gencmd_string_property(response, property, &ret_value, &length) && strncmp(value,ret_value,(size_t)length)==0) { ret = 0; break; } vcos_sleep(10); } release_gencmd_service(); return ret; }
/****************************************************************************** NAME vc_gencmd_send SYNOPSIS int vc_gencmd_send( const char *format, ... ) FUNCTION Send a string to general command service. RETURNS int ******************************************************************************/ int vc_gencmd_send_list ( const char *format, va_list a ) { int success = -1; // Obtain the lock and keep it so no one else can butt in while we await the response. if(lock_obtain() == 0) { int length = vsnprintf( gencmd_client.command_buffer, GENCMD_MAX_LENGTH, format, a ); if (length >= 0 && length < GENCMD_MAX_LENGTH) { int i; use_gencmd_service(); for( i=0; i<gencmd_client.num_connections; i++ ) { success = vchi_msg_queue( gencmd_client.open_handle[i], gencmd_client.command_buffer, length+1, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ); if(success == 0) { // only want to send on one connection, so break on success break; } } release_gencmd_service(); } lock_release(); } return success; }
/****************************************************************************** NAME vc_gencmd_read_response SYNOPSIS int vc_gencmd_read_response FUNCTION Block until something comes back RETURNS Error code from dequeue message ******************************************************************************/ int vc_gencmd_read_response (char *response, int maxlen) { int i = 0; int success = -1; int ret_code = 0; int32_t sem_ok = 0; if(lock_obtain() == 0) { //Note this will ALWAYS reset response buffer and overwrite any partially read responses use_gencmd_service(); do { //TODO : we need to deal with messages coming through on more than one connections properly //At the moment it will always try to read the first connection if there is something there for(i = 0; i < gencmd_client.num_connections; i++) { //Check if there is something in the queue, if so return immediately //otherwise wait for the event and read again success = (int) vchi_msg_dequeue( gencmd_client.open_handle[i], gencmd_client.response_buffer, sizeof(gencmd_client.response_buffer), &gencmd_client.response_length, VCHI_FLAGS_NONE); if(success == 0) { #ifdef __NetBSD__ uint32_t v; #endif #ifdef __NetBSD__ memcpy(&v, gencmd_client.response_buffer, sizeof(v)); ret_code = VC_VTOH32(v); #else ret_code = VC_VTOH32( *(int *)gencmd_client.response_buffer ); #endif break; } else { gencmd_client.response_length = 0; } } } while(!gencmd_client.response_length && vcos_event_wait(&gencmd_client.message_available_event) == VCOS_SUCCESS); if(gencmd_client.response_length && sem_ok == 0) { gencmd_client.response_length -= sizeof(int); //first word is error code memcpy(response, gencmd_client.response_buffer+sizeof(int), (size_t) vcos_min((int)gencmd_client.response_length, (int)maxlen)); } release_gencmd_service(); lock_release(); } // If we read anything, return the VideoCore code. Error codes < 0 mean we failed to // read anything... //How do we let the caller know the response code of gencmd? //return ret_code; return success; }
/****************************************************************************** NAME vc_gencmd SYNOPSIS int vc_gencmd(char *response, int maxlen, const char *format, ...) FUNCTION Send a gencmd and receive the response as per vc_gencmd read_response. RETURNS int ******************************************************************************/ int vc_gencmd(char *response, int maxlen, const char *format, ...) { va_list args; int ret = -1; use_gencmd_service(); va_start(args, format); ret = vc_gencmd_send_list(format, args); va_end (args); if (ret >= 0) { ret = vc_gencmd_read_response(response, maxlen); } release_gencmd_service(); return ret; }
void vc_vchi_gencmd_init (VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections ) { VCOS_STATUS_T status; int32_t success; int i; if (gencmd_client.initialised) return; // record the number of connections memset( &gencmd_client, 0, sizeof(GENCMD_SERVICE_T) ); gencmd_client.num_connections = (int) num_connections; status = vcos_mutex_create(&gencmd_client.lock, "HGencmd"); vcos_assert(status == VCOS_SUCCESS); status = vcos_event_create(&gencmd_client.message_available_event, "HGencmd"); vcos_assert(status == VCOS_SUCCESS); for (i=0; i<gencmd_client.num_connections; i++) { // Create a 'LONG' service on the each of the connections SERVICE_CREATION_T gencmd_parameters = { VCHI_VERSION(VC_GENCMD_VER), MAKE_FOURCC("GCMD"), // 4cc service code connections[i], // passed in fn ptrs 0, // tx fifo size (unused) 0, // tx fifo size (unused) &gencmd_callback, // service callback &gencmd_client.message_available_event, // callback parameter VC_FALSE, // want_unaligned_bulk_rx VC_FALSE, // want_unaligned_bulk_tx VC_FALSE // want_crc }; success = vchi_service_open( initialise_instance, &gencmd_parameters, &gencmd_client.open_handle[i] ); assert( success == 0 ); } gencmd_client.initialised = 1; release_gencmd_service(); }