+/* 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_API_NOTICE(afbBindingRoot, "RX-MSG: discarded, payload exceeds %d bytes", CTRL_MAX_DATA_SZ);
+ return;
+ }
+
+ json_object *j_query = NULL;
+ int node = (int)src_addr;
+ int msgid = (int)msg_id;
+ size_t data_size = (size_t)data_sz;
+
+ /* skip data attribute if possible, wrap_json_unpack may fail to deal with
+ * an empty Base64 string */
+ if (data_size > 0)
+ wrap_json_pack(&j_query, "{s:i, s:i, s:Y*}", "node", node, "msgid", msgid, "data", data_ptr, data_size);
+ else
+ wrap_json_pack(&j_query, "{s:i, s:i}", "node", node, "msgid", msgid);
+
+ afb_event_push(eventDataRx->rx_event, j_query);
+}
+
+/** 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_API_DEBUG(afbBindingRoot, "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)
+{
+ static sd_event_source *src_ptr = NULL;
+
+ if (!src_ptr)
+ {
+ /* first time usage: create and trigger event source */
+ sd_event_add_defer(afb_api_get_event_loop(afbBindingRoot), &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)
+{
+ AFB_API_NOTICE (afbBindingRoot, "Route 0x%X is active=%d, connection label=0x%X", routeId, isActive, connectionLabel);
+}
+
+void UCSI_CB_OnGpioStateChange(void *pTag, uint16_t nodeAddress, uint8_t gpioPinId, bool isHighState)
+{
+ AFB_API_NOTICE (afbBindingRoot, "GPIO state of node 0x%X changed, pin=%d isHigh=%d", nodeAddress, gpioPinId, isHighState);
+}
+
+PUBLIC void UCSI_CB_OnMgrReport(void *pTag, Ucs_MgrReport_t code, uint16_t nodeAddress, Ucs_Rm_Node_t *pNode){
+
+ bool available;
+
+ if (code == UCS_MGR_REP_AVAILABLE) {
+ available = true;
+ }
+ else if (code == UCS_MGR_REP_NOT_AVAILABLE) {
+ available = false;
+ }
+ else {
+ /*untracked event - just exit*/
+ return;
+ }
+
+ if (eventData) {
+
+ json_object *j_event_info = json_object_new_object();
+ json_object_object_add(j_event_info, "node", json_object_new_int(nodeAddress));
+ json_object_object_add(j_event_info, "available", json_object_new_boolean(available));
+
+ afb_event_push(eventData->node_event, j_event_info);
+ }