Browse Source

WIP - Audio Control Profile navigation

Sebastien 5 years ago
parent
commit
4dbed9ecb4
3 changed files with 109 additions and 43 deletions
  1. 101 27
      components/services/audio_controls.c
  2. 7 6
      components/services/audio_controls.h
  3. 1 10
      main/esp_app_main.c

+ 101 - 27
components/services/audio_controls.c

@@ -18,7 +18,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
- 
+ #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -26,6 +26,7 @@
 #include "esp_log.h"
 #include "cJSON.h"
 #include "buttons.h"
+#include "config.h"
 #include "audio_controls.h"
 
 
@@ -36,6 +37,8 @@ typedef struct {
 	actrls_config_map_handler * handler;
 } actrls_config_map_t;
 
+
+
 static esp_err_t actrls_process_member(const cJSON * member, actrls_config_t *cur_config);
 static esp_err_t actrls_process_button(const cJSON * button, actrls_config_t *cur_config);
 static esp_err_t actrls_process_int (const cJSON * member, actrls_config_t *cur_config, uint32_t offset);
@@ -66,34 +69,56 @@ static const char * actrls_action_s[ ] = { EP(ACTRLS_VOLUP),EP(ACTRLS_VOLDOWN),E
 									
 static const char * TAG = "audio controls";
 static actrls_config_t *json_config;
+cJSON * control_profiles = NULL;
 static actrls_t default_controls, current_controls;
 
 static void control_handler(void *client, button_event_e event, button_press_e press, bool long_press) {
 	actrls_config_t *key = (actrls_config_t*) client;
-	actrls_action_e action;
+	actrls_action_detail_t  action_detail;
 
 	switch(press) {
 	case BUTTON_NORMAL:
-		if (long_press) action = key->longpress[event == BUTTON_PRESSED ? 0 : 1].action;
-		else action = key->normal[event == BUTTON_PRESSED ? 0 : 1].action;
+		if (long_press) action_detail = key->longpress[event == BUTTON_PRESSED ? 0 : 1];
+		else action_detail = key->normal[event == BUTTON_PRESSED ? 0 : 1];
 		break;
 	case BUTTON_SHIFTED:
-		if (long_press) action = key->longshifted[event == BUTTON_PRESSED ? 0 : 1].action;
-		else action = key->shifted[event == BUTTON_PRESSED ? 0 : 1].action;
+		if (long_press) action_detail = key->longshifted[event == BUTTON_PRESSED ? 0 : 1];
+		else action_detail = key->shifted[event == BUTTON_PRESSED ? 0 : 1];
 		break;
 	default:
-		action = ACTRLS_NONE;
+		action_detail.action = ACTRLS_NONE;
 		break;
 	}
 	
-	ESP_LOGD(TAG, "control gpio:%u press:%u long:%u event:%u action:%u", key->gpio, press, long_press, event, action);
-
-	if (action > ACTRLS_MAX) {
-		// need to do the remap here using button_remap
-		ESP_LOGD(TAG, "remapping buttons");
-	} else if (action != ACTRLS_NONE) {
-		ESP_LOGD(TAG, "calling action %u", action);
-		if (current_controls[action]) (*current_controls[action])();
+	ESP_LOGD(TAG, "control gpio:%u press:%u long:%u event:%u action:%u", key->gpio, press, long_press, event,action_detail.action);
+
+	if (action_detail.action == ACTRLS_REMAP) {
+		// remap requested
+		ESP_LOGD(TAG, "remapping buttons to profile %s",action_detail.name);
+		cJSON * profile_obj = cJSON_GetObjectItem(control_profiles,action_detail.name);
+		if(profile_obj){
+			actrls_config_t * profile  = (actrls_config_t *) cJSON_GetStringValue(profile_obj);
+			if(profile){
+				actrls_config_t *cur_config =profile;
+				ESP_LOGD(TAG,"Remapping all the buttons that are found in the new profile");
+				while(cur_config){
+					ESP_LOGD(TAG,"Remapping button with gpio %u", cur_config->gpio);
+					button_remap((void*) cur_config, cur_config->gpio, control_handler, cur_config->long_press, cur_config->shifter_gpio);
+					cur_config++;
+				}
+			}
+			else {
+				ESP_LOGE(TAG,"Profile %s exists, but is empty. Cannot remap buttons",action_detail.name);
+			}
+
+		}
+		else {
+			ESP_LOGE(TAG,"Invalid profile name %s. Cannot remap buttons",action_detail.name);
+		}
+
+	} else if (action_detail.action != ACTRLS_NONE) {
+		ESP_LOGD(TAG, "calling action %u", action_detail.action);
+		if (current_controls[action_detail.action]) (*current_controls[action_detail.action])();
 	}
 }
 
@@ -137,13 +162,30 @@ esp_err_t actrls_init(int n, const actrls_config_t *config) {
  * 
  */
 static actrls_action_e actrls_parse_action_json(const char * name){
-
+	actrls_action_e action = ACTRLS_NONE;
+	if(!strcmp("ACTRLS_NONE",name)) return ACTRLS_NONE;
 	for(int i=0;i<ACTRLS_MAX && actrls_action_s[i][0]!='\0' ;i++){
 		if(!strcmp(actrls_action_s[i], name)){
 			return (actrls_action_e) i;
 		}
 	}
-	return ACTRLS_NONE;
+	// Action name wasn't recognized.
+	// Check if this is a profile name that has a match in nvs
+	ESP_LOGD(TAG,"unknown action %s, trying to find matching profile ", name);
+	cJSON * existing = cJSON_GetObjectItem(control_profiles, name);
+
+	if(!existing){
+			ESP_LOGD(TAG,"Loading new audio control profile with name: %s", name);
+			if(actrls_init_json(name)==ESP_OK){
+				action = ACTRLS_REMAP;
+			}
+
+	}
+	else{
+		ESP_LOGD(TAG,"Existing profile %s was referenced", name);
+	}
+
+	return action;
 }
 
 /****************************************************************************************
@@ -207,9 +249,12 @@ static esp_err_t actrls_process_bool (const cJSON * member, actrls_config_t *cur
 static esp_err_t actrls_process_action (const cJSON * member, actrls_config_t *cur_config, uint32_t offset){
 	esp_err_t err = ESP_OK;
 	cJSON * button_action= cJSON_GetObjectItemCaseSensitive(member, "pressed");
-	actrls_action_e*value = (actrls_action_e*)((char *)cur_config + offset);
+	actrls_action_detail_t*value = (actrls_action_detail_t*)((char *)cur_config + offset);
 	if (button_action != NULL) {
-		value[0] = actrls_parse_action_json( button_action->valuestring);
+		value[0].action = actrls_parse_action_json( button_action->valuestring);
+		if(value[0].action == ACTRLS_REMAP){
+			value[0].name = strdup(button_action->valuestring);
+		}
 	}
 	else{
 		ESP_LOGW(TAG,"Action pressed not found in json structure");
@@ -217,7 +262,10 @@ static esp_err_t actrls_process_action (const cJSON * member, actrls_config_t *c
 	}
 	button_action = cJSON_GetObjectItemCaseSensitive(member, "released");
 	if (button_action != NULL) {
-		value[1] = actrls_parse_action_json( button_action->valuestring);
+		value[1].action = actrls_parse_action_json( button_action->valuestring);
+		if(value[1].action == ACTRLS_REMAP){
+			value[1].name = strdup(button_action->valuestring);
+		}
 	}
 	else{
 		ESP_LOGW(TAG,"Action released not found in json structure");
@@ -269,20 +317,28 @@ static esp_err_t actrls_process_button(const cJSON * button, actrls_config_t *cu
 /****************************************************************************************
  * 
  */
-static actrls_config_t * actrls_init_alloc_structure(const cJSON *buttons){
+static actrls_config_t * actrls_init_alloc_structure(const cJSON *buttons, const char * name){
 	int member_count = 0;
 	const cJSON *button;
 	actrls_config_t * json_config=NULL;
+
+	// Check if the main profiles array was created
+	if(!control_profiles){
+		control_profiles = cJSON_CreateObject();
+	}
+
+
 	ESP_LOGD(TAG,"Counting the number of buttons definition");
 	cJSON_ArrayForEach(button, buttons)	{
 		member_count++;
 	}
+
 	ESP_LOGD(TAG, "config contains %u button definitions",
 			member_count);
 	if (member_count != 0) {
-		json_config = malloc(sizeof(actrls_config_t) * member_count);
+		json_config = malloc(sizeof(actrls_config_t) * member_count+1);
 		if(json_config){
-			memset(json_config, 0x00, sizeof(actrls_config_t) * member_count);
+			memset(json_config, 0x00, sizeof(actrls_config_t) * member_count+1);
 		}
 		else {
 			ESP_LOGE(TAG,"Unable to allocate memory to hold configuration for %u buttons ",member_count);
@@ -293,17 +349,31 @@ static actrls_config_t * actrls_init_alloc_structure(const cJSON *buttons){
 		ESP_LOGE(TAG,"No button found in configuration structure");
 	}
 
+	// we're cheating here; we're going to store the control profile
+	// pointer as a string reference;  this will prevent cJSON
+	// from trying to free the structure if we ever want to free the object
+	cJSON * new_profile = cJSON_CreateStringReference((const char *)json_config);
+	cJSON_AddItemToObject(control_profiles, name, new_profile);
+
+
 	return json_config;
 }
 
+
 /****************************************************************************************
  * 
  */
-esp_err_t actrls_init_json(const char *config) {
+esp_err_t actrls_init_json(const char *profile_name) {
 	esp_err_t err = ESP_OK;
-	actrls_config_t *cur_config;
+	actrls_config_t *cur_config = NULL;
+	actrls_config_t *config_root = NULL;
 	const cJSON *button;
-	ESP_LOGD(TAG,"Parsing JSON structure ");
+
+
+	char *config = config_alloc_get_default(NVS_TYPE_STR, profile_name, NULL, 0);
+	if(!config) return ESP_FAIL;
+
+	ESP_LOGD(TAG,"Parsing JSON structure %s", config);
 	cJSON *buttons = cJSON_Parse(config);
 	if (buttons == NULL) {
 		ESP_LOGE(TAG,"JSON Parsing failed for %s", config);
@@ -313,7 +383,7 @@ esp_err_t actrls_init_json(const char *config) {
 		ESP_LOGD(TAG,"Json parsing completed");
 		if (cJSON_IsArray(buttons)) {
 			ESP_LOGD(TAG,"configuration is an array as expected");
-			cur_config = json_config = actrls_init_alloc_structure(buttons);
+			cur_config =config_root= actrls_init_alloc_structure(buttons, profile_name);
 			if(!cur_config) {
 				ESP_LOGE(TAG,"Config buffer was empty. ");
 				cJSON_Delete(buttons);
@@ -344,6 +414,10 @@ esp_err_t actrls_init_json(const char *config) {
 		}
 		cJSON_Delete(buttons);
 	}
+	// Now update the global json_config object.  If we are recursively processing menu structures,
+	// the last init that completes will assigh the first json config object found, which will match
+	// the default config from nvs.
+	json_config = config_root;
 	return err;
 }
 

+ 7 - 6
components/services/audio_controls.h

@@ -23,7 +23,7 @@
 // BEWARE: this is the index of the array of action below (change actrls_action_s as well!)
 typedef enum { 	ACTRLS_NONE = -1, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY, 
 				ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT, 
-				BCTRLS_PUSH, BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT,
+				BCTRLS_PUSH, BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT,ACTRLS_REMAP,
 				ACTRLS_MAX 
 		} actrls_action_e;
 
@@ -31,6 +31,10 @@ typedef void (*actrls_handler)(void);
 typedef actrls_handler actrls_t[ACTRLS_MAX - ACTRLS_NONE - 1];
 
 // BEWARE any change to struct below must be mapped to actrls_config_map
+typedef struct {
+	actrls_action_e action;
+	const char * name;
+} actrls_action_detail_t;
 typedef struct actrl_config_s {
 	int gpio;
 	int type;
@@ -38,14 +42,11 @@ typedef struct actrl_config_s {
 	int	debounce;
 	int long_press;
 	int shifter_gpio;
-	union {
-		actrls_action_e action;
-		struct actrl_config_s *config;	
-	} normal[2], longpress[2], shifted[2], longshifted[2];	// [0] keypressed, [1] keyreleased
+	actrls_action_detail_t normal[2], longpress[2], shifted[2], longshifted[2];	// [0] keypressed, [1] keyreleased
 } actrls_config_t;
 
 esp_err_t actrls_init(int n, const actrls_config_t *config);
-esp_err_t actrls_init_json(const char * config);
+esp_err_t actrls_init_json(const char *profile_name);
 void actrls_set_default(const actrls_t controls);
 void actrls_set(const actrls_t controls);
 void actrls_unset(void);

+ 1 - 10
main/esp_app_main.c

@@ -367,16 +367,7 @@ void app_main()
 	if (actrls_brd) {
 		if(actrls_brd[0] !='\0'){
 			ESP_LOGD(TAG,"Initializing audio control buttons type %s", actrls_brd);
-			char *actrls_brd_json = config_alloc_get_default(NVS_TYPE_STR, actrls_brd, NULL, 0);
-
-			if(actrls_brd_json){
-				ESP_LOGD(TAG,"with config JSON as follow: %s", actrls_brd_json );
-				actrls_init_json(actrls_brd_json);
-				free(actrls_brd_json);
-			}
-			else {
-				ESP_LOGE(TAG,"Audio controls board type %s could not be found",actrls_brd);
-			}
+			actrls_init_json(actrls_brd);
 		}
 		free(actrls_brd);
 	} else {