X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=ucs2-afb%2Fucs_binding.c;h=ddf44b1727f0e268abd4949677eff7e424bab05c;hb=84c3e1b169038e181526b4fbadab3d8f9322717c;hp=b8a1ba89de2db299a6fcc426a970b20e436d4580;hpb=dccdd78ea136c2481f0558cb3030a9add3a2004a;p=apps%2Fagl-service-unicens.git diff --git a/ucs2-afb/ucs_binding.c b/ucs2-afb/ucs_binding.c index b8a1ba8..ddf44b1 100644 --- a/ucs2-afb/ucs_binding.c +++ b/ucs2-afb/ucs_binding.c @@ -24,6 +24,8 @@ #define BUFFER_FRAME_COUNT 10 /* max frames in buffer */ #define WAIT_TIMER_US 1000000 /* default waiting timer 1s */ #define I2C_MAX_DATA_SZ 32 /* max. number of bytes to be written to i2c */ +#define CTRL_MAX_DATA_SZ 45 /* max. number of bytes to be written to control + * channel */ #include #include @@ -42,7 +44,7 @@ #define MAX_FILENAME_LEN (100) #define RX_BUFFER (64) -#define XML_CONFIG_FOLDER "/data/" +#define XML_CONFIG_FOLDER "/var/" #define XML_CONFIG_FILE "config_multichannel_audio_kit.xml" /** Internal structure, enabling multiple instances of this component. @@ -66,11 +68,15 @@ typedef struct { typedef struct { struct afb_event node_event; - } EventData_t; +typedef struct { + struct afb_event rx_event; +} EventDataRx_t; + static ucsContextT *ucsContextS = NULL; static EventData_t *eventData = NULL; +static EventDataRx_t *eventDataRx = NULL; PUBLIC void UcsXml_CB_OnError(const char format[], uint16_t vargsCnt, ...) { /*AFB_DEBUG (afbIface, format, args); */ @@ -190,6 +196,7 @@ STATIC int OnStopCB (sd_event_source *source, uint64_t usec, void *pTag) { UcsXml_FreeVal(ucsContextS->ucsConfig); ucsContextS->ucsConfig = NULL; } + return 0; } /** @@ -205,12 +212,74 @@ void UCSI_CB_OnStop(void *pTag) { sd_event_add_time(afb_daemon_get_event_loop(), NULL, CLOCK_MONOTONIC, 0, 0, OnStopCB, pTag); } +/* helper function: wraps Rx message in json and triggers notification */ +STATIC void NotifyEventRxMsg(uint16_t src_addr, uint16_t msg_id, uint8_t *data_ptr, uint32_t data_sz) { + + if (!eventDataRx) + return; + + if (data_sz > CTRL_MAX_DATA_SZ) { + AFB_NOTICE("RX-MSG: discarded, payload exceeds %d bytes", CTRL_MAX_DATA_SZ); + return; + } + + json_object *j_event_info = json_object_new_object(); + json_object *j_array = json_object_new_array(); + + if (!j_event_info || !j_array) { + if (j_event_info) { + json_object_put(j_event_info); + } + if (j_array) { + json_object_put(j_array); + } + AFB_ERROR("Failed to create json objects"); + return; + } + + uint32_t cnt = 0U; + for (cnt = 0U; cnt < data_sz; cnt++) { + json_object_array_add(j_array, json_object_new_int(data_ptr[cnt])); + } + + json_object_object_add(j_event_info, "node", json_object_new_int(src_addr)); + json_object_object_add(j_event_info, "msgid", json_object_new_int(msg_id)); + json_object_object_add(j_event_info, "data", j_array); + + afb_event_push(eventDataRx->rx_event, j_event_info); +} + +/** Asynchronous processing of Rx messages in mainloop is recommended */ +STATIC int OnAmsMessageReceivedCB (sd_event_source *source, void *pTag) { + ucsContextT *ucsContext = (ucsContextT*) pTag; + uint32_t data_sz = 0U; + uint8_t *data_ptr = NULL; + uint16_t msg_id = 0U; + uint16_t src_addr = 0U; + + while (UCSI_GetAmsMessage(&ucsContext->ucsiData, &msg_id, &src_addr, &data_ptr, &data_sz)) { + NotifyEventRxMsg(src_addr, msg_id, data_ptr, data_sz); + AFB_DEBUG("RX-MSG: src=0x%04X, msg_id=0x%04X, size=%d", src_addr, msg_id, data_sz); + UCSI_ReleaseAmsMessage(&ucsContext->ucsiData); + } + + return 0; +} + /** This callback will be raised, when ever an applicative message on the control channel arrived */ void UCSI_CB_OnAmsMessageReceived(void *pTag) { - /* If not interested, just ignore this event. - Otherwise UCSI_GetAmsMessage may now be called asynchronous (mainloop) to get the content. - Don't forget to call UCSI_ReleaseAmsMessage after that */ + static sd_event_source *src_ptr = NULL; + + if (!src_ptr) + { + /* first time usage: create and trigger event source */ + sd_event_add_defer(afb_daemon_get_event_loop(), &src_ptr, &OnAmsMessageReceivedCB, pTag); + } + else + { + sd_event_source_set_enabled(src_ptr, SD_EVENT_ONESHOT); + } } void UCSI_CB_OnRouteResult(void *pTag, uint16_t routeId, bool isActive, uint16_t connectionLabel) @@ -508,6 +577,75 @@ OnExitError: return; } +PUBLIC void ucs2_subscriberx (struct afb_req request) { + + if (!eventDataRx) { + + eventDataRx = malloc(sizeof(EventDataRx_t)); + if (eventDataRx) { + eventDataRx->rx_event = afb_daemon_make_event("rx-message"); + } + + if (!eventDataRx || !afb_event_is_valid(eventDataRx->rx_event)) { + afb_req_fail_f(request, "create-event", "Cannot create or register event"); + goto OnExitError; + } + } + + if (afb_req_subscribe(request, eventDataRx->rx_event) != 0) { + + afb_req_fail_f (request, "subscribe-event", "Cannot subscribe to event"); + goto OnExitError; + } + + afb_req_success(request,NULL,"event subscription successful"); + +OnExitError: + return; +} + +static json_object * ucs2_validate_command (struct afb_req request, + const char* func_name) { + + struct json_object *j_obj = NULL; + + if (!ucsContextS) { /* check UNICENS is initialized */ + afb_req_fail_f(request, "unicens-init", + "Load a configuration before calling %s.", + func_name); + goto OnErrorExit; + } + + j_obj = afb_req_json(request); + if (!j_obj) { + afb_req_fail_f(request, + "query-notjson","query=%s not a valid json entry", + afb_req_value(request,"")); + goto OnErrorExit; + } + + AFB_DEBUG("request: %s", json_object_to_json_string(j_obj)); + + if (json_object_get_type(j_obj)==json_type_array) { + int len = json_object_array_length(j_obj); + + if (len == 1) { /* only support 1 command in array */ + j_obj = json_object_array_get_idx(j_obj, 0); + } + else { + afb_req_fail_f(request, + "query-array", + "query of multiple %s commands is not supported", + func_name); + j_obj = NULL; + goto OnErrorExit; + } + } + + OnErrorExit: + return j_obj; +} + STATIC void ucs2_writei2c_CB (void *result_ptr, void *request_ptr) { if (request_ptr){ @@ -539,28 +677,34 @@ STATIC void ucs2_writei2c_cmd(struct afb_req request, json_object *j_obj) { uint8_t i2c_data_sz = 0; uint16_t node_addr = 0; struct afb_req *async_req_ptr = NULL; - - node_addr = (uint16_t)json_object_get_int(json_object_object_get(j_obj, "node")); - AFB_NOTICE("node_address: 0x%02X", node_addr); - - if (node_addr == 0) { - afb_req_fail_f(request, "query-params","params wrong or missing"); + json_object *j_tmp; + json_bool key_found; + + if (json_object_object_get_ex(j_obj, "node", &j_tmp)) { + node_addr = (uint16_t)json_object_get_int(j_tmp); + AFB_NOTICE("node_address: 0x%02X", node_addr); + if (node_addr == 0) { + afb_req_fail_f(request, "query-params","param node invalid type"); + goto OnErrorExit; + } + } + else { + afb_req_fail_f(request, "query-params","param node missing"); goto OnErrorExit; } - if (json_object_get_type(json_object_object_get(j_obj, "data"))==json_type_array) { - int size = json_object_array_length(json_object_object_get(j_obj, "data")); + key_found = json_object_object_get_ex(j_obj, "data", &j_tmp); + if (key_found && (json_object_get_type(j_tmp)==json_type_array)) { + int size = json_object_array_length(j_tmp); if ((size > 0) && (size <= I2C_MAX_DATA_SZ)) { int32_t i; int32_t val; struct json_object *j_elem; - struct json_object *j_arr = json_object_object_get(j_obj, "data"); for (i = 0; i < size; i++) { - - j_elem = json_object_array_get_idx(j_arr, i); + j_elem = json_object_array_get_idx(j_tmp, i); val = json_object_get_int(j_elem); if ((val < 0) && (val > 0xFF)){ i = 0; @@ -613,44 +757,110 @@ PUBLIC void ucs2_writei2c (struct afb_req request) { struct json_object *j_obj; - /* check UNICENS is initialised */ - if (!ucsContextS) { - afb_req_fail_f(request, "unicens-init","Should Load Config before using setvol"); - goto OnErrorExit; - } - - j_obj = afb_req_json(request); - if (!j_obj) { - afb_req_fail_f(request, "query-notjson","query=%s not a valid json entry", afb_req_value(request,"")); - goto OnErrorExit; - }; + j_obj = ucs2_validate_command(request, "writei2c"); - AFB_DEBUG("request: %s", json_object_to_json_string(j_obj)); + if (j_obj) { + ucs2_writei2c_cmd(request, j_obj); + } +} - if (json_object_get_type(j_obj)==json_type_array) { +/* write a single control message */ +STATIC void ucs2_sendmessage_cmd(struct afb_req request, json_object *j_obj) { - int cnt; - int len = json_object_array_length(j_obj); + static uint8_t ctrl_data[CTRL_MAX_DATA_SZ]; + uint8_t ctrl_data_sz = 0; + uint16_t node_addr = 0; + uint16_t msg_id = 0; + json_object *j_tmp; + + if (json_object_object_get_ex(j_obj, "node", &j_tmp)) { + node_addr = (uint16_t)json_object_get_int(j_tmp); + AFB_NOTICE("node_address: 0x%02X", node_addr); + if (node_addr == 0) { + afb_req_fail_f(request, "query-params","param node invalid type"); + goto OnErrorExit; + } + } + else { + afb_req_fail_f(request, "query-params","param node missing"); + goto OnErrorExit; + } - if (len != 1) { - afb_req_fail_f(request, "query-array","query of multiple commands is not supported"); + if (json_object_object_get_ex(j_obj, "msgid", &j_tmp)) { + if (json_object_get_type(j_tmp) == json_type_int) { + msg_id = (uint16_t)json_object_get_int(j_tmp); + AFB_NOTICE("msgid: 0x%02X", msg_id); + } + else { + afb_req_fail_f(request, "query-params","param msgid invalid type"); goto OnErrorExit; } + } + else { + afb_req_fail_f(request, "query-params","param msgid missing"); + goto OnErrorExit; + } + + if (json_object_object_get_ex(j_obj, "data", &j_tmp)) { + if (json_object_get_type(j_tmp)==json_type_array) { + int size = json_object_array_length(j_tmp); + if ((size > 0) && (size <= CTRL_MAX_DATA_SZ)) { + int32_t i; + int32_t val; + struct json_object *j_elem; + + for (i = 0; i < size; i++) { + j_elem = json_object_array_get_idx(j_tmp, i); + val = json_object_get_int(j_elem); + if ((val < 0) && (val > 0xFF)){ + i = 0; + break; + } + ctrl_data[i] = (uint8_t)json_object_get_int(j_elem); + } - for (cnt = 0; cnt < len; cnt++) { + if (i != size) { /* check if size matches */ + afb_req_fail_f(request, "query-params", + "parameter data is ambiguous"); + goto OnErrorExit; + } - json_object *j_cmd = json_object_array_get_idx(j_obj, cnt); - ucs2_writei2c_cmd(request, j_cmd); + ctrl_data_sz = (uint8_t)i; + } } } + + if (UCSI_SendAmsMessage(&ucsContextS->ucsiData, /* UCSI_Data_t *pPriv*/ + msg_id, + node_addr, + &ctrl_data[0], + ctrl_data_sz)) { + afb_req_success(request, NULL, "sendmessage started successful"); + } else { - ucs2_writei2c_cmd(request, j_obj); + AFB_NOTICE("sendmessage: scheduling command failed"); + afb_req_fail_f(request, "query-command-queue","command queue overload"); + goto OnErrorExit; } - OnErrorExit: +OnErrorExit: return; } +PUBLIC void ucs2_sendmessage(struct afb_req request) { + struct json_object *j_obj; + + j_obj = ucs2_validate_command(request, "sendmessage"); + + if (j_obj) { + ucs2_sendmessage_cmd(request, j_obj); + } +} + +PUBLIC void ucs2_sendmessageb64(struct afb_req req) { + afb_req_fail_f(req, "not-implemented", "Function not yet implemented."); +} + PUBLIC int ucs2_initbinding(void) { #ifndef DISABLE_AUTOSTART char *filename = GetDefaultConfig();