Embed NanoMQTT in C

This topic shows the smallest synchronous flow needed to connect, subscribe, publish, and service the receive loop in a single-threaded application.

Before you begin

If you plan to use TLS, create and negotiate a NanoSSL connection:

  • Create the NanoSSL handle with SSL_connect().
  • Complete the handshake with SSL_negotiateConnection().
  • Bind the SSL handle to the MQTT connection with MQTT_setTransportSSL(connInst, sslConnInst) before you call MQTT_negotiateConnection().
Examples assume sockets are non-blocking so a single event loop can multiplex TCP/TLS traffic. Build with the asynchronous client enabled (__ENABLE_MQTT_ASYNC_CLIENT__ or --async in the build script) and open your sockets in non-blocking mode. Blocking sockets work, but they prevent multiplexing.
A reachable MQTT 5 or 3.1.1 broker (port 1883 for TCP, 8883 for TLS).

Minimal synchronous example

#include "mqtt_client.h"
#include "ssl_api.h"          /* Needed only for TLS */

static void on_publish(const MqttPublishRx *msg, void *arg)
{
    /* Handle inbound publishes here */
}

/* ---------- 1. Allocate an MQTT connection (stores Client-ID) */
MqttConnectionHandle conn =
    MQTT_connect(MQTT_V5, "device-123", strlen("device-123"));

/* ---------- 2. Bind a transport ----------------------------------------- */
/* (a) Clear-text TCP:                                                     */
/* int socketFd = ... ;  MQTT_setTransportTCP(conn, socketFd);            */
/* (b) TLS transport (shown):                                              */
MQTT_setTransportSSL(conn, sslConnInst);   /* sslConnInst = NanoSSL handle */
/* Transport may be bound at any point *before* MQTT_negotiateConnection.  */

/* ---------- 3. Register control-packet handlers ------------------------- */
MqttPacketHandlers h = { .publishHandler = on_publish };
MQTT_setControlPacketHandlers(conn, &h);

/* ---------- 4. Negotiate the session (CONNECT / CONNACK) --------------- */
MqttConnectOptions opts = {
    .cleanStart        = true,
    .keepAliveInterval = 30,   /* seconds; 0 disables keep-alive */
};
if (MQTT_negotiateConnection(conn, &opts) < 0) {
    /* handle error */
}

/* ---------- 5. Subscribe and publish ------------------------------------ */
MqttSubscribeTopic   subTopic = { .pTopic = "alerts/#", .topicLen = 8, .qos = 1 };
MqttSubscribeOptions subOpts  = { 0 };   /* no extra options */
MQTT_subscribe(conn, &subTopic, 1, &subOpts);

MqttPublishOptions   pubOpts  = { .qos = 0, .retain = false };
const char payload[] = "Hello NanoMQTT";
MQTT_publish(conn, &pubOpts,
             "telemetry", 9,
             payload, sizeof payload - 1);

/* ---------- 6. Main receive loop ---------------------------------------- */
while (running) {
    if (MQTT_recv(conn) < 0) {   /* dispatches callbacks */
        /* handle error or reconnect */
    }
}

/* ---------- 7. Graceful shutdown --------------------------------------- */
MQTT_disconnect(conn, NULL);   /* default DISCONNECT           */
MQTT_closeConnection(conn);    /* free all connection memory   */

How it works

StepCallPurpose
1MQTT_connectAllocate the client state machine and store the Client-ID.
2MQTT_setTransportSSL / MQTT_setTransportTCPBind TLS or clear-text transport before negotiation.
3MQTT_setControlPacketHandlersRegister application callbacks (publish, disconnect, etc.).
4MQTT_negotiateConnectionSend CONNECT, wait for CONNACK, apply keep-alive.
5MQTT_subscribe / MQTT_publishAdd subscriptions or transmit payloads.
6MQTT_recvDrive the synchronous loop; dispatch callbacks.
7MQTT_disconnect / MQTT_closeConnectionClean up network state and free all allocated memory.

Implementation notes

TopicNote
Build toggleNanoMQTT is part of the default TrustCore SDK build. Use ./build.sh nanomqtt (or the --module nanomqtt CMake option) if you want to build only the NanoMQTT components.
Auto-PING logicMQTT_recv() automatically injects a PINGREQ whenever no other data has flowed for one keep-alive interval. Applications do not need to call MQTT_pingRequest() unless they choose to manage keep-alive manually. If the keep-alive interval is 0, NanoMQTT will not send PINGREQ packets.
Memory ownershipMQTT_disconnect() terminates the network session but does not free the client state. Always follow it with MQTT_closeConnection(conn) (or drop the handle) to release memory.