agl-service-unicens: Rx message event 37/12837/1
authorTobias Jahnke <tobias.jahnke@microchip.com>
Wed, 20 Dec 2017 16:29:35 +0000 (17:29 +0100)
committerTobias Jahnke <tobias.jahnke@microchip.com>
Wed, 20 Dec 2017 16:29:35 +0000 (17:29 +0100)
Bug-AGL: SPEC-1177

Implements /subscriberx function. Control Rx messages
will be notified to subscribers. If no subscriber is
assigned, then Rx messages are discarded. This avoids
Rx stuck issues after receiving multiple messages.

Change-Id: Idb71569b8ff6f651833d7d01c37a3eea866daf1d
Signed-off-by: Tobias Jahnke <tobias.jahnke@microchip.com>
conf.d/project/config.cmake
htdocs/UNICENS.html
ucs2-afb/ucs_apidef.h
ucs2-afb/ucs_apidef.json
ucs2-afb/ucs_binding.c

index 02495cb..58f568f 100644 (file)
@@ -199,7 +199,7 @@ set(AFB_REMPORT "1234" CACHE PATH "Default binder listening port")
 
 # Print a helper message when every thing is finished
 # ----------------------------------------------------
-set(CLOSING_MESSAGE "Test with: afb-daemon --ldpaths=. --port=1234 --workdir=. --roothttp=../htdocs --tracereq=common --token='' --verbose")
+set(CLOSING_MESSAGE "Test with: afb-daemon --ldpaths=./package --port=1234 --workdir=. --roothttp=../htdocs --tracereq=common --token= --verbose")
 set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt")
 
 # Optional schema validator about now only XML, LUA and JSON
index a2cdb28..e2505ae 100644 (file)
@@ -16,7 +16,8 @@
     <br>
 
     <ol>
-    <li><button onclick="callbinder('UNICENS','subscribe', {})">Subscribe to events</button></li>
+    <li><button onclick="callbinder('UNICENS','subscribe', {})">Subscribe to network events</button></li>
+    <li><button onclick="callbinder('UNICENS','subscriberx', {})">Subscribe to Rx message events</button></li>
     <li><button onclick="callbinder('UNICENS','initialise', {filename:ucs2_config})">Parse XML and Start UNICENS</button></li>
     </ol>
     <br>
index d3dfd3c..2323599 100644 (file)
@@ -34,24 +34,27 @@ static const char _afb_description_v2_UNICENS[] =
     "mponents/x-permissions/config\"},\"parameters\":[{\"in\":\"query\",\"nam"
     "e\":\"filename\",\"required\":true,\"schema\":{\"type\":\"string\"}}],\""
     "responses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}},\"/sub"
-    "scribe\":{\"description\":\"Subscribe to UNICENS Events.\",\"get\":{\"x-"
+    "scribe\":{\"description\":\"Subscribe to network events.\",\"get\":{\"x-"
     "permissions\":{\"$ref\":\"#/components/x-permissions/monitor\"},\"respon"
-    "ses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}},\"/writei2c\""
-    ":{\"description\":\"Writes I2C command to remote node.\",\"get\":{\"x-pe"
-    "rmissions\":{\"$ref\":\"#/components/x-permissions/monitor\"},\"paramete"
-    "rs\":[{\"in\":\"query\",\"name\":\"node\",\"required\":true,\"schema\":{"
-    "\"type\":\"integer\",\"format\":\"int32\"}},{\"in\":\"query\",\"name\":\""
-    "data\",\"required\":true,\"schema\":{\"type\":\"array\",\"format\":\"int"
-    "32\"},\"style\":\"simple\"}],\"responses\":{\"200\":{\"$ref\":\"#/compon"
-    "ents/responses/200\"}}}},\"/sendmessage\":{\"description\":\"Transmits a"
-    " control message to a node.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/c"
-    "omponents/x-permissions/monitor\"},\"parameters\":[{\"in\":\"query\",\"n"
-    "ame\":\"node\",\"required\":true,\"schema\":{\"type\":\"integer\",\"form"
-    "at\":\"int32\"}},{\"in\":\"query\",\"name\":\"msgid\",\"required\":true,"
-    "\"schema\":{\"type\":\"integer\",\"format\":\"int32\"}},{\"in\":\"query\""
-    ",\"name\":\"data\",\"required\":true,\"schema\":{\"type\":\"array\",\"fo"
-    "rmat\":\"int32\"},\"style\":\"simple\"}],\"responses\":{\"200\":{\"$ref\""
-    ":\"#/components/responses/200\"}}}}}}"
+    "ses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}},\"/subscribe"
+    "rx\":{\"description\":\"Subscribe to Rx control message events.\",\"get\""
+    ":{\"x-permissions\":{\"$ref\":\"#/components/x-permissions/monitor\"},\""
+    "responses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}},\"/wri"
+    "tei2c\":{\"description\":\"Writes I2C command to remote node.\",\"get\":"
+    "{\"x-permissions\":{\"$ref\":\"#/components/x-permissions/monitor\"},\"p"
+    "arameters\":[{\"in\":\"query\",\"name\":\"node\",\"required\":true,\"sch"
+    "ema\":{\"type\":\"integer\",\"format\":\"int32\"}},{\"in\":\"query\",\"n"
+    "ame\":\"data\",\"required\":true,\"schema\":{\"type\":\"array\",\"format"
+    "\":\"int32\"},\"style\":\"simple\"}],\"responses\":{\"200\":{\"$ref\":\""
+    "#/components/responses/200\"}}}},\"/sendmessage\":{\"description\":\"Tra"
+    "nsmits a control message to a node.\",\"get\":{\"x-permissions\":{\"$ref"
+    "\":\"#/components/x-permissions/monitor\"},\"parameters\":[{\"in\":\"que"
+    "ry\",\"name\":\"node\",\"required\":true,\"schema\":{\"type\":\"integer\""
+    ",\"format\":\"int32\"}},{\"in\":\"query\",\"name\":\"msgid\",\"required\""
+    ":true,\"schema\":{\"type\":\"integer\",\"format\":\"int32\"}},{\"in\":\""
+    "query\",\"name\":\"data\",\"required\":true,\"schema\":{\"type\":\"array"
+    "\",\"format\":\"int32\"},\"style\":\"simple\"}],\"responses\":{\"200\":{"
+    "\"$ref\":\"#/components/responses/200\"}}}}}}"
 ;
 
 static const struct afb_auth _afb_auths_v2_UNICENS[] = {
@@ -62,6 +65,7 @@ static const struct afb_auth _afb_auths_v2_UNICENS[] = {
  void ucs2_listconfig(struct afb_req req);
  void ucs2_initialise(struct afb_req req);
  void ucs2_subscribe(struct afb_req req);
+ void ucs2_subscriberx(struct afb_req req);
  void ucs2_writei2c(struct afb_req req);
  void ucs2_sendmessage(struct afb_req req);
 
@@ -84,7 +88,14 @@ static const struct afb_verb_v2 _afb_verbs_v2_UNICENS[] = {
         .verb = "subscribe",
         .callback = ucs2_subscribe,
         .auth = &_afb_auths_v2_UNICENS[1],
-        .info = "Subscribe to UNICENS Events.",
+        .info = "Subscribe to network events.",
+        .session = AFB_SESSION_NONE_V2
+    },
+    {
+        .verb = "subscriberx",
+        .callback = ucs2_subscriberx,
+        .auth = &_afb_auths_v2_UNICENS[1],
+        .info = "Subscribe to Rx control message events.",
         .session = AFB_SESSION_NONE_V2
     },
     {
index a150fb8..954e275 100644 (file)
       }
     },
     "/subscribe": {
-      "description": "Subscribe to UNICENS Events.",
+      "description": "Subscribe to network events.",
+      "get": {
+        "x-permissions": {
+          "$ref": "#/components/x-permissions/monitor"
+        },
+        "responses": {
+          "200": {"$ref": "#/components/responses/200"}
+        }
+      }
+    },
+    "/subscriberx": {
+      "description": "Subscribe to Rx control message events.",
       "get": {
         "x-permissions": {
           "$ref": "#/components/x-permissions/monitor"
index b72aca9..553ed36 100644 (file)
@@ -68,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); */
@@ -208,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)
@@ -511,6 +577,33 @@ 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) {