Offloading MQTT and TLS to LTE Modem for AWS OTA

Hi, this is my first post here on the forum, hoping to get some expert opinions on the best way to implement AWS OTA for my application.

I’m running RTOS on a STM32L475, which is connected to a SimCom SIM7080G LTE modem. The modem is full featured. I already managed to connect to AWS over MQTT with two way authentication, without having to write any code. The modem takes care of all of this.

The end goal is to implement AWS OTA. I’ve already figured out the PAL stuff. Now I am not sure how to setup the communication layer for OTA.

I’ve been doing a lot of reading and I see several possibilities. One approach could be to use the modems TCP function instead of the MQTT function, and implement RTOS coreMQTT, coreMQTTagent and MBedTLS on the STM32 instead. I then only need to customize the send and receive functions in the transport layer to work with the LTE modem.

Another approach would be to offload TLS and MQTT to the SimCom modem. I already have that working and that will save a fair amount of processing and space on the STM32. This has my preference. However, I do not know how to implement that. The OTA interface documentation only mentions publish, subscribe and unsubscribe commands (which all send data). But how data from an MQTT event/callback is supposed to be sent back into the OTA layer is not mentioned, so I do not know how I should code that.

Can anyone here shed some light on this?

Apologies for the delayed response.

Did you see this page? https://www.freertos.org/Documentation/api-ref/ota-for-aws-iot-embedded-sdk/docs/doxygen/output/html/ota_porting.html#ota_porting_mqtt It describes the function pointers that interfaces the OTA library to whichever MQTT stack you are using - the offloaded on in your case.

Here is a copy of the relevant header file which includes some instructions.
It defines the function pointers used to point the MQTT functions to the implementations in your MQTT API: https://github.com/aws/ota-for-aws-iot-embedded-sdk/blob/a5c50e62c88ff5ddfa5dba40da8fb72c48977b99/source/include/ota_mqtt_interface.h

Here is an example of setting the function pointers to the relevant functions in the coreMQTT library - the functions will be different if you are using an offloaded MQTT library: https://github.com/FreeRTOS/coreMQTT-Agent-Demos/blob/202104.00/source/demo-tasks/ota_over_mqtt_demo.c#L1018

Here is the documentation for the OTA_Init() function to which the initialisation structure from the previous link is sent: https://freertos.org/Documentation/api-ref/ota-for-aws-iot-embedded-sdk/docs/doxygen/output/html/ota_init_function.html

Hope this helps.

To add on to Richard’s comments, I would generally caution against using proprietary MQTT / TLS stacks since they can be quite hard to debug without source code or logging when things go wrong.

Given the lack of crypto accelerators and the amount of ram on your target mcu, offloading TLS could be a good option. It really depends on how you plan to provision your devices, your level of support from your module vendor, and how well tested the stack is, especially for edge cases like modem firmware updates.

Either way, I would recommend using EC type keys rather than RSA keys due to their decreased memory usage and computation load. Leveraging the module’s TCP/IP stack is probably a good choice due to your ram constraints.

I’m going to explore offloading MQTT and TLS some more. So far the support from the modem manufacturer has been great.

The documentation of the OTA interface specification for MQTT only lists how to implement subscribe, unsubscribe and publish functions. These are fairly straightforward to implement for me by writing some glue code that calls the corresponding modem AT commands for subscribing, unsubscribing and publishing.

This is however only half of the story. Just implementing these as the OTA interface spec suggests will not give a working solution, since then there is no mechanism to receive MQTT publishes.
So I have been reverse engineering the example to try to understand how that should be done. Apparently what I need to make is a process (in its own thread?) which when an MQTT publish is received from the modem, packs that data in a structure and passes that on to the appropriate callback, which in turn will populate the OTAEventBuffer and call the right OTA_SignalEvent().

This is only my high level understanding at the moment. I’m not sure if I should attempt to modify the subscription manager (don’t know how I would approach that) or make a thread from scratch that does what I just described.

Hello @BaxEDM ,

The documentation for OTA only defines the MQTT interface required for OTA library. The incoming publish must be handled by the application followed by the call to OTA_SignalEvent and your understanding is correct. The events received can be a jobs event ( like receiving job notification ) or a data event ( file block while downloading file ). Please take a look at the prvIncomingPublishCallback where subscription manager handles the jobs or data topics and calls respective callbacks. You can do this without subscription manager as well by matching topics. For example if the incoming publish is jobs topic then handled it like prvMqttJobCallback and if it is streams topic then handle it like prvMqttDataCallback. I am not sure how the incoming publish are handled in the modem software you are using but you can use separate thread or send events from same context.

Let me know if you have more questions.