/****************************************************************************** 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; }
void vc_gencmd_stop () { // Assume a "power down" gencmd has been sent and the lock is held. There will // be no response so this should be called instead. int32_t success,i; if (!gencmd_client.initialised) return; if(lock_obtain() == 0) { use_gencmd_service(); for(i = 0; i< (int32_t)gencmd_client.num_connections; i++) { success = vchi_service_close( gencmd_client.open_handle[i]); assert(success == 0); } gencmd_client.initialised = 0; lock_release(); vcos_mutex_delete(&gencmd_client.lock); vcos_event_delete(&gencmd_client.message_available_event); } }
/****************************************************************************** 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; }