This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC1350: How to verify if messages are received by sensor node?

Part Number: CC1350

For our application we need to make sure that messages from the cloud are actually received by the sensor node.

Especially the part from the gateway through the collector and coprocessor is not providing acknowledgement.

We use linux collector app + cc1350 coprocessor.

From the gateway to the coprocessor there is only the status message success or transaction overflow if the coprocesor buffer is full. Although the TI software does nothing with this message it can be send to the gateway app. So we can at least make sure it is in the coprocessor.

From there on the coprocessor provides the callback function dataCnfCB which support multiple failure options (and of course success).

However as this is asynchronous to the gateway we need some way of tracking each message.

Is there a way of adding an identifier to each message and have the coprocessor reply to dataCnfCB with that identifier so we can track if messages are actually transmitted?

  • Hey Marijn,

    The collector application tracks the sensorMessagesReceived as well as the attempted/sent config and tracking messages. This is tracked in 

    Collector_statistics_t Collector_statistics;

    All you need to do is expose this in the upper layers of your application (i.e. the Local Gateway Application shown in the link below).

    http://software-dl.ti.com/simplelink/esd/ti15.4stack_linux_x64/3.30.00.12/exports/docs/ti154stack/html/ti154stack-linux/linux-example-applications.html#linux-collector-and-gateway-example-applications

    You can also track this statistic from the sensor side in 

    Smsgs_msgStatsField_t Sensor_msgStats

    Here you have the sensor messages attempted as well as the sensor messages sent. If both are the same, then your collector has not missed a message.

  • I would suggest you to implement application level ack by yourself for such requirement.

  • Thanks for the suggestion of the message statistics. I will definitely make this available in our high level application.

    The thing I still need however is a per message ack. Especially for some messages I need to know if they arrived so I can retry them if they failed.

    From the statistic I can tell that a nr of messages did not arrive but not which message that was.

  • Yes that is exactly what I want to do. But in the collector callback

    static void dataCnfCB(ApiMac_mcpsDataCnf_t *pDataCnf)

    I cannot find any message ID.

    Can you point me to a solution to include a message identifier to a message so I can track it back in the confirmation callback?

  • In this case, as YK suggests, I would recommend you send application level messages. In dataIndCB(), you can see the switch statement that checks which message type was received, and then a call to a processXX() function. Inside this processXX() function, you can add your tracking variable.

    If you want to add a custom message, there's a wiki page (here) that outlines what code additions are needed on both the collector/sensor side.

  • Hi Ammar,

    Thanks for the suggestion,

    It could be a solution if no other possibility exists for transport layer ACK.

    However from a network perspective, 15.4 stack has a transport layer so the responsibility for transmitting a message lies firstly in that layer.

    If the transport layer cannot transmit the message it should report back to the next upper layer. The thing is, all the content is already there in software. There is a callback function, dataCnfCB, which has all that information, only not which message that callback is actually for. I'd really like to first solve it there if possible.

    The problem with solving this application level, you have no idea where the message failed, only that a message did not return an answer somehow. For finding out what is going wrong it is much more helpful if the transport layer result is available for the message.

    kind regards,

    Marijn

  • Hey Marjin,

    It took some digging, but I think I found a way to extract the message identifier in the DataCnfCb.

    When each message is sent, it is sent with a particular MsduHandle, which is tied to an Smsgs_cmdIds_t type (see sendMsg on the collector).

    You'll have to modify the getMsduHandle() function and add the appropriate Smsgs_cmdIds_t type in the conditionals. Then, in the DataCnfCb, you'll have to check for the specific MSDU_Handle to know which message was received.

    Please let me know if you're able to get this to work.

  • Hi Ammar,

    Thanks for thinking with us. I see however that the MsduHandle is only a 8-bit uint of which 5 bits are used as a auto-rollover counter and 3 bits as flag to identify either config, broadcast or app message. This leaves no room for an identifier.

    It would be great if I could enlarge it to a 32-bit uint which would be simple from the collector point of view. But the MsduHandle is sent to the coprocessor as wel and it expects an 8-bit there so no way I can just send a 32-bit to it and expect it back...

    Maybe if we use use the collector app on the device rather then on the linux machine we have this more under control but that involves a rather larger change in our iot-gateway application...

  • You're free to modify and use the msdu handle as needed, it is defined in the application layer, and not used by the stack.

    The implementation shown is just an example, so you can modify it to use all bits to receive identifiers in your case. 

    Another way to track messages may be to use the frameCntr, although I don't think this will provide you with specific identifiers for a particular message id.

  • Hi Ammar,

    But can I just increase it to a uint32? I thought that is was sent to the mac layer (at least it is sent to the coprocessor over serial connection) So if I just change it from 8bit to 32 bit uint probably the protocol does not handle that...

    About the framCntr, Can you explain what this is? Can I set it myself or its it just a counter from the mac layer?

  • Hey Marijn,

    I apologize for the late reply. There are some defines for the msdu handle in the stack, so you may get some build errors or warnings preventing you from doing this.

    The frameCntr is just a counter that is incremented each time a message is received by the collector. The frameCntr in CSF.c is the application layer counter, which can be modified or set based on your setup. However, there are internal frame counters as well, but there's less flexibility with these used by the stack.

  • Hi Ammar,

    So in the end there is not really a way to include a unique message id in the message MAC layer to track the message in the dataCnfCB

    The msdu in only 8-bit so only usable for example a type of message.

    The frameCntr is controller by the receiver so no way for us to set it at sending and track it back.

  • Hey Marijn,

    The 8-bit msdu handle should be sufficient, how many message types would you like to track? The msdu handle is part of the message payload being sent. So, if needed, you can just modify the length of the overall packet being sent and append on your identifier data to the message.

    Let me try and reword my explanation of the frameCntr. Each time a message is sent from a device, the frameCntr is incremented for that device. So, if the collector receives data from a specific sensor with the frameCntr showing 1,2,4, then we know that message #3 sent by that sensor was missed. The frameCntr is controlled by the sender.

    The frameCntr is just a counter that is incremented each time a message is received by the collector.

    What I meant here is that the frameCntr is tracked on the collector and updated each time a message is received from its sensors. This is shown in Csf_updateFrameCounter() in csf.c. It is not incremented each time the message is received. I apologize for the confusion.

     

    Does this clarify things? It's certainly possible to track messages from each sensor connected to a collector.

  • Hi Ammar,

    Thanks for the response. Maybe my issue still isn't clear.

    I need to track individual messages from collector to sensor. Not the other way around.

    So not a message type (which the msdu handle supports) but individual unique messages with their own unique id.

    As the collector sends messages asynchronously for our sleepy devices, the send confirmation is a callback on the collector: 

    dataCnfCB

    This callback has currently no data field (that I'm aware of) that we can use for it. You mentioned the msdu handle but that has only 8 bits used to track message types, not message unique identifiers.

    You also mentioned the frameCntr which, if I understand correctly, is updated for each received message from the sensor. So not usable to track unique messages sent from the collector to a sensor.

    So at this moment there is still no usable solution.



  • Hey Marijin,

    I suggest using a combination of tracking the message types and the frameCntr values.

    The frameCntr is updated only on the sender side. If a collector device sends a message to it's sensor, it tags on the frameCntr. The frameCntr is essentially the unique identifier you're looking for. It is incremented each time a message is sent. The only time the same frameCntr will be sent is after it overflows, but that is unlikely to happen as the size of the frameCntr is a 32-bit value.

    Does that make sense?

  • Hello Ammar,

    I did some further digging to find out what you mean by using the frameCntr.

    I think there is some misunderstanding about our setup because the frameCntr is only available to write within the coprocessor.

    Our setup is, as I mentioned in my opening post, the collector application that is running on linux then the coprocessor application running on the cc1350 interfacing with each other over the serial connection.

    So at the point a message #id-xxx arrives from our MQTT bus to the appsrv.c function in the linux collector app and is forwarded to the coprocessor, that is where we lose track of messages, because from there on the transfer is asynchronous. The only synchronous feedback is that the message did arrive in the coprocessor (or not).

    Then the coprocessor gives an asynchronous callback (dataCnf) and that is where the unique identifier should come into play. I see now possibility to track back the message #id-xxx with only the frameCntr or a combination of frameCntr and msduHandle becasue the frameCntr is not available to me at the moment the message is sent to the coprocessor.

    Maybe I should refrase my question to: How do I make the linux collector application send a confirmation to the iot-gateway saying, message #id-xxx that you gave to me earlier has arrived at the sensor.

  • You can pass the message id as part of the message and modify the collector to keep track of which messages have been acked by the sensor.

    I don't think any modifications to the coprocessor are needed.

  • Hi Ammar, I'll get back to this next week when I'm in the office again.

    Thanks!

  • Hi Ammar,

    I looked into your suggestion but I don't see how it is gonna work. (Or I don't understand you correctly) ;-).

    If I pass the message id as part of the message I won't get it back in the dataCnf callback. The dataCnf callback has only metadata available on the message, not contents.

    according to the api_mac.h file, this is the content available in the dataCnf callback

    /*! MCPS data confirm type */
    typedef struct _apimac_mcpsdatacnf
    {
        /*! Contains the status of the data request operation */
        ApiMac_status_t status;
        /*! Application-defined handle value associated with the data request */
        uint8_t msduHandle;
        /*! The time, in backoffs, at which the frame was transmitted */
        uint32_t timestamp;
        /*!
         The time, in internal MAC timer units, at which the frame was
         transmitted
         */
        uint16_t timestamp2;
        /*! The number of retries required to transmit the data frame */
        uint8_t retries;
        /*! The link quality of the received ack frame */
        uint8_t mpduLinkQuality;
        /*! The raw correlation value of the received ack frame */
        uint8_t correlation;
        /*! The RF power of the received ack frame in units dBm */
        int8_t rssi;
        /*! Frame counter value used (if any) for the transmitted frame */
        uint32_t frameCntr;
    } ApiMac_mcpsDataCnf_t;
    

    If I want to add a unique message id I also need to modify something in the coprocessor it seems.

  • Hey Marijn,

    I apologize for the confusion. You are right, the message contents are not passed in the DataCnf callback.

    Taking a step back, the cleanest way to knowing "message #id-xxx that you gave to me earlier has arrived at the sensor" is to do so from the application layer. There's some information on adding custom sensor support (i.e. custom message support), here: https://processors.wiki.ti.com/index.php/Adding_New_Sensor_Support_To_Sub1GHz_Sensor_To_Cloud_Linux_Gateway#Modify_the_.22Sensor_To_Cloud.22_application_to_add_the_Generic_Sensor.

    Perhaps you can set a timer, and if the device does not respond in xx seconds, retry the message. You can also try a different mode of operation. For example, in BCN mode, you should be able to expect a response in the next beacon interval. If no response is received during the next beacon interval, then you know you've missed a message.

  • Hi Ammar,

    Thanks for your reply and suggestions.

    I had already implemented a retry timer in the application layer and this works but it creates additional data overhead in the protocol which should not be necessary.

    Also this 'solution' does not give me enough information about where things go wrong if I don't get a reply from the device.

    If this is the only way we'll just have to work with it and accept this limitation. But looking from a network perspective this functionality should not lie within the application layer.

    Especially if almost all the architecture for handling this is already implemented in the network layer. The confirmation callback is there so the coprocessor 'knows' if a message is accepted by the sensor or not. It just lacks the identification of which message. A simple uint32_t in the ApiMac_mcpsDataReq_t and ApiMac_mcpsDataCnf_t data structure could handle this information.

    Hopefully TI will implement this feature in a next release.