|
@@ -18,7 +18,7 @@
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
*
|
|
|
*/
|
|
|
- #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
|
|
|
+//#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
|
|
|
#include <stdlib.h>
|
|
|
#include <string.h>
|
|
|
#include <unistd.h>
|
|
@@ -29,7 +29,6 @@
|
|
|
#include "config.h"
|
|
|
#include "audio_controls.h"
|
|
|
|
|
|
-
|
|
|
typedef esp_err_t (actrls_config_map_handler) (const cJSON * member, actrls_config_t *cur_config,uint32_t offset);
|
|
|
typedef struct {
|
|
|
char * member;
|
|
@@ -37,8 +36,6 @@ 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);
|
|
@@ -71,6 +68,7 @@ static const char * TAG = "audio controls";
|
|
|
static actrls_config_t *json_config;
|
|
|
cJSON * control_profiles = NULL;
|
|
|
static actrls_t default_controls, current_controls;
|
|
|
+static actrls_hook_t *default_hook, *current_hook;
|
|
|
|
|
|
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;
|
|
@@ -92,34 +90,33 @@ static void control_handler(void *client, button_event_e event, button_press_e p
|
|
|
|
|
|
ESP_LOGD(TAG, "control gpio:%u press:%u long:%u event:%u action:%u", key->gpio, press, long_press, event,action_detail.action);
|
|
|
|
|
|
+ // stop here if control hook served the request
|
|
|
+ if (current_hook && (*current_hook)(key->gpio, action_detail.action, event, press, long_press)) return;
|
|
|
+
|
|
|
+ // otherwise process using configuration
|
|
|
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;
|
|
|
+ if (profile_obj) {
|
|
|
+ actrls_config_t *cur_config = (actrls_config_t *) cJSON_GetStringValue(profile_obj);
|
|
|
+ if (cur_config) {
|
|
|
ESP_LOGD(TAG,"Remapping all the buttons that are found in the new profile");
|
|
|
- while(cur_config){
|
|
|
+ while (cur_config->gpio != -1) {
|
|
|
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 {
|
|
|
+ } else {
|
|
|
ESP_LOGE(TAG,"Profile %s exists, but is empty. Cannot remap buttons",action_detail.name);
|
|
|
}
|
|
|
-
|
|
|
- }
|
|
|
- else {
|
|
|
+ } 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])();
|
|
|
- }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -163,7 +160,8 @@ 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;
|
|
|
+
|
|
|
+ if(!strcasecmp("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;
|
|
@@ -174,15 +172,14 @@ static actrls_action_e actrls_parse_action_json(const char * name){
|
|
|
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{
|
|
|
+ if (!existing) {
|
|
|
+ ESP_LOGD(TAG,"Loading new audio control profile with name: %s", name);
|
|
|
+ if (actrls_init_json(name, false) == ESP_OK) {
|
|
|
+ action = ACTRLS_REMAP;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
ESP_LOGD(TAG,"Existing profile %s was referenced", name);
|
|
|
+ action = ACTRLS_REMAP;
|
|
|
}
|
|
|
|
|
|
return action;
|
|
@@ -224,17 +221,15 @@ static esp_err_t actrls_process_type (const cJSON * member, actrls_config_t *cur
|
|
|
*/
|
|
|
static esp_err_t actrls_process_bool (const cJSON * member, actrls_config_t *cur_config, uint32_t offset){
|
|
|
esp_err_t err = ESP_OK;
|
|
|
- if(!member) {
|
|
|
+ if (!member) {
|
|
|
ESP_LOGE(TAG,"Null json member pointer!");
|
|
|
err = ESP_FAIL;
|
|
|
- }
|
|
|
- else {
|
|
|
+ } else {
|
|
|
ESP_LOGD(TAG,"Processing bool member ");
|
|
|
- if(cJSON_IsBool(member)){
|
|
|
+ if (cJSON_IsBool(member)) {
|
|
|
bool*value = (bool*)((char*) cur_config + offset);
|
|
|
*value = cJSON_IsTrue(member);
|
|
|
- }
|
|
|
- else {
|
|
|
+ } else {
|
|
|
ESP_LOGE(TAG,"Member %s is not a boolean", member->string?member->string:"unknown");
|
|
|
err = ESP_FAIL;
|
|
|
}
|
|
@@ -255,22 +250,14 @@ static esp_err_t actrls_process_action (const cJSON * member, actrls_config_t *c
|
|
|
if(value[0].action == ACTRLS_REMAP){
|
|
|
value[0].name = strdup(button_action->valuestring);
|
|
|
}
|
|
|
- }
|
|
|
- else{
|
|
|
- ESP_LOGW(TAG,"Action pressed not found in json structure");
|
|
|
- err = ESP_FAIL;
|
|
|
- }
|
|
|
+ }
|
|
|
button_action = cJSON_GetObjectItemCaseSensitive(member, "released");
|
|
|
if (button_action != NULL) {
|
|
|
value[1].action = actrls_parse_action_json( button_action->valuestring);
|
|
|
- if(value[1].action == ACTRLS_REMAP){
|
|
|
+ if (value[1].action == ACTRLS_REMAP){
|
|
|
value[1].name = strdup(button_action->valuestring);
|
|
|
}
|
|
|
}
|
|
|
- else{
|
|
|
- ESP_LOGW(TAG,"Action released not found in json structure");
|
|
|
- err = ESP_FAIL;
|
|
|
- }
|
|
|
|
|
|
return err;
|
|
|
}
|
|
@@ -293,7 +280,7 @@ static esp_err_t actrls_process_member(const cJSON * member, actrls_config_t *cu
|
|
|
ESP_LOGE(TAG, "Unknown json structure member : %s", str?str:"");
|
|
|
}
|
|
|
|
|
|
- if(str) free(str);
|
|
|
+ if (str) free(str);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -327,25 +314,20 @@ static actrls_config_t * actrls_init_alloc_structure(const cJSON *buttons, const
|
|
|
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);
|
|
|
+ ESP_LOGD(TAG, "config contains %u button definitions", member_count);
|
|
|
if (member_count != 0) {
|
|
|
- json_config = malloc(sizeof(actrls_config_t) * member_count+1);
|
|
|
- if(json_config){
|
|
|
- memset(json_config, 0x00, sizeof(actrls_config_t) * member_count+1);
|
|
|
- }
|
|
|
- else {
|
|
|
+ json_config = calloc(sizeof(actrls_config_t) * (member_count + 1), 1);
|
|
|
+ if (json_config){
|
|
|
+ json_config[member_count].gpio = -1;
|
|
|
+ } else {
|
|
|
ESP_LOGE(TAG,"Unable to allocate memory to hold configuration for %u buttons ",member_count);
|
|
|
}
|
|
|
-
|
|
|
- }
|
|
|
- else {
|
|
|
+ } else {
|
|
|
ESP_LOGE(TAG,"No button found in configuration structure");
|
|
|
}
|
|
|
|
|
@@ -355,21 +337,34 @@ static actrls_config_t * actrls_init_alloc_structure(const cJSON *buttons, const
|
|
|
cJSON * new_profile = cJSON_CreateStringReference((const char *)json_config);
|
|
|
cJSON_AddItemToObject(control_profiles, name, new_profile);
|
|
|
|
|
|
-
|
|
|
return json_config;
|
|
|
}
|
|
|
|
|
|
+/****************************************************************************************
|
|
|
+ *
|
|
|
+ */
|
|
|
+static void actrls_defaults(actrls_config_t *config) {
|
|
|
+ config->type = BUTTON_LOW;
|
|
|
+ config->pull = false;
|
|
|
+ config->debounce = 0;
|
|
|
+ config->long_press = 0;
|
|
|
+ config->shifter_gpio = -1;
|
|
|
+ config->normal[0].action = config->normal[1].action = ACTRLS_NONE;
|
|
|
+ config->longpress[0].action = config->longpress[1].action = ACTRLS_NONE;
|
|
|
+ config->shifted[0].action = config->shifted[1].action = ACTRLS_NONE;
|
|
|
+ config->longshifted[0].action = config->longshifted[1].action = ACTRLS_NONE;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
/****************************************************************************************
|
|
|
*
|
|
|
*/
|
|
|
-esp_err_t actrls_init_json(const char *profile_name) {
|
|
|
+esp_err_t actrls_init_json(const char *profile_name, bool create) {
|
|
|
esp_err_t err = ESP_OK;
|
|
|
actrls_config_t *cur_config = NULL;
|
|
|
actrls_config_t *config_root = NULL;
|
|
|
const cJSON *button;
|
|
|
|
|
|
-
|
|
|
char *config = config_alloc_get_default(NVS_TYPE_STR, profile_name, NULL, 0);
|
|
|
if(!config) return ESP_FAIL;
|
|
|
|
|
@@ -378,8 +373,7 @@ esp_err_t actrls_init_json(const char *profile_name) {
|
|
|
if (buttons == NULL) {
|
|
|
ESP_LOGE(TAG,"JSON Parsing failed for %s", config);
|
|
|
err = ESP_FAIL;
|
|
|
- }
|
|
|
- else {
|
|
|
+ } else {
|
|
|
ESP_LOGD(TAG,"Json parsing completed");
|
|
|
if (cJSON_IsArray(buttons)) {
|
|
|
ESP_LOGD(TAG,"configuration is an array as expected");
|
|
@@ -396,20 +390,19 @@ esp_err_t actrls_init_json(const char *profile_name) {
|
|
|
if(str){
|
|
|
free(str);
|
|
|
}
|
|
|
+ actrls_defaults(cur_config);
|
|
|
esp_err_t loc_err = actrls_process_button(button, cur_config);
|
|
|
err = (err == ESP_OK) ? loc_err : err;
|
|
|
if (loc_err == ESP_OK) {
|
|
|
- button_create((void*) cur_config, cur_config->gpio,cur_config->type, cur_config->pull,cur_config->debounce,
|
|
|
+ if (create) button_create((void*) cur_config, cur_config->gpio,cur_config->type, cur_config->pull,cur_config->debounce,
|
|
|
control_handler, cur_config->long_press, cur_config->shifter_gpio);
|
|
|
- }
|
|
|
- else{
|
|
|
+ } else {
|
|
|
ESP_LOGE(TAG,"Error parsing button structure. Button will not be registered.");
|
|
|
}
|
|
|
|
|
|
cur_config++;
|
|
|
}
|
|
|
- }
|
|
|
- else {
|
|
|
+ } else {
|
|
|
ESP_LOGE(TAG,"Invalid configuration; array is expected and none received in %s ", config);
|
|
|
}
|
|
|
cJSON_Delete(buttons);
|
|
@@ -424,16 +417,18 @@ esp_err_t actrls_init_json(const char *profile_name) {
|
|
|
/****************************************************************************************
|
|
|
*
|
|
|
*/
|
|
|
-void actrls_set_default(const actrls_t controls) {
|
|
|
+void actrls_set_default(const actrls_t controls, actrls_hook_t *hook) {
|
|
|
memcpy(default_controls, controls, sizeof(actrls_t));
|
|
|
memcpy(current_controls, default_controls, sizeof(actrls_t));
|
|
|
+ default_hook = current_hook = hook;
|
|
|
}
|
|
|
|
|
|
/****************************************************************************************
|
|
|
*
|
|
|
*/
|
|
|
-void actrls_set(const actrls_t controls) {
|
|
|
+void actrls_set(const actrls_t controls, actrls_hook_t *hook) {
|
|
|
memcpy(current_controls, controls, sizeof(actrls_t));
|
|
|
+ current_hook = hook;
|
|
|
}
|
|
|
|
|
|
/****************************************************************************************
|
|
@@ -441,4 +436,5 @@ void actrls_set(const actrls_t controls) {
|
|
|
*/
|
|
|
void actrls_unset(void) {
|
|
|
memcpy(current_controls, default_controls, sizeof(actrls_t));
|
|
|
+ current_hook = default_hook;
|
|
|
}
|