Library for MQTT

Files at this revision

API Documentation at this revision

Comitter:
pavleradojkovic
Date:
Mon Jun 20 16:24:43 2022 +0000
Commit message:
Inital commit

Changed in this revision

mbed-mqtt-master/.mbed Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/.mbedignore Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/CONTRIBUTING.md Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/LICENSE-apache-2.0.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/LICENSE.md Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/README.md Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/TESTS/mqtt/README.md Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/TESTS/mqtt/mqtt/main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/TESTS/mqtt/mqtt/mqtt-sn_legacy.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/TESTS/mqtt/mqtt/mqtt-sn_new.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/TESTS/mqtt/mqtt/mqtt_legacy.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/TESTS/mqtt/mqtt/mqtt_new.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/TESTS/mqtt/mqtt/mqtt_tests.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/UNITTESTS/.mbedignore Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/UNITTESTS/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/UNITTESTS/CMakeSettings.json Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/UNITTESTS/README.md Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/UNITTESTS/googletest-CMakeLists.txt.in Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/UNITTESTS/mbed_unittest.py Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/UNITTESTS/mocks/Network_mock.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/UNITTESTS/paho_mqtt_embedded_c/MQTTClient/test_MQTTClient.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/UNITTESTS/paho_mqtt_embedded_c/MQTTClient/unittest.cmake Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/UNITTESTS/stubs/Countdown_stub.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/UNITTESTS/stubs/MQTTConnectClient_stub.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/UNITTESTS/stubs/MQTTSerializePublish_stub.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/.gitignore Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/.travis.yml Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/CONTRIBUTING.md Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNClient/src/FP.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNClient/src/MQTTLogging.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNClient/src/MQTTSNClient.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNClient/src/linux/linux.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/README.md Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/samples/mainTest.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LGwProxy.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LNetworkUdp.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LPublishManager.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LPublishManager.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LRegisterManager.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LRegisterManager.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LScreen.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LScreen.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LSubscribeManager.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LSubscribeManager.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTaskManager.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTaskManager.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTimer.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTimer.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTopicTable.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTopicTable.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/Payload.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/Payload.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/Util.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/README.md Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/clients.conf Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/gateway.conf Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/predefinedTopic.conf Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWConnectionHandler.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWConnectionHandler.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWPacket.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWPacket.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWPublishHandler.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWPublishHandler.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWSubscribeHandler.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAdapter.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAdapter.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAdapterManager.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAggregater.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAggregater.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClient.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClient.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientList.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientList.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientSendTask.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWConnectionHandler.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWDefines.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWForwarder.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWForwarder.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWLogmonitor.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWLogmonitor.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWMessageIdTable.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPacket.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPacket.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWProcess.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWProcess.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPublishHandler.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWTopic.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWTopic.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWVersion.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWVersion.h.in Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGateway.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGateway.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Network.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Network.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Threading.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Threading.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Timer.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Timer.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/udp/SensorNetwork.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/udp6/SensorNetwork.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/xbee/SensorNetwork.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/mainGateway.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/mainLogmonitor.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestProcess.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestProcess.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestQue.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestQue.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTask.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTask.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTopicIdMap.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTopicIdMap.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTopics.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTopics.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTree23.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTree23.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/mainTestProcess.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/IBMIoTUDPExample.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/lowlevel.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/lowlevel.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/pub0sub1.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/qos-1pub.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/qos-1pub_extended.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/qos0pub.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/qos0pub_register.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/qos1pub.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/pub0sub1.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/qos-1pub.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/qos-1pub_extended.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/qos0pub.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/qos0pub_register.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/qos1pub.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/transport.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/transport.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNConnect.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNConnectClient.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNConnectServer.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNDeserializePublish.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNPacket.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNPacket.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNPublish.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSearch.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSearchClient.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSearchServer.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSerializePublish.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSubscribe.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSubscribeClient.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSubscribeServer.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNUnsubscribe.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNUnsubscribeClient.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNUnsubscribeServer.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/StackTrace.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/test/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/test/build_test Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/test/test1.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/test/test2.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/README.md Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/about.html Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/doc/DoxyfileMQTTSNPacket.in Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/doc/pahologo.png Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/edl-v10 Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/epl-v10 Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/notice.html Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt-sn_embedded_c/travis-build.sh Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/.gitignore Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/.travis.yml Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/CONTRIBUTING.md Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/samples/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/samples/FreeRTOS/MQTTEcho.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/samples/linux/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/samples/linux/build.sh Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/samples/linux/stdoutsub.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/FreeRTOS/MQTTFreeRTOS.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/FreeRTOS/MQTTFreeRTOS.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/MQTTClient.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/MQTTClient.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/cc3200/MQTTCC3200.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/cc3200/MQTTCC3200.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/linux/MQTTLinux.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/linux/MQTTLinux.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/test/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/test/test1.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/arduino/Hello/Hello.ino Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/linux/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/linux/build.sh Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/linux/hello.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/linux/main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/linux/stdoutsub.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/FP.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/MQTTClient.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/MQTTLogging.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/arduino/Countdown.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/arduino/IPStack.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/arduino/WifiIPStack.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/linux/linux.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/mbed/MQTTEthernet.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/mbed/MQTTSocket.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/mbed/MQTTmbed.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/test/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/test/test1.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/baremetalserial/build Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/baremetalserial/ping_nb.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/baremetalserial/pub0sub1_nb.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/baremetalserial/transport.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/baremetalserial/transport.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/build Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/null.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/ping.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/ping_nb.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/pub0sub1.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/pub0sub1_nb.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/qos0pub.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/transport.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/transport.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTConnect.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTConnectClient.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTConnectServer.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTDeserializePublish.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTFormat.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTFormat.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTPacket.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTPacket.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTPublish.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTSerializePublish.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTSubscribe.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTSubscribeClient.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTSubscribeServer.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTUnsubscribe.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTUnsubscribeClient.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTUnsubscribeServer.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/StackTrace.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/test/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/test/build_test Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/test/test1.c Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/README.md Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/about.html Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/doc/DoxyfileMQTTClient-C.in Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/doc/DoxyfileMQTTClient.in Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/doc/DoxyfileMQTTPacket.in Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/doc/pahologo.png Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/edl-v10 Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/epl-v10 Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/library.properties Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/notice.html Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/test/MQTTV3112.py Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/test/mqttsas2.py Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/travis-build.sh Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/travis-env-vars Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/paho_mqtt_embedded_c/travis-install.sh Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/src/MQTTClientMbedOs.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/src/MQTTClientMbedOs.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/src/MQTTNetwork.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/src/MQTTNetworkTLS.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/src/MQTTNetworkUtil.h Show annotated file Show diff for this revision Revisions of this file
mbed-mqtt-master/src/MQTTSNNetworkUDP.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/.mbed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/.mbed	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,1 @@
+ROOT=.
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/.mbedignore
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/.mbedignore	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,11 @@
+paho_mqtt_embedded_c/MQTTClient-C/*
+paho_mqtt_embedded_c/MQTTClient/samples/*
+paho_mqtt_embedded_c/MQTTClient/test/*
+paho_mqtt_embedded_c/MQTTClient/src/arduino/*
+paho_mqtt_embedded_c/MQTTClient/src/linux/*
+paho_mqtt_embedded_c/MQTTPacket/samples/*
+paho_mqtt_embedded_c/MQTTPacket/test/*
+paho_mqtt-sn_embedded_c/MQTTSNClient/src/linux/*
+paho_mqtt-sn_embedded_c/MQTTSNGateway/*
+paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/*
+paho_mqtt-sn_embedded_c/MQTTSNPacket/test/*
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/CONTRIBUTING.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/CONTRIBUTING.md	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,5 @@
+# Contributing to Mbed OS
+
+Mbed OS is an open-source, device software platform for the Internet of Things. Contributions are an important part of the platform, and our goal is to make it as simple as possible to become a contributor.
+
+To encourage productive collaboration, as well as robust, consistent and maintainable code, we have a set of guidelines for [contributing to Mbed OS](https://os.mbed.com/docs/mbed-os/latest/contributing/index.html).
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/LICENSE-apache-2.0.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/LICENSE-apache-2.0.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,165 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and
+distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright
+owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities
+that control, are controlled by, or are under common control with that entity.
+For the purposes of this definition, "control" means (i) the power, direct or
+indirect, to cause the direction or management of such entity, whether by
+contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
+outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising
+permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including
+but not limited to software source code, documentation source, and configuration
+files.
+
+"Object" form shall mean any form resulting from mechanical transformation or
+translation of a Source form, including but not limited to compiled object code,
+generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made
+available under the License, as indicated by a copyright notice that is included
+in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that
+is based on (or derived from) the Work and for which the editorial revisions,
+annotations, elaborations, or other modifications represent, as a whole, an
+original work of authorship. For the purposes of this License, Derivative Works
+shall not include works that remain separable from, or merely link (or bind by
+name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version
+of the Work and any modifications or additions to that Work or Derivative Works
+thereof, that is intentionally submitted to Licensor for inclusion in the Work
+by the copyright owner or by an individual or Legal Entity authorized to submit
+on behalf of the copyright owner. For the purposes of this definition,
+"submitted" means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems, and
+issue tracking systems that are managed by, or on behalf of, the Licensor for
+the purpose of discussing and improving the Work, but excluding communication
+that is conspicuously marked or otherwise designated in writing by the copyright
+owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
+of whom a Contribution has been received by Licensor and subsequently
+incorporated within the Work.
+
+2. Grant of Copyright License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the Work and such
+Derivative Works in Source or Object form.
+
+3. Grant of Patent License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable (except as stated in this section) patent license to make, have
+made, use, offer to sell, sell, import, and otherwise transfer the Work, where
+such license applies only to those patent claims licensable by such Contributor
+that are necessarily infringed by their Contribution(s) alone or by combination
+of their Contribution(s) with the Work to which such Contribution(s) was
+submitted. If You institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work or a
+Contribution incorporated within the Work constitutes direct or contributory
+patent infringement, then any patent licenses granted to You under this License
+for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution.
+
+You may reproduce and distribute copies of the Work or Derivative Works thereof
+in any medium, with or without modifications, and in Source or Object form,
+provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of
+this License; and
+You must cause any modified files to carry prominent notices stating that You
+changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute,
+all copyright, patent, trademark, and attribution notices from the Source form
+of the Work, excluding those notices that do not pertain to any part of the
+Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any
+Derivative Works that You distribute must include a readable copy of the
+attribution notices contained within such NOTICE file, excluding those notices
+that do not pertain to any part of the Derivative Works, in at least one of the
+following places: within a NOTICE text file distributed as part of the
+Derivative Works; within the Source form or documentation, if provided along
+with the Derivative Works; or, within a display generated by the Derivative
+Works, if and wherever such third-party notices normally appear. The contents of
+the NOTICE file are for informational purposes only and do not modify the
+License. You may add Your own attribution notices within Derivative Works that
+You distribute, alongside or as an addendum to the NOTICE text from the Work,
+provided that such additional attribution notices cannot be construed as
+modifying the License.
+You may add Your own copyright statement to Your modifications and may provide
+additional or different license terms and conditions for use, reproduction, or
+distribution of Your modifications, or for any such Derivative Works as a whole,
+provided Your use, reproduction, and distribution of the Work otherwise complies
+with the conditions stated in this License.
+
+5. Submission of Contributions.
+
+Unless You explicitly state otherwise, any Contribution intentionally submitted
+for inclusion in the Work by You to the Licensor shall be under the terms and
+conditions of this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify the terms of
+any separate license agreement you may have executed with Licensor regarding
+such Contributions.
+
+6. Trademarks.
+
+This License does not grant permission to use the trade names, trademarks,
+service marks, or product names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty.
+
+Unless required by applicable law or agreed to in writing, Licensor provides the
+Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+including, without limitation, any warranties or conditions of TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
+solely responsible for determining the appropriateness of using or
+redistributing the Work and assume any risks associated with Your exercise of
+permissions under this License.
+
+8. Limitation of Liability.
+
+In no event and under no legal theory, whether in tort (including negligence),
+contract, or otherwise, unless required by applicable law (such as deliberate
+and grossly negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License or
+out of the use or inability to use the Work (including but not limited to
+damages for loss of goodwill, work stoppage, computer failure or malfunction, or
+any and all other commercial damages or losses), even if such Contributor has
+been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability.
+
+While redistributing the Work or Derivative Works thereof, You may choose to
+offer, and charge a fee for, acceptance of support, warranty, indemnity, or
+other liability obligations and/or rights consistent with this License. However,
+in accepting such obligations, You may act only on Your own behalf and on Your
+sole responsibility, not on behalf of any other Contributor, and only if You
+agree to indemnify, defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason of your
+accepting any such warranty or additional liability.
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/LICENSE.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/LICENSE.md	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,7 @@
+Unless specifically indicated otherwise in a file, files are licensed under the Apache 2.0 license,
+as can be found in: LICENSE-apache-2.0.txt
+
+Folders containing files under different permissive license than Apache 2.0 are listed below. Each folder should contain its own README file with license specified for its files. The original license text is included in those source files.
+
+- [paho_mqtt_embedded_c](./paho_mqtt_embedded_c) - EPL-1.0, EDL-1.0
+- [paho_mqtt-sn_embedded_c](./paho_mqtt-sn_embedded_c) - EPL-1.0, EDL-1.0
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/README.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/README.md	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,107 @@
+### MQTT protocol
+
+MQTT is a machine-to-machine (M2M)/"Internet of Things" connectivity protocol. It was designed as an extremely lightweight publish/subscribe messaging transport. For more details see [http://mqtt.org/](http://mqtt.org/).
+
+By design MQTT operates over TCP protocol, so an MQTTSN (For MQTT for Sensor Networks) was designed, which uses less resources and can operate over connectionless procols (such as UDP), but it requires a special gateway.
+
+Mbed-os only allows you to create an MQTT client device, an external broker is needed for MQTT to operate. Clients can subscribe or publish to a topic, after connecting to a broker.
+
+### Build configuration
+
+MQTT library will compile and run without any additional configuration. It is possible to configure some options with the mbed_app.json file.
+The example below sets up a maximum number of connection, packet size and enables QoS2 operation:
+
+```
+{
+    "macros": {
+        "MQTTCLIENT_QOS2"
+    },
+    "target_overrides": {
+        "*": {
+            "mbed-mqtt.max-connections": "5",
+            "mbed-mqtt.max-packet-size": "1024"
+           }
+    }
+}
+```
+
+See [mbed_lib.json](mbed_lib.json) for all configurable options.
+
+See [test README](TESTS/mqtt/README.md) to find out about tests-specific configuration configuration.
+
+### API and usage
+
+Mbed-os uses [Eclipse paho project emmbedded c implementation of MQTT protocol](https://github.com/eclipse/paho.mqtt.embedded-c) and [MQTT-SN protocol](https://github.com/eclipse/paho.mqtt-sn.embedded-c/).
+
+Mbed-os supports the original paho library interface and provides its own API, which wraps around the paho library.
+
+#### New API ####
+
+The new API expects to receive a pointer to a configured and connected socket. This socket will be used for further communication.
+
+For normal, non-secure operation of the MQTT a `TCPSocket` has to be provided.
+
+For secure communication over TCP a `TLSSocket` has to be provided.
+
+For MQTT-SN communication a `UDPSocket` has to be provided.
+
+For secure MQTT-SN communication, a `DTLSSocket` has to be provided.
+
+After the socket is created, an instance of class `MQTTClient` can be created with the pointer to the socket as an argument. The class will distinguish between MQTT and MQTT-SN operation based on the socket's type.
+
+Example code:
+
+```cpp
+#include <MQTTClientMbedOs.h>
+
+NetworkInterface *net = NetworkInterface::get_default_instance();
+TCPSocket socket;
+MQTTClient client(&socket);
+socket.open(net);
+socket.connect(hostname, port);
+```
+
+The socket has to be opened and connected in order for the client to be able to interact with the broker.
+
+#### Legacy API ####
+
+The original paho library can be used, with mbed-os providing our own `Network` template arguments (see below).
+
+To communicate over MQTT an instance of a template class `MQTT::Client<Network, Timer>` has to be created. mbed-os provides two Network specializations:
+
+* `MQTTNetwork` - to communicate over mbed-os's `TCPSocket`,
+
+* `MQTTNetworkTLS` - to communicate over mbed-os's `TLSSocket`.
+
+Paho's default `Timer` implementation, called `Countdown` and available from `MQTTmbed.h` can be used.
+
+The `MQTT::Client` constructor takes one argument which is a pointer to a successfully connected NetworkInterface.
+
+Below is an example of how to create an instance of an MQTTClient:
+
+```cpp
+#include <MQTTNetwork.h>
+#include <MQTTClient.h>
+#include <MQTTmbed.h> // Countdown
+
+NetworkInterface *net = NetworkInterface::get_default_instance();
+MQTTNetwork mqttNet(net);
+MQTT::Client<MQTTNetwork, Countdown> client(mqttNet);
+mqttNet.connect(mqtt_global::hostname, mqtt_global::port);
+```
+
+The MQTTNetwork has to `connect` to a broker, given its address and port number.
+
+#### API usage ####
+
+Apart from language details and different creation and initialization procedure, the APIs of both the legacy and new API are the same.
+
+Once connected the MQTT/MQTT-SN client is able to:
+
+* `connect` to the broker, based on a filled `MQTTPacket_connectData` structure,
+* `diconnect` from the broker,
+* `subscribe` to a topic and register a callback function to be called whenever a new message arrives,
+* `unsubscribe` from a topic,
+* `publish` messages defined with `MQTT::Message` structure to a topic,
+* if no operation is required, but an MQTT connection should be kept open, the client can `yield`,
+* `MQTTNetworkTLS` requires a certificate to be set using `set_root_cert()` before calling connect.
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/TESTS/mqtt/README.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/TESTS/mqtt/README.md	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,610 @@
+MQTT test plan
+========================
+
+This is a test plan for the Mbed OS MQTT and MQTT-SN protocols. This describes all test cases and their intended behaviors. When an API document is not clear, use this as a reference for implementing correct behavior.
+
+Target API
+----------
+
+The target for this plan is to test (TODO: update links to point to mbed-os master after merge):
+
+-   [legacy MQTTClient paho implementation](../../features/mqtt/paho_mqtt_embedded_c/MQTTClient) with [mbed-os MQTTNetwork implementations](../../mqtt/features/mqtt/src).
+-   [new MQTTClient mbed-os wrapper (both for MQTT and MQTT-SN)](../../mqtt/src/MQTTClientNew.h).
+
+Mbed-os tests are NOT meant to test the underlying Eclipse paho [MQTT](https://github.com/michalpasztamobica/mbed-os/tree/mqtt/features/mqtt/paho_mqtt_embedded_c) and [MQTT-SN](../../features/mqtt/paho_mqtt-sn_embedded_c) libraries. The tests provided are integration tests, checking whether MQTT works correctly with the mbed-os sockets.
+
+Tools to use
+------------
+
+-   Mbed OS.
+-   Standard Mbed OS development tools as described in the [Arm Mbed tools overview](https://os.mbed.com/docs/latest/tools/index.html).
+-   Test server with an MQTT broker.
+
+These test cases themselves do not require any special tooling, other than the MQTT test server described in "Test environment" chapter.
+
+Test environment
+----------------
+
+As a general guideline, network connectivity with public Internet access is required. This satisfies Socket tests, but specific connectivity methods might require some extra configuration or devices within the network.
+
+The test environment consist of DUTs, network connection and an MQTT broker.
+
+### Test server setup
+
+**Required services in the test server**
+
+-   MQTT protcol is enabled on TCP port 1883. Port 8883 for TLS
+-   MQTT-SN protocol is enabled on UDP port 10000.
+
+Configure the firewall to allow this traffic to access the MQTT test server.
+
+Some tests are wrapped with a MQTT_MBED_PUBLIC_TEST_TOPIC_AVAILABLE macro. They will only work if a topic is provided in the broker named "mbed_public_test_topic", that publishes a message with QoS = 0 and content "Test message" with a constant frequency. This is intended for use in testing the subscription without having to publish any additional messages.
+
+**Example configuration for Debian/Ubuntu Linux**
+
+The example test server is using an open-source [Eclipse Mosquitto MQTT broker](https://mosquitto.org/) and [Eclipse paho MQTT-SN Gateway](https://www.eclipse.org/paho/components/mqtt-sn-transparent-gateway/), which are available on many operating systems, and installing them is out of scope of this document. Below is an example of how to install these services into a Debian/Ubuntu based Linux distribution.
+
+***MQTT***
+
+```.sh
+$ sudo apt install mosquitto
+```
+
+The mosquitto broker will start automatically as a deamon on system startup. You can start, stop or restart it using:
+```.sh
+$ sudo service mosquitto [start|stop|restart]
+```
+
+Install the mosquitto clients to be able to test your mosquitto broker locally and generate traffic for a predefined channel:
+
+```.sh
+$ sudo apt install mosquitto-clients
+```
+
+When running the below commands in separate shells:
+
+```.sh
+$ mosquitto_sub -p 1883 -t "testtopic"
+$ mosquitto_pub -p 1883 -t "testtopic" -m "testmessage"
+```
+You should be able to receive the "testmessage" on the subscriber side.
+
+Create a channel that will be fed with messages in a periodic manner. An example of how this can be achieved:
+
+```
+$ watch -n1 mosquitto_pub -p 1883 -m \"Test message\" -t \"mbed_public_test_topic\" -q 0
+```
+
+Make sure QoS is set to 0 (`-q 0`), as this message might be received by multiple devices (or no devices after the tests ends).
+
+Tests which will fail without this functionality are wrapped with a MQTT_MBED_PUBLIC_TEST_TOPIC_AVAILABLE macro.
+
+Optionally edit (or create) the mosquitto broker configuration in /etc/mosquitto/conf.d/ to adjust the port that is used for communication (by default it's 1883):
+
+```
+# Port to use for default listener
+listener 1883
+```
+
+To be able to access the broker from the network you need to open the tcp port that the broker is using:
+```.sh
+$ sudo ufw allow 1883/tcp
+```
+
+Some tests are protected with MQTT_MBED_PASSWORD_PROTECTION_AVAILABLE macro. Those tests can only be run when the MQTT broker is configured to check for a user and password. Follow [this tutorial](http://www.steves-internet-guide.com/mqtt-username-password-example/) to configure the broker.
+
+Make sure that allow_anonymous is set to true, as most test access the broker anonymously.
+
+The tests are by default using user "mbed" and password "1234", so consider setting those on your broker or adjust the tests.
+
+Bear in mind that MQTT user/password is sent in raw text and it has nothing to do with proper TLS encryption described below.
+
+***MQTT TLS***
+
+By default port 8883 is used for TLS-protected MQTT communication.
+
+When the MQTT broker is set up as described above, just follow [this tutorial](http://www.steves-internet-guide.com/mosquitto-tls/) to set up the mqtt broker and all certificates. Use `tls_version tlsv1.2`.
+
+***MQTT-SN***
+
+Once MQTT broker is running it is necessary to set up an MQTT-SN Gateway that would establish a connection to the broker and forward the UDP packets.
+
+Download or clone the [Eclipse paho MQTT-SN implementation](https://github.com/eclipse/paho.mqtt-sn.embedded-c/tree/master/MQTTSNGateway). Follow the guidelines in their repository.
+
+Make sure you adjust the gateway.conf file:
+
+```
+BrokerName=localhost
+```
+
+Also it might be necessary to allow the `PredefinedTopicsList` option in case the Gateway crashes when starting up.
+
+Finally, make sure the Gateway port is emabled for external devices:
+
+```.sh
+$ sudo ufw allow 10000/udp
+```
+
+Providing custom configuration (optional)
+-----------------------------------------
+
+By default the tests will run on a predefined local server as configured in  mbed_lib.json.
+
+It is possible to override the default configuration by providing an `mbed_app.json` file.
+
+The example below will configure the tests to run on a `flespi.io` public MQTT server:
+
+```
+{
+    "config": {
+
+    },
+    "target_overrides": {
+        "*": {
+            "mbed-mqtt.tests-broker-hostname": "\"mqtt.flespi.io\"",
+            "mbed-mqtt.tests-topic": "\"test\"",
+            "mbed-mqtt.tests-public-topic-enable": "false",
+            "mbed-mqtt.tests-public-topic-name": "\"mbed_public_test_topic\"",
+            "mbed-mqtt.tests-username-password-protection-enable": "true",
+            "mbed-mqtt.tests-tls-enable": "false",
+            "mbed-mqtt.tests-username": "\"YOUR_FLESPI_TOKEN\"",
+            "mbed-mqtt.tests-password": "\"\"",
+            "mbed-mqtt.tests-username-always": "false",
+            "mbed-mqtt.tests-mqtt-sn-enable": "false",
+            "target.network-default-interface-type": "ETHERNET"
+           }
+    }
+}
+```
+
+Building test binaries
+--------------------------
+
+For testing the board and driver, test against the Mbed OS master branch to get the most recent, up-to-date test cases and drivers.
+
+To create a build environment:
+
+```.sh
+mbed new network_test
+cd network_test
+cd mbed-os
+git checkout master
+cd ..
+```
+
+MQTT tests will run on any type of connection. See the [relevant section of netsocket tests](../netsocket/README.md#building-test-binaries) to find more information on how to establish connectivity.
+
+Now build test binaries:
+
+```.sh
+mbed test --compile -t <toolchain> -m <target> -n mbed-os-tests-mqtt-mqtt
+```
+
+Running tests
+-------------
+
+When device is connected to network, or in case of wireless device near the access point.
+
+```.sh
+mbed test -n mbed-os-tests-mqtt-mqtt
+```
+
+Test cases for MQTT
+-------------------
+
+The API for legacy MQTT and new MQTT wrapper are identical, so the tests description apply to both of them.
+
+Also the MQTT-SN has the same interface as MQTT, so all "MQTT_*" test also apply to MQTT-SN. 
+ 
+The only difference is in how the Client class is created.
+
+
+### MQTT_CONNECT
+
+**Description:**
+
+Client can connect to broker.
+
+**Preconditions:**
+
+Device is connected to network and connection to MQTT server is established.
+
+**Test steps:**
+
+1. Call `client.connect()` with an valid connectData provided. Check that no error is returned.
+
+**Expected result:**
+
+Call to `client.connect()` succeeds (returns NSAPI_ERROR_OK).
+
+
+### MQTT_CONNECT_NOT_CONNECTED
+
+**Description:**
+
+Client fails to connect when network is not connected.
+
+**Preconditions:**
+
+Device is connected to network.
+
+**Test steps:**
+
+1. Try to connect to a nonexistent MQTT server address or incorrect port.
+2. Call `client.connect()` with a valid connectData provided.
+
+**Expected result:**
+
+Connection fails in step 1. Call to `client.connect()` returns -1 error in step 2.
+
+
+### MQTT_SUBSCRIBE
+
+Client can subscribe to a topic.
+
+**Preconditions:**
+
+Device is connected to network, connection to MQTT broker is established (see the _CONNECT tests).
+
+**Test steps:**
+
+1. Call `client.subscribe()` with a valid topic and QoS0.
+
+**Expected result:**
+
+Call to `client.connect()` succeeds (returns NSAPI_ERROR_OK) in step 1.
+
+
+### MQTT_SUBSCRIBE_NETWORK_NOT_CONNECTED
+
+Client returns an error if subscribing to a topic when there is no connection to MQTT server.
+
+**Preconditions:**
+
+Device is connected to network, but not connected to broker or server.
+
+**Test steps:**
+
+1. Call `client.subscribe()` with a valid topic and QoS0.
+
+**Expected result:**
+
+Call to `client.subscribe()` returns -1 in step 1.
+
+
+### MQTT_SUBSCRIBE_CLIENT_NOT_CONNECTED
+
+Client returns an error if subscribing to a topic when there is no connection to MQTT broker.
+
+**Preconditions:**
+
+Device is connected to network and a connection to MQTT server is established.
+
+**Test steps:**
+
+1. Call `client.connect()` with an invalid connectData provided (for example: empty clientID).
+2. Call `client.subscribe()` with a valid topic and QoS0.
+
+**Expected result:**
+
+Call to `client.subscribe()` returns -1 in step 3.
+
+
+### MQTT_SUBSCRIBE_TOPIC_TOO_LONG
+
+Client returns an error if subscribing to a topic longer than MAX_MQTT_PACKET_SIZE.
+
+**Preconditions:**
+
+Device is connected to network and a connection to MQTT broker is established.
+
+**Test steps:**
+
+1. Generate a valid string of length larger than MAX_MQTT_PACKET_SIZE.
+2. Call `client.subscribe()` with the too long topic created in step 1 and QoS0.
+
+**Expected result:**
+
+Call to `client.subscribe()` returns -1 in step 2.
+
+
+### MQTT_SUBSCRIBE_INVALID_MESSAGE_HANDLER
+
+Client returns an error if subscribing to a topic without providing a valid message handler.
+
+**Preconditions:**
+
+Device is connected to network and a connection to MQTT broker is established.
+
+**Test steps:**
+
+1. Call `client.connect()` with an invalid connectData provided (for example: empty clientID).
+2. Call `client.subscribe()` with a valid topic, QoS0 and NULL provided intead of message handler function pointer.
+
+**Expected result:**
+
+Call to `client.subscribe()` returns -1 in step 2.
+
+
+### MQTT_SUBSCRIBE_RECEIVE
+
+Client is able to receive MQTT messages after subscribing to a predefined topic.
+
+**Preconditions:**
+
+Device is connected to network and a connection to MQTT broker is established.
+
+The MQTT broker has a topic "mbed_public_test_topic", which is guaranteed to generate a message before the test times out.
+
+**Test steps:**
+
+1. Call `client.subscribe()` with topic set to "mbed_public_test_topic", QoS0 and a message handler that would prove successful message reception (for example increment a counter).
+2. Wait until a message is received.
+3. Verify that a message was received.
+4. Unsubscribe from the "mbed_public_test_topic" topic.
+
+**Expected result:**
+
+A message is received from the topic in steps 2 and 3. Test does not time out. 
+
+
+### MQTT_UNSUBSCRIBE_WITHOUT_SUBSCRIBE
+
+Client is able to unsubscribe without subscribing to any topic.
+
+**Preconditions:**
+
+Device is connected to network and a connection to MQTT broker is established.
+
+**Test steps:**
+
+1. Unsubscribe from a valid topic.
+
+**Expected result:**
+
+Call to `client.unsubscribe()` returns NSAPI_ERROR_OK. 
+
+
+### MQTT_UNSUBSCRIBE_INVALID
+
+Client returns an error when invalid topic name is provided.
+
+**Preconditions:**
+
+Device is connected to network and a connection to MQTT broker is established.
+
+**Test steps:**
+
+1. Unsubscribe from a topic which is an empty string.
+2. Unsubscribe from a topic which has topic of length longer than MAX_MQTT_PACKET_SIZE.
+
+**Expected result:**
+
+Both calls to `client.unsubscribe()` return -1.
+
+### MQTT_PUBLISH
+
+Client is able to publish MQTT messages to a topic.
+
+**Preconditions:**
+
+Device is connected to network and a connection to MQTT broker is established.
+
+**Test steps:**
+
+1. Call `client.publish()` with a valid topic and message with QoS1.
+2. Call `client.publish()` with a valid topic and message with QoS2.
+3. Call `client.publish()` with a valid topic and message with QoS3.
+
+**Expected result:**
+
+All calls return NSAPI_ERROR_OK.
+
+### MQTT_PUBLISH_NOT_CONNECTED
+
+Client returns an error if publishing to a topic when there is no connection to MQTT broker.
+
+**Preconditions:**
+
+Device is connected to network and a connection to MQTT server is established.
+
+**Test steps:**
+
+1. Call `client.publish()` with a valid topic and QoS0.
+
+**Expected result:**
+
+Call to `client.publish()` returns -1 in step 1.
+
+
+### MQTT_PUBLISH_TOPIC_TOO_LONG
+
+Client returns an error if publishing to a topic with name longer than MAX_MQTT_PACKET_SIZE.
+
+**Preconditions:**
+
+Device is connected to network and a connection to MQTT broker is established.
+
+**Test steps:**
+
+1. Generate a valid string of length larger than MAX_MQTT_PACKET_SIZE.
+2. Call `client.subscribe()` with the too long topic created in step 1 and QoS0.
+
+**Expected result:**
+
+Call to `client.publish()` returns -1 in step 2.
+
+### MQTT_CONNECT_USER_PASSWORD_INCORRECT
+
+Client returns an error when incorrect password is provided to a password-protected broker.
+
+**Preconditions:**
+
+Device is connected to network and a connection to MQTT server is established.
+
+The broker is password-protected (see set up instructions for details).
+
+**Test steps:**
+
+1. Call `client.connect()` with an incorrect user and password specified.
+
+**Expected result:**
+
+Call to `client.connect()` returns -1.
+
+### MQTT_CONNECT_SUBSCRIBE_PUBLISH
+
+Client is able to subscribe to a topic, publish to it and receive its own messages in a loopback.
+
+**Preconditions:**
+
+Device is connected to network and a connection to MQTT broker is established.
+
+**Test steps:**
+
+All steps should be performed for QoS 0, 1 and 2.
+
+1. Call `client.subscribe()` with a valid topic and register a message handler to verify that messages are recieved (for example with a message counter).
+2. Call `client.publish()` with a previously used topic.
+3. Compare the message counter
+
+**Expected result:**
+
+All calls return no errors and the message is received correctly (for example - message counter increases).
+
+### MQTT_CONNECT_SUBSCRIBE_PUBLISH_USER_PASSWORD
+
+Client is able to provide user and password and subscribe to a topic, publish to it and receive its own messages in a loopback.
+
+**Preconditions:**
+
+Device is connected to network and a connection to MQTT server is established.
+
+The broker is password-protected (see set up instructions for details).
+
+**Test steps:**
+
+All steps should be performed for QoS 0, 1 and 2.
+
+1. Call `client.connect()` with a valid and correct user and password specified.
+2. Call `client.subscribe()` with a valid topic and register a message handler to verify that messages are recieved (for example with a message counter). 
+3. Call `client.publish()` with a previously used topic.
+4. Compare the message counter.
+
+**Expected result:**
+
+All calls return no errors and the message is received correctly (for example - message counter increases).
+
+Test case for MQTT with TLS
+---------------------------
+
+These tests apply only for TLSSocket class both for MQTT legacy API and the new mbed-os wrapper.
+
+In fact MQTT does not provide any TLS support, it uses the underlying TLSSocket to take care of this.
+
+The test case is however relevant in order to verify correct integration of MQTT with TLSSocket and provides a valuable example of how to set up a secure MQTT connection.
+
+### MQTT_TLS_CONNECT_SUBSCRIBE_PUBLISH
+
+Client is able to securely subscribe to a topic, publish to it and receive its own messages in a loopback.
+
+Important: a secure port should be used for this test (by default 8883).
+
+**Preconditions:**
+
+Device is connected to network over a secured socket and a connection to MQTT broker is established.
+
+**Test steps:**
+
+All steps should be performed for QoS 0, 1 and 2.
+
+1. Call `client.subscribe()` with a valid topic and register a message handler to verify that messages are recieved (for example with a message counter).
+2. Call `client.publish()` with a previously used topic.
+3. Compare the message counter
+
+**Expected result:**
+
+All calls return no errors and the message is received correctly (for example - message counter increases).
+
+
+Test cases for MQTT-SN
+----------------------
+
+Most of the MQTT-SN API is identical to MQTT and should follow the tests described earlier. Exceptions:
+
+* MQTT-SN does not provide the user/password functionality so MQTT_CONNECT_USER_PASSWORD_INCORRECT and MQTT_CONNECT_SUBSCRIBE_PUBLISH_USER_PASSWORD cannot be executed for MQTT-SN
+
+The MQTT-SN-specific tests are listed below.
+
+### MQTTSN_IS_CONNECTED
+
+Client can tell that it is connected.
+
+**Preconditions:**
+
+Device is connected to network and a connection to MQTT-SN broker is established.
+
+**Test steps:**
+
+1. Call `client.isConnected()`
+
+**Expected result:**
+
+Call to `client.isConnected()` returns true.
+
+### MQTTSN_IS_CONNECTED_CLIENT_NOT_CONNECTED
+
+Client can tell that it is not connected.
+
+**Preconditions:**
+
+Device is connected to network and a connection to MQTT-SN server (but not broker) is established.
+
+**Test steps:**
+
+1. Call `client.isConnected()`
+
+**Expected result:**
+
+Call to `client.isConnected()` returns false.
+
+### MQTTSN_IS_CONNECTED_NETWORK_NOT_CONNECTED
+
+Client can tell that it is not connected.
+
+**Preconditions:**
+
+Device is connected to network.
+
+**Test steps:**
+
+1. Call `client.isConnected()`
+2. Try to connect client to a non-existent broker.
+3. Call `client.isConnected()`
+
+**Expected result:**
+
+Connection fails in step 2.
+Call to `client.isConnected()` returns false in steps 1 and 3.
+
+### MQTTSN_UDP_CONNECT_SUBSCRIBE_PUBLISH
+
+Client is able to use a UDP Socket to subscribe to a topic, publish to it and receive its own messages in a loopback.
+
+Important: See MQTT-SN section to set up an MQTT-SN gateway for communication. Use an appropriate port (by default 10000).
+
+**Preconditions:**
+
+Device is connected to network over a UDP socket and a connection to MQTT broker is established.
+
+**Test steps:**
+
+All steps should be performed for QoS 0, 1 and 2.
+
+1. Call `client.subscribe()` with a valid topic and register a message handler to verify that messages are recieved (for example with a message counter).
+2. Call `client.publish()` with a previously used topic.
+3. Compare the message counter
+
+**Expected result:**
+
+All calls return no errors and the message is received correctly (for example - message counter increases).
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/TESTS/mqtt/mqtt/main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/TESTS/mqtt/mqtt/main.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2019, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mbed.h"
+#include "mqtt_tests.h"
+#include "greentea-client/test_env.h"
+#include "utest.h"
+
+using namespace utest::v1;
+
+#if !defined(MBEDTLS_SSL_CLI_C) && MBED_CONF_MBED_MQTT_TESTS_TLS_ENABLE
+#warning "Cannot run TLS tests (MBED_CONF_MBED_MQTT_TESTS_TLS_ENABLE) with TLS disabled (no MBEDTLS_SSL_CLI_C)"
+#define MBED_CONF_MBED_MQTT_TESTS_TLS_ENABLE false
+#endif
+
+const char *mqtt_global::SSL_CA_PEM =
+
+#ifdef MQTT_TESTS_CA_CERT_FLESPI
+
+    /* mqtt.flespi.io - requires token as username! */
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIGzDCCBbSgAwIBAgIMPFEC2JrizEiAhCVqMA0GCSqGSIb3DQEBCwUAMEwxCzAJ\n"
+    "BgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMSIwIAYDVQQDExlB\n"
+    "bHBoYVNTTCBDQSAtIFNIQTI1NiAtIEcyMB4XDTE3MTIxMTEyMjgzN1oXDTIwMTIx\n"
+    "MTEyMjgzN1owOTEhMB8GA1UECxMYRG9tYWluIENvbnRyb2wgVmFsaWRhdGVkMRQw\n"
+    "EgYDVQQDDAsqLmZsZXNwaS5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n"
+    "ggEBAMVsit1Mh2Ytyym51hFaMcryuiJxl56TFCaeBeppimNw9Fc43xFrWd9yyEp3\n"
+    "BuWHjd29srtOBrThImXoCfbcSy7NpzlOSJlShhBfpyNiodE6N6DkHOisUibhWwj2\n"
+    "otR5VYmP7AQPzpfaKhM0CRcAB733X5Yd/stvbCVQB9069Zyd+lHteL+zKR73muFA\n"
+    "DYZp8angPB9m6fJwbW6LMsFjt19cB31HrDbFg8VXxkgJ/7F988dyHcuReEJTyI+C\n"
+    "XbW9vFyF+/RYm0Gjha3FZcXEV+W1VwP/ZIjiZzlYCxUM72yr96Pfw2X3HG+D3v0t\n"
+    "/uOoCZGXUm7hJtjPXirhFwV0o7UCAwEAAaOCA78wggO7MA4GA1UdDwEB/wQEAwIF\n"
+    "oDCBiQYIKwYBBQUHAQEEfTB7MEIGCCsGAQUFBzAChjZodHRwOi8vc2VjdXJlMi5h\n"
+    "bHBoYXNzbC5jb20vY2FjZXJ0L2dzYWxwaGFzaGEyZzJyMS5jcnQwNQYIKwYBBQUH\n"
+    "MAGGKWh0dHA6Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9nc2FscGhhc2hhMmcyMFcG\n"
+    "A1UdIARQME4wQgYKKwYBBAGgMgEKCjA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3\n"
+    "dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAIBgZngQwBAgEwCQYDVR0TBAIw\n"
+    "ADA+BgNVHR8ENzA1MDOgMaAvhi1odHRwOi8vY3JsMi5hbHBoYXNzbC5jb20vZ3Mv\n"
+    "Z3NhbHBoYXNoYTJnMi5jcmwwIQYDVR0RBBowGIILKi5mbGVzcGkuaW+CCWZsZXNw\n"
+    "aS5pbzAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFOKx\n"
+    "KLsJ/+eKGfPhv553Hwwh43cMMB8GA1UdIwQYMBaAFPXN1TwIUPlqTzq3l9pWg+Zp\n"
+    "0mj3MIIB9QYKKwYBBAHWeQIEAgSCAeUEggHhAd8AdgDd6x0reg1PpiCLga2BaHB+\n"
+    "Lo6dAdVciI09EcTNtuy+zAAAAWBFjG/AAAAEAwBHMEUCIQDRPNudq8fp8HvpMFDN\n"
+    "pvxiMRhYqgVTUhTYr7KJc30dBQIgZRgSp3ytL9kfGtJmGDfXYp6ffyZO1JJnbSd3\n"
+    "BF2GSC4AdQBWFAaaL9fC7NP14b1Esj7HRna5vJkRXMDvlJhV1onQ3QAAAWBFjHAY\n"
+    "AAAEAwBGMEQCICIqW+E4s6O2FbiNqh7li0kMLo1zOKrfmEitnSKIx2DbAiBhtxsd\n"
+    "3e97ravHoGAW3yXRF3jwezfEwyRQ3xXHA98BNAB2AKS5CZC0GFgUh7sTosxncAo8\n"
+    "NZgE+RvfuON3zQ7IDdwQAAABYEWMcpQAAAQDAEcwRQIgJ0EiJuYsYOeyziLXrN+C\n"
+    "dFmaDNyPGbLFWm5VqCi1OpcCIQDTM7TyakLFmBXrEkeJXuOH+ECJ2l4ZVIcoGrdM\n"
+    "UahOCgB2ALvZ37wfinG1k5Qjl6qSe0c4V5UKq1LoGpCWZDaOHtGFAAABYEWMc0wA\n"
+    "AAQDAEcwRQIhAN5+7KD0MrK4d7rbkwHf9fZh0yERoD4F+eEijXiqCruTAiBpIHOb\n"
+    "eEK5xp1IQV7dZQw/eknxyGffqHI6ctYNDpe5DjANBgkqhkiG9w0BAQsFAAOCAQEA\n"
+    "U9yjiRzpDp+Alz68X4K7EbyrGJQJRma5Bkm0IaCwv2gNnOsqRVQPMLz69ft42SbK\n"
+    "ECMGipkiz9VilRmMX82TGuKLuxgZEfYkWr31A7EYjzZ+iFyYMilbI+DA+pi7zcAA\n"
+    "a9wa2D9DT7IC0e9pv1gqiWjA92KJcy+LZt9+xeQCpmdBefxIRZ2g1oKXrUSnlfCt\n"
+    "jZ153YD11Lqrq5ZMS2fedkzNHmasKYJdipXoXcpTywGn6QEDFe22V+HCdDsLWw3d\n"
+    "1MHKVCc+vNcDG0FkrItWjB857pwdZN36VqVVvGuio4oeGOmTHMNzLahN6mA4tABN\n"
+    "Ht7LDqFUSy2ZL4yTyCqEnA==\n"
+    "-----END CERTIFICATE-----"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIETTCCAzWgAwIBAgILBAAAAAABRE7wNjEwDQYJKoZIhvcNAQELBQAwVzELMAkG\n"
+    "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\n"
+    "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNDAyMjAxMDAw\n"
+    "MDBaFw0yNDAyMjAxMDAwMDBaMEwxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\n"
+    "YWxTaWduIG52LXNhMSIwIAYDVQQDExlBbHBoYVNTTCBDQSAtIFNIQTI1NiAtIEcy\n"
+    "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2gHs5OxzYPt+j2q3xhfj\n"
+    "kmQy1KwA2aIPue3ua4qGypJn2XTXXUcCPI9A1p5tFM3D2ik5pw8FCmiiZhoexLKL\n"
+    "dljlq10dj0CzOYvvHoN9ItDjqQAu7FPPYhmFRChMwCfLew7sEGQAEKQFzKByvkFs\n"
+    "MVtI5LHsuSPrVU3QfWJKpbSlpFmFxSWRpv6mCZ8GEG2PgQxkQF5zAJrgLmWYVBAA\n"
+    "cJjI4e00X9icxw3A1iNZRfz+VXqG7pRgIvGu0eZVRvaZxRsIdF+ssGSEj4k4HKGn\n"
+    "kCFPAm694GFn1PhChw8K98kEbSqpL+9Cpd/do1PbmB6B+Zpye1reTz5/olig4het\n"
+    "ZwIDAQABo4IBIzCCAR8wDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C\n"
+    "AQAwHQYDVR0OBBYEFPXN1TwIUPlqTzq3l9pWg+Zp0mj3MEUGA1UdIAQ+MDwwOgYE\n"
+    "VR0gADAyMDAGCCsGAQUFBwIBFiRodHRwczovL3d3dy5hbHBoYXNzbC5jb20vcmVw\n"
+    "b3NpdG9yeS8wMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nbG9iYWxzaWdu\n"
+    "Lm5ldC9yb290LmNybDA9BggrBgEFBQcBAQQxMC8wLQYIKwYBBQUHMAGGIWh0dHA6\n"
+    "Ly9vY3NwLmdsb2JhbHNpZ24uY29tL3Jvb3RyMTAfBgNVHSMEGDAWgBRge2YaRQ2X\n"
+    "yolQL30EzTSo//z9SzANBgkqhkiG9w0BAQsFAAOCAQEAYEBoFkfnFo3bXKFWKsv0\n"
+    "XJuwHqJL9csCP/gLofKnQtS3TOvjZoDzJUN4LhsXVgdSGMvRqOzm+3M+pGKMgLTS\n"
+    "xRJzo9P6Aji+Yz2EuJnB8br3n8NA0VgYU8Fi3a8YQn80TsVD1XGwMADH45CuP1eG\n"
+    "l87qDBKOInDjZqdUfy4oy9RU0LMeYmcI+Sfhy+NmuCQbiWqJRGXy2UzSWByMTsCV\n"
+    "odTvZy84IOgu/5ZR8LrYPZJwR2UcnnNytGAMXOLRc3bgr07i5TelRS+KIz6HxzDm\n"
+    "MTh89N1SyvNTBCVXVmaU6Avu5gMUTu79bZRknl7OedSyps9AsUSoPocZXun4IRZZ\n"
+    "Uw==\n"
+    "-----END CERTIFICATE-----\n";
+
+#elif defined(MQTT_TESTS_CA_CERT_MOSQUITTO)
+
+    /* test.mosquitto.org */
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIC8DCCAlmgAwIBAgIJAOD63PlXjJi8MA0GCSqGSIb3DQEBBQUAMIGQMQswCQYD\n"
+    "VQQGEwJHQjEXMBUGA1UECAwOVW5pdGVkIEtpbmdkb20xDjAMBgNVBAcMBURlcmJ5\n"
+    "MRIwEAYDVQQKDAlNb3NxdWl0dG8xCzAJBgNVBAsMAkNBMRYwFAYDVQQDDA1tb3Nx\n"
+    "dWl0dG8ub3JnMR8wHQYJKoZIhvcNAQkBFhByb2dlckBhdGNob28ub3JnMB4XDTEy\n"
+    "MDYyOTIyMTE1OVoXDTIyMDYyNzIyMTE1OVowgZAxCzAJBgNVBAYTAkdCMRcwFQYD\n"
+    "VQQIDA5Vbml0ZWQgS2luZ2RvbTEOMAwGA1UEBwwFRGVyYnkxEjAQBgNVBAoMCU1v\n"
+    "c3F1aXR0bzELMAkGA1UECwwCQ0ExFjAUBgNVBAMMDW1vc3F1aXR0by5vcmcxHzAd\n"
+    "BgkqhkiG9w0BCQEWEHJvZ2VyQGF0Y2hvby5vcmcwgZ8wDQYJKoZIhvcNAQEBBQAD\n"
+    "gY0AMIGJAoGBAMYkLmX7SqOT/jJCZoQ1NWdCrr/pq47m3xxyXcI+FLEmwbE3R9vM\n"
+    "rE6sRbP2S89pfrCt7iuITXPKycpUcIU0mtcT1OqxGBV2lb6RaOT2gC5pxyGaFJ+h\n"
+    "A+GIbdYKO3JprPxSBoRponZJvDGEZuM3N7p3S/lRoi7G5wG5mvUmaE5RAgMBAAGj\n"
+    "UDBOMB0GA1UdDgQWBBTad2QneVztIPQzRRGj6ZHKqJTv5jAfBgNVHSMEGDAWgBTa\n"
+    "d2QneVztIPQzRRGj6ZHKqJTv5jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUA\n"
+    "A4GBAAqw1rK4NlRUCUBLhEFUQasjP7xfFqlVbE2cRy0Rs4o3KS0JwzQVBwG85xge\n"
+    "REyPOFdGdhBY2P1FNRy0MDr6xr+D2ZOwxs63dG1nnAnWZg7qwoLgpZ4fESPD3PkA\n"
+    "1ZgKJc2zbSQ9fCPxt2W3mdVav66c6fsb7els2W2Iz7gERJSX\n"
+    "-----END CERTIFICATE-----";
+
+#else
+
+    /* Local mosquitto server certificate */
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDzzCCAregAwIBAgIJAJF6EpVf4OtEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV\n"
+    "BAYTAlBMMRAwDgYDVQQIDAdtYXNvdmlhMREwDwYDVQQHDAhXYXJzemF3YTENMAsG\n"
+    "A1UECgwEbW9iaTEMMAoGA1UECwwDc2lsMRUwEwYDVQQDDAwxOTIuMTY4LjguNTIx\n"
+    "FjAUBgkqhkiG9w0BCQEWB21AbS5jb20wHhcNMTkwNTIxMDkzNjQ4WhcNMjQwNTIw\n"
+    "MDkzNjQ4WjB+MQswCQYDVQQGEwJQTDEQMA4GA1UECAwHbWFzb3ZpYTERMA8GA1UE\n"
+    "BwwIV2Fyc3phd2ExDTALBgNVBAoMBG1vYmkxDDAKBgNVBAsMA3NpbDEVMBMGA1UE\n"
+    "AwwMMTkyLjE2OC44LjUyMRYwFAYJKoZIhvcNAQkBFgdtQG0uY29tMIIBIjANBgkq\n"
+    "hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz9+wntWYYOeDrd4EdUXF09OG54LbRyCY\n"
+    "nB+hzjVaPZM36RLE1ea/S04sb3T5MT5QzGi987B9KtAcDQMY9sSjv7XC8wqCv9wd\n"
+    "HDeSf3zRyiVFSbhjWBi4i7BcEHLEjXUinWowwE7QV8UpAKJUsWBX1w8vbe7ooYvX\n"
+    "y3JNPMfhtwGSVtqY0PeAHviLo6Lg8oFJFocFHeDh08W9p5J51SdRh4/CK+eVRpLd\n"
+    "N1vtEePNuemZyM2HT839rPO53j9/Vvbl2nEfDCn3+jSPCcNSwiBsz0ErxZgW76fV\n"
+    "wJnhcBSStMVrd1KhAcf1Um56jSIXMT0sMDk4j8sr/7ROJ72HjXSntwIDAQABo1Aw\n"
+    "TjAdBgNVHQ4EFgQUhOGXTz5aztPFKmEV2g/tKwA8NMswHwYDVR0jBBgwFoAUhOGX\n"
+    "Tz5aztPFKmEV2g/tKwA8NMswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n"
+    "AQEATnQzWf+MYEwtKDZfrxR5SJnBHc5H4Frq2wNVY+h+p/dOUxpshfa0/2AgDGzX\n"
+    "+pIQpA9o5Zo00sX6Fa7gazheWw0iytSEIlFy9vvEm9EG2iH/Bsoki4E6GM334xUF\n"
+    "1o+LH6vVm0J3DIGOAUup6gLs2efGME59hFJefooEAzVhVqgSgPVV09ZCSMo8M6no\n"
+    "qlUfl2sGOJ5mchA3bdGuF2YlWACngwgf/cOUunkoZixz2Nou6ma8antAKTGl9fkK\n"
+    "320LiO6s7tnQ13B9fjd9sZMnIZVZVO962oGm7KaLWAQPrLNX5hypIpo3iHqdepbG\n"
+    "cOTba8KCydjqsOaXl/nYT+1ULQ==\n"
+    "-----END CERTIFICATE-----";
+#endif
+/*
+ * (optional) Client certificate here in PEM format.
+ * Set NULL if you don't use.
+ * "-----BEGIN CERTIFICATE-----\n"
+ * ...
+ * "-----END CERTIFICATE-----\n";
+ */
+const char *mqtt_global::SSL_CLIENT_CERT_PEM = NULL;
+
+/*
+ * (optional) Client private key here in PEM format.
+ * Set NULL if you don't use.
+ * "-----BEGIN RSA PRIVATE KEY-----\n"
+ * ...
+ * "-----END RSA PRIVATE KEY-----\n";
+ */
+const char *mqtt_global::SSL_CLIENT_PRIVATE_KEY_PEM = NULL;
+
+#define MQTT_MBED_PASSWORD_PROTECTION_AVAILABLE
+
+MQTT::Message mqtt_global::default_message;
+MQTTSN::Message mqtt_global::default_message_sn;
+
+Case cases[] = {
+
+    // Legacy API
+    Case("MQTT_LEGACY_CONNECT", MQTT_LEGACY_CONNECT),
+    Case("MQTT_LEGACY_CONNECT_NOT_CONNECTED", MQTT_LEGACY_CONNECT_NOT_CONNECTED),
+    Case("MQTT_LEGACY_SUBSCRIBE", MQTT_LEGACY_SUBSCRIBE),
+    Case("MQTT_LEGACY_SUBSCRIBE_NETWORK_NOT_CONNECTED", MQTT_LEGACY_SUBSCRIBE_NETWORK_NOT_CONNECTED),
+    Case("MQTT_LEGACY_SUBSCRIBE_CLIENT_NOT_CONNECTED", MQTT_LEGACY_SUBSCRIBE_CLIENT_NOT_CONNECTED),
+    Case("MQTT_LEGACY_SUBSCRIBE_TOPIC_TOO_LONG", MQTT_LEGACY_SUBSCRIBE_TOPIC_TOO_LONG),
+    Case("MQTT_LEGACY_SUBSCRIBE_INVALID_MESSAGE_HANDLER", MQTT_LEGACY_SUBSCRIBE_INVALID_MESSAGE_HANDLER),
+#if MBED_CONF_MBED_MQTT_TESTS_PUBLIC_TOPIC_ENABLE
+    Case("MQTT_LEGACY_SUBSCRIBE_RECEIVE", MQTT_LEGACY_SUBSCRIBE_RECEIVE),
+#endif
+    Case("MQTT_LEGACY_UNSUBSCRIBE_WITHOUT_SUBSCRIBE", MQTT_LEGACY_UNSUBSCRIBE_WITHOUT_SUBSCRIBE),
+    Case("MQTT_LEGACY_UNSUBSCRIBE_INVALID", MQTT_LEGACY_UNSUBSCRIBE_INVALID),
+    Case("MQTT_LEGACY_PUBLISH", MQTT_LEGACY_PUBLISH),
+    Case("MQTT_LEGACY_PUBLISH_NOT_CONNECTED", MQTT_LEGACY_PUBLISH_NOT_CONNECTED),
+    Case("MQTT_LEGACY_PUBLISH_TOPIC_TOO_LONG", MQTT_LEGACY_PUBLISH_TOPIC_TOO_LONG),
+#if MBED_CONF_MBED_MQTT_TESTS_USERNAME_PASSWORD_PROTECTION_ENABLE
+    Case("MQTT_LEGACY_CONNECT_USER_PASSWORD_INCORRECT", MQTT_LEGACY_CONNECT_USER_PASSWORD_INCORRECT),
+#endif
+#if MBED_CONF_MBED_MQTT_TESTS_USERNAME_PASSWORD_PROTECTION_ENABLE
+    Case("MQTT_LEGACY_CONNECT_SUBSCRIBE_PUBLISH_USER_PASSWORD", MQTT_LEGACY_CONNECT_SUBSCRIBE_PUBLISH_USER_PASSWORD),
+#endif
+    Case("MQTT_LEGACY_CONNECT_SUBSCRIBE_PUBLISH", MQTT_LEGACY_CONNECT_SUBSCRIBE_PUBLISH),
+#if MBED_CONF_MBED_MQTT_TESTS_TLS_ENABLE
+    Case("MQTT_LEGACY_TLS_CONNECT_SUBSCRIBE_PUBLISH", MQTT_LEGACY_TLS_CONNECT_SUBSCRIBE_PUBLISH),
+#endif
+
+#if MBED_CONF_MBED_MQTT_TESTS_MQTT_SN_ENABLE
+    // MQTT-SN
+    Case("MQTTSN_LEGACY_CONNECT", MQTTSN_LEGACY_CONNECT),
+    Case("MQTTSN_LEGACY_CONNECT_NOT_CONNECTED", MQTTSN_LEGACY_CONNECT_NOT_CONNECTED),
+    Case("MQTTSN_LEGACY_SUBSCRIBE", MQTTSN_LEGACY_SUBSCRIBE),
+    Case("MQTTSN_LEGACY_SUBSCRIBE_NETWORK_NOT_CONNECTED", MQTTSN_LEGACY_SUBSCRIBE_NETWORK_NOT_CONNECTED),
+//    Case("MQTTSN_LEGACY_SUBSCRIBE_CLIENT_NOT_CONNECTED", MQTTSN_LEGACY_SUBSCRIBE_CLIENT_NOT_CONNECTED),
+    Case("MQTTSN_LEGACY_SUBSCRIBE_TOPIC_TOO_LONG", MQTTSN_LEGACY_SUBSCRIBE_TOPIC_TOO_LONG),
+    Case("MQTTSN_LEGACY_SUBSCRIBE_INVALID_MESSAGE_HANDLER", MQTTSN_LEGACY_SUBSCRIBE_INVALID_MESSAGE_HANDLER),
+#if MBED_CONF_MBED_MQTT_TESTS_PUBLIC_TOPIC_ENABLE
+    Case("MQTTSN_LEGACY_SUBSCRIBE_RECEIVE", MQTTSN_LEGACY_SUBSCRIBE_RECEIVE),
+#endif
+    Case("MQTTSN_LEGACY_UNSUBSCRIBE_WITHOUT_SUBSCRIBE", MQTTSN_LEGACY_UNSUBSCRIBE_WITHOUT_SUBSCRIBE),
+    Case("MQTTSN_LEGACY_UNSUBSCRIBE_INVALID", MQTTSN_LEGACY_UNSUBSCRIBE_INVALID),
+    Case("MQTTSN_LEGACY_PUBLISH", MQTTSN_LEGACY_PUBLISH),
+    Case("MQTTSN_LEGACY_PUBLISH_NOT_CONNECTED", MQTTSN_LEGACY_PUBLISH_NOT_CONNECTED),
+    Case("MQTTSN_LEGACY_PUBLISH_TOPIC_TOO_LONG", MQTTSN_LEGACY_PUBLISH_TOPIC_TOO_LONG),
+    Case("MQTTSN_LEGACY_UDP_CONNECT_SUBSCRIBE_PUBLISH", MQTTSN_LEGACY_UDP_CONNECT_SUBSCRIBE_PUBLISH),
+    Case("MQTTSN_LEGACY_IS_CONNECTED", MQTTSN_LEGACY_IS_CONNECTED),
+    Case("MQTTSN_LEGACY_IS_CONNECTED_CLIENT_NOT_CONNECTED", MQTTSN_LEGACY_IS_CONNECTED_CLIENT_NOT_CONNECTED),
+    Case("MQTTSN_LEGACY_IS_CONNECTED_NETWORK_NOT_CONNECTED", MQTTSN_LEGACY_IS_CONNECTED_NETWORK_NOT_CONNECTED),
+#endif
+
+    // New mbed-os API
+    Case("MQTT_CONNECT", MQTT_CONNECT),
+    Case("MQTT_CONNECT_NOT_CONNECTED", MQTT_CONNECT_NOT_CONNECTED),
+    Case("MQTT_SUBSCRIBE", MQTT_SUBSCRIBE),
+    Case("MQTT_SUBSCRIBE_NETWORK_NOT_CONNECTED", MQTT_SUBSCRIBE_NETWORK_NOT_CONNECTED),
+    Case("MQTT_SUBSCRIBE_CLIENT_NOT_CONNECTED", MQTT_SUBSCRIBE_CLIENT_NOT_CONNECTED),
+    Case("MQTT_SUBSCRIBE_TOPIC_TOO_LONG", MQTT_SUBSCRIBE_TOPIC_TOO_LONG),
+    Case("MQTT_SUBSCRIBE_INVALID_MESSAGE_HANDLER", MQTT_SUBSCRIBE_INVALID_MESSAGE_HANDLER),
+#if MBED_CONF_MBED_MQTT_TESTS_PUBLIC_TOPIC_ENABLE
+    Case("MQTT_SUBSCRIBE_RECEIVE", MQTT_SUBSCRIBE_RECEIVE),
+#endif
+    Case("MQTT_UNSUBSCRIBE_WITHOUT_SUBSCRIBE", MQTT_UNSUBSCRIBE_WITHOUT_SUBSCRIBE),
+    Case("MQTT_UNSUBSCRIBE_INVALID", MQTT_UNSUBSCRIBE_INVALID),
+    Case("MQTT_PUBLISH", MQTT_PUBLISH),
+    Case("MQTT_PUBLISH_NOT_CONNECTED", MQTT_PUBLISH_NOT_CONNECTED),
+    Case("MQTT_PUBLISH_TOPIC_TOO_LONG", MQTT_PUBLISH_TOPIC_TOO_LONG),
+#if MBED_CONF_MBED_MQTT_TESTS_USERNAME_PASSWORD_PROTECTION_ENABLE
+    Case("MQTT_CONNECT_USER_PASSWORD_INCORRECT", MQTT_CONNECT_USER_PASSWORD_INCORRECT),
+#endif
+#if MBED_CONF_MBED_MQTT_TESTS_USERNAME_PASSWORD_PROTECTION_ENABLE
+    Case("MQTT_CONNECT_SUBSCRIBE_PUBLISH_USER_PASSWORD", MQTT_CONNECT_SUBSCRIBE_PUBLISH_USER_PASSWORD),
+#endif
+    Case("MQTT_CONNECT_SUBSCRIBE_PUBLISH", MQTT_CONNECT_SUBSCRIBE_PUBLISH),
+#if MBED_CONF_MBED_MQTT_TESTS_TLS_ENABLE
+    Case("MQTT_TLS_CONNECT_SUBSCRIBE_PUBLISH", MQTT_TLS_CONNECT_SUBSCRIBE_PUBLISH),
+#endif
+
+#if MBED_CONF_MBED_MQTT_TESTS_MQTT_SN_ENABLE
+    // MQTT-SN new API
+    Case("MQTTSN_TEST_CONNECT", MQTTSN_TEST_CONNECT),
+    Case("MQTTSN_CONNECT_NOT_CONNECTED", MQTTSN_CONNECT_NOT_CONNECTED),
+    Case("MQTTSN_TEST_SUBSCRIBE", MQTTSN_TEST_SUBSCRIBE),
+    Case("MQTTSN_SUBSCRIBE_NETWORK_NOT_CONNECTED", MQTTSN_SUBSCRIBE_NETWORK_NOT_CONNECTED),
+//    Case("MQTTSN_SUBSCRIBE_CLIENT_NOT_CONNECTED", MQTTSN_SUBSCRIBE_CLIENT_NOT_CONNECTED),
+    Case("MQTTSN_SUBSCRIBE_TOPIC_TOO_LONG", MQTTSN_SUBSCRIBE_TOPIC_TOO_LONG),
+    Case("MQTTSN_SUBSCRIBE_INVALID_MESSAGE_HANDLER", MQTTSN_SUBSCRIBE_INVALID_MESSAGE_HANDLER),
+#if MBED_CONF_MBED_MQTT_TESTS_PUBLIC_TOPIC_ENABLE
+    Case("MQTTSN_SUBSCRIBE_RECEIVE", MQTTSN_SUBSCRIBE_RECEIVE),
+#endif
+    Case("MQTTSN_UNSUBSCRIBE_WITHOUT_SUBSCRIBE", MQTTSN_UNSUBSCRIBE_WITHOUT_SUBSCRIBE),
+    Case("MQTTSN_UNSUBSCRIBE_INVALID", MQTTSN_UNSUBSCRIBE_INVALID),
+    Case("MQTTSN_TEST_PUBLISH", MQTTSN_TEST_PUBLISH),
+    Case("MQTTSN_PUBLISH_NOT_CONNECTED", MQTTSN_PUBLISH_NOT_CONNECTED),
+    Case("MQTTSN_PUBLISH_TOPIC_TOO_LONG", MQTTSN_PUBLISH_TOPIC_TOO_LONG),
+    Case("MQTTSN_UDP_CONNECT_SUBSCRIBE_PUBLISH", MQTTSN_UDP_CONNECT_SUBSCRIBE_PUBLISH),
+#if MBED_CONF_MBED_MQTT_TESTS_TLS_ENABLE
+    Case("MQTTSN_DTLS_CONNECT_SUBSCRIBE_PUBLISH", MQTTSN_DTLS_CONNECT_SUBSCRIBE_PUBLISH),
+#endif
+    Case("MQTTSN_IS_CONNECTED", MQTTSN_IS_CONNECTED),
+    Case("MQTTSN_IS_CONNECTED_CLIENT_NOT_CONNECTED", MQTTSN_IS_CONNECTED_CLIENT_NOT_CONNECTED),
+    Case("MQTTSN_IS_CONNECTED_NETWORK_NOT_CONNECTED", MQTTSN_IS_CONNECTED_NETWORK_NOT_CONNECTED),
+#endif
+};
+
+int arrivedcount = 0;
+int arrivedcountSN = 0;
+
+void messageArrived(MQTT::MessageData &md)
+{
+    MQTT::Message &message = md.message;
+    printf("Message arrived: qos %d, retained %d, dup %d, packetid %d\r\n", message.qos, message.retained, message.dup, message.id);
+    printf("Payload %.*s\r\n", message.payloadlen, (char *)message.payload);
+    ++arrivedcount;
+    printf("arrived msg: %d\n", arrivedcount);
+}
+
+void messageArrivedSN(MQTTSN::MessageData &md)
+{
+    MQTTSN::Message &message = md.message;
+    printf("Message arrived SN: qos %d, retained %d, dup %d, packetid %d\r\n", message.qos, message.retained, message.dup, message.id);
+    printf("Payload %.*s\r\n", message.payloadlen, (char *)message.payload);
+    ++arrivedcountSN;
+    printf("arrived msg: %d\n", arrivedcountSN);
+}
+
+void init_topic_sn(MQTTSN_topicid &topic_sn)
+{
+    topic_sn.type = MQTTSN_TOPIC_TYPE_NORMAL;
+    topic_sn.data.long_.len = strlen(mqtt_global::topic);
+    topic_sn.data.long_.name = const_cast<char *>(mqtt_global::topic);
+}
+
+void init_topic_sn_too_long(MQTTSN_topicid &topic_sn)
+{
+    topic_sn.type = MQTTSN_TOPIC_TYPE_NORMAL;
+    topic_sn.data.long_.len = strlen(mqtt_global::topic_too_long);
+    topic_sn.data.long_.name = const_cast<char *>(mqtt_global::topic_too_long);
+}
+
+// Test setup
+utest::v1::status_t test_setup(const size_t number_of_cases)
+{
+#ifdef MBED_GREENTEA_TEST_INTERFACE_TIMEOUT_S
+    GREENTEA_SETUP(MBED_GREENTEA_TEST_INTERFACE_TIMEOUT_S, "default_auto");
+#else
+    GREENTEA_SETUP(480, "default_auto");
+#endif
+
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    nsapi_error_t err = net->connect();
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, err);
+
+    SocketAddress addr;
+    err = net->get_ip_address(&addr);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, err);
+
+    printf("MBED: TCPClient IP address is '%s'\n", addr.get_ip_address());
+
+    // Generate an string of length MAX_MQTT_PACKET_SIZE+1 with alphabet letters.
+    char c = 'a';
+    for (int i = 0; i < MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE + 1; i++) {
+        mqtt_global::topic_too_long[i] = c;
+        if (c < 'z') {
+            c++;
+        } else {
+            c = 'a';
+        }
+    }
+
+    // Prepare a default message, to avoid code duplication at a later stage.
+    sprintf(mqtt_global::message_buffer, "%s", "MQTT_MBED_OS_TEST_MESSAGE");
+    mqtt_global::default_message.qos = MQTT::QOS0;
+    mqtt_global::default_message.retained = false;
+    mqtt_global::default_message.dup = false;
+    mqtt_global::default_message.payload = (void *)mqtt_global::message_buffer;
+    mqtt_global::default_message.payloadlen = strlen(mqtt_global::message_buffer) + 1;
+
+    sprintf(mqtt_global::message_buffer, "%s", "MQTTSN_MBED_OS_TEST_MESSAGE");
+    mqtt_global::default_message_sn.qos = MQTTSN::QOS0;
+    mqtt_global::default_message_sn.retained = false;
+    mqtt_global::default_message_sn.dup = false;
+    mqtt_global::default_message_sn.payload = (void *)mqtt_global::message_buffer;
+    mqtt_global::default_message_sn.payloadlen = strlen(mqtt_global::message_buffer) + 1;
+
+    mqtt_global::mbed_public_test_topic_sn.type = MQTTSN_TOPIC_TYPE_NORMAL;
+    mqtt_global::mbed_public_test_topic_sn.data.long_.len = strlen(mqtt_global::mbed_public_test_topic) + 1;
+    mqtt_global::mbed_public_test_topic_sn.data.long_.name = const_cast<char *>(mqtt_global::mbed_public_test_topic);
+
+    return verbose_test_setup_handler(number_of_cases);
+}
+
+void greentea_teardown(const size_t passed, const size_t failed, const failure_t failure)
+{
+    NetworkInterface::get_default_instance()->disconnect();
+    return greentea_test_teardown_handler(passed, failed, failure);
+}
+
+Specification specification(test_setup, cases);
+
+int main()
+{
+    return !Harness::run(specification);
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/TESTS/mqtt/mqtt/mqtt-sn_legacy.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/TESTS/mqtt/mqtt/mqtt-sn_legacy.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2019, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <MQTTSNNetworkUDP.h>
+#include "mqtt_tests.h"
+
+#include <MQTTSNClient.h>
+#include <MQTTmbed.h> // Countdown
+
+#define MQTTSN_LEGACY_API_INIT() \
+    arrivedcountSN = 0; \
+    NetworkInterface *net = NetworkInterface::get_default_instance(); \
+    MQTTSNNetworkUDP mqttNet(net); \
+    MQTTSN::Client<MQTTSNNetworkUDP, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE> client(mqttNet); \
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, mqttNet.connect(mqtt_global::hostname, mqtt_global::port_udp)); \
+    MQTTSNPacket_connectData data = MQTTSNPacket_connectData_initializer;
+
+#define MQTTSN_LEGACY_API_DEINIT() TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, mqttNet.disconnect());
+
+void MQTTSN_LEGACY_CONNECT()
+{
+    MQTTSN_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_LEGACY_CONNECT";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTTSN_LEGACY_API_DEINIT();
+}
+
+void MQTTSN_LEGACY_CONNECT_NOT_CONNECTED()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    MQTTSNNetworkUDP mqttNet(net);
+    MQTTSN::Client<MQTTSNNetworkUDP, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE> client(mqttNet);
+    //Connect in UDP is not real, it will return success...
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, mqttNet.connect("i.dont.exist", mqtt_global::port_udp));
+    MQTTSNPacket_connectData data = MQTTSNPacket_connectData_initializer;
+    //... but we should not be able to connect to the server.
+    TEST_ASSERT_EQUAL(-1, client.connect(data));
+}
+
+void MQTTSN_LEGACY_SUBSCRIBE()
+{
+    MQTTSN_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_LEGACY_TEST_SUBSCRIBE";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTTSN_topicid topic_sn;
+    init_topic_sn(topic_sn);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(topic_sn, MQTTSN::QOS0, messageArrivedSN));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(topic_sn));
+    init_topic_sn(topic_sn);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(topic_sn, MQTTSN::QOS1, messageArrivedSN));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(topic_sn));
+    init_topic_sn(topic_sn);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(topic_sn, MQTTSN::QOS2, messageArrivedSN));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(topic_sn));
+    MQTTSN_LEGACY_API_DEINIT();
+
+}
+
+void MQTTSN_LEGACY_SUBSCRIBE_NETWORK_NOT_CONNECTED()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    MQTTSNNetworkUDP mqttNet(net);
+    MQTTSN::Client<MQTTSNNetworkUDP, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE> client(mqttNet);
+    //Connect in UDP is not real, it will return success...
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, mqttNet.connect("i.dont.exist", mqtt_global::port));
+    MQTTSNPacket_connectData data = MQTTSNPacket_connectData_initializer;
+    data.clientID.cstring = (char *)"MQTTSN_LEGACY_SUBSCRIBE_NETWORK_NOT_CONNECTED";
+    // ... but the connect should fail ...
+    TEST_ASSERT_EQUAL(-1, client.connect(data));
+    MQTTSN_topicid topic_sn;
+    init_topic_sn(topic_sn);
+    // ... and subscribe should also fail.
+    TEST_ASSERT_EQUAL(-1, client.subscribe(topic_sn, MQTTSN::QOS0, messageArrivedSN));
+}
+
+void MQTTSN_LEGACY_SUBSCRIBE_CLIENT_NOT_CONNECTED()
+{
+    MQTTSN_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
+    MQTTSN_topicid topic_sn;
+    init_topic_sn(topic_sn);
+    TEST_ASSERT_EQUAL(-1, client.connect(data));
+    TEST_ASSERT_EQUAL(-1, client.subscribe(topic_sn, MQTTSN::QOS0, messageArrivedSN));
+    MQTTSN_LEGACY_API_DEINIT();
+}
+
+void MQTTSN_LEGACY_SUBSCRIBE_TOPIC_TOO_LONG()
+{
+    MQTTSN_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_LEGACY_SUBSCRIBE_TOPIC_TOO_LONG";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTTSN_topicid topic_sn;
+    init_topic_sn_too_long(topic_sn);
+    TEST_ASSERT_EQUAL(-1, client.subscribe(topic_sn, MQTTSN::QOS0, messageArrivedSN));
+    MQTTSN_LEGACY_API_DEINIT();
+}
+
+void MQTTSN_LEGACY_SUBSCRIBE_INVALID_MESSAGE_HANDLER()
+{
+    MQTTSN_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_LEGACY_SUBSCRIBE_INVALID_MESSAGE_HANDLER";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTTSN_topicid topic_sn;
+    init_topic_sn(topic_sn);
+    // There is no NULL check inside the subscribe function.
+    TEST_ASSERT_EQUAL(-1, client.subscribe(topic_sn, MQTTSN::QOS0, NULL));
+    MQTTSN_LEGACY_API_DEINIT();
+}
+
+void MQTTSN_LEGACY_SUBSCRIBE_RECEIVE()
+{
+    MQTTSN_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_LEGACY_SUBSCRIBE_INVALID_MESSAGE_HANDLER";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    int arrivedCountBeforeSubscription = arrivedcountSN;
+    MQTTSN_topicid topic_sn;
+    topic_sn.type = MQTTSN_TOPIC_TYPE_NORMAL;
+    topic_sn.data.long_.len = strlen(mqtt_global::mbed_public_test_topic);
+    topic_sn.data.long_.name = const_cast<char *>(mqtt_global::mbed_public_test_topic);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(topic_sn, MQTTSN::QOS0, messageArrivedSN));
+    // TODO get the callbacks working for MQTT-SN
+    while (arrivedCountBeforeSubscription == arrivedcountSN) {
+        client.yield(100);
+    }
+    TEST_ASSERT_TRUE(arrivedCountBeforeSubscription < arrivedcountSN);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(topic_sn));
+    MQTTSN_LEGACY_API_DEINIT();
+}
+
+void MQTTSN_LEGACY_UNSUBSCRIBE_WITHOUT_SUBSCRIBE()
+{
+    MQTTSN_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_LEGACY_UNSUBSCRIBE_WITHOUT_SUBSCRIBE";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTTSN_topicid topic_sn;
+    init_topic_sn(topic_sn);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(topic_sn));
+    MQTTSN_LEGACY_API_DEINIT();
+}
+
+void MQTTSN_LEGACY_UNSUBSCRIBE_INVALID()
+{
+    MQTTSN_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_LEGACY_UNSUBSCRIBE_INVALID";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTTSN_topicid topic_sn_too_long;
+    init_topic_sn_too_long(topic_sn_too_long);
+    TEST_ASSERT_EQUAL(-1, client.unsubscribe(topic_sn_too_long));
+    MQTTSN_LEGACY_API_DEINIT();
+}
+
+void MQTTSN_LEGACY_PUBLISH()
+{
+    MQTTSN_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_LEGACY_PUBLISH";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTTSN_topicid topic_sn;
+    init_topic_sn(topic_sn);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(topic_sn, mqtt_global::default_message_sn));
+    MQTTSN::Message msg = mqtt_global::default_message_sn;
+    msg.qos = MQTTSN::QOS1;
+    // TODO: get QoS 1 and 2 working. Maybe we need to reconnect?
+//    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(topic_sn, msg));
+//    msg.qos = MQTTSN::QOS2;
+//    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(topic_sn, msg));
+    MQTTSN_LEGACY_API_DEINIT();
+}
+
+void MQTTSN_LEGACY_PUBLISH_NOT_CONNECTED()
+{
+    MQTTSN_LEGACY_API_INIT();
+    MQTTSN_topicid topic_sn;
+    init_topic_sn(topic_sn);
+    TEST_ASSERT_EQUAL(-1, client.publish(topic_sn, mqtt_global::default_message_sn));
+    MQTTSN_LEGACY_API_DEINIT();
+}
+
+void MQTTSN_LEGACY_PUBLISH_TOPIC_TOO_LONG()
+{
+    MQTTSN_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_PUBLISH";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    // TODO verify if this is passing intentionally or if this is a bug?
+//    TEST_ASSERT_EQUAL(-1, client.publish(mqtt_global::topic_too_long, mqtt_global::default_message));
+    MQTTSN_LEGACY_API_DEINIT();
+}
+
+// QTT-SN does not provide the user/password functionality so
+// MQTT_CONNECT_USER_PASSWORD_INCORRECT and MQTT_CONNECT_SUBSCRIBE_PUBLISH_USER_PASSWORD
+// cannot be executed for MQTT-SN
+
+void MQTTSN_LEGACY_IS_CONNECTED()
+{
+    MQTTSN_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_LEGACY_IS_CONNECTED";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    TEST_ASSERT_TRUE(client.isConnected());
+    MQTTSN_LEGACY_API_DEINIT();
+}
+
+void MQTTSN_LEGACY_IS_CONNECTED_CLIENT_NOT_CONNECTED()
+{
+    MQTTSN_LEGACY_API_INIT();
+    TEST_ASSERT_FALSE(client.isConnected());
+    MQTTSN_LEGACY_API_DEINIT();
+}
+
+void MQTTSN_LEGACY_IS_CONNECTED_NETWORK_NOT_CONNECTED()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    MQTTSNNetworkUDP mqttNet(net);
+    MQTTSN::Client<MQTTSNNetworkUDP, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE> client(mqttNet);
+    //Connect in UDP is not real, it will return success...
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, mqttNet.connect("i.dont.exist", mqtt_global::port));
+    MQTTSNPacket_connectData data = MQTTSNPacket_connectData_initializer;
+    data.clientID.cstring = (char *)"MQTTSN_LEGACY_SUBSCRIBE_NETWORK_NOT_CONNECTED";
+
+    TEST_ASSERT_FALSE(client.isConnected());
+
+    // ... but the connect should fail ...
+    TEST_ASSERT_EQUAL(-1, client.connect(data));
+
+    TEST_ASSERT_FALSE(client.isConnected());
+}
+
+void MQTTSN_LEGACY_UDP_CONNECT_SUBSCRIBE_PUBLISH()
+{
+    arrivedcountSN = 0;
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    MQTTSNNetworkUDP mqttNet(net);
+
+    MQTTSN::Client<MQTTSNNetworkUDP, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE> client(mqttNet);
+
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, mqttNet.connect(mqtt_global::hostname, mqtt_global::port_udp));
+
+    send_messages_sn< MQTTSN::Client<MQTTSNNetworkUDP, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE> >(client, "MQTTSN_LEGACY_UDP_CONNECT_SUBSCRIBE_PUBLISH");
+
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, mqttNet.disconnect());
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/TESTS/mqtt/mqtt/mqtt-sn_new.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/TESTS/mqtt/mqtt/mqtt-sn_new.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2019, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mqtt_tests.h"
+
+#include <MQTTClientMbedOs.h>
+
+#define MQTTSN_API_INIT() \
+    arrivedcountSN = 0; \
+    NetworkInterface *net = NetworkInterface::get_default_instance(); \
+    SocketAddress sockAddr; \
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, net->gethostbyname(mqtt_global::hostname, &sockAddr)); \
+    sockAddr.set_port(mqtt_global::port_udp); \
+    UDPSocket socket; \
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.open(net)); \
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.connect(sockAddr)); \
+    MQTTClient client(&socket); \
+    MQTTSNPacket_connectData data = MQTTSNPacket_connectData_initializer;
+
+#define MQTTSN_API_DEINIT() \
+        TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.close());\
+
+void MQTTSN_TEST_CONNECT()
+{
+    MQTTSN_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_CONNECT";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTTSN_API_DEINIT();
+}
+
+void MQTTSN_CONNECT_NOT_CONNECTED()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    SocketAddress sockAddr("i.dont.exist", mqtt_global::port_udp);
+    UDPSocket socket;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.open(net));
+
+    //Connect in UDP is not real, it will return success...
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.connect(sockAddr));
+    MQTTClient client(&socket);
+    MQTTSNPacket_connectData data = MQTTSNPacket_connectData_initializer;
+
+    //... but we should not be able to connect to the server.
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.connect(data));
+}
+
+void MQTTSN_TEST_SUBSCRIBE()
+{
+    MQTTSN_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_TEST_SUBSCRIBE";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTTSN_topicid topic_sn;
+    init_topic_sn(topic_sn);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(topic_sn, MQTTSN::QOS0, messageArrivedSN));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(topic_sn));
+    init_topic_sn(topic_sn);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(topic_sn, MQTTSN::QOS1, messageArrivedSN));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(topic_sn));
+    init_topic_sn(topic_sn);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(topic_sn, MQTTSN::QOS2, messageArrivedSN));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(topic_sn));
+    MQTTSN_API_DEINIT();
+
+}
+
+void MQTTSN_SUBSCRIBE_NETWORK_NOT_CONNECTED()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    SocketAddress sockAddr("i.dont.exist", mqtt_global::port_udp);
+    UDPSocket socket;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.open(net));
+
+    //Connect in UDP is not real, it will return success...
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.connect(sockAddr));
+    MQTTClient client(&socket);
+    MQTTSNPacket_connectData data = MQTTSNPacket_connectData_initializer;
+    data.clientID.cstring = (char *)"MQTTSN_SUBSCRIBE_NETWORK_NOT_CONNECTED";
+    // ... but the connect should fail ...
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.connect(data));
+    MQTTSN_topicid topic_sn;
+    init_topic_sn(topic_sn);
+    // ... and subscribe should also fail.
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.subscribe(topic_sn, MQTTSN::QOS0, messageArrivedSN));
+}
+
+void MQTTSN_SUBSCRIBE_CLIENT_NOT_CONNECTED()
+{
+    MQTTSN_API_INIT();
+    data.clientID.cstring = (char *)"12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
+    MQTTSN_topicid topic_sn;
+    init_topic_sn(topic_sn);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.connect(data));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.subscribe(topic_sn, MQTTSN::QOS0, messageArrivedSN));
+    MQTTSN_API_DEINIT();
+}
+
+void MQTTSN_SUBSCRIBE_TOPIC_TOO_LONG()
+{
+    MQTTSN_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_SUBSCRIBE_TOPIC_TOO_LONG";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTTSN_topicid topic_sn;
+    init_topic_sn_too_long(topic_sn);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.subscribe(topic_sn, MQTTSN::QOS0, messageArrivedSN));
+    MQTTSN_API_DEINIT();
+}
+
+void MQTTSN_SUBSCRIBE_INVALID_MESSAGE_HANDLER()
+{
+    MQTTSN_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_SUBSCRIBE_INVALID_MESSAGE_HANDLER";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTTSN_topicid topic_sn;
+    init_topic_sn(topic_sn);
+    // There is no NULL check inside the subscribe function.
+//    TEST_ASSERT_EQUAL(-1, client.subscribe(topic_sn, MQTTSN::QOS0, NULL));
+    MQTTSN_API_DEINIT();
+}
+
+void MQTTSN_SUBSCRIBE_RECEIVE()
+{
+    MQTTSN_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_SUBSCRIBE_INVALID_MESSAGE_HANDLER";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    int arrivedCountBeforeSubscription = arrivedcountSN;
+    MQTTSN_topicid topic_sn;
+    topic_sn.type = MQTTSN_TOPIC_TYPE_NORMAL;
+    topic_sn.data.long_.len = strlen(mqtt_global::mbed_public_test_topic);
+    topic_sn.data.long_.name = const_cast<char *>(mqtt_global::mbed_public_test_topic);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(topic_sn, MQTTSN::QOS0, messageArrivedSN));
+    // TODO get the callbacks working for MQTT-SN
+    while (arrivedCountBeforeSubscription == arrivedcountSN) {
+        client.yield(100);
+    }
+    TEST_ASSERT_TRUE(arrivedCountBeforeSubscription < arrivedcountSN);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(topic_sn));
+    MQTTSN_API_DEINIT();
+}
+
+void MQTTSN_UNSUBSCRIBE_WITHOUT_SUBSCRIBE()
+{
+    MQTTSN_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_UNSUBSCRIBE_WITHOUT_SUBSCRIBE";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTTSN_topicid topic_sn;
+    init_topic_sn(topic_sn);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(topic_sn));
+    MQTTSN_API_DEINIT();
+}
+
+void MQTTSN_UNSUBSCRIBE_INVALID()
+{
+    MQTTSN_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_UNSUBSCRIBE_INVALID";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTTSN_topicid topic_sn_too_long;
+    init_topic_sn_too_long(topic_sn_too_long);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.unsubscribe(topic_sn_too_long));
+    MQTTSN_API_DEINIT();
+}
+
+void MQTTSN_TEST_PUBLISH()
+{
+    MQTTSN_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_PUBLISH";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTTSN_topicid topic_sn;
+    init_topic_sn(topic_sn);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(topic_sn, mqtt_global::default_message_sn));
+    MQTTSN::Message msg = mqtt_global::default_message_sn;
+    msg.qos = MQTTSN::QOS1;
+    // TODO: get QoS 1 and 2 working. Maybe we need to reconnect?
+//    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(topic_sn, msg));
+//    msg.qos = MQTTSN::QOS2;
+//    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(topic_sn, msg));
+    MQTTSN_API_DEINIT();
+}
+
+void MQTTSN_PUBLISH_NOT_CONNECTED()
+{
+    MQTTSN_API_INIT();
+    MQTTSN_topicid topic_sn;
+    init_topic_sn(topic_sn);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.publish(topic_sn, mqtt_global::default_message_sn));
+    MQTTSN_API_DEINIT();
+}
+
+void MQTTSN_PUBLISH_TOPIC_TOO_LONG()
+{
+    MQTTSN_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_PUBLISH";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    // TODO verify if this is passing intentionally or if this is a bug?
+//    TEST_ASSERT_EQUAL(-1, client.publish(mqtt_global::topic_too_long, mqtt_global::default_message));
+    MQTTSN_API_DEINIT();
+}
+
+// QTT-SN does not provide the user/password functionality so
+// MQTT_CONNECT_USER_PASSWORD_INCORRECT and MQTT_CONNECT_SUBSCRIBE_PUBLISH_USER_PASSWORD
+// cannot be executed for MQTT-SN
+
+void MQTTSN_IS_CONNECTED()
+{
+    MQTTSN_API_INIT();
+    data.clientID.cstring = (char *)"MQTTSN_IS_CONNECTED";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    TEST_ASSERT_TRUE(client.isConnected());
+    MQTTSN_API_DEINIT();
+}
+
+void MQTTSN_IS_CONNECTED_CLIENT_NOT_CONNECTED()
+{
+    MQTTSN_API_INIT();
+    TEST_ASSERT_FALSE(client.isConnected());
+    MQTTSN_API_DEINIT();
+}
+
+void MQTTSN_IS_CONNECTED_NETWORK_NOT_CONNECTED()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    SocketAddress sockAddr("i.dont.exist", mqtt_global::port_udp);
+    UDPSocket socket;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.open(net));
+
+    //Connect in UDP is not real, it will return success...
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.connect(sockAddr));
+    MQTTClient client(&socket);
+    MQTTSNPacket_connectData data = MQTTSNPacket_connectData_initializer;
+    data.clientID.cstring = (char *)"MQTTSN_IS_CONNECTED_NETWORK_NOT_CONNECTED";
+
+    TEST_ASSERT_FALSE(client.isConnected());
+
+    // ... but the connect should fail ...
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.connect(data));
+
+    TEST_ASSERT_FALSE(client.isConnected());
+}
+
+void MQTTSN_UDP_CONNECT_SUBSCRIBE_PUBLISH()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    SocketAddress sockAddr(mqtt_global::hostname, mqtt_global::port_udp);
+    UDPSocket socket;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.open(net));
+    TEST_ASSERT(NSAPI_ERROR_OK == socket.connect(sockAddr));
+    MQTTClient client(&socket);
+
+    send_messages_sn< MQTTClient >(client, "MQTT_FULL_NEW_UDP");
+
+    socket.close();
+}
+
+#if defined(MBEDTLS_SSL_CLI_C)
+void MQTTSN_DTLS_CONNECT_SUBSCRIBE_PUBLISH()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    DTLSSocket *socket = new DTLSSocket; // Allocate on heap to avoid stack overflow.
+    TEST_ASSERT(NSAPI_ERROR_OK == socket->open(net));
+    SocketAddress addr;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, net->gethostbyname(mqtt_global::hostname, &addr));
+    addr.set_port(mqtt_global::port_udp);
+    TEST_ASSERT(NSAPI_ERROR_OK == socket->set_root_ca_cert(mqtt_global::SSL_CA_PEM));
+    int ret = socket->connect(addr);
+    TEST_ASSERT(NSAPI_ERROR_OK == ret);
+
+    MQTTClient client(socket);
+
+    send_messages_sn< MQTTClient >(client, "MQTTSN_DTLS_CONNECT_SUBSCRIBE_PUBLISH");
+
+    socket->close();
+    delete socket;
+}
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/TESTS/mqtt/mqtt/mqtt_legacy.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/TESTS/mqtt/mqtt/mqtt_legacy.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2019, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <MQTTNetwork.h>
+#include <MQTTNetworkTLS.h>
+#include "mqtt_tests.h"
+
+#include <MQTTClient.h>
+#include <MQTTmbed.h> // Countdown
+
+#define MQTT_LEGACY_API_INIT() \
+    arrivedcount = 0; \
+    NetworkInterface *net = NetworkInterface::get_default_instance(); \
+    MQTTNetwork mqttNet(net); \
+    MQTT::Client<MQTTNetwork, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE> client(mqttNet); \
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, mqttNet.connect(mqtt_global::hostname, mqtt_global::port)); \
+    MQTTPacket_connectData data = MQTTPacket_connectData_initializer; \
+    MQTT_API_ATTACH_USERNAME_PASSWORD()\
+    data.MQTTVersion = 3;
+
+#define MQTT_LEGACY_API_DEINIT() TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, mqttNet.disconnect());
+
+void MQTT_LEGACY_CONNECT()
+{
+    MQTT_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_LEGACY_CONNECT";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTT_LEGACY_API_DEINIT();
+}
+
+void MQTT_LEGACY_CONNECT_NOT_CONNECTED()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    MQTTNetwork mqttNet(net);
+    MQTT::Client<MQTTNetwork, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE> client(mqttNet);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_DNS_FAILURE, mqttNet.connect("i.dont.exist", mqtt_global::port));
+    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+    TEST_ASSERT_EQUAL(-1, client.connect(data));
+}
+
+void MQTT_LEGACY_SUBSCRIBE()
+{
+    MQTT_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_LEGACY_SUBSCRIBE";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(mqtt_global::topic, MQTT::QOS0, messageArrived));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(mqtt_global::topic, MQTT::QOS1, messageArrived));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(mqtt_global::topic, MQTT::QOS2, messageArrived));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(mqtt_global::topic));
+    MQTT_LEGACY_API_DEINIT();
+
+}
+
+void MQTT_LEGACY_SUBSCRIBE_NETWORK_NOT_CONNECTED()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    MQTTNetwork mqttNet(net);
+    MQTT::Client<MQTTNetwork, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE> client(mqttNet);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_DNS_FAILURE, mqttNet.connect("i.dont.exist", mqtt_global::port));
+    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+    data.MQTTVersion = 3;
+    data.clientID.cstring = (char *)"MQTT_LEGACY_SUBSCRIBE_NETWORK_NOT_CONNECTED";
+    TEST_ASSERT_EQUAL(-1, client.connect(data));
+    TEST_ASSERT_EQUAL(-1, client.subscribe(mqtt_global::topic, MQTT::QOS0, messageArrived));
+}
+
+void MQTT_LEGACY_SUBSCRIBE_CLIENT_NOT_CONNECTED()
+{
+    MQTT_LEGACY_API_INIT();
+    // Intentionally skip connecting.
+    TEST_ASSERT_EQUAL(-1, client.subscribe(mqtt_global::topic, MQTT::QOS0, messageArrived));
+    MQTT_LEGACY_API_DEINIT();
+}
+
+void MQTT_LEGACY_SUBSCRIBE_TOPIC_TOO_LONG()
+{
+    MQTT_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_LEGACY_SUBSCRIBE_TOPIC_TOO_LONG";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    TEST_ASSERT_EQUAL(-1, client.subscribe(mqtt_global::topic_too_long, MQTT::QOS0, messageArrived));
+    MQTT_LEGACY_API_DEINIT();
+}
+
+void MQTT_LEGACY_SUBSCRIBE_INVALID_MESSAGE_HANDLER()
+{
+    MQTT_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_LEGACY_SUBSCRIBE_INVALID_MESSAGE_HANDLER";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    TEST_ASSERT_EQUAL(-1, client.subscribe(mqtt_global::topic, MQTT::QOS0, NULL));
+    MQTT_LEGACY_API_DEINIT();
+}
+
+void MQTT_LEGACY_SUBSCRIBE_RECEIVE()
+{
+    MQTT_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_LEGACY_SUBSCRIBE_INVALID_MESSAGE_HANDLER";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    int arrivedCountBeforeSubscription = arrivedcount;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(mqtt_global::mbed_public_test_topic, MQTT::QOS0, messageArrived));
+    while (arrivedCountBeforeSubscription == arrivedcount) {
+        client.yield(100);
+    }
+    TEST_ASSERT_TRUE(arrivedCountBeforeSubscription < arrivedcount);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(mqtt_global::mbed_public_test_topic));
+    MQTT_LEGACY_API_DEINIT();
+}
+
+void MQTT_LEGACY_UNSUBSCRIBE_WITHOUT_SUBSCRIBE()
+{
+    MQTT_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_LEGACY_UNSUBSCRIBE_WITHOUT_SUBSCRIBE";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(mqtt_global::topic));
+    MQTT_LEGACY_API_DEINIT();
+}
+
+void MQTT_LEGACY_UNSUBSCRIBE_INVALID()
+{
+    MQTT_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_LEGACY_UNSUBSCRIBE_INVALID";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    TEST_ASSERT_EQUAL(-1, client.unsubscribe(""));
+    TEST_ASSERT_EQUAL(-1, client.unsubscribe(mqtt_global::topic_too_long));
+    MQTT_LEGACY_API_DEINIT();
+}
+
+void MQTT_LEGACY_PUBLISH()
+{
+    MQTT_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_LEGACY_nnPUBLISH";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(mqtt_global::topic, mqtt_global::default_message));
+    MQTT::Message msg = mqtt_global::default_message;
+    msg.qos = MQTT::QOS1;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(mqtt_global::topic, msg));
+    msg.qos = MQTT::QOS2;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(mqtt_global::topic, msg));
+    MQTT_LEGACY_API_DEINIT();
+}
+
+void MQTT_LEGACY_PUBLISH_NOT_CONNECTED()
+{
+    MQTT_LEGACY_API_INIT();
+    TEST_ASSERT_EQUAL(-1, client.publish(mqtt_global::topic, mqtt_global::default_message));
+    MQTT_LEGACY_API_DEINIT();
+}
+
+void MQTT_LEGACY_PUBLISH_TOPIC_TOO_LONG()
+{
+    MQTT_LEGACY_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_LEGACY_PUBLISH";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    // TODO verify if this is passing intentionally or if this is a bug?
+//    TEST_ASSERT_EQUAL(-1, client.publish(mqtt_global::topic_too_long, mqtt_global::default_message));
+    MQTT_LEGACY_API_DEINIT();
+}
+
+void MQTT_LEGACY_CONNECT_USER_PASSWORD_INCORRECT()
+{
+    MQTT_LEGACY_API_INIT();
+    data.MQTTVersion = 3;
+    data.clientID.cstring = (char *)"MQTT_LEGACY_CONNECT_USER_PASSWORD_INCORRECT";
+    data.username.cstring = (char *)"wronguser";
+    data.password.cstring = (char *)"wrongpassword";
+    TEST_ASSERT_NOT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    // Sending works. The retval from MQTTDeserialize_connack (5) is returned... Bug?
+    MQTT_LEGACY_API_DEINIT();
+}
+
+void MQTT_LEGACY_CONNECT_SUBSCRIBE_PUBLISH()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    MQTTNetwork mqttNet(net);
+    MQTT::Client<MQTTNetwork, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE> client(mqttNet);
+
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, mqttNet.connect(mqtt_global::hostname, mqtt_global::port));
+
+    send_messages< MQTT::Client<MQTTNetwork, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE> >(client, "MQTT_LEGACY_CONNECT_SUBSCRIBE_PUBLISH");
+
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, mqttNet.disconnect());
+}
+
+void MQTT_LEGACY_CONNECT_SUBSCRIBE_PUBLISH_USER_PASSWORD()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    MQTTNetwork mqttNet(net);
+    MQTT::Client<MQTTNetwork, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE> client(mqttNet);
+
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, mqttNet.connect(mqtt_global::hostname, mqtt_global::port));
+
+    send_messages< MQTT::Client<MQTTNetwork, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE> >(client, "MQTT_LEGACY_CONNECT_SUBSCRIBE_PUBLISH_USER_PASSWORD", true);
+
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, mqttNet.disconnect());
+}
+
+#if defined(MBEDTLS_SSL_CLI_C)
+void MQTT_LEGACY_TLS_CONNECT_SUBSCRIBE_PUBLISH()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    MQTTNetworkTLS mqttNet(net);
+
+    MQTT::Client<MQTTNetworkTLS, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE> client(mqttNet);
+
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, mqttNet.connect(mqtt_global::hostname, mqtt_global::port_tls,
+                      mqtt_global::SSL_CA_PEM, mqtt_global::SSL_CLIENT_CERT_PEM, mqtt_global::SSL_CLIENT_PRIVATE_KEY_PEM));
+
+    send_messages< MQTT::Client<MQTTNetworkTLS, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE> >(client, "MQTT_LEGACYTLS_CONNECT_SUBSCRIBE_PUBLISH");
+
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, mqttNet.disconnect());
+}
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/TESTS/mqtt/mqtt/mqtt_new.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/TESTS/mqtt/mqtt/mqtt_new.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2019, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <MQTTClientMbedOs.h>
+#include "mqtt_tests.h"
+#include "unity/unity.h"
+
+#define MQTT_API_INIT() \
+    arrivedcount = 0; \
+    NetworkInterface *net = NetworkInterface::get_default_instance(); \
+    TCPSocket socket; \
+    SocketAddress addr; \
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.open(net)); \
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, net->gethostbyname(mqtt_global::hostname, &addr)); \
+    addr.set_port(mqtt_global::port); \
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.connect(addr)); \
+    MQTTClient client(&socket); \
+    MQTTPacket_connectData data = MQTTPacket_connectData_initializer; \
+    MQTT_API_ATTACH_USERNAME_PASSWORD() \
+    data.MQTTVersion = 3;
+
+#define MQTT_API_DEINIT() \
+        TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.close());
+
+void MQTT_CONNECT()
+{
+    MQTT_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_CONNECT";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTT_API_DEINIT();
+}
+
+void MQTT_CONNECT_NOT_CONNECTED()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    SocketAddress sockAddr(mqtt_global::hostname, mqtt_global::port);
+    TCPSocket socket;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.open(net));
+    MQTTClient client(&socket);
+    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.connect(data));
+}
+
+void MQTT_SUBSCRIBE()
+{
+    MQTT_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_SUBSCRIBE";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(mqtt_global::topic, MQTT::QOS0, messageArrived));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(mqtt_global::topic, MQTT::QOS1, messageArrived));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(mqtt_global::topic, MQTT::QOS2, messageArrived));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(mqtt_global::topic));
+    MQTT_API_DEINIT();
+
+}
+
+void MQTT_SUBSCRIBE_NETWORK_NOT_CONNECTED()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    TCPSocket socket;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.open(net));
+    SocketAddress addr; // intentionally empty
+    TEST_ASSERT_NOT_EQUAL(NSAPI_ERROR_OK, socket.connect(addr));
+    MQTTClient client(&socket);
+    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+    data.MQTTVersion = 3;
+    data.clientID.cstring = (char *)"MQTT_SUBSCRIBE_NETWORK_NOT_CONNECTED";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.connect(data));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.subscribe(mqtt_global::topic, MQTT::QOS0, messageArrived));
+}
+
+void MQTT_SUBSCRIBE_CLIENT_NOT_CONNECTED()
+{
+    MQTT_API_INIT();
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.subscribe(mqtt_global::topic, MQTT::QOS0, messageArrived));
+    MQTT_API_DEINIT();
+}
+
+void MQTT_SUBSCRIBE_TOPIC_TOO_LONG()
+{
+    MQTT_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_SUBSCRIBE_TOPIC_TOO_LONG";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.subscribe(mqtt_global::topic_too_long, MQTT::QOS0, messageArrived));
+    MQTT_API_DEINIT();
+}
+
+void MQTT_SUBSCRIBE_INVALID_MESSAGE_HANDLER()
+{
+    MQTT_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_SUBSCRIBE_INVALID_MESSAGE_HANDLER";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.subscribe(mqtt_global::topic, MQTT::QOS0, NULL));
+    MQTT_API_DEINIT();
+}
+
+void MQTT_SUBSCRIBE_RECEIVE()
+{
+    MQTT_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_SUBSCRIBE_INVALID_MESSAGE_HANDLER";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    int arrivedCountBeforeSubscription = arrivedcount;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(mqtt_global::mbed_public_test_topic, MQTT::QOS0, messageArrived));
+    while (arrivedCountBeforeSubscription == arrivedcount) {
+        client.yield(100);
+    }
+    TEST_ASSERT_TRUE(arrivedCountBeforeSubscription < arrivedcount);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(mqtt_global::mbed_public_test_topic));
+    MQTT_API_DEINIT();
+}
+
+void MQTT_UNSUBSCRIBE_WITHOUT_SUBSCRIBE()
+{
+    MQTT_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_UNSUBSCRIBE_WITHOUT_SUBSCRIBE";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(mqtt_global::topic));
+    MQTT_API_DEINIT();
+}
+
+void MQTT_UNSUBSCRIBE_INVALID()
+{
+    MQTT_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_UNSUBSCRIBE_INVALID";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.unsubscribe(""));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.unsubscribe(mqtt_global::topic_too_long));
+    MQTT_API_DEINIT();
+}
+
+void MQTT_PUBLISH()
+{
+    MQTT_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_PUBLISH";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(mqtt_global::topic, mqtt_global::default_message));
+    MQTT::Message msg = mqtt_global::default_message;
+    msg.qos = MQTT::QOS1;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(mqtt_global::topic, msg));
+    msg.qos = MQTT::QOS2;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(mqtt_global::topic, msg));
+    MQTT_API_DEINIT();
+}
+
+void MQTT_PUBLISH_NOT_CONNECTED()
+{
+    MQTT_API_INIT();
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_CONNECTION, client.publish(mqtt_global::topic, mqtt_global::default_message));
+    MQTT_API_DEINIT();
+}
+
+void MQTT_PUBLISH_TOPIC_TOO_LONG()
+{
+    MQTT_API_INIT();
+    data.clientID.cstring = (char *)"MQTT_PUBLISH";
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    // TODO verify if this is passing intentionally or if this is a bug?
+//    TEST_ASSERT_EQUAL(-1, client.publish(mqtt_global::topic_too_long, mqtt_global::default_message));
+    MQTT_API_DEINIT();
+}
+
+void MQTT_CONNECT_USER_PASSWORD_INCORRECT()
+{
+    MQTT_API_INIT();
+    data.MQTTVersion = 3;
+    data.clientID.cstring = (char *)"MQTT_CONNECT_USER_PASSWORD_INCORRECT";
+    data.username.cstring = (char *)"wronguser";
+    data.password.cstring = (char *)"wrongpassword";
+    TEST_ASSERT_NOT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    // Sending works. The retval from MQTTDeserialize_connack (5) is returned... Bug?
+    MQTT_API_DEINIT();
+}
+
+void MQTT_CONNECT_SUBSCRIBE_PUBLISH()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    TCPSocket socket;
+    socket.open(net);
+    SocketAddress addr;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, net->gethostbyname(mqtt_global::hostname, &addr));
+    addr.set_port(mqtt_global::port);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, socket.connect(addr));
+    socket.connect(addr);
+
+    MQTTClient client(&socket);
+
+    send_messages<MQTTClient>(client, "MQTT_CONNECT_SUBSCRIBE_PUBLISH");
+
+    socket.close();
+}
+#if defined(MBEDTLS_SSL_CLI_C)
+void MQTT_TLS_CONNECT_SUBSCRIBE_PUBLISH()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    TLSSocket *socket = new TLSSocket; // Allocate on heap to avoid stack overflow.
+    TEST_ASSERT(NSAPI_ERROR_OK == socket->open(net));
+    TEST_ASSERT(NSAPI_ERROR_OK == socket->set_root_ca_cert(mqtt_global::SSL_CA_PEM));
+    SocketAddress addr;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, net->gethostbyname(mqtt_global::hostname, &addr));
+    addr.set_port(mqtt_global::port_tls);
+    int ret = socket->connect(addr);
+    TEST_ASSERT(NSAPI_ERROR_OK == ret);
+
+    MQTTClient client(socket);
+
+    send_messages<MQTTClient>(client, "MQTT_TLS_CONNECT_SUBSCRIBE_PUBLISH");
+
+    socket->close();
+    delete socket;
+}
+#endif
+
+void MQTT_CONNECT_SUBSCRIBE_PUBLISH_USER_PASSWORD()
+{
+    NetworkInterface *net = NetworkInterface::get_default_instance();
+    TCPSocket socket;
+    socket.open(net);
+    SocketAddress addr;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, net->gethostbyname(mqtt_global::hostname, &addr));
+    addr.set_port(mqtt_global::port);
+    socket.connect(addr);
+
+    MQTTClient client(&socket);
+
+    send_messages<MQTTClient>(client, "MQTT_CONNECT_SUBSCRIBE_PUBLISH_USER_PASSWORD");
+
+    socket.close();
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/TESTS/mqtt/mqtt/mqtt_tests.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/TESTS/mqtt/mqtt/mqtt_tests.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2019, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MQTT_TESTS_H
+#define MQTT_TESTS_H
+
+#include <MQTTClientMbedOs.h>
+
+#include "unity/unity.h"
+
+namespace mqtt_global {
+// For TLS hostname must match the "Common Name" set in the server certificate
+//const char* hostname = "test.mosquitto.org";
+static const char *hostname = MBED_CONF_MBED_MQTT_TESTS_BROKER_HOSTNAME;
+static const char *topic = MBED_CONF_MBED_MQTT_TESTS_TOPIC;
+static const char *mbed_public_test_topic = MBED_CONF_MBED_MQTT_TESTS_PUBLIC_TOPIC_NAME;
+static char topic_too_long[MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE + 1];
+static MQTTSN_topicid mbed_public_test_topic_sn;
+static const int port = 1883;
+static const int port_tls = 8883;
+static const int port_udp = 10000;
+extern const char *SSL_CA_PEM;
+extern const char *SSL_CLIENT_CERT_PEM;
+extern const char *SSL_CLIENT_PRIVATE_KEY_PEM;
+extern MQTT::Message default_message;
+extern MQTTSN::Message default_message_sn;
+static char message_buffer[100];
+}
+
+#if MBED_CONF_MBED_MQTT_TESTS_USERNAME_ALWAYS
+#define MQTT_API_ATTACH_USERNAME_PASSWORD() \
+    data.username.cstring = (char*)MBED_CONF_MBED_MQTT_TESTS_USERNAME; \
+    data.password.cstring = (char*)MBED_CONF_MBED_MQTT_TESTS_PASSWORD;
+#else
+#define MQTT_API_ATTACH_USERNAME_PASSWORD() // Just to nothing
+#endif
+
+extern int arrivedcount;
+extern int arrivedcountSN;
+void messageArrived(MQTT::MessageData &md);
+void messageArrivedSN(MQTTSN::MessageData &md);
+
+/*
+ * Test cases
+ */
+void MQTT_LEGACY_CONNECT_NOT_CONNECTED();
+void MQTT_LEGACY_CONNECT();
+void MQTT_LEGACY_SUBSCRIBE();
+void MQTT_LEGACY_SUBSCRIBE_NETWORK_NOT_CONNECTED();
+void MQTT_LEGACY_SUBSCRIBE_CLIENT_NOT_CONNECTED();
+void MQTT_LEGACY_SUBSCRIBE_TOPIC_TOO_LONG();
+void MQTT_LEGACY_SUBSCRIBE_INVALID_MESSAGE_HANDLER();
+void MQTT_LEGACY_SUBSCRIBE_RECEIVE();
+void MQTT_LEGACY_UNSUBSCRIBE_WITHOUT_SUBSCRIBE();
+void MQTT_LEGACY_UNSUBSCRIBE_INVALID();
+void MQTT_LEGACY_PUBLISH();
+void MQTT_LEGACY_PUBLISH_NOT_CONNECTED();
+void MQTT_LEGACY_PUBLISH_TOPIC_TOO_LONG();
+void MQTT_LEGACY_CONNECT_USER_PASSWORD_INCORRECT();
+void MQTT_LEGACY_CONNECT_SUBSCRIBE_PUBLISH();
+void MQTT_LEGACY_CONNECT_SUBSCRIBE_PUBLISH_USER_PASSWORD();
+void MQTT_LEGACY_TLS_CONNECT_SUBSCRIBE_PUBLISH();
+
+void MQTTSN_LEGACY_CONNECT_NOT_CONNECTED();
+void MQTTSN_LEGACY_CONNECT();
+void MQTTSN_LEGACY_SUBSCRIBE();
+void MQTTSN_LEGACY_SUBSCRIBE_NETWORK_NOT_CONNECTED();
+void MQTTSN_LEGACY_SUBSCRIBE_CLIENT_NOT_CONNECTED();
+void MQTTSN_LEGACY_SUBSCRIBE_TOPIC_TOO_LONG();
+void MQTTSN_LEGACY_SUBSCRIBE_INVALID_MESSAGE_HANDLER();
+void MQTTSN_LEGACY_SUBSCRIBE_RECEIVE();
+void MQTTSN_LEGACY_UNSUBSCRIBE_WITHOUT_SUBSCRIBE();
+void MQTTSN_LEGACY_UNSUBSCRIBE_INVALID();
+void MQTTSN_LEGACY_PUBLISH();
+void MQTTSN_LEGACY_PUBLISH_NOT_CONNECTED();
+void MQTTSN_LEGACY_PUBLISH_TOPIC_TOO_LONG();
+void MQTTSN_LEGACY_IS_CONNECTED();
+void MQTTSN_LEGACY_IS_CONNECTED_CLIENT_NOT_CONNECTED();
+void MQTTSN_LEGACY_IS_CONNECTED_NETWORK_NOT_CONNECTED();
+void MQTTSN_LEGACY_UDP_CONNECT_SUBSCRIBE_PUBLISH();
+
+// New API:
+void MQTT_CONNECT_NOT_CONNECTED();
+void MQTT_CONNECT();
+void MQTT_SUBSCRIBE();
+void MQTT_SUBSCRIBE_NETWORK_NOT_CONNECTED();
+void MQTT_SUBSCRIBE_CLIENT_NOT_CONNECTED();
+void MQTT_SUBSCRIBE_TOPIC_TOO_LONG();
+void MQTT_SUBSCRIBE_INVALID_MESSAGE_HANDLER();
+void MQTT_SUBSCRIBE_RECEIVE();
+void MQTT_UNSUBSCRIBE_WITHOUT_SUBSCRIBE();
+void MQTT_UNSUBSCRIBE_INVALID();
+void MQTT_PUBLISH();
+void MQTT_PUBLISH_NOT_CONNECTED();
+void MQTT_PUBLISH_TOPIC_TOO_LONG();
+void MQTT_CONNECT_USER_PASSWORD_INCORRECT();
+void MQTT_CONNECT_SUBSCRIBE_PUBLISH();
+void MQTT_CONNECT_SUBSCRIBE_PUBLISH_USER_PASSWORD();
+void MQTT_TLS_CONNECT_SUBSCRIBE_PUBLISH();
+
+
+void MQTTSN_CONNECT_NOT_CONNECTED();
+void MQTTSN_TEST_CONNECT(); // Avoid clash with MQTTSN enum.
+void MQTTSN_TEST_SUBSCRIBE(); // Avoid clash with MQTTSN enum.
+void MQTTSN_SUBSCRIBE_NETWORK_NOT_CONNECTED();
+void MQTTSN_SUBSCRIBE_CLIENT_NOT_CONNECTED();
+void MQTTSN_SUBSCRIBE_TOPIC_TOO_LONG();
+void MQTTSN_SUBSCRIBE_INVALID_MESSAGE_HANDLER();
+void MQTTSN_SUBSCRIBE_RECEIVE();
+void MQTTSN_UNSUBSCRIBE_WITHOUT_SUBSCRIBE();
+void MQTTSN_UNSUBSCRIBE_INVALID();
+void MQTTSN_TEST_PUBLISH();
+void MQTTSN_PUBLISH_NOT_CONNECTED();
+void MQTTSN_PUBLISH_TOPIC_TOO_LONG();
+void MQTTSN_IS_CONNECTED();
+void MQTTSN_IS_CONNECTED_CLIENT_NOT_CONNECTED();
+void MQTTSN_IS_CONNECTED_NETWORK_NOT_CONNECTED();
+void MQTTSN_UDP_CONNECT_SUBSCRIBE_PUBLISH();
+void MQTTSN_DTLS_CONNECT_SUBSCRIBE_PUBLISH();
+
+template <class Client> void send_messages(Client &client, char *clientID, bool user_password = false)
+{
+    arrivedcount = 0;
+    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+    data.MQTTVersion = 3;
+    data.clientID.cstring = (char *)clientID;
+    if (user_password || MBED_CONF_MBED_MQTT_TESTS_USERNAME_ALWAYS) {
+        data.username.cstring = (char *)MBED_CONF_MBED_MQTT_TESTS_USERNAME;
+        data.password.cstring = (char *)MBED_CONF_MBED_MQTT_TESTS_PASSWORD;
+    }
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(mqtt_global::topic, MQTT::QOS2, messageArrived));
+
+    MQTT::Message message = mqtt_global::default_message;
+
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(mqtt_global::topic, message));
+
+    while (arrivedcount < 1) {
+        printf(".");
+        client.yield(10);
+    }
+
+    // QoS 1
+    char buf[100];
+    sprintf(buf, "QoS 1 %s\n", clientID);
+    message.qos = MQTT::QOS1;
+    message.payloadlen = strlen(buf) + 1;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(mqtt_global::topic, message));
+
+    while (arrivedcount < 2) {
+        printf(".");
+        client.yield(10);
+    }
+
+    // QoS 2
+#if MQTTCLIENT_QOS2
+    sprintf(buf, "QoS 2 %s\n", clientID);
+    message.qos = MQTT::QOS2;
+    message.payloadlen = strlen(buf) + 1;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(mqtt_global::topic, message));
+    while (arrivedcount < 3) {
+        client.yield(100);
+    }
+#endif
+
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(mqtt_global::topic));
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.disconnect() != 0);
+}
+
+/**
+ * @brief Initialize the topic with default values.
+ *
+ * MQTT-SN subscribe() might modify the topic, so we can't use a predefined global variable.
+ */
+void init_topic_sn(MQTTSN_topicid &topic_sn);
+void init_topic_sn_too_long(MQTTSN_topicid &topic_sn);
+
+template <class Client> void send_messages_sn(Client &client, char *clientID)
+{
+    arrivedcountSN = 0;
+    MQTTSNPacket_connectData data = MQTTSNPacket_connectData_initializer;
+    data.clientID.cstring = clientID;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.connect(data));
+    MQTTSN_topicid topic;
+    init_topic_sn(topic);
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.subscribe(topic, MQTTSN::QOS2, messageArrivedSN));
+
+    // QoS 0
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(topic, mqtt_global::default_message_sn));
+    while (arrivedcountSN < 1) {
+        client.yield(10);
+    }
+
+    // QoS 1
+    MQTTSN::Message message;
+    char buf[100];
+    sprintf(buf, "QoS 1 %s\n", clientID);
+    message.qos = MQTTSN::QOS0;
+    message.retained = false;
+    message.dup = false;
+    message.payload = (void *)buf;
+    message.payloadlen = strlen(buf) + 1;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(topic, message));
+    while (arrivedcountSN < 2) {
+        client.yield(10);
+    }
+
+#if MQTTCLIENT_QOS2
+    // QoS 2
+    sprintf(buf, "QoS 2 %s\n", clientID);
+    message.qos = MQTTSN::QOS2;
+    message.payloadlen = strlen(buf) + 1;
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.publish(topic, message));
+    while (arrivedcountSN < 3) {
+        client.yield(10);
+    }
+#endif
+
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.unsubscribe(topic)); //mqtt_global::topic_sn
+    TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, client.disconnect() != 0);
+}
+
+#endif //MQTT_TESTS_H
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/UNITTESTS/.mbedignore
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/UNITTESTS/.mbedignore	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,1 @@
+*
\ No newline at end of file
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/UNITTESTS/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/UNITTESTS/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,172 @@
+cmake_minimum_required(VERSION 3.0.2)
+
+set(PROJECT_NAME unittests)
+set(LIB_NAME MbedOS)
+
+project(${PROJECT_NAME} CXX C)
+
+# Setup c++ standard
+macro(use_cxx14)
+    if (CMAKE_VERSION VERSION_LESS 3.1)
+        if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+            set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++14")
+        endif()
+    else()
+        set(CMAKE_CXX_STANDARD 14)
+        set(CMAKE_CXX_STANDARD_REQUIRED ON)
+    endif()
+endmacro()
+
+use_cxx14()
+
+####################
+# GTEST
+####################
+
+# Download and unpack googletest at configure time
+configure_file(googletest-CMakeLists.txt.in googletest-download/CMakeLists.txt)
+execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
+    RESULT_VARIABLE result
+    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
+if (result)
+    message(FATAL_ERROR "CMake failed for google test: ${result}")
+endif()
+execute_process(COMMAND ${CMAKE_COMMAND} --build .
+    RESULT_VARIABLE result
+    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
+if (result)
+    message(FATAL_ERROR "Build failed for google test: ${result}")
+endif()
+
+# Prevent overriding the parent project's compiler/linker
+# settings on Windows
+set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
+
+# Add googletest directly to our build. This defines
+# the gtest and gtest_main targets.
+add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
+                 ${CMAKE_BINARY_DIR}/googletest-build
+                 EXCLUDE_FROM_ALL)
+
+# The gtest/gtest_main/gmock/gmock_main targets carry header search path
+# dependencies automatically when using CMake 2.8.11 or
+# later.
+target_include_directories(gmock_main SYSTEM BEFORE INTERFACE
+  "$<BUILD_INTERFACE:${gtest_SOURCE_DIR}/include>"
+  "$<BUILD_INTERFACE:${gmock_SOURCE_DIR}/include>")
+
+####################
+# TESTING
+####################
+
+include(CTest)
+
+set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
+  "${CMAKE_BINARY_DIR}/Testing"
+)
+
+####################
+# CODE COVERAGE SETUP
+####################
+
+if (COVERAGE)
+
+  if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
+    message(WARNING "Non-debug build may result misleading code coverage results.")
+  endif()
+
+  # Append coverage compiler flags
+  set(COVERAGE_COMPILER_FLAGS "-g -O0 --coverage -fprofile-arcs -ftest-coverage")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}")
+
+endif(COVERAGE)
+
+####################
+# UNIT TESTS
+####################
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUNITTEST")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNITTEST")
+
+# Set include dirs.
+set(unittest-includes-base
+  "${PROJECT_SOURCE_DIR}/../paho_mqtt_embedded_c/MQTTClient/src"
+  "${PROJECT_SOURCE_DIR}/../paho_mqtt_embedded_c/MQTTPacket/src"
+  "${PROJECT_SOURCE_DIR}/stubs"
+)
+
+# Create a list for test suites.
+set(TEST_SUITES)
+
+# Get all matched tests.
+file(GLOB_RECURSE unittest-file-list
+  "unittest.cmake"
+)
+
+if ("${unittest-file-list}" STREQUAL "")
+  message(FATAL_ERROR "No tests found. Exiting...")
+endif()
+
+# Create unit test targets
+foreach(testfile ${unittest-file-list})
+  ####################
+  # DEFINE TARGETS
+  ####################
+
+  # Init file lists.
+  set(unittest-includes ${unittest-includes-base})
+  set(unittest-sources)
+  set(unittest-test-sources)
+
+  # Get source files
+  include("${testfile}")
+
+  get_filename_component(TEST_SUITE_DIR ${testfile} DIRECTORY)
+
+  file(RELATIVE_PATH
+       TEST_SUITE_NAME # output
+       ${PROJECT_SOURCE_DIR} # root
+       ${TEST_SUITE_DIR} #abs dirpath
+  )
+
+  string(REGEX REPLACE "/|\\\\" "-" TEST_SUITE_NAME ${TEST_SUITE_NAME})
+
+  set(TEST_SUITES ${TEST_SUITES} ${TEST_SUITE_NAME})
+
+  set(LIBS_TO_BE_LINKED gmock_main)
+
+  # Build directories list
+  set(BUILD_DIRECTORIES)
+
+  if (unittest-sources)
+    # Create the testable static library.
+    add_library("${TEST_SUITE_NAME}.${LIB_NAME}" STATIC ${unittest-sources})
+    target_include_directories("${TEST_SUITE_NAME}.${LIB_NAME}" PRIVATE
+      ${unittest-includes})
+    set(LIBS_TO_BE_LINKED ${LIBS_TO_BE_LINKED} "${TEST_SUITE_NAME}.${LIB_NAME}")
+
+    # Append lib build directory to list
+    list(APPEND BUILD_DIRECTORIES "./CMakeFiles/${TEST_SUITE_NAME}.${LIB_NAME}.dir")
+  endif(unittest-sources)
+
+  if (unittest-test-sources)
+    # Create the executable.
+    add_executable(${TEST_SUITE_NAME} ${unittest-test-sources})
+    target_include_directories(${TEST_SUITE_NAME} PRIVATE
+      ${unittest-includes})
+
+    # Link the executable with the libraries.
+    target_link_libraries(${TEST_SUITE_NAME} ${LIBS_TO_BE_LINKED})
+
+    add_test(NAME "${TEST_SUITE_NAME}" COMMAND ${TEST_SUITE_NAME})
+
+    # Append test build directory to list
+    list(APPEND BUILD_DIRECTORIES "./CMakeFiles/${TEST_SUITE_NAME}.dir")
+  else()
+    message(WARNING "No test source files found for ${TEST_SUITE_NAME}.\n")
+  endif(unittest-test-sources)
+
+  set_target_properties("${TEST_SUITE_NAME}.${LIB_NAME}" PROPERTIES LINKER_LANGUAGE CXX)
+endforeach(testfile)
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/UNITTESTS/CMakeSettings.json
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/UNITTESTS/CMakeSettings.json	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,30 @@
+{
+  "configurations": [
+    {
+      "name": "GNU-Debug",
+      "generator": "Ninja",
+      "configurationType": "Debug",
+      "inheritEnvironments": [ "mingw64" ],
+      "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
+      "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
+      "environments": [
+        {
+          "environment": "mingw64"
+        }
+      ]
+    },
+    {
+      "name": "GNU-Release",
+      "generator": "Ninja",
+      "configurationType": "Release",
+      "inheritEnvironments": [ "mingw64" ],
+      "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
+      "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
+      "environments": [
+        {
+          "environment": "mingw64"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/UNITTESTS/README.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/UNITTESTS/README.md	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,306 @@
+## Unit testing
+
+This document describes how to write and use unit tests for Arm Mbed OS. 
+
+### Introduction
+
+Unit tests test code in small sections on a host machine. Unlike other testing tools, unit testing doesn't require embedded hardware or need to build a full operating system. Because of this, unit testing can result in faster tests than other tools. Unit testing happens in a build environment where you test each C or C++ class or module in isolation. Build test suites into separate test binaries and stub all access outside to remove dependencies on any specific embedded hardware or software combination. This allows you to complete tests using native compilers on the build machine.
+
+### Prerequisites
+
+Please install the following dependencies to use Mbed OS unit testing:
+
+* GNU toolchains.
+   * GCC 6 or later. We recommend you use MinGW-W64 on Windows, but any Windows port of the above GCC versions works. Default compilers can be used on Mac OS instead of GCC to shorten build times, but code coverage results can differ.
+* CMake 3.0 or newer.
+* Python 2.7.x, 3.5 or newer.
+* Pip 10.0 or newer.
+* Gcovr 4.1 or newer.
+* Arm Mbed CLI 1.8.0 or newer.
+
+Detailed instructions for supported operating systems are below.
+
+#### Installing dependencies on Debian or Ubuntu
+
+In a terminal window:
+
+1. `sudo apt-get -y install build-essential cmake`
+1. Install Python and Pip with:
+
+   ```
+   sudo apt-get -y install python python-setuptools
+   sudo easy_install pip
+   ```
+
+1. Install Gcovr and [Mbed CLI](https://os.mbed.com/docs/mbed-os/latest/tools/developing-mbed-cli.html) with `pip install "gcovr>=4.1" mbed-cli`.
+
+#### Installing dependencies on macOS
+
+In a terminal window:
+
+1. Install [Homebrew](https://brew.sh/).
+1. Install Xcode Command Line Tools with `xcode-select --install`.
+1. Install CMake with: `brew install cmake`.
+1. Install Python and Pip:
+
+   ```
+   brew install python
+   sudo easy_install pip
+   ```
+
+1. Install Gcovr and [Mbed CLI](https://os.mbed.com/docs/mbed-os/latest/tools/developing-mbed-cli.html) with `pip install "gcovr>=4.1" mbed-cli`.
+1. (Optional) Install GCC with `brew install gcc`.
+
+#### Installing dependencies on Windows
+
+In a terminal window:
+
+1. Download and install MinGW-W64 from [SourceForge](https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/).
+1. Download CMake binaries from https://cmake.org/download/, and run the installer.
+1. Download Python 2.7 or Python 3 from https://www.python.org/getit/, and run the installer.
+1. Add MinGW, CMake and Python into system PATH.
+1. Install Gcovr and [Mbed CLI](https://os.mbed.com/docs/mbed-os/latest/tools/developing-mbed-cli.html) with `pip install "gcovr>=4.1" mbed-cli`.
+
+### Test code structure
+
+Find unit tests in the Mbed OS repository under the `UNITTESTS` folder. We recommend unit test files use an identical directory path as the file under test. This makes it easier to find unit tests for a particular class or a module. For example, if the file you're testing is `some/example/path/ClassName.cpp`, then all the test files are in the `UNITTESTS/some/example/path/ClassName` directory. Each test suite needs to have its own `unittest.cmake` file for test configuration.
+
+All the class stubs should be located in the `UNITTESTS/stubs` directory. A single stub class can be used by multiple test suites and should follow the naming convention `ClassName_stub.cpp` for the source file, and `ClassName_stub.h` for the header file. Use the actual header files for the unit tests, and don't stub headers if possible. The stubbed headers reside in the `UNITTESTS/target_h` directory.
+
+#### Test discovery
+
+Registering unit tests to run happens automatically, and the test runner handles registration. However, test files do not automatically  build. Build unit tests with a separate system that searches for unit tests under the `UNITTESTS` directory.
+
+For the build system to find and build any test suite automatically, include a unit test configuration file named `unittest.cmake` for each unit test suite. This configuration file lists all the source files required for the test build.
+
+#### Test names
+
+The build system automatically generates names of test suites. The name is constructed by taking a relative file path from the UNITTESTS directory to the test directory and replacing path separators with dashes. For example, the test suite name for `some/example/path/ClassName.cpp` is `some-example-path-ClassName`. Suite names are used when deciding which test suites to run.
+
+### Unit testing with Mbed CLI
+
+Mbed CLI supports unit tests through the `mbed test --unittests` command. For information on using Mbed CLI, please see the [CLI documentation](https://os.mbed.com/docs/mbed-os/latest/tools/developing-mbed-cli.html).
+
+### Writing unit tests
+
+A unit tests suite consists of one or more test cases. The test cases should cover all the functions in a class under test. All the external dependencies are stubbed including the other classes in the same module. Avoid stubbing header files. Finally, analyze code coverage to ensure all code is tested, and no dead code is found.
+
+Unit tests are written using [Google Test v1.8.1](https://github.com/google/googletest/releases/tag/release-1.8.1).
+
+Please see the [documentation for Google Test](https://github.com/google/googletest/blob/master/googletest/docs/primer.md) to learn how to write unit tests using its framework. See the [documentation for Google Mock](https://github.com/google/googletest/blob/master/googlemock/docs/Documentation.md) if you want to write and use C++ mock classes instead of stubs.
+
+#### Test suite configuration
+
+Create two files in the test directory for each test suite:
+
+* Unit test source file (`test_ClassName.cpp`).
+* Unit test configuration file (`unittest.cmake`).
+
+List all the required files for the build in the `unittest.cmake` file with paths relative to the `UNITTESTS` folder. Use the following variables to list the source files and include paths:
+
+* **unittest-includes**: List of header include paths. You can use this to extend or overwrite default paths listed in `UNITTESTS/CMakeLists.txt`.
+* **unittest-sources**: List of files under test.
+* **unittest-test-sources**: List of test sources and stubs.
+
+You can also set custom compiler flags and other configurations supported by CMake in `unittest.cmake`.
+
+#### Example
+
+With the following steps, you can write a simple unit test. This example creates dummy classes to be tested, creates and configures unit tests for a class and stubs all external dependencies.
+
+1. Create the following dummy classes in `mbed-os/example`:
+
+    **MyClass.h**
+
+    ```
+    #ifndef MYCLASS_H_
+    #define MYCLASS_H_
+
+    namespace example {
+
+    class MyClass {
+    public:
+        int myFunction();
+    };
+
+    }
+
+    #endif
+    ```
+
+    **MyClass.cpp**
+
+    ```
+    #include "MyClass.h"
+    #include "OtherClass.h"
+
+    namespace example {
+
+    int MyClass::myFunction() {
+        OtherClass o = OtherClass();
+        return o.otherFunction();
+    }
+
+    }
+    ```
+
+    **OtherClass.h**
+
+    ```
+    #ifndef OTHERCLASS_H_
+    #define OTHERCLASS_H_
+
+    namespace example {
+
+    class OtherClass {
+    public:
+        int otherFunction();
+    };
+
+    }
+
+    #endif
+    ```
+
+    **OtherClass.cpp**
+
+    ```
+    #include "OtherClass.h"
+
+    namespace example {
+
+    int OtherClass::otherFunction() {
+        return 1;
+    }
+
+    }
+    ```
+
+1. Create a directory for MyClass unit tests in `UNITTESTS/example/MyClass`.
+1. Create a configuration file and a source file for MyClass unit tests in `UNITTESTS/example/MyClass`:
+
+    **unittest.cmake**
+
+    ```
+    # Add here additional test specific include paths
+    set(unittest-includes ${unittest-includes}
+        ../example
+    )
+
+    # Add here classes under test
+    set(unittest-sources
+        ../example/MyClass.cpp
+    )
+
+    # Add here test classes and stubs
+    set(unittest-test-sources
+        example/MyClass/test_MyClass.cpp
+        stubs/OtherClass_stub.cpp
+    )
+    ```
+
+    **test_MyClass.cpp**
+
+    ```
+    #include "gtest/gtest.h"
+    #include "example/MyClass.h"
+
+    class TestMyClass : public testing::Test {
+    protected:
+        example::MyClass *obj;
+
+        virtual void SetUp()
+        {
+            obj = new example::MyClass();
+        }
+
+        virtual void TearDown()
+        {
+            delete obj;
+        }
+    };
+
+    TEST_F(TestMyClass, constructor)
+    {
+        EXPECT_TRUE(obj);
+    }
+
+    TEST_F(TestMyClass, myfunction)
+    {
+        EXPECT_EQ(obj->myFunction(), 0);
+    }
+    ```
+
+1. Stub all external dependencies. Create the following stub in `UNITTESTS/stubs`:
+
+    **OtherClass_stub.cpp**
+
+    ```
+    #include "example/OtherClass.h"
+
+    namespace example {
+
+    int OtherClass::otherFunction() {
+        return 0;
+    }
+
+    }
+    ```
+
+This example does not use any Mbed OS code, but if your unit tests do, then remember to update header stubs in `UNITTESTS/target_h` and source stubs in `UNITTESTS/stubs` with any missing type or function declarations. 
+
+### Building and running unit tests
+
+Use Mbed CLI to build and run unit tests. For advanced use, you can run CMake and a Make program directly.
+
+#### Build tests directly with CMake
+
+1. Create a build directory `mkdir UNITTESTS/build`.
+1. Move to the build directory `cd UNITTESTS/build`.
+1. Run CMake using a relative path to `UNITTESTS` folder as the argument. So from `UNITTESTS/build` use `cmake ..`:
+   * Add `-g [generator]` if generating other than Unix Makefiles such in case of MinGW use `-g "MinGW Makefiles"`.
+   * Add `-DCMAKE_MAKE_PROGRAM=<value>`, `-DCMAKE_CXX_COMPILER=<value>` and `-DCMAKE_C_COMPILER=<value>` to use a specific Make program and compilers.
+   * Add `-DCMAKE_BUILD_TYPE=Debug` for a debug build.
+   * Add `-DCOVERAGE=True` to add coverage compiler flags.
+   * Add `-Dgtest_disable_pthreads=ON` to run in a single thread.
+   * See the [CMake manual](https://cmake.org/cmake/help/v3.0/manual/cmake.1.html) for more information.
+1. Run a Make program to build tests.
+
+#### Run tests directly with CTest
+
+Run a test binary in the build directory to run a unit test suite. To run multiple test suites at once, use the CTest test runner. Run CTest with `ctest`. Add `-v` to get results for each test case. See the [CTest manual](https://cmake.org/cmake/help/v3.0/manual/ctest.1.html) for more information.
+
+#### Run tests with GUI test runner
+
+1. Install `gtest-runner` according to the [documentation](https://github.com/nholthaus/gtest-runner).
+1. Run `gtest-runner`.
+1. Add test executables into the list and run.
+
+### Debugging
+
+1. Use Mbed CLI to build a debug build. For advanced use, run CMake directly with `-DCMAKE_BUILD_TYPE=Debug`, and then run a Make program.
+1. Run GDB with a test executable as an argument to debug unit tests.
+1. Run tests with Valgrind to analyze the test memory profile.
+
+### Get code coverage
+
+Use Mbed CLI to generate code coverage reports. For advanced use, follow these steps:
+
+1. Run CMake with both `-DCMAKE_BUILD_TYPE=Debug` and `-DCOVERAGE=True`.
+1. Run a Make program to build the tests.
+1. Run the tests.
+1. Run Gcovr or any other code coverage tool directly in the build directory.
+
+### Troubleshooting
+
+**Problem:** Generic problems with CMake or with the build process.
+* **Solution**: Delete the build directory. Make sure that CMake, g++, GCC and a Make program can be found in the path and are correct versions.
+
+**Problem:** (Windows) Virus protection identifies files generated by CMake as malicious and quarantines the files.
+* **Solution**: Restore false-positive files from the quarantine.
+
+**Problem:** (Windows) Git with shell installation adds sh.exe to the path and then CMake throws an error: sh.exe was found in your PATH. For MinGW make to work correctly, sh.exe must NOT be in your path.
+* **Solution**:  Remove sh.exe from the system path.
+
+**Problem:** (Mac OS) CMake compiler check fails on Mac OS Mojave when using GCC-8.
+* **Solution**: Make sure gnm (binutils) is not installed. Uninstall binutils with `brew uninstall binutils`.
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/UNITTESTS/googletest-CMakeLists.txt.in
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/UNITTESTS/googletest-CMakeLists.txt.in	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 2.8.11)
+
+project(googletest-download NONE)
+
+include(ExternalProject)
+ExternalProject_Add(googletest
+  GIT_REPOSITORY    https://github.com/google/googletest.git
+  GIT_TAG           release-1.8.1
+  SOURCE_DIR        "${CMAKE_BINARY_DIR}/googletest-src"
+  BINARY_DIR        "${CMAKE_BINARY_DIR}/googletest-build"
+  CONFIGURE_COMMAND ""
+  BUILD_COMMAND     ""
+  INSTALL_COMMAND   ""
+  TEST_COMMAND      ""
+)
\ No newline at end of file
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/UNITTESTS/mbed_unittest.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/UNITTESTS/mbed_unittest.py	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,162 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2018, Arm Limited
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+UNIT TEST BUILD & RUN
+"""
+
+from __future__ import print_function
+import os
+import logging
+import re
+
+from unit_test.options import get_options_parser, \
+                              pretty_print_test_options
+from unit_test.settings import DEFAULT_CMAKE_GENERATORS
+from unit_test.test import UnitTestTool
+from unit_test.new import UnitTestGeneratorTool
+from unit_test.coverage import CoverageAPI
+
+def _mbed_unittest_test(options, cwd, pwd):
+    if options is None:
+        return
+
+    if options.coverage:
+        options.debug_build = True
+
+    if options.cmake_generator is None:
+        options.cmake_generator = DEFAULT_CMAKE_GENERATORS.get(
+            options.make_program,
+            "Unix Makefiles")
+
+    # Do not clean directory if only run.
+    if options.clean and options.run_only and not options.compile_only:
+        options.clean = False
+
+    # Build and run by default
+    if (not options.compile_only and
+            not options.run_only and
+            not options.clean):
+        options.compile_only = True
+        options.run_only = True
+
+    # Set build path
+    if not os.path.isabs(options.build):
+        options.build = os.path.normpath(
+            os.path.join(cwd, options.build))
+
+    pretty_print_test_options(options)
+
+    # Create test tool
+    tool = UnitTestTool(make_program=options.make_program)
+
+    # Prepare build directory
+    tool.prepare_build_directory(path_to_src=pwd,
+                                 build_path=options.build,
+                                 clean=options.clean)
+
+    if options.compile_only:
+        # Create makefiles
+        src_path = os.path.relpath(pwd, options.build)
+        tool.create_makefiles(path_to_src=src_path,
+                              generator=options.cmake_generator,
+                              coverage_output_type=options.coverage,
+                              debug=options.debug_build)
+
+        # Build tests
+        tool.build_tests()
+
+    if options.run_only:
+        tool.run_tests(filter_regex=options.test_regex)
+
+        # If code coverage generation:
+        if options.coverage:
+            cov_api = CoverageAPI(
+                mbed_os_root=os.path.normpath(os.path.join(pwd, "..")),
+                build_dir=options.build)
+
+            # Generate reports
+            outputs = [options.coverage]
+            if options.coverage == "both":
+                outputs = ["html", "xml"]
+
+            excludes = [pwd, options.build]
+
+            if not options.include_headers:
+                excludes.append(re.compile(".*\\.h"))
+
+            cov_api.generate_reports(outputs=outputs,
+                                     excludes=excludes,
+                                     filter_regex=options.test_regex,
+                                     build_path=options.build)
+
+def _mbed_unittest_new(options, pwd):
+    if options is None:
+        return
+
+    generator = UnitTestGeneratorTool()
+
+    mbed_os_root = os.path.normpath(
+        os.path.join(pwd, "..")
+    )
+
+    for filepath in options.new_files:
+        generator.create(
+            mbed_os_root=mbed_os_root,
+            filepath=filepath)
+
+def mbed_unittest(options=None):
+    """
+    Create, build and run unit tests
+    """
+
+    if options is None:
+        return
+
+    cwd = os.getcwd()
+
+    # Change current working directory to script location
+    unittest_dir = os.path.dirname(os.path.realpath(__file__))
+    os.chdir(unittest_dir)
+
+    if options.new_files:
+        _mbed_unittest_new(options, unittest_dir)
+    else:
+        _mbed_unittest_test(options, cwd, unittest_dir)
+
+def mbed_unittest_main():
+    """
+    Create, build and run unit tests - main
+    """
+
+    # Get parser and parse command line arguments
+    parser = get_options_parser()
+    options = parser.parse_args()
+
+    # Setup logger
+    if options.log_level:
+        logging.basicConfig(level=getattr(logging, options.log_level),
+                            format="%(message)s")
+    else:
+        logging.basicConfig(level=logging.INFO,
+                            format="%(message)s")
+
+    mbed_unittest(options)
+
+if __name__ == "__main__":
+    mbed_unittest_main()
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/UNITTESTS/mocks/Network_mock.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/UNITTESTS/mocks/Network_mock.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019, Arm Limited and affiliates
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "gmock/gmock.h"
+
+using ::testing::_;
+using ::testing::Return;
+
+class Network_mock {
+public:
+    Network_mock() {
+
+    }
+
+    int connect(const char* hostname, int port) {
+        return 0;
+    }
+
+    MOCK_METHOD3(read, int(unsigned char* buffer, int len, int timeout_ms));
+
+    int write(unsigned char* buffer, int len, int timeout) {
+        return len;
+    }
+
+    int disconnect() {
+        return 0;
+    }
+};
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/UNITTESTS/paho_mqtt_embedded_c/MQTTClient/test_MQTTClient.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/UNITTESTS/paho_mqtt_embedded_c/MQTTClient/test_MQTTClient.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2019, Arm Limited and affiliates
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../mocks/Network_mock.h"
+#include "../stubs/Countdown_stub.h"
+#include "gtest/gtest.h"
+#include "MQTTClient.h"
+
+using ::testing::SetArrayArgument;
+
+class TestMQTTClient : public testing::Test {
+public:
+protected:
+    MQTT::Client<Network_mock, Countdown_stub, 100>* client;
+    Network_mock* net;
+
+    virtual void SetUp()
+    {
+        net = new Network_mock;
+        client = new MQTT::Client<Network_mock, Countdown_stub, 100>(*net);
+    }
+
+    virtual void TearDown()
+    {
+        delete client;
+        delete net;
+    }
+};
+
+static void messageHandler(MQTT::MessageData& data) {}
+
+TEST_F(TestMQTTClient, incorrect_topic_length)
+{
+    ::testing::InSequence s;
+
+    // Install a message handler so that isTopicMatched() can get called.
+    client->setMessageHandler("*", &messageHandler);
+
+    unsigned char bytes[10] = {
+            0x30, // Packet type (PUBLISH) + flags
+            0x03, // Remaining length byte
+            0x02, 0x03, // Topic length (h'0x0203 = d'515)
+            0x04, 0x05, 0x06 // Topic (much too short, for the length)
+            };
+
+    // Packet type (PUBLISH) + flags
+    EXPECT_CALL(*net, read(_, _, _))
+        .Times(1)
+         .WillOnce(DoAll(SetArrayArgument<0>(bytes, bytes+1), Return(1)));
+
+    // Remaining length byte
+    EXPECT_CALL(*net, read(_, _, _))
+        .Times(1)
+        .WillOnce(DoAll(SetArrayArgument<0>(bytes+1, bytes+2), Return(1)));
+
+    // Remaining length byte
+    EXPECT_CALL(*net, read(_, _, _))
+        .Times(1)
+        .WillOnce(DoAll(SetArrayArgument<0>(bytes+2, bytes+5), Return(3)));
+
+    EXPECT_EQ(-1, client->yield(5));
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/UNITTESTS/paho_mqtt_embedded_c/MQTTClient/unittest.cmake
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/UNITTESTS/paho_mqtt_embedded_c/MQTTClient/unittest.cmake	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,17 @@
+
+####################
+# UNIT TESTS
+####################
+
+set(unittest-sources
+  ../paho_mqtt_embedded_c/MQTTClient/src/MQTTClient.h
+  ../paho_mqtt_embedded_c/MQTTPacket/src/MQTTDeserializePublish.c
+  ../paho_mqtt_embedded_c/MQTTPacket/src/MQTTPacket.c
+)
+
+set(unittest-test-sources
+  paho_mqtt_embedded_c/MQTTClient/test_MQTTClient.cpp
+  mocks/Network_mock.h
+  stubs/MQTTConnectClient_stub.cpp
+  stubs/MQTTSerializePublish_stub.cpp
+)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/UNITTESTS/stubs/Countdown_stub.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/UNITTESTS/stubs/Countdown_stub.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019, Arm Limited and affiliates
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class Countdown_stub {
+public:
+    Countdown_stub() {
+    }
+
+    Countdown_stub(int ms) {
+    }
+
+    bool expired() {
+        return false;
+    }
+
+    void countdown_ms(int ms) {
+    }
+
+    void countdown(int seconds) {
+    }
+
+    int left_ms() {
+        return 0;
+    }
+};
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/UNITTESTS/stubs/MQTTConnectClient_stub.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/UNITTESTS/stubs/MQTTConnectClient_stub.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019, Arm Limited and affiliates
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MQTTPacket.h"
+
+int MQTTSerialize_connectLength(MQTTPacket_connectData* options)
+{
+    int len = 1;
+
+    return len;
+}
+
+int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options)
+{
+    return buflen;
+}
+
+int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen)
+{
+    return 1;
+}
+
+int MQTTSerialize_zero(unsigned char* buf, int buflen, unsigned char packettype)
+{
+    return 1;
+}
+
+int MQTTSerialize_disconnect(unsigned char* buf, int buflen)
+{
+    return MQTTSerialize_zero(buf, buflen, DISCONNECT);
+}
+
+int MQTTSerialize_pingreq(unsigned char* buf, int buflen)
+{
+    return MQTTSerialize_zero(buf, buflen, PINGREQ);
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/UNITTESTS/stubs/MQTTSerializePublish_stub.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/UNITTESTS/stubs/MQTTSerializePublish_stub.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019, Arm Limited and affiliates
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MQTTPacket.h"
+
+int MQTTSerialize_publishLength(int qos, MQTTString topicName, int payloadlen)
+{
+	return payloadlen;
+}
+
+int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
+		MQTTString topicName, unsigned char* payload, int payloadlen)
+{
+	return payloadlen;
+}
+
+int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
+{
+	return buflen;
+}
+
+int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid)
+{
+	return MQTTSerialize_ack(buf, buflen, PUBACK, 0, packetid);
+}
+
+int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid)
+{
+	return MQTTSerialize_ack(buf, buflen, PUBREL, dup, packetid);
+}
+
+int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid)
+{
+	return MQTTSerialize_ack(buf, buflen, PUBCOMP, 0, packetid);
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/mbed_lib.json
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/mbed_lib.json	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,53 @@
+{
+    "name": "mbed-mqtt",
+    "config": {
+        "max-packet-size": {
+            "help": "Max serialized MQTT packet size, set by template parameter in paho library.",
+            "value": "200"
+        },
+        "max-connections": {
+            "help": "Max simultaneous connections, set by template parameter in paho library.",
+            "value": "5"
+        },
+        "tests-broker-hostname": {
+            "help": "Name or address of the broker server hostname.",
+            "value": "\"192.168.8.52\""
+        },
+        "tests-topic": {
+            "help": "Name of the public test topic that publishes message frequently. Required for *_SUBSCRIBE_RECEIVE tests.",
+            "value": "\"test\""
+        },
+        "tests-public-topic-enable": {
+            "help": "Set to true if there is a publicly available topic that gets messages posted frequently. See tests-public-topic-name. Required for *_SUBSCRIBE_RECEIVE tests.",
+            "value": "false"
+        },
+        "tests-public-topic-name": {
+            "help": "Name of the public test topic that publishes message frequently. Required for *_SUBSCRIBE_RECEIVE tests.",
+            "value": "\"mbed_public_test_topic\""
+        },
+        "tests-mqtt-sn-enable": {
+            "help": "Set to true if an MQTT-SN Gateway is available.",
+            "value": "false"
+        },
+        "tests-username-password-protection-enable": {
+            "help": "Set to true if the MQTT broker has username/password protection enabled. Provide the username and password in tests-username and tests-password.",
+            "value": "false"
+        },
+        "tests-tls-enable": {
+            "help": "Set to true if the MQTT broker has TLS protection enabled. NOTE: you need to set certificate in mqtt_global::SSL_CA_PEM.",
+            "value": "false"
+        },
+        "tests-username": {
+            "help": "MQTT messages username. To be used in the *USER_PASSWORD* tests. See also tests-username-always",
+            "value": "\"mbed\""
+        },
+        "tests-password": {
+            "help": "MQTT messages password. To be used in the *USER_PASSWORD* tests. See also tests-username-always",
+            "value": "\"1234\""
+        },
+        "tests-username-always": {
+            "help": "Always attach the username and password to messages (some brokers require this).",
+            "value": "false"
+        }
+    }
+}
\ No newline at end of file
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/.gitignore
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/.gitignore	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,12 @@
+/dep/
+/build/
+/build.paho/
+*.swp
+*.pyc
+/doc/MQTTSNClient/
+/doc/MQTTSNPacket/
+/rbmutex.key
+/ringbuffer.key
+/Release/
+/Debug/
+/core
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/.travis.yml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/.travis.yml	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,33 @@
+language: cpp
+compiler: 
+    - g++
+
+install:
+    - if ["$CXX" = "g++" ]; then export CXX="g++-4.8"; fi
+
+addons:
+  apt:
+    sources:
+    - ubuntu-toolchain-r-test
+    packages:
+    - g++-4.8
+    - cmake
+    - cmake-data
+    
+script: 
+  - ./travis-build.sh
+
+  - cd MQTTSNGateway
+  - make SENSORNET="xbee"
+  - make SENSORNET="udp"  
+  - make SENSORNET="udp6"
+  
+  - make test
+    
+  - cd GatewayTester
+  - make 
+  
+notifications:
+  emails:
+    - tomoaki@tomy-tech.com
+    
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,41 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+PROJECT("paho-mqttsn" CXX)
+MESSAGE(STATUS "CMake version: " ${CMAKE_VERSION})
+MESSAGE(STATUS "CMake system name: " ${CMAKE_SYSTEM_NAME})
+
+SET(CMAKE_SCRIPTS "${CMAKE_SOURCE_DIR}/cmake")
+SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")
+
+## build settings
+SET(PAHO_VERSION_MAJOR 1)
+SET(PAHO_VERSION_MINOR 0)
+SET(PAHO_VERSION_PATCH 0)
+SET(CLIENT_VERSION ${PAHO_VERSION_MAJOR}.${PAHO_VERSION_MINOR}.${PAHO_VERSION_PATCH})
+
+STRING(TIMESTAMP BUILD_TIMESTAMP UTC)
+MESSAGE(STATUS "Timestamp is ${BUILD_TIMESTAMP}")
+
+SET(CPACK_PACKAGE_VERSION_MAJOR ${PAHO_VERSION_MAJOR})
+SET(CPACK_PACKAGE_VERSION_MINOR ${PAHO_VERSION_MINOR})
+SET(CPACK_PACKAGE_VERSION_PATCH ${PAHO_VERSION_PATCH})
+INCLUDE(CPack)
+
+ENABLE_TESTING()
+
+ADD_SUBDIRECTORY(MQTTSNPacket)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/CONTRIBUTING.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/CONTRIBUTING.md	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,68 @@
+# Contributing to Paho
+
+Thanks for your interest in this project!
+
+You can contribute bugfixes and new features by sending pull requests through GitHub.
+
+## Legal
+
+In order for your contribution to be accepted, it must comply with the Eclipse Foundation IP policy.
+
+Please read the [Eclipse Foundation policy on accepting contributions via Git](http://wiki.eclipse.org/Development_Resources/Contributing_via_Git).
+
+1. Sign the [Eclipse ECA](http://www.eclipse.org/legal/ECA.php)
+  1. Register for an Eclipse Foundation User ID. You can register [here](https://dev.eclipse.org/site_login/createaccount.php).
+  2. Log into the [Eclipse projects forge](https://www.eclipse.org/contribute/cla), and click on 'Eclipse Contributor Agreement'.
+2. Go to your [account settings](https://dev.eclipse.org/site_login/myaccount.php#open_tab_accountsettings) and add your GitHub username to your account.
+3. Make sure that you _sign-off_ your Git commits in the following format:
+  ``` Signed-off-by: Alex Smith <alexsmith@nowhere.com> ``` This is usually at the bottom of the commit message. You can automate this by adding the '-s' flag when you make the commits. e.g.   ```git commit -s -m "Adding a cool feature"```
+4. Ensure that the email address that you make your commits with is the same one you used to sign up to the Eclipse Foundation website with.
+
+## Contributing a change
+
+## Contributing a change
+
+1. [Fork the repository on GitHub](https://github.com/eclipse/paho.mqtt-sn.embedded-c/fork)
+2. Clone the forked repository onto your computer: ``` git clone https://github.com/<your username>/paho.mqtt-sn.embedded-c.git ```
+3. Create a new branch from the latest ```develop``` branch with ```git checkout -b YOUR_BRANCH_NAME origin/develop```
+4. Make your changes
+5. If developing a new feature, make sure to include JUnit tests.
+6. Ensure that all new and existing tests pass.
+7. Commit the changes into the branch: ``` git commit -s ``` Make sure that your commit message is meaningful and describes your changes correctly.
+8. If you have a lot of commits for the change, squash them into a single / few commits.
+9. Push the changes in your branch to your forked repository.
+10. Finally, go to [https://github.com/eclipse/paho.mqtt-sn.embedded-c](https://github.com/eclipse/paho.mqtt-sn.embedded-c) and create a pull request from your "YOUR_BRANCH_NAME" branch to the ```develop``` one to request review and merge of the commits in your pushed branch.
+
+
+What happens next depends on the content of the patch. If it is 100% authored
+by the contributor and is less than 1000 lines (and meets the needs of the
+project), then it can be pulled into the main repository. If not, more steps
+are required. These are detailed in the
+[legal process poster](http://www.eclipse.org/legal/EclipseLegalProcessPoster.pdf).
+
+
+
+## Developer resources:
+
+
+Information regarding source code management, builds, coding standards, and more.
+
+- [https://projects.eclipse.org/projects/iot.paho/developer](https://projects.eclipse.org/projects/iot.paho/developer)
+
+Contact:
+--------
+
+Contact the project developers via the project's development
+[mailing list](https://dev.eclipse.org/mailman/listinfo/paho-dev).
+
+Search for bugs:
+----------------
+
+This project uses GitHub Issues here: [github.com/eclipse/paho.mqtt-sn.embedded-c/issues](https://github.com/eclipse/paho.mqtt-sn.embedded-c/issues) to track ongoing development and issues.
+
+Create a new bug:
+-----------------
+
+Be sure to search for existing bugs before you create another one. Remember that contributions are always welcome!
+
+- [Create new Paho bug](https://github.com/eclipse/paho.mqtt-sn.embedded-c/issues/new)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNClient/src/FP.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNClient/src/FP.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2014 
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Sam Grove - initial API and implementation and/or initial documentation
+ *    Ian Craggs - added attached and detached member functions
+ *    Sam Grove - removed need for FP.cpp
+ *******************************************************************************/
+
+#ifndef FP_H
+#define FP_H
+
+/** Example using the FP Class with global functions
+ * @code
+ *  #include "mbed.h"
+ *  #include "FP.h"
+ *
+ *  FP<void,bool>fp;
+ *  DigitalOut myled(LED1);
+ *
+ *  void handler(bool value)
+ *  {
+ *      myled = value;
+ *      return;
+ *  }
+ *
+ *  int main()
+ *  {
+ *      fp.attach(&handler);
+ *
+ *      while(1)
+ *      {
+ *          fp(1);
+ *          wait(0.2);
+ *          fp(0);
+ *          wait(0.2);
+ *      }
+ *  }
+ * @endcode
+ */
+
+/** Example using the FP Class with different class member functions
+ * @code
+ *  #include "mbed.h"
+ *  #include "FP.h"
+ *
+ *  FP<void,bool>fp;
+ *  DigitalOut myled(LED4);
+ *
+ *  class Wrapper
+ *  {
+ *  public:
+ *      Wrapper(){}
+ *
+ *      void handler(bool value)
+ *      {
+ *          myled = value;
+ *          return;
+ *      }
+ *  };
+ *
+ *  int main()
+ *  {
+ *      Wrapper wrapped;
+ *      fp.attach(&wrapped, &Wrapper::handler);
+ *
+ *      while(1)
+ *      {
+ *          fp(1);
+ *          wait(0.2);
+ *          fp(0);
+ *          wait(0.2);
+ *      }
+ *  }
+ * @endcode
+ */
+
+/** Example using the FP Class with member FP and member function
+* @code
+*  #include "mbed.h"
+*  #include "FP.h"
+*
+*  DigitalOut myled(LED2);
+*
+*  class Wrapper
+*  {
+*  public:
+*      Wrapper()
+*      {
+*          fp.attach(this, &Wrapper::handler);
+*      }
+*
+*      void handler(bool value)
+*      {
+*          myled = value;
+*          return;
+*      }
+*
+*      FP<void,bool>fp;
+*  };
+*
+*  int main()
+*  {
+*      Wrapper wrapped;
+*
+*      while(1)
+*      {
+*          wrapped.fp(1);
+*          wait(0.2);
+*          wrapped.fp(0);
+*          wait(0.2);
+*      }
+*  }
+* @endcode
+*/
+
+/**
+ *  @class FP
+ *  @brief API for managing Function Pointers
+ */
+template<class retT, class argT>
+class FP
+{
+public:
+    /** Create the FP object - only one callback can be attached to the object, that is
+     *  a member function or a global function, not both at the same time
+     */
+    FP()
+    {
+        obj_callback = 0;
+        c_callback = 0;
+    }
+
+    /** Add a callback function to the object
+     *  @param item - Address of the initialized object
+     *  @param member - Address of the member function (dont forget the scope that the function is defined in)
+     */
+    template<class T>
+    void attach(T *item, retT (T::*method)(argT))
+    {
+        obj_callback = (FPtrDummy *)(item);
+        method_callback = (retT (FPtrDummy::*)(argT))(method);
+        return;
+    }
+
+    /** Add a callback function to the object
+     *  @param function - The address of a globally defined function
+     */
+    void attach(retT (*function)(argT))
+    {
+        c_callback = function;
+    }
+
+    /** Invoke the function attached to the class
+     *  @param arg - An argument that is passed into the function handler that is called
+     *  @return The return from the function hanlder called by this class
+     */
+    retT operator()(argT arg) const
+    {
+        if( 0 != c_callback ) {
+            return obj_callback ? (obj_callback->*method_callback)(arg) : (*c_callback)(arg);
+        }
+        return (retT)0;
+    }
+
+    /** Determine if an callback is currently hooked
+     *  @return 1 if a method is hooked, 0 otherwise
+     */
+    bool attached()
+    {
+        return obj_callback || c_callback;
+    }
+
+    /** Release a function from the callback hook
+     */
+    void detach()
+    {
+        obj_callback = 0;
+        c_callback = 0;
+    }
+
+private:
+
+    // empty type used for casting
+    class FPtrDummy;
+
+    FPtrDummy *obj_callback;
+
+    /**
+     *  @union Funciton
+     *  @brief Member or global callback function
+     */
+    union {
+        retT (*c_callback)(argT);                   /*!< Footprint for a global function */
+        retT (FPtrDummy::*method_callback)(argT);   /*!< Footprint for a member function */
+    };
+};
+
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNClient/src/MQTTLogging.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNClient/src/MQTTLogging.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#if !defined(MQTT_LOGGING_H)
+#define MQTT_LOGGING_H
+
+#define STREAM      stdout
+#if !defined(DEBUG)
+#define DEBUG(...)    \
+    {\
+    fprintf(STREAM, "DEBUG:   %s L#%d ", __PRETTY_FUNCTION__, __LINE__);  \
+    fprintf(STREAM, ##__VA_ARGS__); \
+    fflush(STREAM); \
+    }
+#endif
+#if !defined(LOG)
+#define LOG(...)    \
+    {\
+    fprintf(STREAM, "LOG:   %s L#%d ", __PRETTY_FUNCTION__, __LINE__);  \
+    fprintf(STREAM, ##__VA_ARGS__); \
+    fflush(STREAM); \
+    }
+#endif
+#if !defined(WARN)
+#define WARN(...)   \
+    { \
+    fprintf(STREAM, "WARN:  %s L#%d ", __PRETTY_FUNCTION__, __LINE__);  \
+    fprintf(STREAM, ##__VA_ARGS__); \
+    fflush(STREAM); \
+    }
+#endif 
+#if !defined(ERROR)
+#define ERROR(...)  \
+    { \
+    fprintf(STREAM, "ERROR: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \
+    fprintf(STREAM, ##__VA_ARGS__); \
+    fflush(STREAM); \
+    exit(1); \
+    }
+#endif
+
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNClient/src/MQTTSNClient.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNClient/src/MQTTSNClient.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,923 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2015 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#if !defined(MQTTSNCLIENT_H)
+#define MQTTSNCLIENT_H
+
+#include "FP.h"
+#include "MQTTSNPacket.h"
+#include "stdio.h"
+#include "MQTTLogging.h"
+
+// Data limits
+#if !defined(MAX_REGISTRATIONS)
+    #define MAX_REGISTRATIONS 5
+#endif
+#if !defined(MAX_REGISTRATION_TOPIC_NAME_LENGTH)
+    #define MAX_REGISTRATION_TOPIC_NAME_LENGTH 20
+#endif
+#if !defined(MAX_INCOMING_QOS2_MESSAGES)
+    #define MAX_INCOMING_QOS2_MESSAGES 10
+#endif
+
+#if !defined(MQTTSNCLIENT_QOS1)
+    #define MQTTSNCLIENT_QOS1 1
+#endif
+#if !defined(MQTTSNCLIENT_QOS2)
+    #define MQTTSNCLIENT_QOS2 0
+#endif
+
+namespace MQTTSN
+{
+
+
+enum QoS { QOS0, QOS1, QOS2 };
+
+// all failure return codes must be negative
+enum returnCode { MAX_SUBSCRIPTIONS_EXCEEDED = -3, BUFFER_OVERFLOW = -2, FAILURE = -1, SUCCESS = 0 };
+
+
+struct Message
+{
+    enum QoS qos;
+    bool retained;
+    bool dup;
+    unsigned short id;
+    void *payload;
+    size_t payloadlen;
+};
+
+
+struct MessageData
+{
+    MessageData(MQTTSN_topicid &aTopic, struct Message &aMessage)  : message(aMessage), topic(aTopic)
+    { }
+
+    struct Message &message;
+    MQTTSN_topicid &topic;
+};
+
+
+class PacketId
+{
+public:
+    PacketId()
+    {
+        next = 0;
+    }
+
+    int getNext()
+    {
+        return next = (next == MAX_PACKET_ID) ? 1 : next + 1;
+    }
+
+private:
+    static const int MAX_PACKET_ID = 65535;
+    int next;
+};
+
+
+/**
+ * @class MQTTSNClient
+ * @brief blocking, non-threaded MQTTSN client API
+ *
+ * This version of the API blocks on all method calls, until they are complete.  This means that only one
+ * MQTT request can be in process at any one time.
+ * @param Network a network class which supports send, receive
+ * @param Timer a timer class with the methods:
+ */
+template<class Network, class Timer, int MAX_PACKET_SIZE = 100, int MAX_MESSAGE_HANDLERS = 5>
+class Client
+{
+
+public:
+
+    typedef void (*messageHandler)(MessageData&);
+
+    /** Construct the client
+     *  @param network - pointer to an instance of the Network class - must be connected to the endpoint
+     *      before calling MQTT connect
+     *  @param limits an instance of the Limit class - to alter limits as required
+     */
+    Client(Network& network, unsigned int command_timeout_ms = 30000);
+
+    /** Set the default message handling callback - used for any message which does not match a subscription message handler
+     *  @param mh - pointer to the callback function
+     */
+    void setDefaultMessageHandler(messageHandler mh)
+    {
+        defaultMessageHandler.attach(mh);
+    }
+
+    /** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack
+     *  The nework object must be connected to the network endpoint before calling this
+     *  Default connect options are used
+     *  @return success code -
+     */
+    int connect();
+    
+    /** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack
+     *  The nework object must be connected to the network endpoint before calling this
+     *  @param options - connect options
+     *  @return success code -
+     */
+    int connect(MQTTSNPacket_connectData& options);
+
+    /** MQTT Publish - send an MQTT publish packet and wait for all acks to complete for all QoSs
+     *  @param topic - the topic to publish to
+     *  @param message - the message to send
+     *  @return success code -
+     */
+    int publish(MQTTSN_topicid& topic, Message& message);
+    
+    /** MQTT Publish - send an MQTT publish packet and wait for all acks to complete for all QoSs
+     *  @param topic - the topic to publish to
+     *  @param payload - the data to send
+     *  @param payloadlen - the length of the data
+     *  @param qos - the QoS to send the publish at
+     *  @param retained - whether the message should be retained
+     *  @return success code -
+     */
+    int publish(MQTTSN_topicid &topic, void* payload, size_t payloadlen, enum QoS qos = QOS0, bool retained = false);
+    
+    /** MQTT Publish - send an MQTT publish packet and wait for all acks to complete for all QoSs
+     *  @param topic - the topic to publish to
+     *  @param payload - the data to send
+     *  @param payloadlen - the length of the data
+     *  @param id - the packet id used - returned 
+     *  @param qos - the QoS to send the publish at
+     *  @param retained - whether the message should be retained
+     *  @return success code -
+     */
+    int publish(MQTTSN_topicid& topic, void* payload, size_t payloadlen, unsigned short& id, enum QoS qos = QOS1, bool retained = false);
+    
+    /** MQTT Subscribe - send an MQTT subscribe packet and wait for the suback
+     *  @param topicFilter - a topic pattern which can include wildcards
+     *  @param qos - the MQTT QoS to subscribe at
+     *  @param mh - the callback function to be invoked when a message is received for this subscription
+     *  @return success code -
+     */
+    int subscribe(MQTTSN_topicid& topicFilter, enum QoS qos, messageHandler mh);
+
+    /** MQTT Unsubscribe - send an MQTT unsubscribe packet and wait for the unsuback
+     *  @param topicFilter - a topic pattern which can include wildcards
+     *  @return success code -
+     */
+    int unsubscribe(MQTTSN_topicid& topicFilter);
+
+    /** MQTT Disconnect - send an MQTT disconnect packet, and clean up any state
+     *  @param duration - used for sleeping clients, 0 means no duration
+     *  @return success code -
+     */
+    int disconnect(unsigned short duration = 0);
+
+    /** A call to this API must be made within the keepAlive interval to keep the MQTT connection alive
+     *  yield can be called if no other MQTT operation is needed.  This will also allow messages to be
+     *  received.
+     *  @param timeout_ms the time to wait, in milliseconds
+     *  @return success code - on failure, this means the client has disconnected
+     */
+    int yield(unsigned long timeout_ms = 1000L);
+
+    /** Is the client connected?
+     *  @return flag - is the client connected or not?
+     */
+    bool isConnected()
+    {
+        return isconnected;
+    }
+    
+protected:
+
+    int cycle(Timer& timer);
+    int waitfor(int packet_type, Timer& timer);
+
+private:
+
+    int keepalive();
+    int publish(int len, Timer& timer, enum QoS qos);
+
+    int decodePacket(int* value, int timeout);
+    int readPacket(Timer& timer);
+    int sendPacket(int length, Timer& timer);
+    int deliverMessage(MQTTSN_topicid& topic, Message& message);
+    bool isTopicMatched(char* topicFilter, MQTTSNString& topicName);
+
+    Network& ipstack;
+    unsigned long command_timeout_ms;
+
+    unsigned char sendbuf[MAX_PACKET_SIZE];
+    unsigned char readbuf[MAX_PACKET_SIZE];
+
+    Timer last_sent, last_received;
+    unsigned short duration;
+    bool ping_outstanding;
+    bool cleansession;
+
+    PacketId packetid;
+
+    struct MessageHandlers
+    {
+        MQTTSN_topicid* topicFilter;
+        FP<void, MessageData&> fp;
+    } messageHandlers[MAX_MESSAGE_HANDLERS];      // Message handlers are indexed by subscription topic
+
+    FP<void, MessageData&> defaultMessageHandler;
+
+    bool isconnected;
+    
+    struct Registrations
+    {
+        unsigned short id;
+        char name[MAX_REGISTRATION_TOPIC_NAME_LENGTH];
+    } registrations[MAX_REGISTRATIONS];
+
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+    unsigned char pubbuf[MAX_PACKET_SIZE];  // store the last publish for sending on reconnect
+    int inflightLen;
+    unsigned short inflightMsgid;
+    enum QoS inflightQoS;
+#endif
+
+#if MQTTCLIENT_QOS2
+    bool pubrel;
+    unsigned short incomingQoS2messages[MAX_INCOMING_QOS2_MESSAGES];
+    bool isQoS2msgidFree(unsigned short id);
+    bool useQoS2msgid(unsigned short id);
+#endif
+
+};
+
+}
+
+
+template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS>
+MQTTSN::Client<Network, Timer, a, MAX_MESSAGE_HANDLERS>::Client(Network& network, unsigned int command_timeout_ms)  : ipstack(network), packetid()
+{
+    ping_outstanding = false;
+    for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+        messageHandlers[i].topicFilter = 0;
+    this->command_timeout_ms = command_timeout_ms;
+    isconnected = false;
+    
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+    inflightMsgid = 0;
+    inflightQoS = QOS0;
+#endif
+
+    
+#if MQTTCLIENT_QOS2
+    pubrel = false;
+    for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
+        incomingQoS2messages[i] = 0;
+#endif
+}
+
+#if MQTTCLIENT_QOS2
+template<class Network, class Timer, int a, int b>
+bool MQTTSN::Client<Network, Timer, a, b>::isQoS2msgidFree(unsigned short id)
+{
+    for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
+    {
+        if (incomingQoS2messages[i] == id)
+            return false;
+    }
+    return true;
+}
+
+
+template<class Network, class Timer, int a, int b>
+bool MQTTSN::Client<Network, Timer, a, b>::useQoS2msgid(unsigned short id)
+{
+    for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
+    {
+        if (incomingQoS2messages[i] == 0)
+        {
+            incomingQoS2messages[i] = id;
+            return true;
+        }
+    }
+    return false;
+}
+#endif
+
+
+template<class Network, class Timer, int a, int b>
+int MQTTSN::Client<Network, Timer, a, b>::sendPacket(int length, Timer& timer)
+{
+    int rc = FAILURE,
+        sent = 0;
+
+    while (sent < length && !timer.expired())
+    {
+        rc = ipstack.write(&sendbuf[sent], length, timer.left_ms());
+        if (rc < 0)  // there was an error writing the data
+            break;
+        sent += rc;
+    }
+    if (sent == length)
+    {
+        if (this->duration > 0)
+            last_sent.countdown(this->duration); // record the fact that we have successfully sent the packet
+        rc = SUCCESS;
+    }
+    else
+        rc = FAILURE;
+        
+#if defined(MQTT_DEBUG)
+    char printbuf[50];
+    DEBUG("Rc %d from sending packet %s\n", rc, MQTTPacket_toString(printbuf, sizeof(printbuf), sendbuf, length));
+#endif
+    return rc;
+}
+
+
+template<class Network, class Timer, int a, int b>
+int MQTTSN::Client<Network, Timer, a, b>::decodePacket(int* value, int timeout)
+{
+    unsigned char c;
+    int multiplier = 1;
+    int len = 0;
+    const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4;
+
+    *value = 0;
+    do
+    {
+        int rc = MQTTSNPACKET_READ_ERROR;
+
+        if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
+        {
+            rc = MQTTSNPACKET_READ_ERROR; /* bad data */
+            goto exit;
+        }
+        rc = ipstack.read(&c, 1, timeout);
+        if (rc != 1)
+            goto exit;
+        *value += (c & 127) * multiplier;
+        multiplier *= 128;
+    } while ((c & 128) != 0);
+exit:
+    return len;
+}
+
+
+/**
+ * If any read fails in this method, then we should disconnect from the network, as on reconnect
+ * the packets can be retried.
+ * @param timeout the max time to wait for the packet read to complete, in milliseconds
+ * @return the MQTT packet type, or -1 if none
+ */
+template<class Network, class Timer, int MAX_PACKET_SIZE, int b>
+int MQTTSN::Client<Network, Timer, MAX_PACKET_SIZE, b>::readPacket(Timer& timer)
+{
+    int rc = FAILURE;
+    int len = 0;  // the length of the whole packet including length field 
+    int lenlen = 0;
+    int datalen = 0;
+
+    #define MQTTSN_MIN_PACKET_LENGTH 2
+    // 1. read the packet, datagram style 
+    if ((len = ipstack.read(readbuf, MAX_PACKET_SIZE, timer.left_ms())) < MQTTSN_MIN_PACKET_LENGTH)
+        goto exit;
+        
+    // 2. read the length.  This is variable in itself 
+    lenlen = MQTTSNPacket_decode(readbuf, len, &datalen);
+    if (datalen != len)
+        goto exit; // there was an error 
+        
+    rc = readbuf[lenlen];
+    if (this->duration > 0)
+        last_received.countdown(this->duration); // record the fact that we have successfully received a packet
+exit:
+        
+#if defined(MQTT_DEBUG)
+    char printbuf[50];
+    DEBUG("Rc %d from receiving packet %s\n", rc, MQTTPacket_toString(printbuf, sizeof(printbuf), readbuf, len));
+#endif
+    return rc;
+}
+
+
+// assume topic filter and name is in correct format
+// # can only be at end
+// + and # can only be next to separator
+template<class Network, class Timer, int a, int b>
+bool MQTTSN::Client<Network, Timer, a, b>::isTopicMatched(char* topicFilter, MQTTSNString& topicName)
+{
+    char* curf = topicFilter;
+    char* curn = topicName.lenstring.data;
+    char* curn_end = curn + topicName.lenstring.len;
+
+    while (*curf && curn < curn_end)
+    {
+        if (*curn == '/' && *curf != '/')
+            break;
+        if (*curf != '+' && *curf != '#' && *curf != *curn)
+            break;
+        if (*curf == '+')
+        {   // skip until we meet the next separator, or end of string
+            char* nextpos = curn + 1;
+            while (nextpos < curn_end && *nextpos != '/')
+                nextpos = ++curn + 1;
+        }
+        else if (*curf == '#')
+            curn = curn_end - 1;    // skip until end of string
+        curf++;
+        curn++;
+    };
+
+    return (curn == curn_end) && (*curf == '\0');
+}
+
+
+
+template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS>
+int MQTTSN::Client<Network, Timer, a, MAX_MESSAGE_HANDLERS>::deliverMessage(MQTTSN_topicid& topic, Message& message)
+{
+    int rc = FAILURE;
+
+    // we have to find the right message handler - indexed by topic
+    for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+    {
+        MQTTSNString str = MQTTSNString_initializer;
+        str.lenstring.data = topic.data.long_.name;
+        str.lenstring.len = topic.data.long_.len;
+        if (messageHandlers[i].topicFilter != 0 && (MQTTSNTopic_equals(&topic, messageHandlers[i].topicFilter) ||
+                isTopicMatched(messageHandlers[i].topicFilter->data.long_.name, str)))
+        {
+            if (messageHandlers[i].fp.attached())
+            {
+                MessageData md(topic, message);
+                messageHandlers[i].fp(md);
+                rc = SUCCESS;
+            }
+        }
+    }
+
+    if (rc == FAILURE && defaultMessageHandler.attached())
+    {
+        MessageData md(topic, message);
+        defaultMessageHandler(md);
+        rc = SUCCESS;
+    }
+
+    return rc;
+}
+
+
+
+template<class Network, class Timer, int a, int b>
+int MQTTSN::Client<Network, Timer, a, b>::yield(unsigned long timeout_ms)
+{
+    int rc = SUCCESS;
+    Timer timer;
+
+    timer.countdown_ms(timeout_ms);
+    while (!timer.expired())
+    {
+        if (cycle(timer) == FAILURE)
+        {
+            rc = FAILURE;
+            break;
+        }
+    }
+
+    return rc;
+}
+
+
+template<class Network, class Timer, int MAX_PACKET_SIZE, int b>
+int MQTTSN::Client<Network, Timer, MAX_PACKET_SIZE, b>::cycle(Timer& timer)
+{
+    /* get one piece of work off the wire and one pass through */
+
+    // read the socket, see what work is due
+    unsigned short packet_type = readPacket(timer);
+
+    int len = 0;
+    unsigned char rc = SUCCESS;
+
+    switch (packet_type)
+    {
+        case MQTTSN_CONNACK:
+        case MQTTSN_PUBACK:
+        case MQTTSN_SUBACK:
+        case MQTTSN_REGACK:
+            break;
+        case MQTTSN_REGISTER:
+        {
+            unsigned short topicid, packetid;
+            MQTTSNString topicName;
+            rc = MQTTSN_RC_ACCEPTED;
+            if (MQTTSNDeserialize_register(&topicid, &packetid, &topicName, readbuf, MAX_PACKET_SIZE) != 1)
+                goto exit;
+            len = MQTTSNSerialize_regack(sendbuf, MAX_PACKET_SIZE, topicid, packetid, rc);
+            if (len <= 0)
+                rc = FAILURE;
+            else
+                rc = sendPacket(len, timer);
+            break;
+        }
+        case MQTTSN_PUBLISH:
+            MQTTSN_topicid topicid;
+            Message msg;
+            if (MQTTSNDeserialize_publish((unsigned char*)&msg.dup, (int*)&msg.qos, (unsigned char*)&msg.retained, (unsigned short*)&msg.id, &topicid,
+                                 (unsigned char**)&msg.payload, (int*)&msg.payloadlen, readbuf, MAX_PACKET_SIZE) != 1)
+                goto exit;
+#if MQTTCLIENT_QOS2
+            if (msg.qos != QOS2)
+#endif
+                deliverMessage(topicid, msg);
+#if MQTTCLIENT_QOS2
+            else if (isQoS2msgidFree(msg.id))
+            {
+                if (useQoS2msgid(msg.id))
+                    deliverMessage(topicid, msg);
+                else
+                    WARN("Maximum number of incoming QoS2 messages exceeded");
+            }   
+#endif
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+            if (msg.qos != QOS0)
+            {
+                if (msg.qos == QOS1)
+                    len = MQTTSNSerialize_puback(sendbuf, MAX_PACKET_SIZE, topicid.data.id, msg.id, 0);
+                else if (msg.qos == QOS2)
+                    len = MQTTSNSerialize_pubrec(sendbuf, MAX_PACKET_SIZE, msg.id);
+                if (len <= 0)
+                    rc = FAILURE;
+                else
+                    rc = sendPacket(len, timer);
+                if (rc == FAILURE)
+                    goto exit; // there was a problem
+            }
+            break;
+#endif
+#if MQTTCLIENT_QOS2
+        case MQTTSN_PUBREC:
+            unsigned short mypacketid;
+            unsigned char dup, type;
+            if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, MAX_PACKET_SIZE) != 1)
+                rc = FAILURE;
+            else if ((len = MQTTSerialize_ack(sendbuf, MAX_PACKET_SIZE, PUBREL, 0, mypacketid)) <= 0)
+                rc = FAILURE;
+            else if ((rc = sendPacket(len, timer)) != SUCCESS) // send the PUBREL packet
+                rc = FAILURE; // there was a problem
+            if (rc == FAILURE)
+                goto exit; // there was a problem
+            break;
+        case MQTTSN_PUBCOMP:
+            break;
+#endif
+        case MQTTSN_PINGRESP:
+            ping_outstanding = false;
+            break;
+    }
+    keepalive();
+exit:
+    if (rc == SUCCESS)
+        rc = packet_type;
+    return rc;
+}
+
+
+template<class Network, class Timer, int MAX_PACKET_SIZE, int b>
+int MQTTSN::Client<Network, Timer, MAX_PACKET_SIZE, b>::keepalive()
+{
+    int rc = FAILURE;
+
+    if (duration == 0)
+    {
+        rc = SUCCESS;
+        goto exit;
+    }
+
+    if (last_sent.expired() || last_received.expired())
+    {
+        if (!ping_outstanding)
+        {
+            MQTTSNString clientid = MQTTSNString_initializer;
+            Timer timer(1000);
+            int len = MQTTSNSerialize_pingreq(sendbuf, MAX_PACKET_SIZE, clientid);
+            if (len > 0 && (rc = sendPacket(len, timer)) == SUCCESS) // send the ping packet
+                ping_outstanding = true;
+        }
+    }
+
+exit:
+    return rc;
+}
+
+
+// only used in single-threaded mode where one command at a time is in process
+template<class Network, class Timer, int a, int b>
+int MQTTSN::Client<Network, Timer, a, b>::waitfor(int packet_type, Timer& timer)
+{
+    int rc = FAILURE;
+
+    do
+    {
+        if (timer.expired())
+            break; // we timed out
+    }
+    while ((rc = cycle(timer)) != packet_type);
+
+    return rc;
+}
+
+
+template<class Network, class Timer, int MAX_PACKET_SIZE, int b>
+int MQTTSN::Client<Network, Timer, MAX_PACKET_SIZE, b>::connect(MQTTSNPacket_connectData& options)
+{
+    Timer connect_timer(command_timeout_ms);
+    int rc = FAILURE;
+    int len = 0;
+
+    if (isconnected) // don't send connect packet again if we are already connected
+        goto exit;
+
+    this->duration = options.duration;
+    this->cleansession = options.cleansession;
+    if ((len = MQTTSNSerialize_connect(sendbuf, MAX_PACKET_SIZE, &options)) <= 0)
+        goto exit;
+    if ((rc = sendPacket(len, connect_timer)) != SUCCESS)  // send the connect packet
+        goto exit; // there was a problem
+
+    if (this->duration > 0)
+        last_received.countdown(this->duration);
+    // this will be a blocking call, wait for the connack
+    if (waitfor(MQTTSN_CONNACK, connect_timer) == MQTTSN_CONNACK)
+    {
+        //unsigned char connack_rc = 255;
+        int connack_rc = 255;
+        if (MQTTSNDeserialize_connack(&connack_rc, readbuf, MAX_PACKET_SIZE) == 1)
+            rc = connack_rc;
+        else
+            rc = FAILURE;
+    }
+    else
+        rc = FAILURE;
+        
+#if MQTTCLIENT_QOS2
+    // resend an inflight publish
+    if (inflightMsgid >0 && inflightQoS == QOS2 && pubrel)
+    {
+        if ((len = MQTTSerialize_ack(sendbuf, MAX_PACKET_SIZE, PUBREL, 0, inflightMsgid)) <= 0)
+            rc = FAILURE;
+        else
+            rc = publish(len, connect_timer, inflightQoS);
+    }
+    else
+#endif
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+    if (inflightMsgid > 0)
+    {
+        memcpy(sendbuf, pubbuf, MAX_PACKET_SIZE);
+        rc = publish(inflightLen, connect_timer, inflightQoS);
+    }
+#endif
+
+exit:
+    if (rc == SUCCESS)
+        isconnected = true;
+    return rc;
+}
+
+
+template<class Network, class Timer, int MAX_PACKET_SIZE, int b>
+int MQTTSN::Client<Network, Timer, MAX_PACKET_SIZE, b>::connect()
+{
+    MQTTSNPacket_connectData default_options = MQTTSNPacket_connectData_initializer;
+    return connect(default_options);
+}
+
+
+template<class Network, class Timer, int MAX_PACKET_SIZE, int MAX_MESSAGE_HANDLERS>
+int MQTTSN::Client<Network, Timer, MAX_PACKET_SIZE, MAX_MESSAGE_HANDLERS>::subscribe(MQTTSN_topicid& topicFilter, enum QoS qos, messageHandler messageHandler)
+{
+    int rc = FAILURE;
+    Timer timer(command_timeout_ms);
+    int len = 0;
+
+    if (!isconnected)
+        return FAILURE; // goto exit cannot cross variable initialization
+        
+    bool freeHandler = false;
+    for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+    {
+        if (messageHandlers[i].topicFilter == 0)
+        {
+            freeHandler = true;
+            break;
+        }
+    }
+    if (!freeHandler)
+    {                                 // No message handler free
+        rc = MAX_SUBSCRIPTIONS_EXCEEDED;
+        goto exit; 
+    }
+
+    len = MQTTSNSerialize_subscribe(sendbuf, MAX_PACKET_SIZE, 0, qos, packetid.getNext(), &topicFilter);
+    if (len <= 0)
+        goto exit;
+    if ((rc = sendPacket(len, timer)) != SUCCESS) // send the subscribe packet
+        goto exit;             // there was a problem
+
+    if (waitfor(MQTTSN_SUBACK, timer) == MQTTSN_SUBACK)      // wait for suback
+    {
+        int grantedQoS = -1;
+        unsigned short mypacketid;
+        unsigned char rc;
+        if (MQTTSNDeserialize_suback(&grantedQoS, &topicFilter.data.id, &mypacketid, &rc, readbuf, MAX_PACKET_SIZE) != 1)
+            goto exit;
+
+        if (qos != grantedQoS)
+            goto exit;
+
+        if (rc == MQTTSN_RC_ACCEPTED)
+        {
+            for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+            {
+                if (messageHandlers[i].topicFilter == 0)
+                {
+                    messageHandlers[i].topicFilter = &topicFilter;
+                    messageHandlers[i].fp.attach(messageHandler);
+                    rc = 0;
+                    break;
+                }
+            }
+        }
+    }
+    else
+        rc = FAILURE;
+
+exit:
+    if (rc != SUCCESS)
+        isconnected = false;
+    return rc;
+}
+
+
+template<class Network, class Timer, int MAX_PACKET_SIZE, int MAX_MESSAGE_HANDLERS>
+int MQTTSN::Client<Network, Timer, MAX_PACKET_SIZE, MAX_MESSAGE_HANDLERS>::unsubscribe(MQTTSN_topicid& topicFilter)
+{
+    int rc = FAILURE;
+    Timer timer(command_timeout_ms);
+    int len = 0;
+
+    if (!isconnected)
+        goto exit;
+
+    if ((len = MQTTSNSerialize_unsubscribe(sendbuf, MAX_PACKET_SIZE, packetid.getNext(), &topicFilter)) <= 0)
+        goto exit;
+    if ((rc = sendPacket(len, timer)) != SUCCESS) // send the unsubscribe packet
+        goto exit; // there was a problem
+
+    if (waitfor(MQTTSN_UNSUBACK, timer) == MQTTSN_UNSUBACK)
+    {
+        unsigned short mypacketid;  // should be the same as the packetid above
+        if (MQTTSNDeserialize_unsuback(&mypacketid, readbuf, MAX_PACKET_SIZE) == 1)
+            rc = 0;
+    }
+    else
+        rc = FAILURE;
+
+exit:
+    if (rc != SUCCESS)
+        isconnected = false;
+    return rc;
+}
+
+
+template<class Network, class Timer, int MAX_PACKET_SIZE, int b>
+int MQTTSN::Client<Network, Timer, MAX_PACKET_SIZE, b>::publish(int len, Timer& timer, enum QoS qos)
+{
+    int rc;
+    
+    if ((rc = sendPacket(len, timer)) != SUCCESS) // send the publish packet
+        goto exit; // there was a problem
+
+#if MQTTCLIENT_QOS1 
+    if (qos == QOS1)
+    {
+        if (waitfor(MQTTSN_PUBACK, timer) == MQTTSN_PUBACK)
+        {
+            unsigned short mypacketid;
+            unsigned char type;
+            if (MQTTSNDeserialize_ack(&type, &mypacketid, readbuf, MAX_PACKET_SIZE) != 1)
+                rc = FAILURE;
+            else if (inflightMsgid == mypacketid)
+                inflightMsgid = 0;
+        }
+        else
+            rc = FAILURE;
+    }
+#elif MQTTCLIENT_QOS2
+    else if (qos == QOS2)
+    {
+        if (waitfor(PUBCOMP, timer) == PUBCOMP)
+        {
+            unsigned short mypacketid;
+            unsigned char type;
+            if (MQTTDeserialize_ack(&type, &mypacketid, readbuf, MAX_PACKET_SIZE) != 1)
+                rc = FAILURE;
+            else if (inflightMsgid == mypacketid)
+                inflightMsgid = 0;
+        }
+        else
+            rc = FAILURE;
+    }
+#endif
+
+exit:
+    if (rc != SUCCESS)
+        isconnected = false;
+    return rc;
+}
+
+
+
+template<class Network, class Timer, int MAX_PACKET_SIZE, int b>
+int MQTTSN::Client<Network, Timer, MAX_PACKET_SIZE, b>::publish(MQTTSN_topicid& topic, void* payload, size_t payloadlen, unsigned short& id, enum QoS qos, bool retained)
+{
+    int rc = FAILURE;
+    Timer timer(command_timeout_ms);
+    int len = 0;
+
+    if (!isconnected)
+        goto exit;
+
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+    if (qos == QOS1 || qos == QOS2)
+        id = packetid.getNext();
+#endif
+
+    len = MQTTSNSerialize_publish(sendbuf, MAX_PACKET_SIZE, 0, qos, retained, id,
+              topic, (unsigned char*)payload, payloadlen);
+    if (len <= 0)
+        goto exit;
+        
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+    if (!cleansession)
+    {
+        memcpy(pubbuf, sendbuf, len);
+        inflightMsgid = id;
+        inflightLen = len;
+        inflightQoS = qos;
+#if MQTTCLIENT_QOS2
+        pubrel = false;
+#endif
+    }
+#endif
+        
+    rc = publish(len, timer, qos);
+exit:
+    return rc;
+}
+
+
+template<class Network, class Timer, int MAX_PACKET_SIZE, int b>
+int MQTTSN::Client<Network, Timer, MAX_PACKET_SIZE, b>::publish(MQTTSN_topicid& topicName, void* payload, size_t payloadlen, enum QoS qos, bool retained)
+{
+    unsigned short id = 0;  // dummy - not used for anything
+    return publish(topicName, payload, payloadlen, id, qos, retained);
+}
+
+
+template<class Network, class Timer, int MAX_PACKET_SIZE, int b>
+int MQTTSN::Client<Network, Timer, MAX_PACKET_SIZE, b>::publish(MQTTSN_topicid& topicName, Message& message)
+{
+    return publish(topicName, message.payload, message.payloadlen, message.qos, message.retained);
+}
+
+
+template<class Network, class Timer, int MAX_PACKET_SIZE, int b>
+int MQTTSN::Client<Network, Timer, MAX_PACKET_SIZE, b>::disconnect(unsigned short duration)
+{
+    int rc = FAILURE;
+    Timer timer(command_timeout_ms);     // we might wait for incomplete incoming publishes to complete
+    int int_duration = (duration == 0) ? -1 : (int)duration;
+    int len = MQTTSNSerialize_disconnect(sendbuf, MAX_PACKET_SIZE, int_duration);
+    if (len > 0)
+        rc = sendPacket(len, timer);            // send the disconnect packet
+
+    isconnected = false;
+    return rc;
+}
+
+
+#endif
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNClient/src/linux/linux.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNClient/src/linux/linux.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2015 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+
+class IPStack 
+{
+public:    
+    IPStack()
+    {
+
+    }
+    
+	int Socket_error(const char* aString)
+	{
+		int rc = 0;
+		//if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS && errno != EWOULDBLOCK)
+		//{
+			if (strcmp(aString, "shutdown") != 0 || (errno != ENOTCONN && errno != ECONNRESET))
+			{
+				if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS && errno != EWOULDBLOCK)
+				printf("Socket error %s in %s for socket %d\n", strerror(errno), aString, mysock);
+				rc = errno;
+			}
+		//}
+		return rc;
+	}
+
+    int connect(const char* hostname, int port)
+    {
+		int type = SOCK_STREAM;
+		struct sockaddr_in address;
+		int rc = -1;
+		sa_family_t family = AF_INET;
+		struct addrinfo *result = NULL;
+		struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL};
+
+		if ((rc = getaddrinfo(hostname, NULL, &hints, &result)) == 0)
+		{
+			struct addrinfo* res = result;
+
+			/* prefer ip4 addresses */
+			while (res)
+			{
+				if (res->ai_family == AF_INET)
+				{
+					result = res;
+					break;
+				}
+				res = res->ai_next;
+			}
+
+			if (result->ai_family == AF_INET)
+			{
+				address.sin_port = htons(port);
+				address.sin_family = family = AF_INET;
+				address.sin_addr = ((struct sockaddr_in*)(result->ai_addr))->sin_addr;
+			}
+			else
+				rc = -1;
+
+			freeaddrinfo(result);
+		}
+
+		if (rc == 0)
+		{
+			mysock = socket(family, type, 0);
+			if (mysock != -1)
+			{
+				//int opt = 1;
+
+				//if (setsockopt(mysock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&opt, sizeof(opt)) != 0)
+				//	printf("Could not set SO_NOSIGPIPE for socket %d", mysock);
+				
+				rc = ::connect(mysock, (struct sockaddr*)&address, sizeof(address));
+			}
+		}
+
+        return rc;
+    }
+
+    int read(unsigned char* buffer, int len, int timeout_ms)
+    {
+		struct timeval interval = {timeout_ms / 1000, (timeout_ms % 1000) * 1000};
+		if (interval.tv_sec < 0 || (interval.tv_sec == 0 && interval.tv_usec <= 0))
+		{
+			interval.tv_sec = 0;
+			interval.tv_usec = 100;
+		}
+
+		setsockopt(mysock, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval, sizeof(struct timeval));
+
+		int bytes = 0;
+		while (bytes < len)
+		{
+			int rc = ::recv(mysock, &buffer[bytes], (size_t)(len - bytes), 0);
+			if (rc == -1)
+			{
+				if (Socket_error("read") != 0)
+				{
+					bytes = -1;
+					break;
+				}
+			}
+			else
+				bytes += rc;
+		}
+		return bytes;
+    }
+    
+    int write(unsigned char* buffer, int len, int timeout)
+    {
+		struct timeval tv;
+
+		tv.tv_sec = 0;  /* 30 Secs Timeout */
+		tv.tv_usec = timeout * 1000;  // Not init'ing this can cause strange errors
+
+		setsockopt(mysock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
+		int	rc = ::write(mysock, buffer, len);
+		//printf("write rc %d\n", rc);
+		return rc;
+    }
+
+	int disconnect()
+	{
+		return ::close(mysock);
+	}
+    
+private:
+
+    int mysock; 
+    
+};
+
+
+class Countdown
+{
+public:
+    Countdown()
+    { 
+	
+    }
+
+    Countdown(int ms)
+    { 
+		countdown_ms(ms);
+    }
+    
+
+    bool expired()
+    {
+		struct timeval now, res;
+		gettimeofday(&now, NULL);
+		timersub(&end_time, &now, &res);		
+		//printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000);
+		//if (res.tv_sec > 0 || res.tv_usec > 0)
+		//	printf("expired %d %d\n", res.tv_sec, res.tv_usec);
+        return res.tv_sec < 0 || (res.tv_sec == 0 && res.tv_usec <= 0);
+    }
+    
+
+    void countdown_ms(int ms)  
+    {
+		struct timeval now;
+		gettimeofday(&now, NULL);
+		struct timeval interval = {ms / 1000, (ms % 1000) * 1000};
+		//printf("interval %d %d\n", interval.tv_sec, interval.tv_usec);
+		timeradd(&now, &interval, &end_time);
+    }
+
+    
+    void countdown(int seconds)
+    {
+		struct timeval now;
+		gettimeofday(&now, NULL);
+		struct timeval interval = {seconds, 0};
+		timeradd(&now, &interval, &end_time);
+    }
+
+    
+    int left_ms()
+    {
+		struct timeval now, res;
+		gettimeofday(&now, NULL);
+		timersub(&end_time, &now, &res);
+		//printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000);
+        return (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000;
+    }
+    
+private:
+
+	struct timeval end_time;
+};
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/README.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/README.md	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,119 @@
+###Gateway Test Program.    
+**sample/mainTest.cpp** is a Test sample coading.   
+Each test is described as one function. test1(), test2()...     
+````
+/*------------------------------------------------------
+ *    Test functions
+ *
+ *    you can use 4 commands in Test functions
+ *
+ *    1) PUBLISH(const char* topicName,
+ *               uint8_t*    payload,
+ *               uint16_t    len,
+ *               uint8_t     qos,
+ *               bool        retain = false);
+ *
+ *    2) SUBSCRIBE(const char*   topicName,
+ *                 TopicCallback onPublish,
+ *                 uint8_t qos);
+ *
+ *    3) UNSUBSCRIBE(const char* topicName);
+ *
+ *    4) DISCONNECT(uint16_t sleepInSecs);
+ *
+ *------------------------------------------------------*/
+
+void test1(void)
+{
+	char payload[300];
+	sprintf(payload, "ESP8266-08b133 ");
+	uint8_t qos = 0;
+	PUBLISH(topic1,(uint8_t*)payload, strlen(payload), qos);
+}
+
+void test2(void)
+{
+	uint8_t qos = 1;
+	SUBSCRIBE(topic2, on_publish02, qos);
+}
+````
+**TEST_LIST** is a test senario. Test functions are executed one by one. 
+```` 
+/*------------------------------------------------------
+ *    A List of Test Tasks
+ *------------------------------------------------------*/
+
+TEST_LIST = {// e.g. TEST( Label, Test),
+			 TEST("Publish topic1",     test1),
+			 TEST("Subscribe topic2",   test2),
+			 TEST("Publish topic2",     test3),
+			 TEST("Unsubscribe topic2", test4),
+			 TEST("Publish topic2",     test3),
+			 TEST("Disconnect",         test5),
+			 END_OF_TEST_LIST
+			};
+```` 
+
+### **step1. Build **   
+````
+$ git clone https://github.com/eclipse/paho.mqtt-sn.embedded-c 
+$ cd paho.mqtt-sn.embedded-c/MQTTSNGateway/GatewayTester       
+$ make   
+$ make install   
+$ make clean
+```       
+MQTT-SNGatewayTester program is copied into ../../../ directory.
+
+    
+### **step2. Execute Gateway Tester.**     
+
+````    
+$ cd ../../..   
+$ ./MQTT-SNGatewayTester
+  
+ ***************************************************************************
+ * MQTT-SN Gateway Tester
+ * Part of Project Paho in Eclipse
+ * (http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt-sn.embedded-c.git/)
+ *
+ * Author : Tomoaki YAMAGUCHI
+ * Version: 0.0.0
+ ***************************************************************************
+
+Attempting to Connect the Broker.....
+
+sendto 225.1.1.1      :1883   03 01 00
+
+recved 192.168.11.5   :1883   03 01 00
+sendto 225.1.1.1      :1883   03 01 00
+
+recved 192.168.11.5   :1883   03 01 00
+
+recved 192.168.11.17  :10000  03 02 01
+sendto 192.168.11.17  :10000  13 04 0c 01 03 84 47 61 74 65 77 61 79 54 65 73 74 65 72
+
+recved 192.168.11.17  :10000  02 06
+sendto 192.168.11.17  :10000  0c 07 00 77 69 6c 6c 54 6f 70 69 63
+
+recved 192.168.11.17  :10000  02 08
+sendto 192.168.11.17  :10000  0d 09 77 69 6c 6c 4d 65 73 73 61 67 65
+
+recved 192.168.11.17  :10000  03 05 00
+
+
+ Connected to the Broker
+
+ Attempting OnConnect.....
+sendto 192.168.11.17  :10000  13 12 20 00 01 74 79 34 74 77 2f 63 6c 69 65 6e 74 49 64
+
+recved 192.168.11.17  :10000  08 13 20 00 01 00 01 00
+
+
+ SUBSCRIBE complete. ty4tw/clientId
+
+ OnConnect complete
+ Test Ready.
+
+Execute Publish topic1 Test ? ( Y/N ) :  
+
+````    
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/samples/ClientPub/mainPub.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,166 @@
+/****************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ *---------------------------------------------------------------------------
+ *
+ *   MQTT-SN GATEWAY TEST CLIENT
+ *
+ *   Supported functions.
+ *
+ *   void PUBLISH  ( const char* topicName, uint8_t* payload, uint16_t len, uint8_t qos, bool retain = false );
+ *
+ *   void PUBLISH  ( uint16_t topicId, uint8_t* payload, uint16_t len, uint8_t qos, bool retain = false );
+ *
+ *  void SUBSCRIBE ( const char* topicName, TopicCallback onPublish, uint8_t qos );
+ *
+ *  void SUBSCRIBE ( uint16_t topicId, TopicCallback onPublish, uint8_t qos );
+ *
+ *  void UNSUBSCRIBE ( const char* topicName );
+ *
+ *  void UNSUBSCRIBE ( uint16_t topicId );
+ *
+ *   void DISCONNECT ( uint16_t sleepInSecs );
+ *
+ *   void CONNECT ( void );
+ *
+ *   void DISPLAY( format, .....);    <== instead of printf()
+ *
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation
+ ***************************************************************************/
+
+#include "LMqttsnClientApp.h"
+#include "LMqttsnClient.h"
+#include "LScreen.h"
+
+using namespace std;
+using namespace linuxAsyncClient;
+extern LMqttsnClient* theClient;
+extern LScreen* theScreen;
+
+/*------------------------------------------------------
+ *    UDP Configuration    (theNetcon)
+ *------------------------------------------------------*/
+UDPCONF  = {
+    "ClientPUB", // ClientId
+    {225,1,1,1},         // Multicast group IP
+    1883,                // Multicast group Port
+    20010,               // Local PortNo
+};
+
+/*------------------------------------------------------
+ *    Client Configuration  (theMqcon)
+ *------------------------------------------------------*/
+MQTTSNCONF = {
+    300,            //KeepAlive [seconds]
+    true,          //Clean session
+    300,           //Sleep duration [seconds]
+    "",            //WillTopic
+    "",            //WillMessage
+    0,             //WillQos
+    false          //WillRetain
+};
+
+/*------------------------------------------------------
+ *     Define Topics
+ *------------------------------------------------------*/
+const char* topic1 = "ty4tw/topic1";
+const char* topic2 = "ty4tw/topic2";
+const char* topic3 = "ty4tw/topic3";
+const char* topic57 = "ty4tw/topic5/7";
+
+/*------------------------------------------------------
+ *       Callback routines for Subscribed Topics
+ *------------------------------------------------------*/
+
+/*------------------------------------------------------
+ *      A Link list of Callback routines and Topics
+ *------------------------------------------------------*/
+
+SUBSCRIBE_LIST = {// e.g. SUB(topic, callback, QoS),
+                  END_OF_SUBSCRIBE_LIST
+                 };
+
+
+/*------------------------------------------------------
+ *    Test functions
+ *------------------------------------------------------*/
+
+void publishTopic1(void)
+{
+    char payload[300];
+    sprintf(payload, "publish \"ty4tw/Topic1\" \n");
+    uint8_t qos = 0;
+    PUBLISH(topic1,(uint8_t*)payload, strlen(payload), qos);
+}
+
+void publishTopic2(void)
+{
+    char payload[300];
+    sprintf(payload, "publish \"ty4tw/topic2\" \n");
+    uint8_t qos = 0;
+    PUBLISH(topic2,(uint8_t*)payload, strlen(payload), qos);
+}
+
+void publishTopic57(void)
+{
+    char payload[300];
+    sprintf(payload, "publish \"ty4tw/topic57\" \n");
+    uint8_t qos = 0;
+    PUBLISH(topic2,(uint8_t*)payload, strlen(payload), qos);
+}
+
+
+void disconnect(void)
+{
+    DISCONNECT(0);
+}
+
+
+/*------------------------------------------------------
+ *    A List of Test functions is valid in case of
+ *    line 23 of LMqttsnClientApp.h is commented out.
+ *    //#define CLIENT_MODE
+ *------------------------------------------------------*/
+
+TEST_LIST = {// e.g. TEST( Label, Test),
+             TEST("Step1:Publish topic1",     publishTopic1),
+             TEST("Step2:Publish topic57",     publishTopic57),
+             TEST("Step3:Publish topic2",     publishTopic2),
+             TEST("Step4:Disconnect",        disconnect),
+             END_OF_TEST_LIST
+            };
+
+
+/*------------------------------------------------------
+ *    List of tasks is valid in case of line23 of
+ *    LMqttsnClientApp.h is uncommented.
+ *    #define CLIENT_MODE
+ *------------------------------------------------------*/
+TASK_LIST = {// e.g. TASK( task, executing duration in second),
+            TASK(publishTopic1, 4),  // publishTopic1() is executed every 4 seconds
+            TASK(publishTopic2, 7),  // publishTopic2() is executed every 7 seconds
+             END_OF_TASK_LIST
+            };
+
+
+/*------------------------------------------------------
+ *    Initialize function
+ *------------------------------------------------------*/
+void setup(void)
+{
+    SetForwarderMode(false);
+}
+
+
+/*****************  END OF  PROGRAM ********************/
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/samples/ClientPubQoS-1/mainPubQoS-1.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,161 @@
+/****************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ *---------------------------------------------------------------------------
+ *
+ *   MQTT-SN GATEWAY TEST CLIENT
+ *
+ *   Supported functions.
+ *
+ *   void PUBLISH  ( const char* topicName, uint8_t* payload, uint16_t len, uint8_t qos, bool retain = false );
+ *
+ *   void PUBLISH  ( uint16_t topicId, uint8_t* payload, uint16_t len, uint8_t qos, bool retain = false );
+ *
+ *  void SUBSCRIBE ( const char* topicName, TopicCallback onPublish, uint8_t qos );
+ *
+ *  void SUBSCRIBE ( uint16_t topicId, TopicCallback onPublish, uint8_t qos );
+ *
+ *  void UNSUBSCRIBE ( const char* topicName );
+ *
+ *  void UNSUBSCRIBE ( uint16_t topicId );
+ *
+ *   void DISCONNECT ( uint16_t sleepInSecs );
+ *
+ *   void CONNECT ( void );
+ *
+ *   void DISPLAY( format, .....);    <== instead of printf()
+ *
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation
+ ***************************************************************************/
+
+#include "LMqttsnClientApp.h"
+#include "LMqttsnClient.h"
+#include "LScreen.h"
+
+using namespace std;
+using namespace linuxAsyncClient;
+extern LMqttsnClient* theClient;
+extern LScreen* theScreen;
+
+/*------------------------------------------------------
+ *    UDP Configuration    (theNetcon)
+ *------------------------------------------------------*/
+UDPCONF  = {
+    "QoS-1_Client01", // ClientId
+    {225,1,1,1},         // Multicast group IP
+    1883,                // Multicast group Port
+    20001,               // Local PortNo
+};
+
+/*------------------------------------------------------
+ *    Client Configuration  (theMqcon)
+ *------------------------------------------------------*/
+MQTTSNCONF = {
+    300,            //KeepAlive [seconds]
+    true,          //Clean session
+    300,           //Sleep duration [seconds]
+    "",            //WillTopic
+    "",            //WillMessage
+    0,             //WillQos
+    false          //WillRetain
+};
+
+/*------------------------------------------------------
+ *     Define Topics
+ *------------------------------------------------------*/
+
+
+/*------------------------------------------------------
+ *       Callback routines for Subscribed Topics
+ *------------------------------------------------------*/
+
+/*------------------------------------------------------
+ *      A Link list of Callback routines and Topics
+ *------------------------------------------------------*/
+SUBSCRIBE_LIST = {// e.g. SUB(TopicType, topicName, TopicId, callback, QoSx),
+
+                  END_OF_SUBSCRIBE_LIST
+                 };
+
+/*------------------------------------------------------
+ *    Test functions
+ *------------------------------------------------------*/
+
+void publishTopic1(void)
+{
+    char payload[300];
+    sprintf(payload, "publish \"ty4tw/Topic1\" \n");
+    uint8_t qos = 3;
+    PUBLISH(1,(uint8_t*)payload, strlen(payload), qos);
+}
+
+void publishTopic2(void)
+{
+    char payload[300];
+    sprintf(payload, "publish \"ty4tw/topic2\" \n");
+    uint8_t qos = 3;
+    PUBLISH(2,(uint8_t*)payload, strlen(payload), qos);
+}
+
+void publishTopic57(void)
+{
+    char payload[300];
+    sprintf(payload, "publish \"ty4tw/topic57\" \n");
+    uint8_t qos = 3;
+    PUBLISH(5,(uint8_t*)payload, strlen(payload), qos);
+}
+
+
+void disconnect(void)
+{
+    DISCONNECT(0);
+}
+
+
+/*------------------------------------------------------
+ *    A List of Test functions is valid in case of
+ *    line 23 of LMqttsnClientApp.h is commented out.
+ *    //#define CLIENT_MODE
+ *------------------------------------------------------*/
+
+TEST_LIST = {// e.g. TEST( Label, Test),
+             TEST("Step1:Publish topic1",     publishTopic1),
+             TEST("Step2:Publish topic57",     publishTopic57),
+             TEST("Step3:Publish topic2",     publishTopic2),
+             END_OF_TEST_LIST
+            };
+
+
+/*------------------------------------------------------
+ *    List of tasks is invalid in case of line23 of
+ *    LMqttsnClientApp.h is commented out.
+ *    #define CLIENT_MODE
+ *------------------------------------------------------*/
+TASK_LIST = {// e.g. TASK( task, executing duration in second),
+            TASK(publishTopic1, 4),  // publishTopic1() is executed every 4 seconds
+            TASK(publishTopic2, 7),  // publishTopic2() is executed every 7 seconds
+             END_OF_TASK_LIST
+            };
+
+
+/*------------------------------------------------------
+ *    Initialize function
+ *------------------------------------------------------*/
+void setup(void)
+{
+    SetQoSMinus1Mode(true);
+}
+
+
+/*****************  END OF  PROGRAM ********************/
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/samples/ClientSub/mainSub.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,207 @@
+/****************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ *---------------------------------------------------------------------------
+ *
+ *   MQTT-SN GATEWAY TEST CLIENT
+ *
+ *   Supported functions.
+ *
+ *   void PUBLISH  ( const char* topicName, uint8_t* payload, uint16_t len, uint8_t qos, bool retain = false );
+ *
+ *   void PUBLISH  ( uint16_t topicId, uint8_t* payload, uint16_t len, uint8_t qos, bool retain = false );
+ *
+ *  void SUBSCRIBE ( const char* topicName, TopicCallback onPublish, uint8_t qos );
+ *
+ *  void SUBSCRIBE ( uint16_t topicId, TopicCallback onPublish, uint8_t qos );
+ *
+ *  void UNSUBSCRIBE ( const char* topicName );
+ *
+ *  void UNSUBSCRIBE ( uint16_t topicId );
+ *
+ *   void DISCONNECT ( uint16_t sleepInSecs );
+ *
+ *   void CONNECT ( void );
+ *
+ *   void DISPLAY( format, .....);    <== instead of printf()
+ *
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation
+ ***************************************************************************/
+
+#include "LMqttsnClientApp.h"
+#include "LMqttsnClient.h"
+#include "LScreen.h"
+
+using namespace std;
+using namespace linuxAsyncClient;
+extern LMqttsnClient* theClient;
+extern LScreen* theScreen;
+
+/*------------------------------------------------------
+ *    UDP Configuration    (theNetcon)
+ *------------------------------------------------------*/
+UDPCONF  = {
+	"ClientSUB", // ClientId
+	{225,1,1,1},         // Multicast group IP
+	1883,                // Multicast group Port
+	20011,               // Local PortNo
+};
+
+/*------------------------------------------------------
+ *    Client Configuration  (theMqcon)
+ *------------------------------------------------------*/
+MQTTSNCONF = {
+	 60,            //KeepAlive [seconds]
+	true,          //Clean session
+	300,           //Sleep duration [seconds]
+	"",            //WillTopic
+	"",            //WillMessage
+    0,             //WillQos
+    false          //WillRetain
+};
+
+/*------------------------------------------------------
+ *     Define Topics
+ *------------------------------------------------------*/
+const char* topic1 = "ty4tw/topic1";
+const char* topic2 = "ty4tw/topic2";
+const char* topic3 = "ty4tw/topic3";
+const char* topic4 = "a";
+const char* topic5 = "ty4tw/#";
+
+
+/*------------------------------------------------------
+ *       Callback routines for Subscribed Topics
+ *------------------------------------------------------*/
+int on_Topic01(uint8_t* pload, uint16_t ploadlen)
+{
+	DISPLAY("\n\nTopic1 recv.\n");
+	char c = pload[ploadlen-1];
+	pload[ploadlen-1]= 0;   // set null terminator
+	DISPLAY("Payload -->%s%c<--\n\n",pload, c);
+	return 0;
+}
+
+int on_Topic02(uint8_t* pload, uint16_t ploadlen)
+{
+	DISPLAY("\n\nTopic2 recv.\n");
+	pload[ploadlen-1]= 0;   // set null terminator
+	DISPLAY("Payload -->%s <--\n\n",pload);
+	return 0;
+}
+
+int on_Topic03(uint8_t* pload, uint16_t ploadlen)
+{
+	DISPLAY("\n\nNew callback recv TopicA\n");
+	pload[ploadlen-1]= 0;   // set null terminator
+	DISPLAY("Payload -->%s <--\n\n",pload);
+	return 0;
+}
+
+int on_Topic05(uint8_t* pload, uint16_t ploadlen)
+{
+    DISPLAY("\n\nNew callback recv TopicA\n");
+    pload[ploadlen-1]= 0;   // set null terminator
+    DISPLAY("Payload -->%s <--\n\n",pload);
+    return 0;
+}
+
+/*------------------------------------------------------
+ *      A Link list of Callback routines and Topics
+ *------------------------------------------------------*/
+
+SUBSCRIBE_LIST = {// e.g. SUB(TopicType, topicName, TopicId, callback, QoSx),
+
+                  // SUB(MQTTSN_TOPIC_TYPE_NORMAL, topic5, 0, on_Topic05, QoS1),
+                  //SUB(MQTTSN_TOPIC_TYPE_NORMAL, topic2, 0, on_Topic02, QoS1),
+                  END_OF_SUBSCRIBE_LIST
+                 };
+
+
+
+/*------------------------------------------------------
+ *    Test functions
+ *------------------------------------------------------*/
+
+
+void subscribeTopic1(void)
+{
+    uint8_t qos = 1;
+    SUBSCRIBE(topic1, on_Topic01, qos);
+}
+
+void subscribeTopic2(void)
+{
+	uint8_t qos = 1;
+	SUBSCRIBE(topic2, on_Topic02, qos);
+}
+
+void subscribeTopic5(void)
+{
+    uint8_t qos = 1;
+    SUBSCRIBE(topic5, on_Topic05, qos);
+}
+
+void disconnect(void)
+{
+	DISCONNECT(0);
+}
+
+void connect(void)
+{
+	CONNECT();
+}
+
+void asleep(void)
+{
+	DISCONNECT(theMqcon.sleepDuration);
+}
+
+/*------------------------------------------------------
+ *    A List of Test functions is valid in case of
+ *    line 23 of LMqttsnClientApp.h is commented out.
+ *    //#define CLIENT_MODE
+ *------------------------------------------------------*/
+
+TEST_LIST = {// e.g. TEST( Label, Test),
+			 TEST("Step1:Subscribe topic5",     subscribeTopic5),
+			 //TEST("Step2:Subscribe topic2",     subscribeTopic2),
+			 TEST("Step2:Disconnect",     asleep),
+			 TEST("Step3:Cconnect",     connect),
+			 TEST("Step4:Disconnect",     asleep),
+			 END_OF_TEST_LIST
+			};
+
+
+/*------------------------------------------------------
+ *    List of tasks is valid in case of line23 of
+ *    LMqttsnClientApp.h is uncommented.
+ *    #define CLIENT_MODE
+ *------------------------------------------------------*/
+TASK_LIST = {// e.g. TASK( task, executing duration in second),
+             END_OF_TASK_LIST
+            };
+
+
+/*------------------------------------------------------
+ *    Initialize function
+ *------------------------------------------------------*/
+void setup(void)
+{
+    SetForwarderMode(false);
+}
+
+
+/*****************  END OF  PROGRAM ********************/
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/samples/mainTest.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/samples/mainTest.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,227 @@
+/****************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ *---------------------------------------------------------------------------
+ *
+ *   MQTT-SN GATEWAY TEST CLIENT
+ *
+ *   Supported functions.
+ *
+ *   void PUBLISH  ( const char* topicName, uint8_t* payload, uint16_t len, uint8_t qos, bool retain = false );
+ *
+ *   void PUBLISH  ( uint16_t topicId, uint8_t* payload, uint16_t len, uint8_t qos, bool retain = false );
+ *
+ *  void SUBSCRIBE ( const char* topicName, TopicCallback onPublish, uint8_t qos );
+ *
+ *  void SUBSCRIBE ( uint16_t topicId, TopicCallback onPublish, uint8_t qos );
+ *
+ *  void UNSUBSCRIBE ( const char* topicName );
+ *
+ *  void UNSUBSCRIBE ( uint16_t topicId );
+ *
+ *   void DISCONNECT ( uint16_t sleepInSecs );
+ *
+ *   void CONNECT ( void );
+ *
+ *   void DISPLAY( format, .....);    <== instead of printf()
+ *
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation
+ ***************************************************************************/
+
+#include "LMqttsnClientApp.h"
+#include "LMqttsnClient.h"
+#include "LScreen.h"
+
+using namespace std;
+using namespace linuxAsyncClient;
+extern LMqttsnClient* theClient;
+extern LScreen* theScreen;
+
+/*------------------------------------------------------
+ *    UDP Configuration    (theNetcon)
+ *------------------------------------------------------*/
+UDPCONF  = {
+	"GatewayTestClient", // ClientId
+	{225,1,1,1},         // Multicast group IP
+	1883,                // Multicast group Port
+	20020,               // Local PortNo
+};
+
+/*------------------------------------------------------
+ *    Client Configuration  (theMqcon)
+ *------------------------------------------------------*/
+MQTTSNCONF = {
+	60,            //KeepAlive [seconds]
+	true,          //Clean session
+	300,           //Sleep duration [seconds]
+	"",            //WillTopic
+	"",            //WillMessage
+    0,             //WillQos
+    false          //WillRetain
+};
+
+/*------------------------------------------------------
+ *     Define Topics
+ *------------------------------------------------------*/
+const char* topic1 = "ty4tw/topic1";
+const char* topic2 = "ty4tw/topic2";
+const char* topic3 = "ty4tw/topic3";
+const char* topic4 = "ty4tw/topic4";
+const char* topic51 = "ty4tw/topic5/1";
+const char* topic52 = "ty4tw/topic5/2";
+const char* topic53 = "ty4tw/topic5/3";
+const char* topic50 = "ty4tw/topic5/+";
+
+
+/*------------------------------------------------------
+ *       Callback routines for Subscribed Topics
+ *------------------------------------------------------*/
+int on_Topic01(uint8_t* pload, uint16_t ploadlen)
+{
+	DISPLAY("\n\nTopic1 recv.\n");
+	char c = pload[ploadlen-1];
+	pload[ploadlen-1]= 0;   // set null terminator
+	DISPLAY("Payload -->%s%c<--\n\n",pload, c);
+	return 0;
+}
+
+int on_Topic02(uint8_t* pload, uint16_t ploadlen)
+{
+	DISPLAY("\n\nTopic2 recv.\n");
+	pload[ploadlen-1]= 0;   // set null terminator
+	DISPLAY("Payload -->%s <--\n\n",pload);
+	return 0;
+}
+
+int on_Topic03(uint8_t* pload, uint16_t ploadlen)
+{
+	DISPLAY("\n\nNew callback recv Topic3\n");
+	pload[ploadlen-1]= 0;   // set null terminator
+	DISPLAY("Payload -->%s <--\n\n",pload);
+	return 0;
+}
+
+/*------------------------------------------------------
+ *      A Link list of Callback routines and Topics
+ *------------------------------------------------------*/
+
+SUBSCRIBE_LIST = {// e.g. SUB(TopicType, topicName, TopicId, callback, QoSx),
+				  SUB(MQTTSN_TOPIC_TYPE_NORMAL, topic1, 0, on_Topic01, QoS1),
+				  SUB(MQTTSN_TOPIC_TYPE_NORMAL, topic2, 0, on_Topic02, QoS1),
+				  END_OF_SUBSCRIBE_LIST
+				 };
+
+
+/*------------------------------------------------------
+ *    Test functions
+ *------------------------------------------------------*/
+void subscribePredefTopic1(void)
+{
+    SUBSCRIBE(1, on_Topic03, QoS1);
+}
+
+void publishTopic1(void)
+{
+	char payload[300];
+	sprintf(payload, "publish \"ty4tw/Topic1\" \n");
+	PUBLISH(topic1,(uint8_t*)payload, strlen(payload), QoS0);
+}
+
+void subscribeTopic2(void)
+{
+	SUBSCRIBE(10, on_Topic02, QoS1);
+}
+
+void publishTopic2(void)
+{
+	char payload[300];
+	sprintf(payload, "publish \"ty4tw/topic2\" \n");
+	PUBLISH(topic2,(uint8_t*)payload, strlen(payload), QoS1);
+}
+
+
+
+void unsubscribe(void)
+{
+	UNSUBSCRIBE(topic2);
+}
+
+void subscribechangeCallback(void)
+{
+	SUBSCRIBE(topic2, on_Topic02, QoS1);
+}
+
+void test3(void)
+{
+	char payload[300];
+	sprintf(payload, "TEST3 ");
+	uint8_t qos = 0;
+	PUBLISH(topic2,(uint8_t*)payload, strlen(payload), qos);
+}
+
+void disconnect(void)
+{
+	DISCONNECT(0);
+}
+
+void asleep(void)
+{
+	DISCONNECT(theMqcon.sleepDuration);
+}
+
+/*------------------------------------------------------
+ *    A List of Test functions is valid in case of
+ *    line 23 of LMqttsnClientApp.h is commented out.
+ *    //#define CLIENT_MODE
+ *------------------------------------------------------*/
+
+TEST_LIST = {// e.g. TEST( Label, Test),
+            TEST("Step0:Subscribe predef topic1",     subscribePredefTopic1),
+			 TEST("Step1:Publish topic1",     publishTopic1),
+			 TEST("Step2:Publish topic2",     publishTopic2),
+			 TEST("Step3:Subscribe topic2",   subscribeTopic2),
+			 TEST("Step4:Publish topic2",     publishTopic2),
+			 TEST("Step5:Unsubscribe topic2", unsubscribe),
+			 TEST("Step6:Publish topic2",     publishTopic2),
+			 TEST("Step7:subscribe again",    subscribechangeCallback),
+			 TEST("Step8:Publish topic2",     publishTopic2),
+			 TEST("Step9:Sleep     ",         asleep),
+			 TEST("Step10:Publish topic1",    publishTopic1),
+			 TEST("Step11:Disconnect",        disconnect),
+			 END_OF_TEST_LIST
+			};
+
+
+/*------------------------------------------------------
+ *    List of tasks is valid in case of line23 of
+ *    LMqttsnClientApp.h is uncommented.
+ *    #define CLIENT_MODE
+ *------------------------------------------------------*/
+TASK_LIST = {// e.g. TASK( task, executing duration in second),
+			TASK(publishTopic1, 4),  // publishTopic1() is executed every 4 seconds
+			TASK(publishTopic2, 7),  // publishTopic2() is executed every 7 seconds
+             END_OF_TASK_LIST
+            };
+
+
+/*------------------------------------------------------
+ *    Initialize function
+ *------------------------------------------------------*/
+void setup(void)
+{
+    SetForwarderMode(false);
+}
+
+
+/*****************  END OF  PROGRAM ********************/
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LGwProxy.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,673 @@
+/**************************************************************************************
+ * Copyright (c) 2016-2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+
+#include "LMqttsnClientApp.h"
+#include "LGwProxy.h"
+#include "LMqttsnClient.h"
+#include "LScreen.h"
+
+using namespace std;
+using namespace linuxAsyncClient;
+
+extern void setUint16(uint8_t* pos, uint16_t val);
+extern uint16_t getUint16(const uint8_t* pos);
+extern LMqttsnClient* theClient;
+extern LScreen* theScreen;
+
+/*=====================================
+ Class GwProxy
+ ======================================*/
+static const char* packet_names[] = { "ADVERTISE", "SEARCHGW", "GWINFO", "RESERVED", "CONNECT", "CONNACK",
+        "WILLTOPICREQ", "WILLTOPIC", "WILLMSGREQ", "WILLMSG", "REGISTER", "REGACK", "PUBLISH", "PUBACK", "PUBCOMP",
+        "PUBREC", "PUBREL", "RESERVED", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", "PINGREQ", "PINGRESP",
+        "DISCONNECT", "RESERVED", "WILLTOPICUPD", "WILLTOPICRESP", "WILLMSGUPD", "WILLMSGRESP" };
+
+LGwProxy::LGwProxy()
+{
+    _nextMsgId = 0;
+    _status = GW_LOST;
+    _gwId = 0;
+    _willTopic = 0;
+    _willMsg = 0;
+    _qosWill = 0;
+    _retainWill = 0;
+    _tkeepAlive = MQTTSN_DEFAULT_KEEPALIVE;
+    _tAdv = MQTTSN_DEFAULT_DURATION;
+    _cleanSession = 0;
+    _pingStatus = 0;
+    _connectRetry = MQTTSN_RETRY_COUNT;
+    _tSleep = 0;
+    _tWake = 0;
+    _initialized = 0;
+    _isForwarderMode = false;
+    _isQoSMinus1Mode = false;
+}
+
+LGwProxy::~LGwProxy()
+{
+    _topicTbl.clearTopic();
+}
+
+void LGwProxy::initialize(LUdpConfig netconf, LMqttsnConfig mqconf)
+{
+    _network.initialize(netconf);
+    _clientId = netconf.clientId;
+    _willTopic = mqconf.willTopic;
+    _willMsg = mqconf.willMsg;
+    _qosWill = mqconf.willQos;
+    _retainWill = mqconf.willRetain;
+    _cleanSession = mqconf.cleanSession;
+    _tkeepAlive = mqconf.keepAlive;
+    _initialized = 1;
+}
+
+void LGwProxy::connect()
+{
+    char* pos;
+
+    while (_status != GW_CONNECTED)
+    {
+        pos = _msg;
+
+        if (_status == GW_LOST)
+        {
+
+            *pos++ = 3;
+            *pos++ = MQTTSN_TYPE_SEARCHGW;
+            *pos = 0;                        // SERCHGW
+            _status = GW_SEARCHING;
+            writeGwMsg();
+        }
+        else if (_status == GW_SEND_WILLMSG)
+        {
+            *pos++ = 2 + (uint8_t) strlen(_willMsg);
+            *pos++ = MQTTSN_TYPE_WILLMSG;
+            strcpy(pos, _willMsg);          // WILLMSG
+            _status = GW_WAIT_CONNACK;
+            writeGwMsg();
+        }
+        else if (_status == GW_SEND_WILLTOPIC)
+        {
+            *pos++ = 3 + (uint8_t) strlen(_willTopic);
+            *pos++ = MQTTSN_TYPE_WILLTOPIC;
+            *pos++ = _qosWill | _retainWill;
+            strcpy(pos, _willTopic);        // WILLTOPIC
+            _status = GW_WAIT_WILLMSGREQ;
+            writeGwMsg();
+        }
+        else if (_status == GW_CONNECTING || _status == GW_DISCONNECTED || _status == GW_SLEPT)
+        {
+            uint8_t clientIdLen = uint8_t(strlen(_clientId) > 23 ? 23 : strlen(_clientId));
+            if (_isQoSMinus1Mode)
+            {
+                _status = GW_CONNECTED;
+            }
+            else
+            {
+                *pos++ = 6 + clientIdLen;
+                *pos++ = MQTTSN_TYPE_CONNECT;
+                pos++;
+                if (_cleanSession)
+                {
+                    _msg[2] = MQTTSN_FLAG_CLEAN;
+                }
+                *pos++ = MQTTSN_PROTOCOL_ID;
+                setUint16((uint8_t*) pos, _tkeepAlive);
+                pos += 2;
+                strncpy(pos, _clientId, clientIdLen);
+                _msg[6 + clientIdLen] = 0;
+                _status = GW_WAIT_CONNACK;
+                if (_willMsg && _willTopic && _status != GW_SLEPT)
+                {
+                    if (strlen(_willMsg) && strlen(_willTopic))
+                    {
+                        _msg[2] = _msg[2] | MQTTSN_FLAG_WILL;   // CONNECT
+                        _status = GW_WAIT_WILLTOPICREQ;
+                    }
+                }
+                writeGwMsg();
+                _connectRetry = MQTTSN_RETRY_COUNT;
+            }
+        }
+        getConnectResponce();
+    }
+    return;
+}
+
+int LGwProxy::getConnectResponce(void)
+{
+    int len = readMsg();
+
+    if (len == 0)
+    {
+        if (_sendUTC + MQTTSN_TIME_RETRY < time(NULL))
+        {
+            if (_msg[1] == MQTTSN_TYPE_CONNECT)
+            {
+                _connectRetry--;
+            }
+            if (--_retryCount > 0)
+            {
+                writeMsg((const uint8_t*) _msg);  // Not writeGwMsg() : not to reset the counter.
+                _sendUTC = time(NULL);
+            }
+            else
+            {
+                _sendUTC = 0;
+                if (_status > GW_SEARCHING && _connectRetry > 0)
+                {
+                    _status = GW_CONNECTING;
+                }
+                else
+                {
+                    _status = GW_LOST;
+                    _gwId = 0;
+                }
+                return -1;
+            }
+        }
+        return 0;
+    }
+    else if (_mqttsnMsg[0] == MQTTSN_TYPE_GWINFO && _status == GW_SEARCHING)
+    {
+        _network.setGwAddress();
+        _gwId = _mqttsnMsg[1];
+        _status = GW_CONNECTING;
+    }
+    else if (_mqttsnMsg[0] == MQTTSN_TYPE_WILLTOPICREQ && _status == GW_WAIT_WILLTOPICREQ)
+    {
+        _status = GW_SEND_WILLTOPIC;
+    }
+    else if (_mqttsnMsg[0] == MQTTSN_TYPE_WILLMSGREQ && _status == GW_WAIT_WILLMSGREQ)
+    {
+        _status = GW_SEND_WILLMSG;
+    }
+    else if (_mqttsnMsg[0] == MQTTSN_TYPE_CONNACK && _status == GW_WAIT_CONNACK)
+    {
+        if (_mqttsnMsg[1] == MQTTSN_RC_ACCEPTED)
+        {
+            _status = GW_CONNECTED;
+            _connectRetry = MQTTSN_RETRY_COUNT;
+            setPingReqTimer();
+            if (_tSleep)
+            {
+                _tSleep = 0;
+            }
+            else
+            {
+                DISPLAY("\033[0m\033[0;32m\n\n Connected to the Broker\033[0m\033[0;37m\n\n");
+
+                if (_cleanSession || _initialized == 1)
+                {
+                    _topicTbl.clearTopic();
+                    _initialized = 0;
+                    theClient->onConnect();  // SUBSCRIBEs are conducted
+                }
+            }
+        }
+        else
+        {
+            _status = GW_CONNECTING;
+        }
+    }
+    return 1;
+}
+
+void LGwProxy::reconnect(void)
+{
+    D_MQTTLOG("...Gateway reconnect\r\n");
+    _status = GW_DISCONNECTED;
+    connect();
+}
+
+void LGwProxy::disconnect(uint16_t secs)
+{
+    _tSleep = secs;
+    _tWake = 0;
+
+    _msg[1] = MQTTSN_TYPE_DISCONNECT;
+
+    if (secs)
+    {
+        _msg[0] = 4;
+        setUint16((uint8_t*) _msg + 2, secs);
+        _status = GW_SLEEPING;
+    }
+    else
+    {
+        _msg[0] = 2;
+        _keepAliveTimer.stop();
+        _status = GW_DISCONNECTING;
+    }
+
+    _retryCount = MQTTSN_RETRY_COUNT;
+    writeMsg((const uint8_t*) _msg);
+    _sendUTC = time(NULL);
+
+    while (_status != GW_DISCONNECTED && _status != GW_SLEPT)
+    {
+        if (getDisconnectResponce() < 0)
+        {
+            _status = GW_LOST;
+            DISPLAY("\033[0m\033[0;31m\n\n!!!!!! DISCONNECT  Error !!!!!\033[0m\033[0;37m \n\n");
+            return;
+        }
+    }
+}
+
+int LGwProxy::getDisconnectResponce(void)
+{
+    int len = readMsg();
+
+    if (len == 0)
+    {
+        if (_sendUTC + MQTTSN_TIME_RETRY < time(NULL))
+        {
+            if (--_retryCount >= 0)
+            {
+                writeMsg((const uint8_t*) _msg);
+                _sendUTC = time(NULL);
+            }
+            else
+            {
+                _status = GW_LOST;
+                _gwId = 0;
+                return -1;
+            }
+        }
+        return 0;
+    }
+    else if (_mqttsnMsg[0] == MQTTSN_TYPE_DISCONNECT)
+    {
+        if (_status == GW_SLEEPING)
+        {
+            _status = GW_SLEPT;
+            uint32_t remain = _keepAliveTimer.getRemain();
+            theClient->setSleepMode(remain);
+
+            /* Wake up and starts from this point. */
+
+        }
+        else
+        {
+            _status = GW_DISCONNECTED;
+        }
+    }
+    return 0;
+}
+
+int LGwProxy::getMessage(void)
+{
+    int len = readMsg();
+    if (len < 0)
+    {
+        return len;   //error
+    }
+#ifdef DEBUG_MQTTSN
+    if (len)
+    {
+        D_MQTTLOG(" recved msgType %x\n", _mqttsnMsg[0]);
+    }
+#endif
+
+    if (len == 0)
+    {
+        // Check PINGREQ required
+        checkPingReq();
+
+        // Check ADVERTISE valid
+        checkAdvertise();
+
+        // Check Timeout of REGISTERs
+        _regMgr.checkTimeout();
+
+        // Check Timeout of PUBLISHes,
+        theClient->getPublishManager()->checkTimeout();
+
+        // Check Timeout of SUBSCRIBEs,
+        theClient->getSubscribeManager()->checkTimeout();
+
+    }
+    else if (_mqttsnMsg[0] == MQTTSN_TYPE_PUBLISH)
+    {
+        theClient->getPublishManager()->published(_mqttsnMsg, len);
+
+    }
+    else if (_mqttsnMsg[0] == MQTTSN_TYPE_PUBACK || _mqttsnMsg[0] == MQTTSN_TYPE_PUBCOMP
+            || _mqttsnMsg[0] == MQTTSN_TYPE_PUBREC || _mqttsnMsg[0] == MQTTSN_TYPE_PUBREL)
+    {
+        theClient->getPublishManager()->responce(_mqttsnMsg, (uint16_t) len);
+
+    }
+    else if (_mqttsnMsg[0] == MQTTSN_TYPE_SUBACK || _mqttsnMsg[0] == MQTTSN_TYPE_UNSUBACK)
+    {
+        theClient->getSubscribeManager()->responce(_mqttsnMsg);
+
+    }
+    else if (_mqttsnMsg[0] == MQTTSN_TYPE_REGISTER)
+    {
+        _regMgr.responceRegister(_mqttsnMsg, len);
+
+    }
+    else if (_mqttsnMsg[0] == MQTTSN_TYPE_REGACK)
+    {
+        _regMgr.responceRegAck(getUint16(_mqttsnMsg + 3), getUint16(_mqttsnMsg + 1));
+
+    }
+    else if (_mqttsnMsg[0] == MQTTSN_TYPE_PINGRESP)
+    {
+        if (_pingStatus == GW_WAIT_PINGRESP)
+        {
+            _pingStatus = 0;
+            setPingReqTimer();
+
+            if (_tSleep > 0)
+            {
+                _tWake += _tkeepAlive;
+                if (_tWake < _tSleep)
+                {
+                    theClient->setSleepMode(_tkeepAlive * 1000UL);
+                }
+                else
+                {
+                    DISPLAY("\033[0m\033[0;32m\n\n Get back to ACTIVE.\033[0m\033[0;37m\n\n");
+                    _tWake = 0;
+                    connect();
+                }
+            }
+        }
+    }
+    else if (_mqttsnMsg[0] == MQTTSN_TYPE_DISCONNECT)
+    {
+        _status = GW_LOST;
+        _gwAliveTimer.stop();
+        _keepAliveTimer.stop();
+    }
+    else if (_mqttsnMsg[0] == MQTTSN_TYPE_ADVERTISE)
+    {
+        if (getUint16((const uint8_t*) (_mqttsnMsg + 2)) < 61)
+        {
+            _tAdv = getUint16((const uint8_t*) (_mqttsnMsg + 2)) * 1500;
+        }
+        else
+        {
+            _tAdv = getUint16((const uint8_t*) (_mqttsnMsg + 2)) * 1100;
+        }
+        _gwAliveTimer.start(_tAdv);
+    }
+    return 0;
+}
+
+uint16_t LGwProxy::registerTopic(char* topicName, uint16_t topicId)
+{
+    uint16_t id = topicId;
+    if (id == 0)
+    {
+        id = _topicTbl.getTopicId(topicName);
+        _regMgr.registerTopic(topicName);
+    }
+    return id;
+}
+
+int LGwProxy::writeMsg(const uint8_t* msg)
+{
+    uint16_t len;
+    uint8_t pos;
+    uint8_t rc = 0;
+
+    if (msg[0] == 0x01)
+    {
+        len = getUint16(msg + 1);
+        pos = 2;
+    }
+    else
+    {
+        len = msg[0];
+        pos = 1;
+    }
+
+    if (msg[0] == 3 && msg[1] == MQTTSN_TYPE_SEARCHGW)
+    {
+        rc = _network.broadcast(msg, len);
+    }
+    else
+    {
+        if (_isForwarderMode)
+        {
+            // create a forwarder encapsulation message  WirelessNodeId is a 4bytes fake data
+            uint8_t* buf = (uint8_t*) malloc(len + 7);
+            buf[0] = 7;
+            buf[1] = MQTTSN_TYPE_ENCAPSULATED;
+            buf[2] = 1;
+            buf[3] = 'w';
+            buf[4] = 'n';
+            buf[5] = 'I';
+            buf[6] = 'd';
+            memcpy(buf + 7, msg, len);
+            if (buf)
+                rc = _network.unicast(buf, len + 7);
+            free(buf);
+            DISPLAY("  Encapsulated\n ");
+        }
+        else
+        {
+            rc = _network.unicast(msg, len);
+        }
+
+        if (rc > 0)
+        {
+            if (msg[pos] >= MQTTSN_TYPE_ADVERTISE && msg[pos] <= MQTTSN_TYPE_WILLMSGRESP)
+            {
+                DISPLAY("  send %s\n", packet_names[msg[pos]]);
+            }
+        }
+    }
+    return rc;
+}
+
+void LGwProxy::writeGwMsg(void)
+{
+    _retryCount = MQTTSN_RETRY_COUNT;
+    writeMsg((const uint8_t*) _msg);
+    _sendUTC = time(NULL);
+}
+
+int LGwProxy::readMsg(void)
+{
+    int len = 0;
+    uint8_t* msg = _network.getMessage(&len);
+    _mqttsnMsg = msg;
+
+    if (len == 0)
+    {
+        return 0;
+    }
+
+    if (_mqttsnMsg[0] == 0x01)
+    {
+        int msgLen = (int) getUint16((const uint8_t*) _mqttsnMsg + 1);
+        if (len != msgLen)
+        {
+            _mqttsnMsg += 3;
+            len = msgLen - 3;
+        }
+    }
+    else
+    {
+        _mqttsnMsg += 1;
+        len -= 1;
+    }
+
+    if (*_mqttsnMsg == MQTTSN_TYPE_ENCAPSULATED)
+    {
+        int lenEncap = len + 1;
+
+        if (msg[lenEncap] == 0x01)
+        {
+            int msgLen = (int) getUint16((const uint8_t*) (msg + lenEncap + 1));
+            msg += (lenEncap + 3);
+            len = msgLen - 3;
+        }
+        else
+        {
+            msg += (lenEncap + 1);
+            len = *(msg - 1);
+        }
+        _mqttsnMsg = msg;
+        DISPLAY("  recv encapslated message\n");
+    }
+
+    if (*_mqttsnMsg >= MQTTSN_TYPE_ADVERTISE && *_mqttsnMsg <= MQTTSN_TYPE_WILLMSGRESP)
+    {
+        DISPLAY("  recv %s\n", packet_names[*_mqttsnMsg]);
+    }
+    return len;
+}
+
+void LGwProxy::setWillTopic(const char* willTopic, uint8_t qos, bool retain)
+{
+    _willTopic = willTopic;
+    _retainWill = _qosWill = 0;
+    if (qos == 1)
+    {
+        _qosWill = MQTTSN_FLAG_QOS_1;
+    }
+    else if (qos == 2)
+    {
+        _qosWill = MQTTSN_FLAG_QOS_2;
+    }
+    if (retain)
+    {
+        _retainWill = MQTTSN_FLAG_RETAIN;
+    }
+}
+void LGwProxy::setWillMsg(const char* willMsg)
+{
+    _willMsg = willMsg;
+}
+
+void LGwProxy::setCleanSession(bool flg)
+{
+    if (flg)
+    {
+        _cleanSession = MQTTSN_FLAG_CLEAN;
+    }
+    else
+    {
+        _cleanSession = 0;
+    }
+}
+
+uint16_t LGwProxy::getNextMsgId(void)
+{
+    _nextMsgId++;
+    if (_nextMsgId == 0)
+    {
+        _nextMsgId = 1;
+    }
+    return _nextMsgId;
+}
+
+void LGwProxy::checkPingReq(void)
+{
+    if ( _isQoSMinus1Mode )
+    {
+        return;
+    }
+
+    uint8_t msg[2];
+    msg[0] = 0x02;
+    msg[1] = MQTTSN_TYPE_PINGREQ;
+
+    if ((_status == GW_CONNECTED || _status == GW_SLEPT) && isPingReqRequired() && _pingStatus != GW_WAIT_PINGRESP)
+    {
+        _pingStatus = GW_WAIT_PINGRESP;
+        _pingRetryCount = MQTTSN_RETRY_COUNT;
+
+        writeMsg((const uint8_t*) msg);
+        _pingSendUTC = time(NULL);
+    }
+    else if (_pingStatus == GW_WAIT_PINGRESP)
+    {
+        if (_pingSendUTC + MQTTSN_TIME_RETRY < time(NULL))
+        {
+            if (--_pingRetryCount > 0)
+            {
+                writeMsg((const uint8_t*) msg);
+                _pingSendUTC = time(NULL);
+            }
+            else
+            {
+                _status = GW_LOST;
+                _gwId = 0;
+                _pingStatus = 0;
+                _keepAliveTimer.stop();
+                D_MQTTLOG("   !!! PINGREQ Timeout\n");
+            }
+        }
+    }
+}
+
+void LGwProxy::checkAdvertise(void)
+{
+    if (_gwAliveTimer.isTimeUp())
+    {
+        _status = GW_LOST;
+        _gwId = 0;
+        _pingStatus = 0;
+        _gwAliveTimer.stop();
+        _keepAliveTimer.stop();
+        D_MQTTLOG("   !!! ADVERTISE Timeout\n");
+    }
+}
+
+LTopicTable* LGwProxy::getTopicTable(void)
+{
+    return &_topicTbl;
+}
+
+LRegisterManager* LGwProxy::getRegisterManager(void)
+{
+    return &_regMgr;
+}
+
+bool LGwProxy::isPingReqRequired(void)
+{
+    return _keepAliveTimer.isTimeUp(_tkeepAlive * 1000UL);
+}
+
+void LGwProxy::setPingReqTimer(void)
+{
+    _keepAliveTimer.start(_tkeepAlive * 1000UL);
+}
+
+const char* LGwProxy::getClientId(void)
+{
+    return _clientId;
+}
+
+void LGwProxy::setForwarderMode(bool valid)
+{
+    _isForwarderMode = valid;
+}
+
+void LGwProxy::setQoSMinus1Mode(bool valid)
+{
+    _isQoSMinus1Mode = valid;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LGwProxy.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LGwProxy.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,118 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef GWPROXY_H_
+#define GWPROXY_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "LMqttsnClientApp.h"
+#include "LNetworkUdp.h"
+#include "LRegisterManager.h"
+#include "LTimer.h"
+#include "LTopicTable.h"
+
+using namespace std;
+
+#define GW_LOST              0
+#define GW_SEARCHING         1
+#define GW_CONNECTING        2
+#define GW_WAIT_WILLTOPICREQ 3
+#define GW_SEND_WILLTOPIC    4
+#define GW_WAIT_WILLMSGREQ   5
+#define GW_SEND_WILLMSG      6
+#define GW_WAIT_CONNACK      7
+#define GW_CONNECTED         8
+#define GW_DISCONNECTING     9
+#define GW_SLEEPING         10
+#define GW_DISCONNECTED     11
+#define GW_SLEPT            12
+
+#define GW_WAIT_PINGRESP     1
+
+namespace linuxAsyncClient {
+/*========================================
+       Class LGwProxy
+ =======================================*/
+class LGwProxy{
+public:
+    LGwProxy();
+    ~LGwProxy();
+
+    void     initialize(LUdpConfig netconf, LMqttsnConfig mqconf);
+    void     connect(void);
+    void     disconnect(uint16_t sec = 0);
+    int      getMessage(void);
+    uint16_t registerTopic(char* topic, uint16_t toipcId);
+
+    void     setWillTopic(const char* willTopic, uint8_t qos, bool retain = false);
+    void     setWillMsg(const char* willMsg);
+    void     setCleanSession(bool);
+    void     setKeepAliveDuration(uint16_t duration);
+    void     setAdvertiseDuration(uint16_t duration);
+    void     setForwarderMode(bool valid);
+    void     setQoSMinus1Mode(bool valid);
+    void     reconnect(void);
+    int      writeMsg(const uint8_t* msg);
+    void     setPingReqTimer(void);
+    uint16_t getNextMsgId();
+    LTopicTable* getTopicTable(void);
+    LRegisterManager* getRegisterManager(void);
+    const char*    getClientId(void);
+private:
+    int      readMsg(void);
+    void     writeGwMsg(void);
+    void     checkPingReq(void);
+    void     checkAdvertise(void);
+    int      getConnectResponce(void);
+    int      getDisconnectResponce(void);
+    bool     isPingReqRequired(void);
+
+    LNetwork     _network;
+    uint8_t*    _mqttsnMsg;
+    uint16_t    _nextMsgId;
+    const char* _clientId;
+    const char* _willTopic;
+    const char* _willMsg;
+    uint8_t     _cleanSession;
+    uint8_t    _initialized;
+    uint8_t     _retainWill;
+    uint8_t     _qosWill;
+    uint8_t     _gwId;
+    uint16_t    _tkeepAlive;
+    uint32_t    _tAdv;
+    time_t      _sendUTC;
+    int         _retryCount;
+    int         _connectRetry;
+    uint8_t     _status;
+    time_t    _pingSendUTC;
+    uint8_t     _pingRetryCount;
+    uint8_t     _pingStatus;
+    LRegisterManager _regMgr;
+    LTopicTable  _topicTbl;
+    LTimer       _gwAliveTimer;
+    LTimer       _keepAliveTimer;
+    uint16_t    _tSleep;
+    uint16_t    _tWake;
+    bool _isForwarderMode;
+    bool _isQoSMinus1Mode;
+    char        _msg[MQTTSN_MAX_MSG_LENGTH + 1];
+};
+
+} /* end of namespace */
+#endif /* GWPROXY_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LMqttsnClient.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,242 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+
+#include "LGwProxy.h"
+#include "LMqttsnClientApp.h"
+#include "LMqttsnClient.h"
+#include "LScreen.h"
+
+using namespace std;
+using namespace linuxAsyncClient;
+
+extern TaskList      theTaskList[];
+extern TestList      theTestList[];
+extern OnPublishList theOnPublishList[];
+extern MQTTSNCONF;
+extern UDPCONF;
+extern void setup(void);
+
+/*=====================================
+          LMqttsnClient
+ ======================================*/
+LMqttsnClient* theClient = new LMqttsnClient();
+LScreen* theScreen = new LScreen();
+bool theOTAflag = false;
+bool theClientMode = true;
+
+
+/*-------------------------------------
+ *    main
+ *------------------------------------*/
+
+int main(int argc, char** argv)
+{
+#ifndef CLIENT_MODE
+	char c = 0;
+	printf("\n%s", PAHO_COPYRIGHT4);
+	printf("\n%s\n", PAHO_COPYRIGHT0);
+	printf("%s\n", PAHO_COPYRIGHT1);
+	printf("%s\n", PAHO_COPYRIGHT2);
+	printf(" *\n%s\n", PAHO_COPYRIGHT3);
+	printf("%s\n", TESTER_VERSION);
+	printf("%s\n", PAHO_COPYRIGHT4);
+
+	theClientMode = false;
+	PROMPT(" Do you like Tomoaki ? ( y/n ) : ");
+	while (true)
+	{
+		if (CHECKKEYIN(&c))
+		{
+			if ( toupper(c) == 'N' )
+			{
+				DISPLAY("\033[0;31m\n**** Sorry ****\033[0;37m\n\n");
+				PROMPT("");
+				return 0;
+			}
+		}
+		else if ( toupper(c) == 'Y' )
+		{
+			DISPLAY("\033[0m\033[0;32mAttempting to Connect the Broker.....\033[0m\033[0;37m\n");
+			PROMPT("");
+			break;
+		}
+	}
+#endif
+
+	setup();
+	theClient->addTask(theClientMode);
+	theClient->initialize( theNetcon, theMqcon);
+	do
+	{
+		theClient->run();
+	}
+	while (theClientMode);
+
+	delete theScreen;
+	delete theClient;
+	return 0;
+}
+
+/*=====================================
+        Class LMqttsnClient
+ ======================================*/
+LMqttsnClient::LMqttsnClient()
+{
+
+}
+
+LMqttsnClient::~LMqttsnClient()
+{
+
+}
+
+void LMqttsnClient::initialize(LUdpConfig netconf, LMqttsnConfig mqconf)
+{
+	_gwProxy.initialize(netconf, mqconf);
+	setSleepDuration(mqconf.sleepDuration);
+}
+
+void LMqttsnClient::addTask(bool clientMode)
+{
+	if ( clientMode )
+	{
+		_taskMgr.add(theTaskList);
+	}
+	else
+	{
+		_taskMgr.add(theTestList);
+	}
+}
+
+
+LGwProxy* LMqttsnClient::getGwProxy(void)
+{
+	return &_gwProxy;
+}
+
+LPublishManager* LMqttsnClient::getPublishManager(void)
+{
+	return &_pubMgr;
+}
+;
+
+LSubscribeManager* LMqttsnClient::getSubscribeManager(void)
+{
+	return &_subMgr;
+}
+;
+
+LRegisterManager* LMqttsnClient::getRegisterManager(void)
+{
+	return _gwProxy.getRegisterManager();
+}
+
+LTaskManager* LMqttsnClient::getTaskManager(void)
+{
+	return &_taskMgr;
+}
+;
+
+LTopicTable* LMqttsnClient::getTopicTable(void)
+{
+	return _gwProxy.getTopicTable();
+}
+
+void LMqttsnClient::publish(const char* topicName, Payload* payload, uint8_t qos, bool retain)
+{
+	_pubMgr.publish(topicName, payload, qos, retain);
+}
+
+void LMqttsnClient::publish(const char* topicName, uint8_t* payload, uint16_t len, uint8_t qos, bool retain)
+{
+	_pubMgr.publish(topicName, payload, len, qos, retain);
+}
+
+void LMqttsnClient::publish(uint16_t topicId, Payload* payload, uint8_t qos, bool retain)
+{
+	_pubMgr.publish(topicId, payload, qos, retain);
+}
+
+void LMqttsnClient::publish(uint16_t topicId, uint8_t* payload, uint16_t len, uint8_t qos, bool retain)
+{
+	_pubMgr.publish(topicId, payload, len, qos, retain);
+}
+
+void LMqttsnClient::subscribe(const char* topicName, TopicCallback onPublish, uint8_t qos)
+{
+	_subMgr.subscribe(topicName, onPublish, qos);
+}
+
+void LMqttsnClient::subscribe(uint16_t topicId, TopicCallback onPublish, uint8_t qos)
+{
+	_subMgr.subscribe(topicId, onPublish, qos);
+}
+
+void LMqttsnClient::unsubscribe(const char* topicName)
+{
+	_subMgr.unsubscribe(topicName);
+}
+
+void LMqttsnClient::unsubscribe(const uint16_t topicId)
+{
+    _subMgr.unsubscribe(topicId);
+}
+
+void LMqttsnClient::disconnect(uint16_t sleepInSecs)
+{
+	_gwProxy.disconnect(sleepInSecs);
+}
+
+void LMqttsnClient::run()
+{
+	_gwProxy.connect();
+	_taskMgr.run();
+}
+
+void LMqttsnClient::setSleepMode(uint32_t duration)
+{
+	// ToDo:  set WDT and sleep mode
+	DISPLAY("\033[0m\033[0;32m\n\n Get into SLEEP mode %u [msec].\033[0m\033[0;37m\n\n", duration);
+}
+
+void LMqttsnClient::sleep(void)
+{
+	disconnect(_sleepDuration);
+}
+
+void LMqttsnClient::setSleepDuration(uint32_t duration)
+{
+	_sleepDuration = duration;
+}
+
+void LMqttsnClient::onConnect(void)
+{
+        _subMgr.onConnect();
+}
+
+const char* LMqttsnClient::getClientId(void)
+{
+	return _gwProxy.getClientId();
+}
+
+uint16_t LMqttsnClient::getTopicId(const char* topicName)
+{
+    return _gwProxy.getTopicTable()->getTopicId(topicName);
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LMqttsnClient.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,85 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef MQTTSNCLIENT_H_
+#define MQTTSNCLIENT_H_
+
+#include <stdio.h>
+#include <string.h>
+
+#include "LGwProxy.h"
+#include "LMqttsnClientApp.h"
+#include "LTimer.h"
+#include "Payload.h"
+#include "LPublishManager.h"
+#include "LSubscribeManager.h"
+#include "LTaskManager.h"
+
+using namespace std;
+
+namespace linuxAsyncClient {
+
+struct OnPublishList
+{
+    MQTTSN_topicTypes type;
+	const char* topic;
+	uint16_t id;
+	int (*pubCallback)(uint8_t* payload, uint16_t payloadlen);
+	uint8_t qos;
+};
+
+/*========================================
+       Class LMqttsnClient
+ =======================================*/
+class LMqttsnClient{
+public:
+    LMqttsnClient();
+    ~LMqttsnClient();
+    void onConnect(void);
+    void publish(const char* topicName, Payload* payload, uint8_t qos, bool retain = false);
+    void publish(const char* topicName, uint8_t* payload, uint16_t len, uint8_t qos, bool retain = false);
+    void publish(uint16_t topicId, Payload* payload, uint8_t qos, bool retain = false);
+    void publish(uint16_t topicId, uint8_t* payload, uint16_t len, uint8_t qos, bool retain = false);
+    void subscribe(const char* topicName, TopicCallback onPublish, uint8_t qos);
+    void subscribe(uint16_t topicId, TopicCallback onPublish, uint8_t qos);
+    void unsubscribe(const char* topicName);
+    void unsubscribe(const uint16_t topicId);
+    void disconnect(uint16_t sleepInSecs);
+    void initialize(LUdpConfig netconf, LMqttsnConfig mqconf);
+    void run(void);
+    void addTask(bool test);
+    void setSleepDuration(uint32_t duration);
+    void setSleepMode(uint32_t duration);
+    void sleep(void);
+	const char* getClientId(void);
+	uint16_t getTopicId(const char* topicName);
+    LGwProxy*          getGwProxy(void);
+    LPublishManager*   getPublishManager(void);
+    LSubscribeManager* getSubscribeManager(void);
+    LRegisterManager*  getRegisterManager(void);
+    LTaskManager*      getTaskManager(void);
+    LTopicTable*       getTopicTable(void);
+private:
+    LTaskManager      _taskMgr;
+    LPublishManager   _pubMgr;
+    LSubscribeManager _subMgr;
+    LGwProxy          _gwProxy;
+    uint32_t          _sleepDuration;
+};
+
+
+} /* end of namespace */
+#endif /* MQTTSNCLIENT_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LMqttsnClientApp.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,206 @@
+/**************************************************************************************
+ * Copyright (c) 2016-2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef MQTTSNCLIENTAPP_H_
+#define MQTTSNCLIENTAPP_H_
+
+/*======================================
+ *     Program mode Flag
+ ======================================*/
+//#define CLIENT_MODE
+
+/*======================================
+ *         Debug Flag
+ ======================================*/
+//#define DEBUG_NW
+//#define DEBUG_MQTTSN
+
+/****************************************
+      MQTT-SN Parameters
+*****************************************/
+#define MAX_INFLIGHT_MSG   10
+#define MQTTSN_MAX_MSG_LENGTH  1024
+#define MQTTSN_MAX_PACKET_SIZE 1024
+
+#define MQTTSN_DEFAULT_KEEPALIVE   900     // 1H
+#define MQTTSN_DEFAULT_DURATION    900     // 15min
+#define MQTTSN_TIME_SEARCHGW         3
+#define MQTTSN_TIME_RETRY           10
+#define MQTTSN_RETRY_COUNT           3
+
+/****************************************
+      Application config structures
+*****************************************/
+typedef unsigned char  uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int   uint32_t;
+typedef signed char    int8_t;
+typedef signed short   int16_t;
+typedef signed int     int32_t;
+
+/****************************************
+      Application config structures
+*****************************************/
+
+struct LMqttsnConfig{
+	uint16_t keepAlive;
+	bool     cleanSession;
+	uint32_t sleepDuration;
+	const char* willTopic;
+	const char* willMsg;
+    uint8_t  willQos;
+    bool     willRetain;
+};
+
+struct LUdpConfig{
+	const char* clientId;
+	uint8_t  ipAddress[4];
+	uint16_t gPortNo;
+	uint16_t uPortNo;
+};
+
+
+typedef enum
+{
+    MQTTSN_TOPIC_TYPE_NORMAL,
+    MQTTSN_TOPIC_TYPE_PREDEFINED,
+    MQTTSN_TOPIC_TYPE_SHORT
+} MQTTSN_topicTypes;
+
+
+/*======================================
+      MACROs for Application
+=======================================*/
+#define MQTTSN_CONFIG    MqttsnConfig  theMqttsnConfig
+#define NETWORK_CONFIG   UdpConfig theNetworkConfig
+
+#define CONNECT(...) theClient->getGwProxy()->connect(__VA_ARGS__)
+#define PUBLISH(...)     theClient->publish(__VA_ARGS__)
+#define SUBSCRIBE(...)   theClient->subscribe(__VA_ARGS__)
+#define UNSUBSCRIBE(...) theClient->unsubscribe(__VA_ARGS__)
+#define DISCONNECT(...)  theClient->disconnect(__VA_ARGS__)
+
+#define TASK_LIST         TaskList theTaskList[]
+#define TASK(...)         {__VA_ARGS__, 0, 0}
+#define END_OF_TASK_LIST  {0, 0, 0, 0}
+#define TEST_LIST		  TestList theTestList[]
+#define TEST(...)         {__VA_ARGS__, 0}
+#define END_OF_TEST_LIST  {0, 0, 0}
+#define SUBSCRIBE_LIST    OnPublishList theOnPublishList[]
+#define SUB(...)          {__VA_ARGS__}
+#define END_OF_SUBSCRIBE_LIST {MQTTSN_TOPIC_TYPE_NORMAL,0,0,0, 0}
+#define UDPCONF  LUdpConfig theNetcon
+#define MQTTSNCONF LMqttsnConfig  theMqcon
+#define SetForwarderMode(...)  theClient->getGwProxy()->setForwarderMode(__VA_ARGS__)
+#define SetQoSMinus1Mode(...) theClient->getGwProxy()->setQoSMinus1Mode(__VA_ARGS__)
+
+#ifdef CLIENT_MODE
+#define DISPLAY(...)
+#define PROMPT(...)
+#define CHECKKEYIN(...) theScreen->checkKeyIn(__VA_ARGS__)
+#else
+#define DISPLAY(...) theScreen->display(__VA_ARGS__)
+#define PROMPT(...) theScreen->prompt(__VA_ARGS__)
+#define CHECKKEYIN(...) theScreen->checkKeyIn(__VA_ARGS__)
+#endif
+/*======================================
+      MACROs for debugging
+========================================*/
+#ifndef DEBUG_NW
+	#define D_NWLOG(...)
+#else
+	#define D_NWLOG(...)    printf(__VA_ARGS__)
+#endif
+
+#ifndef DEBUG_MQTTSN
+	#define D_MQTTLOG(...)
+#else
+	#define D_MQTTLOG(...)  printf(__VA_ARGS__)
+#endif
+
+#ifndef DEBUG_OTA
+	#define D_OTALOG(...)
+#else
+	#define D_OTALOG(...)   printf(__VA_ARGS__)
+#endif
+
+/*======================================
+      MQTT-SN Defines
+========================================*/
+#define QoS0  0
+#define QoS1  1
+#define QoS2  2
+#define Q0Sm1 3
+#define MQTTSN_TYPE_ADVERTISE     0x00
+#define MQTTSN_TYPE_SEARCHGW      0x01
+#define MQTTSN_TYPE_GWINFO        0x02
+#define MQTTSN_TYPE_CONNECT       0x04
+#define MQTTSN_TYPE_CONNACK       0x05
+#define MQTTSN_TYPE_WILLTOPICREQ  0x06
+#define MQTTSN_TYPE_WILLTOPIC     0x07
+#define MQTTSN_TYPE_WILLMSGREQ    0x08
+#define MQTTSN_TYPE_WILLMSG       0x09
+#define MQTTSN_TYPE_REGISTER      0x0A
+#define MQTTSN_TYPE_REGACK        0x0B
+#define MQTTSN_TYPE_PUBLISH       0x0C
+#define MQTTSN_TYPE_PUBACK        0x0D
+#define MQTTSN_TYPE_PUBCOMP       0x0E
+#define MQTTSN_TYPE_PUBREC        0x0F
+#define MQTTSN_TYPE_PUBREL        0x10
+#define MQTTSN_TYPE_SUBSCRIBE     0x12
+#define MQTTSN_TYPE_SUBACK        0x13
+#define MQTTSN_TYPE_UNSUBSCRIBE   0x14
+#define MQTTSN_TYPE_UNSUBACK      0x15
+#define MQTTSN_TYPE_PINGREQ       0x16
+#define MQTTSN_TYPE_PINGRESP      0x17
+#define MQTTSN_TYPE_DISCONNECT    0x18
+#define MQTTSN_TYPE_WILLTOPICUPD  0x1A
+#define MQTTSN_TYPE_WILLTOPICRESP 0x1B
+#define MQTTSN_TYPE_WILLMSGUPD    0x1C
+#define MQTTSN_TYPE_WILLMSGRESP   0x1D
+#define MQTTSN_TYPE_ENCAPSULATED  0xFE
+
+#define MQTTSN_TOPIC_TYPE           0x03
+
+#define MQTTSN_FLAG_DUP     0x80
+#define MQTTSN_FLAG_QOS_0   0x0
+#define MQTTSN_FLAG_QOS_1   0x20
+#define MQTTSN_FLAG_QOS_2   0x40
+#define MQTTSN_FLAG_QOS_M1  0x60
+#define MQTTSN_FLAG_RETAIN  0x10
+#define MQTTSN_FLAG_WILL    0x08
+#define MQTTSN_FLAG_CLEAN   0x04
+
+#define MQTTSN_PROTOCOL_ID  0x01
+#define MQTTSN_HEADER_SIZE  2
+
+#define MQTTSN_RC_ACCEPTED                  0x00
+#define MQTTSN_RC_REJECTED_CONGESTION       0x01
+#define MQTTSN_RC_REJECTED_INVALID_TOPIC_ID 0x02
+#define MQTTSN_RC_REJECTED_NOT_SUPPORTED    0x03
+
+/*=================================
+ *    Starting prompt
+ ==================================*/
+#define TESTER_VERSION " * Version: 2.0.0"
+
+#define PAHO_COPYRIGHT0 " * MQTT-SN Gateway Tester"
+#define PAHO_COPYRIGHT1 " * Part of Project Paho in Eclipse"
+#define PAHO_COPYRIGHT2 " * (http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt-sn.embedded-c.git/)"
+#define PAHO_COPYRIGHT3 " * Author : Tomoaki YAMAGUCHI"
+#define PAHO_COPYRIGHT4 " ***************************************************************************"
+
+#endif /* MQTTSNCLIENTAPP_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LNetworkUdp.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,389 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <termios.h>
+
+#include "LNetworkUdp.h"
+#include "LTimer.h"
+#include "LScreen.h"
+
+#include "LMqttsnClientApp.h"
+
+using namespace std;
+using namespace linuxAsyncClient;
+
+extern uint16_t getUint16(const uint8_t* pos);
+extern uint32_t getUint32(const uint8_t* pos);
+extern LScreen* theScreen;
+extern bool theClientMode;
+/*=========================================
+       Class LNetwork
+ =========================================*/
+LNetwork::LNetwork(){
+	_sleepflg = false;
+	resetGwAddress();
+}
+
+LNetwork::~LNetwork(){
+
+}
+
+int LNetwork::broadcast(const uint8_t* xmitData, uint16_t dataLen){
+	return LUdpPort::multicast(xmitData, (uint32_t)dataLen);
+}
+
+int  LNetwork::unicast(const uint8_t* xmitData, uint16_t dataLen){
+	return LUdpPort::unicast(xmitData, dataLen, _gwIpAddress, _gwPortNo);
+}
+
+
+uint8_t*  LNetwork::getMessage(int* len){
+	*len = 0;
+	if (checkRecvBuf()){
+		uint16_t recvLen = LUdpPort::recv(_rxDataBuf, MQTTSN_MAX_PACKET_SIZE, false, &_ipAddress, &_portNo);
+		if(_gwIpAddress && isUnicast() && (_ipAddress != _gwIpAddress) && (_portNo != _gwPortNo)){
+			return 0;
+		}
+
+		if(recvLen < 0){
+			*len = recvLen;
+			return 0;
+		}else{
+			if(_rxDataBuf[0] == 0x01){
+				*len = getUint16(_rxDataBuf + 1 );
+			}else{
+				*len = _rxDataBuf[0];
+			}
+			//if(recvLen != *len){
+			//	*len = 0;
+			//	return 0;
+			//}else{
+				return _rxDataBuf;
+			//}
+		}
+	}
+	return 0;
+}
+
+void LNetwork::setGwAddress(void){
+	_gwPortNo = _portNo;
+	_gwIpAddress = _ipAddress;
+}
+
+void LNetwork::setFixedGwAddress(void){
+    _gwPortNo = LUdpPort::_gPortNo;
+    _gwIpAddress = LUdpPort::_gIpAddr;
+}
+
+void LNetwork::resetGwAddress(void){
+	_gwIpAddress = 0;
+	_gwPortNo = 0;
+}
+
+
+bool LNetwork::initialize(LUdpConfig  config){
+	return LUdpPort::open(config);
+}
+
+void LNetwork::setSleep(){
+	_sleepflg = true;
+}
+
+/*=========================================
+       Class udpStack
+ =========================================*/
+LUdpPort::LUdpPort(){
+    _disconReq = false;
+    _sockfdUcast = -1;
+    _sockfdMcast = -1;
+    _castStat = 0;
+}
+
+LUdpPort::~LUdpPort(){
+    close();
+}
+
+
+void LUdpPort::close(){
+	if(_sockfdMcast > 0){
+		::close( _sockfdMcast);
+		_sockfdMcast = -1;
+	if(_sockfdUcast > 0){
+		::close( _sockfdUcast);
+			_sockfdUcast = -1;
+		}
+	}
+}
+
+bool LUdpPort::open(LUdpConfig config){
+	const int reuse = 1;
+	char loopch = 1;
+
+	uint8_t sav = config.ipAddress[3];
+	config.ipAddress[3] = config.ipAddress[0];
+	config.ipAddress[0] = sav;
+	sav = config.ipAddress[2];
+	config.ipAddress[2] = config.ipAddress[1];
+	config.ipAddress[1] = sav;
+
+	_gPortNo = htons(config.gPortNo);
+	_gIpAddr = getUint32((const uint8_t*)config.ipAddress);
+	_uPortNo = htons(config.uPortNo);
+
+	if( _gPortNo == 0 || _gIpAddr == 0 || _uPortNo == 0){
+		return false;
+	}
+
+	_sockfdUcast = socket(AF_INET, SOCK_DGRAM, 0);
+	if (_sockfdUcast < 0){
+		return false;
+	}
+
+	setsockopt(_sockfdUcast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
+
+	struct sockaddr_in addr;
+	addr.sin_family = AF_INET;
+	addr.sin_port = _uPortNo;
+	addr.sin_addr.s_addr = INADDR_ANY;
+
+	if( ::bind ( _sockfdUcast, (struct sockaddr*)&addr,  sizeof(addr)) <0){
+		return false;
+	}
+
+	_sockfdMcast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (_sockfdMcast < 0){
+		return false;
+	}
+
+	struct sockaddr_in addrm;
+	addrm.sin_family = AF_INET;
+	addrm.sin_port = _gPortNo;
+	addrm.sin_addr.s_addr = htonl(INADDR_ANY);
+
+	setsockopt(_sockfdMcast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
+
+	if( ::bind ( _sockfdMcast, (struct sockaddr*)&addrm,  sizeof(addrm)) <0){
+		return false;
+	}
+
+	if(setsockopt(_sockfdMcast, IPPROTO_IP, IP_MULTICAST_LOOP,(char*)&loopch, sizeof(loopch)) <0 ){
+		D_NWLOG("\033[0m\033[0;31merror IP_MULTICAST_LOOP in UdpPPort::open\033[0m\033[0;37m\n");
+		DISPLAY("\033[0m\033[0;31m\nerror IP_MULTICAST_LOOP in UdpPPort::open\033[0m\033[0;37m\n");
+		close();
+		return false;
+	}
+
+	ip_mreq mreq;
+	mreq.imr_interface.s_addr = INADDR_ANY;
+	mreq.imr_multiaddr.s_addr = _gIpAddr;
+
+	if( setsockopt(_sockfdMcast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq) )< 0){
+		D_NWLOG("\033[0m\033[0;31merror IP_ADD_MEMBERSHIP in UdpPort::open\033[0m\033[0;37m\n");
+		DISPLAY("\033[0m\033[0;31m\nerror IP_ADD_MEMBERSHIP in UdpPort::open\033[0m\033[0;37m\n");
+		close();
+		return false;
+	}
+	return true;
+}
+
+bool LUdpPort::isUnicast(){
+	return ( _castStat == STAT_UNICAST);
+}
+
+
+int LUdpPort::unicast(const uint8_t* buf, uint32_t length, uint32_t ipAddress, uint16_t port  ){
+	struct sockaddr_in dest;
+	dest.sin_family = AF_INET;
+	dest.sin_port = port;
+	dest.sin_addr.s_addr = ipAddress;
+
+	int status = ::sendto( _sockfdUcast, buf, length, 0, (const sockaddr*)&dest, sizeof(dest) );
+	if( status < 0){
+		D_NWLOG("errno == %d in UdpPort::unicast\n", errno);
+		DISPLAY("errno == %d in UdpPort::unicast\n", errno);
+	}else{
+		D_NWLOG("sendto %-15s:%-6u",inet_ntoa(dest.sin_addr),htons(port));
+		for(uint16_t i = 0; i < length ; i++){
+			D_NWLOG(" %02x", *(buf + i));
+		}
+		D_NWLOG("\n");
+
+		if ( !theClientMode )
+		{
+			char sbuf[SCREEN_BUFF_SIZE];
+			int pos = 0;
+			sprintf(sbuf,"\033[0;34msendto %-15s:%-6u",inet_ntoa(dest.sin_addr),htons(port));
+			pos = strlen(sbuf);
+			for(uint16_t i = 0; i < length ; i++){
+				sprintf(sbuf + pos, " %02x", *(buf + i));
+				if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20 )  // -20 for Escape sequence
+				{
+					break;
+				}
+				pos += 3;
+			}
+			sprintf(sbuf + strlen(sbuf), "\033[0;37m\n");
+			theScreen->display(sbuf);
+		}
+	}
+	return status;
+}
+
+
+int LUdpPort::multicast( const uint8_t* buf, uint32_t length ){
+	struct sockaddr_in dest;
+	dest.sin_family = AF_INET;
+	dest.sin_port = _gPortNo;
+	dest.sin_addr.s_addr = _gIpAddr;
+
+	int status = ::sendto( _sockfdMcast, buf, length, 0, (const sockaddr*)&dest, sizeof(dest) );
+	if( status < 0){
+		D_NWLOG("\033[0m\033[0;31merrno == %d in UdpPort::multicast\033[0m\033[0;37m\n", errno);
+		DISPLAY("\033[0m\033[0;31merrno == %d in UdpPort::multicast\033[0m\033[0;37m\n", errno);
+		return errno;
+	}else{
+		D_NWLOG("sendto %-15s:%-6u",inet_ntoa(dest.sin_addr),htons(_gPortNo));
+
+		for(uint16_t i = 0; i < length ; i++){
+			D_NWLOG(" %02x", *(buf + i));
+			DISPLAY(" %02x", *(buf + i));
+		}
+		D_NWLOG("\n");
+
+		if ( !theClientMode )
+		{
+			char sbuf[SCREEN_BUFF_SIZE];
+			int pos = 0;
+			sprintf(sbuf,"\033[0;34msendto %-15s:%-6u",inet_ntoa(dest.sin_addr),htons(_gPortNo));
+			pos = strlen(sbuf);
+			for(uint16_t i = 0; i < length ; i++){
+				sprintf(sbuf + pos, " %02x", *(buf + i));
+				if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20 )
+				{
+					break;
+				}
+				pos += 3;
+			}
+			sprintf(sbuf + strlen(sbuf), "\033[0;37m\n");
+			theScreen->display(sbuf);
+		}
+		return status;
+	}
+
+}
+
+bool LUdpPort::checkRecvBuf(){
+	struct timeval timeout;
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 50000;    // 50 msec
+
+	uint8_t buf[2];
+	fd_set recvfds;
+	int maxSock = 0;
+
+	FD_ZERO(&recvfds);
+	FD_SET(_sockfdUcast, &recvfds);
+	FD_SET(_sockfdMcast, &recvfds);
+
+	if(_sockfdMcast > _sockfdUcast){
+		maxSock = _sockfdMcast;
+	}else{
+		maxSock = _sockfdUcast;
+	}
+
+	select(maxSock + 1, &recvfds, 0, 0, &timeout);
+
+	if(FD_ISSET(_sockfdUcast, &recvfds)){
+		if( ::recv(_sockfdUcast, buf, 1,  MSG_DONTWAIT | MSG_PEEK) > 0){
+			_castStat = STAT_UNICAST;
+			return true;
+		}
+	}else if(FD_ISSET(_sockfdMcast, &recvfds)){
+		if( ::recv(_sockfdMcast, buf, 1,  MSG_DONTWAIT | MSG_PEEK) > 0){
+			_castStat = STAT_MULTICAST;
+			return true;
+		}
+	}
+	_castStat = 0;
+	return false;
+}
+
+int LUdpPort::recv(uint8_t* buf, uint16_t len, bool flg, uint32_t* ipAddressPtr, uint16_t* portPtr){
+	int flags = flg ? MSG_DONTWAIT : 0;
+	return recvfrom (buf, len, flags, ipAddressPtr, portPtr );
+}
+
+int LUdpPort::recvfrom (uint8_t* buf, uint16_t length, int flags, uint32_t* ipAddressPtr, uint16_t* portPtr ){
+	struct sockaddr_in sender;
+	int status;
+	socklen_t addrlen = sizeof(sender);
+	memset(&sender, 0, addrlen);
+
+	if(isUnicast()){
+		status = ::recvfrom( _sockfdUcast, buf, length, flags, (struct sockaddr*)&sender, &addrlen );
+	}else if(_castStat == STAT_MULTICAST){
+		status = ::recvfrom( _sockfdMcast, buf, length, flags, (struct sockaddr*)&sender, &addrlen );
+	}else{
+		return 0;
+	}
+
+	if (status < 0 && errno != EAGAIN)	{
+		D_NWLOG("\033[0m\033[0;31merrno == %d in UdpPort::recvfrom \033[0m\033[0;37m\n", errno);
+		DISPLAY("\033[0m\033[0;31merrno == %d in UdpPort::recvfrom \033[0m\033[0;37m\n", errno);
+	}else if(status > 0){
+		*ipAddressPtr = sender.sin_addr.s_addr;
+		*portPtr = sender.sin_port;
+		D_NWLOG("\nrecved %-15s:%-6u",inet_ntoa(sender.sin_addr), htons(*portPtr));
+		for(uint16_t i = 0; i < status ; i++){
+			D_NWLOG(" %02x", *(buf + i));
+		}
+		D_NWLOG("\n");
+
+		if ( !theClientMode )
+		{
+			char sbuf[SCREEN_BUFF_SIZE];
+			int pos = 0;
+			sprintf(sbuf, "\033[0;34mrecved %-15s:%-6u",inet_ntoa(sender.sin_addr), htons(*portPtr));
+			pos = strlen(sbuf);
+			for(uint16_t i = 0; i < status ; i++){
+				sprintf(sbuf + pos, " %02x", *(buf + i));
+				if (strlen(sbuf) > SCREEN_BUFF_SIZE - 20 )
+				{
+					break;
+				}
+				pos += 3;
+			}
+			sprintf(sbuf + strlen(sbuf), "\033[0;37m\n");
+			theScreen->display(sbuf);
+		}
+		return status;
+	}else{
+		return 0;
+	}
+	return status;
+}
+
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LNetworkUdp.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LNetworkUdp.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,108 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef NETWORKUDP_H_
+#define NETWORKUDP_H_
+
+#include <sys/time.h>
+#include <iostream>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string>
+#include <arpa/inet.h>
+
+#include "LMqttsnClientApp.h"
+
+#define SOCKET_MAXHOSTNAME  200
+#define SOCKET_MAXCONNECTIONS  5
+#define SOCKET_MAXRECV  500
+#define SOCKET_MAXBUFFER_LENGTH 500 // buffer size
+
+#define STAT_UNICAST   1
+#define STAT_MULTICAST 2
+
+using namespace std;
+
+namespace linuxAsyncClient {
+/*========================================
+       Class LUpdPort
+ =======================================*/
+class LUdpPort{
+    friend class LNetwork;
+public:
+	LUdpPort();
+	virtual ~LUdpPort();
+
+	bool open(LUdpConfig config);
+
+	int unicast(const uint8_t* buf, uint32_t length, uint32_t ipaddress, uint16_t port  );
+	int multicast( const uint8_t* buf, uint32_t length );
+	int recv(uint8_t* buf, uint16_t len, bool nonblock, uint32_t* ipaddress, uint16_t* port );
+	int recv(uint8_t* buf, int flags);
+	bool checkRecvBuf();
+	bool isUnicast();
+
+private:
+	void close();
+	int recvfrom ( uint8_t* buf, uint16_t len, int flags, uint32_t* ipaddress, uint16_t* port );
+
+	int      _sockfdUcast;
+	int      _sockfdMcast;
+	uint16_t _gPortNo;
+	uint16_t _uPortNo;
+	uint32_t _gIpAddr;
+	uint8_t  _castStat;
+	bool   _disconReq;
+
+};
+
+#define NO_ERROR	0
+#define PACKET_EXCEEDS_LENGTH  1
+/*===========================================
+               Class  Network
+ ============================================*/
+class LNetwork : public LUdpPort {
+public:
+    LNetwork();
+    ~LNetwork();
+
+    int  broadcast(const uint8_t* payload, uint16_t payloadLen);
+    int  unicast(const uint8_t* payload, uint16_t payloadLen);
+    void setGwAddress(void);
+    void resetGwAddress(void);
+    void setFixedGwAddress(void);
+    bool initialize(LUdpConfig  config);
+    uint8_t*  getMessage(int* len);
+private:
+    void setSleep();
+    int  readApiFrame(void);
+
+    uint32_t _gwIpAddress;
+	uint16_t _gwPortNo;
+	uint32_t _ipAddress;
+	uint16_t _portNo;
+    int     _returnCode;
+    bool _sleepflg;
+    uint8_t _rxDataBuf[MQTTSN_MAX_PACKET_SIZE + 1];  // defined in MqttsnClientApp.h
+
+};
+
+
+}    /* end of namespace */
+#endif /* NETWORKUDP_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LPublishManager.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LPublishManager.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,480 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "LMqttsnClientApp.h"
+#include "LTimer.h"
+#include "LGwProxy.h"
+#include "LMqttsnClient.h"
+#include "LPublishManager.h"
+#include "LScreen.h"
+
+using namespace std;
+using namespace linuxAsyncClient;
+
+extern void setUint16(uint8_t* pos, uint16_t val);
+extern uint16_t getUint16(const uint8_t* pos);
+extern LMqttsnClient* theClient;
+extern bool theOTAflag;
+extern LScreen* theScreen;
+/*========================================
+ Class PublishManager
+ =======================================*/
+const char* NULLCHAR = "";
+
+LPublishManager::LPublishManager()
+{
+    _first = 0;
+    _last = 0;
+    _elmCnt = 0;
+    _publishedFlg = SAVE_TASK_INDEX;
+}
+
+LPublishManager::~LPublishManager()
+{
+    PubElement* elm = _first;
+    PubElement* sav = 0;
+    while (elm)
+    {
+        sav = elm->next;
+        if (elm != 0)
+        {
+            delElement(elm);
+        }
+        elm = sav;
+    }
+}
+
+void LPublishManager::publish(const char* topicName, Payload* payload, uint8_t qos, bool retain)
+{
+    publish(topicName, payload->getRowData(), payload->getLen(), qos, retain);
+}
+
+void LPublishManager::publish(const char* topicName, uint8_t* payload, uint16_t len, uint8_t qos, bool retain)
+{
+    uint16_t msgId = 0;
+    uint8_t topicType = MQTTSN_TOPIC_TYPE_SHORT;
+    if ( strlen(topicName) > 2 )
+    {
+        topicType = MQTTSN_TOPIC_TYPE_NORMAL;
+    }
+
+    if ( qos > 0  && qos < 3 )
+    {
+        msgId = theClient->getGwProxy()->getNextMsgId();
+    }
+
+    PubElement* elm = add(topicName, 0, payload, len, qos, retain, msgId, topicType);
+
+    if (elm->status == TOPICID_IS_READY)
+    {
+        sendPublish(elm);
+    }
+    else
+    {
+        theClient->getGwProxy()->registerTopic((char*) topicName, 0);
+    }
+}
+
+void LPublishManager::publish(uint16_t topicId, Payload* payload, uint8_t qos, bool retain)
+{
+    publish(topicId, payload->getRowData(), payload->getLen(), qos, retain);
+}
+
+void LPublishManager::publish(uint16_t topicId, uint8_t* payload, uint16_t len, uint8_t qos, bool retain)
+{
+    uint16_t msgId = 0;
+    if ( qos > 0 && qos < 3 )
+    {
+        msgId = theClient->getGwProxy()->getNextMsgId();
+    }
+    PubElement* elm = add(NULLCHAR, topicId, payload, len, qos, retain, msgId, MQTTSN_TOPIC_TYPE_PREDEFINED);
+    sendPublish(elm);
+}
+
+void LPublishManager::sendPublish(PubElement* elm)
+{
+    if (elm == 0)
+    {
+        return;
+    }
+
+    theClient->getGwProxy()->connect();
+
+    uint8_t msg[MQTTSN_MAX_MSG_LENGTH + 1];
+    uint8_t org = 0;
+    if (elm->payloadlen > 128)
+    {
+        msg[0] = 0x01;
+        setUint16(msg + 1, elm->payloadlen + 9);
+        org = 2;
+    }
+    else
+    {
+        msg[0] = (uint8_t) elm->payloadlen + 7;
+    }
+    msg[org + 1] = MQTTSN_TYPE_PUBLISH;
+    msg[org + 2] = elm->flag;
+    if ((elm->retryCount < MQTTSN_RETRY_COUNT))
+    {
+        msg[org + 2] = msg[org + 2] | MQTTSN_FLAG_DUP;
+    }
+    if ((elm->flag & 0x03) == MQTTSN_TOPIC_TYPE_SHORT )
+    {
+        memcpy(msg + org + 3, elm->topicName, 2);
+    }
+    else
+    {
+        setUint16(msg + org + 3, elm->topicId);
+    }
+    setUint16(msg + org + 5, elm->msgId);
+    memcpy(msg + org + 7, elm->payload, elm->payloadlen);
+
+    theClient->getGwProxy()->writeMsg(msg);
+    theClient->getGwProxy()->setPingReqTimer();
+    if ( ((elm->flag & 0x60) == MQTTSN_FLAG_QOS_0 ) || ( (elm->flag & 0x60) == MQTTSN_FLAG_QOS_M1) )
+    {
+        DISPLAY("\033[0m\033[0;32m Topic \"%s\" was Published. \033[0m\033[0;37m\n\n", elm->topicName);
+        remove(elm);  // PUBLISH Done
+        return;
+    }
+    else if ((elm->flag & 0x60) == MQTTSN_FLAG_QOS_1)
+    {
+        elm->status = WAIT_PUBACK;
+    }
+    else if ((elm->flag & 0x60) == MQTTSN_FLAG_QOS_2)
+    {
+        elm->status = WAIT_PUBREC;
+    }
+
+    elm->sendUTC = time(NULL);
+    elm->retryCount--;
+}
+
+void LPublishManager::sendSuspend(const char* topicName, uint16_t topicId, uint8_t topicType)
+{
+    PubElement* elm = _first;
+    while (elm)
+    {
+        if (strcmp(elm->topicName, topicName) == 0 && elm->status == TOPICID_IS_SUSPEND)
+        {
+            elm->topicId = topicId;
+            elm->flag |= topicType;
+            elm->status = TOPICID_IS_READY;
+            sendPublish(elm);
+            elm = 0;
+        }
+        else
+        {
+            elm = elm->next;
+        }
+    }
+}
+
+void LPublishManager::sendPubAck(uint16_t topicId, uint16_t msgId, uint8_t rc)
+{
+    uint8_t msg[7];
+    msg[0] = 7;
+    msg[1] = MQTTSN_TYPE_PUBACK;
+    setUint16(msg + 2, topicId);
+    setUint16(msg + 4, msgId);
+    msg[6] = rc;
+    theClient->getGwProxy()->writeMsg(msg);
+}
+
+void LPublishManager::sendPubRel(PubElement* elm)
+{
+    uint8_t msg[4];
+    msg[0] = 4;
+    msg[1] = MQTTSN_TYPE_PUBREL;
+    setUint16(msg + 2, elm->msgId);
+    theClient->getGwProxy()->writeMsg(msg);
+}
+
+bool LPublishManager::isDone(void)
+{
+    return (_first == 0);
+}
+
+bool LPublishManager::isMaxFlight(void)
+{
+    return (_elmCnt > MAX_INFLIGHT_MSG / 2);
+}
+
+void LPublishManager::responce(const uint8_t* msg, uint16_t msglen)
+{
+    if (msg[0] == MQTTSN_TYPE_PUBACK)
+    {
+        uint16_t msgId = getUint16(msg + 3);
+        PubElement* elm = getElement(msgId);
+        if (elm == 0)
+        {
+            return;
+        }
+        if (msg[5] == MQTTSN_RC_ACCEPTED)
+        {
+            if (elm->status == WAIT_PUBACK)
+            {
+                DISPLAY("\033[0m\033[0;32m Topic \"%s\"  Id : %d was Published. \033[0m\033[0;37m\n\n", elm->topicName, elm->topicId);
+                remove(elm); // PUBLISH Done
+            }
+        }
+        else if (msg[5] == MQTTSN_RC_REJECTED_INVALID_TOPIC_ID)
+        {
+            elm->status = TOPICID_IS_SUSPEND;
+            elm->topicId = 0;
+            elm->retryCount = MQTTSN_RETRY_COUNT;
+            elm->sendUTC = 0;
+            theClient->getGwProxy()->registerTopic((char*) elm->topicName, 0);
+        }
+    }
+    else if (msg[0] == MQTTSN_TYPE_PUBREC)
+    {
+        PubElement* elm = getElement(getUint16(msg + 1));
+        if (elm == 0)
+        {
+            return;
+        }
+        if (elm->status == WAIT_PUBREC || elm->status == WAIT_PUBCOMP)
+        {
+            sendPubRel(elm);
+            elm->status = WAIT_PUBCOMP;
+            elm->sendUTC = time(NULL);
+        }
+    }
+    else if (msg[0] == MQTTSN_TYPE_PUBCOMP)
+    {
+        PubElement* elm = getElement(getUint16(msg + 1));
+        if (elm == 0)
+        {
+            return;
+        }
+        if (elm->status == WAIT_PUBCOMP)
+        {
+            DISPLAY("\033[0m\033[0;32m Topic \"%s\"  Id : %d was Published. \033[0m\033[0;37m\n\n", elm->topicName, elm->topicId);
+            remove(elm);  // PUBLISH Done
+        }
+    }
+}
+
+void LPublishManager::published(uint8_t* msg, uint16_t msglen)
+{
+    uint16_t topicId = getUint16(msg + 2);
+
+    if (msg[1] & MQTTSN_FLAG_QOS_1)
+    {
+        sendPubAck(topicId, getUint16(msg + 4), MQTTSN_RC_ACCEPTED);
+    }
+
+    _publishedFlg = NEG_TASK_INDEX;
+    theClient->getTopicTable()->execCallback(topicId, msg + 6, msglen - 6,  (MQTTSN_topicTypes)(msg[1] & MQTTSN_TOPIC_TYPE));
+    _publishedFlg = SAVE_TASK_INDEX;
+}
+
+void LPublishManager::checkTimeout(void)
+{
+    PubElement* elm = _first;
+    while (elm)
+    {
+        if (elm->sendUTC > 0 && elm->sendUTC + MQTTSN_TIME_RETRY < time(NULL))
+        {
+            if (elm->retryCount >= 0)
+            {
+                sendPublish(elm);
+                D_MQTTLOG("...Timeout retry\r\n");
+            }
+            else
+            {
+                theClient->getGwProxy()->reconnect();
+                elm->retryCount = MQTTSN_RETRY_COUNT;
+                break;
+            }
+        }
+        elm = elm->next;
+    }
+}
+
+PubElement* LPublishManager::getElement(uint16_t msgId)
+{
+    PubElement* elm = _first;
+    while (elm)
+    {
+        if (elm->msgId == msgId)
+        {
+            break;
+        }
+        else
+        {
+            elm = elm->next;
+        }
+    }
+    return elm;
+}
+
+PubElement* LPublishManager::getElement(const char* topicName)
+{
+    PubElement* elm = _first;
+    while (elm)
+    {
+        if (strcmp(elm->topicName, topicName) == 0)
+        {
+            break;
+        }
+        else
+        {
+            elm = elm->next;
+        }
+    }
+    return elm;
+}
+
+void LPublishManager::remove(PubElement* elm)
+{
+    if (elm)
+        {
+            if (elm->prev == 0)
+            {
+                _first = elm->next;
+                if (elm->next == 0)
+                {
+                    _last = 0;
+                }
+                else
+                {
+                    elm->next->prev = 0;
+                    _last = elm->next;
+                }
+            }
+            else
+            {
+                if ( elm->next == 0 )
+                {
+                    _last = elm->prev;
+                }
+                elm->prev->next = elm->next;
+            }
+            delElement(elm);
+        }
+}
+
+void LPublishManager::delElement(PubElement* elm)
+{
+    if (elm->taskIndex >= 0)
+    {
+        theClient->getTaskManager()->done(elm->taskIndex);
+    }
+    _elmCnt--;
+    if ( elm->payload )
+    {
+        free(elm->payload);
+    }
+    free(elm);
+}
+
+/*
+ PubElement* PublishManager::add(const char* topicName, uint16_t topicId, MQTTSNPayload* payload, uint8_t qos, uint8_t retain, uint16_t msgId){
+ return add(topicName, topicId, payload->getRowData(), payload->getLen(), qos, retain, msgId);
+ }*/
+
+PubElement* LPublishManager::add(const char* topicName, uint16_t topicId, uint8_t* payload, uint16_t len, uint8_t qos,
+        uint8_t retain, uint16_t msgId, uint8_t topicType)
+{
+    PubElement* elm = (PubElement*) calloc(1, sizeof(PubElement));
+
+    if (elm == 0)
+    {
+        return elm;
+    }
+    if (_last == 0)
+    {
+        _first = elm;
+        _last = elm;
+    }
+    else
+    {
+        elm->prev = _last;
+        _last->next = elm;
+        _last = elm;
+    }
+
+    elm->topicName = topicName;
+    elm->flag |= topicType;
+
+    if (qos == 0)
+    {
+        elm->flag |= MQTTSN_FLAG_QOS_0;
+    }
+    else if (qos == 1)
+    {
+        elm->flag |= MQTTSN_FLAG_QOS_1;
+    }
+    else if (qos == 2)
+    {
+        elm->flag |= MQTTSN_FLAG_QOS_2;
+    }
+    else if (qos == 3)
+    {
+        elm->flag |= MQTTSN_FLAG_QOS_M1;
+    }
+    if (retain)
+    {
+        elm->flag |= MQTTSN_FLAG_RETAIN;
+    }
+
+    if (topicId)
+    {
+        elm->status = TOPICID_IS_READY;
+        elm->topicId = topicId;
+    }
+    else
+    {
+        uint16_t id = theClient->getTopicId(topicName);
+        if ( id )
+        {
+            elm->status = TOPICID_IS_READY;
+            elm->topicId = id;
+        }
+    }
+
+    elm->payloadlen = len;
+    elm->msgId = msgId;
+    elm->retryCount = MQTTSN_RETRY_COUNT;
+    elm->sendUTC = 0;
+
+    if (_publishedFlg == NEG_TASK_INDEX)
+    {
+        elm->taskIndex = -1;
+    }
+    else
+    {
+        elm->taskIndex = theClient->getTaskManager()->getIndex();
+        theClient->getTaskManager()->suspend(elm->taskIndex);
+    }
+
+    elm->payload = (uint8_t*) malloc(len);
+    if (elm->payload == 0)
+    {
+        delElement(elm);
+        return 0;
+    }
+    memcpy(elm->payload, payload, len);
+
+    ++_elmCnt;
+    return elm;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LPublishManager.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LPublishManager.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,90 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#ifndef PUBLISHMANAGER_H_
+#define PUBLISHMANAGER_H_
+
+#include <time.h>
+#include "LMqttsnClientApp.h"
+#include "LTimer.h"
+#include "LTopicTable.h"
+#include "Payload.h"
+
+using namespace std;
+
+namespace linuxAsyncClient {
+
+#define TOPICID_IS_SUSPEND  0
+#define TOPICID_IS_READY    1
+#define WAIT_PUBACK         2
+#define WAIT_PUBREC         3
+#define WAIT_PUBREL         4
+#define WAIT_PUBCOMP        5
+
+#define SAVE_TASK_INDEX     1
+#define NEG_TASK_INDEX      0
+
+
+typedef struct PubElement{
+    uint16_t  msgId;
+    uint16_t  topicId;
+    const char* topicName;
+    uint8_t*  payload;
+    uint16_t  payloadlen;
+    time_t    sendUTC;
+    int       (*callback)(void);
+    int       retryCount;
+    int       taskIndex;
+    PubElement* prev;
+    PubElement* next;
+    uint8_t   flag;
+    uint8_t   status;  // 0:SUSPEND, 1:READY
+} PubElement;
+
+/*========================================
+       Class LPublishManager
+ =======================================*/
+class LPublishManager{
+public:
+	LPublishManager();
+    ~LPublishManager();
+    void publish(const char* topicName, Payload* payload, uint8_t qos, bool retain = false);
+    void publish(const char* topicName, uint8_t* payload, uint16_t len, uint8_t qos, bool retain = false);
+    void publish(uint16_t topicId, Payload* payload, uint8_t qos, bool retain = false);
+    void publish(uint16_t topicId, uint8_t* payload, uint16_t len, uint8_t qos, bool retain = false);
+    void responce(const uint8_t* msg, uint16_t msglen);
+    void published(uint8_t* msg, uint16_t msglen);
+    void checkTimeout(void);
+    void sendSuspend(const char* topicName, uint16_t topicId, uint8_t topicType);
+    bool isDone(void);
+    bool isMaxFlight(void);
+private:
+    PubElement* getElement(uint16_t msgId);
+    PubElement* getElement(const char* topicName);
+    PubElement* add(const char* topicName, uint16_t topicId, uint8_t* payload, uint16_t len,
+    		        uint8_t qos, uint8_t retain, uint16_t msgId, uint8_t topicType);
+	void remove(PubElement* elm);
+	void sendPublish(PubElement* elm);
+	void sendPubAck(uint16_t topicId, uint16_t msgId, uint8_t rc);
+    void sendPubRel(PubElement* elm);
+    void delElement(PubElement* elm);
+	PubElement* _first;
+	PubElement* _last;
+	uint8_t     _elmCnt;
+	uint8_t     _publishedFlg;
+};
+ 
+} /* tomyAsyncClient */
+#endif /* PUBLISHMANAGER_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LRegisterManager.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LRegisterManager.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,263 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "LMqttsnClientApp.h"
+#include "LTimer.h"
+#include "LGwProxy.h"
+#include "LMqttsnClient.h"
+#include "LRegisterManager.h"
+
+using namespace std;
+using namespace linuxAsyncClient;
+
+extern void setUint16(uint8_t* pos, uint16_t val);
+extern LMqttsnClient* theClient;
+/*=====================================
+ Class RegisterQue
+ =====================================*/
+LRegisterManager::LRegisterManager()
+{
+	_first = 0;
+	_last = 0;
+}
+
+LRegisterManager::~LRegisterManager()
+{
+	RegQueElement* elm = _first;
+	RegQueElement* sav = 0;
+	while (elm)
+	{
+		sav = elm->next;
+		if (elm != 0)
+		{
+			free(elm);
+		}
+		elm = sav;
+	}
+}
+
+RegQueElement* LRegisterManager::add(const char* topic, uint16_t msgId)
+{
+	RegQueElement* elm = (RegQueElement*) calloc(1, sizeof(RegQueElement));
+
+	if (elm)
+	{
+		if (_last == 0)
+		{
+			_first = elm;
+			_last = elm;
+		}
+		else
+		{
+			elm->prev = _last;
+			_last->next = elm;
+			_last = elm;
+		}
+		elm->topicName = topic;
+		elm->msgId = msgId;
+		elm->retryCount = MQTTSN_RETRY_COUNT;
+		elm->sendUTC = 0;
+	}
+	return elm;
+}
+
+void LRegisterManager::remove(RegQueElement* elm)
+{
+	if (elm)
+		{
+			if (elm->prev == 0)
+			{
+				_first = elm->next;
+				if (elm->next == 0)
+				{
+					_last = 0;
+				}
+				else
+				{
+					elm->next->prev = 0;
+					_last = elm->next;
+				}
+			}
+			else
+			{
+				if ( elm->next == 0 )
+				{
+					_last = elm->prev;
+				}
+				elm->prev->next = elm->next;
+			}
+			free(elm);
+		}
+}
+
+bool LRegisterManager::isDone(void)
+{
+	return _first == 0;
+}
+
+const char* LRegisterManager::getTopic(uint16_t msgId)
+{
+	RegQueElement* elm = _first;
+	while (elm)
+	{
+		if (elm->msgId == msgId)
+		{
+			return elm->topicName;
+		}
+		else
+		{
+			elm = elm->next;
+		}
+	}
+	return 0;
+}
+
+void LRegisterManager::send(RegQueElement* elm)
+{
+	uint8_t msg[MQTTSN_MAX_MSG_LENGTH + 1];
+	msg[0] = 6 + strlen(elm->topicName);
+	msg[1] = MQTTSN_TYPE_REGISTER;
+	msg[2] = msg[3] = 0;
+	setUint16(msg + 4, elm->msgId);
+	strcpy((char*) msg + 6, elm->topicName);
+	theClient->getGwProxy()->connect();
+	theClient->getGwProxy()->writeMsg(msg);
+	elm->sendUTC = time(NULL);
+	elm->retryCount--;
+}
+
+RegQueElement* LRegisterManager::getElement(const char* topicName)
+{
+	RegQueElement* elm = _first;
+	while (elm)
+	{
+		if (strcmp(elm->topicName, topicName))
+		{
+			elm = elm->next;
+		}
+		else
+		{
+			return elm;
+		}
+	}
+	return 0;
+}
+
+RegQueElement* LRegisterManager::getElement(uint16_t msgId)
+{
+	RegQueElement* elm = _first;
+	while (elm)
+	{
+		if (elm->msgId == msgId)
+		{
+			break;
+		}
+		else
+		{
+			elm = elm->next;
+		}
+	}
+	return elm;
+}
+
+void LRegisterManager::registerTopic(char* topicName)
+{
+	RegQueElement* elm = getElement(topicName);
+	if (elm == 0)
+	{
+		uint16_t msgId = theClient->getGwProxy()->getNextMsgId();
+		elm = add(topicName, msgId);
+		send(elm);
+	}
+}
+
+void LRegisterManager::responceRegAck(uint16_t msgId, uint16_t topicId)
+{
+	const char* topicName = getTopic(msgId);
+	MQTTSN_topicTypes type = MQTTSN_TOPIC_TYPE_NORMAL;
+	if (topicName)
+	{
+		theClient->getGwProxy()->getTopicTable()->setTopicId((char*) topicName, topicId,  type); // Add Topic to TopicTable
+		RegQueElement* elm = getElement(msgId);
+		remove(elm);
+		theClient->getPublishManager()->sendSuspend((char*) topicName, topicId, type);
+	}
+}
+
+void LRegisterManager::responceRegister(uint8_t* msg, uint16_t msglen)
+{
+	// *msg is terminated with 0x00 by Network::getMessage()
+	uint8_t regack[7];
+	regack[0] = 7;
+	regack[1] = MQTTSN_TYPE_REGACK;
+	memcpy(regack + 2, msg + 1, 4);
+
+	LTopic* tp = theClient->getGwProxy()->getTopicTable()->match((char*) msg + 5);
+	if (tp)
+	{
+		TopicCallback callback = tp->getCallback();
+		void* topicName = calloc(strlen((char*) msg + 5) + 1, sizeof(char));
+		theClient->getGwProxy()->getTopicTable()->add((char*) topicName, MQTTSN_TOPIC_TYPE_NORMAL, 0, callback, 1);
+		regack[6] = MQTTSN_RC_ACCEPTED;
+	}
+	else
+	{
+		regack[6] = MQTTSN_RC_REJECTED_INVALID_TOPIC_ID;
+	}
+	theClient->getGwProxy()->writeMsg(regack);
+}
+
+uint8_t LRegisterManager::checkTimeout(void)
+{
+	RegQueElement* elm = _first;
+	RegQueElement* sav;
+	while (elm)
+	{
+		if (elm->sendUTC + MQTTSN_TIME_RETRY < time(NULL))
+		{
+			if (elm->retryCount >= 0)
+			{
+				send(elm);
+			}
+			else
+			{
+				if (elm->next)
+				{
+					sav = elm->prev;
+					remove(elm);
+					if (sav)
+					{
+						elm = sav;
+					}
+					else
+					{
+						break;
+					}
+				}
+				else
+				{
+					remove(elm);
+					break;
+				}
+			}
+		}
+		elm = elm->next;
+	}
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LRegisterManager.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LRegisterManager.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,57 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef REGISTERQUE_H_
+#define REGISTERQUE_H_
+
+#include <time.h>
+#include "LMqttsnClientApp.h"
+
+namespace linuxAsyncClient {
+/*======================================
+      structure LRegisterQue
+ ======================================*/
+typedef struct RegQueElement{
+	const char* topicName;
+	uint16_t msgId;
+    int      retryCount;
+    time_t   sendUTC;
+	RegQueElement* prev;
+	RegQueElement* next;
+}RegQueElement;
+
+class LRegisterManager{
+public:
+	LRegisterManager();
+	~LRegisterManager();
+	void registerTopic(char* topicName);
+	void responceRegAck(uint16_t msgId, uint16_t topicId);
+	void responceRegister(uint8_t* msg, uint16_t msglen);
+	bool isDone(void);
+	uint8_t checkTimeout();
+	const char* getTopic(uint16_t msgId);
+private:
+	RegQueElement* getElement(const char* topicName);
+	RegQueElement* getElement(uint16_t msgId);
+	RegQueElement* add(const char* topicName, uint16_t msgId);
+	void remove(RegQueElement* elm);
+	void send(RegQueElement* elm);
+	RegQueElement* _first;
+	RegQueElement* _last;
+};
+}
+
+#endif /* REGISTERQUE_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LScreen.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LScreen.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,134 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <string>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+
+#include "LScreen.h"
+
+using namespace std;
+using namespace linuxAsyncClient;
+
+LScreen::LScreen()
+{
+	_hight = 0;
+	_width = 0;
+	fcntl(0, F_SETFL, O_NONBLOCK );
+}
+
+LScreen::~LScreen()
+{
+
+}
+
+void LScreen::getSize(void)
+{
+	struct winsize wsize ;
+	ioctl(STDOUT_FILENO, TIOCGWINSZ, &wsize);
+	_width = wsize.ws_col ? wsize.ws_col : 132;
+	_hight = wsize.ws_row ? wsize.ws_row : 10;
+}
+
+void LScreen::clear(void)
+{
+	getSize();
+	printf("\033[2J");
+	reprompt();
+
+}
+
+void  LScreen::display(const char* format, ...)
+{
+	va_list args;
+	va_start(args, format);
+	vdisplay(format, args);
+	va_end(args);
+	reprompt();
+}
+
+void  LScreen::vdisplay(const char* format, va_list args)
+{
+	vsprintf(_buffer, format, args);
+	fprintf(stdout, "\033[%d;%dH\033[2K", _hight, 1);
+	fprintf(stdout,"%s", _buffer);
+	reprompt();
+}
+
+void  LScreen::prompt(const char* format, ...)
+{
+	va_list args;
+	va_start(args, format);
+	vprompt(format, args);
+	va_end(args);
+}
+
+void  LScreen::vprompt(const char* format, va_list args)
+{
+	getSize();
+	int pos = 0;
+	string fmt = format;
+
+	if ( ( pos = fmt.find("\n")) > 0 )
+	{
+		fmt.replace(pos, 1, " ");
+	}
+
+	vsprintf(_buffer, format, args);
+	_prompt = _buffer;
+	reprompt();
+}
+
+void  LScreen::reprompt(void)
+{
+	int len = 0;
+	if ( (len =_prompt.size()) >= _width )
+	{
+		len = _width - 1;
+	}
+	fprintf(stdout,"\033[%d;%dH", _hight, 1);
+	fprintf(stdout,"\033[0;33m%s\033[0K\033[0;37m", _prompt.substr(0, len).c_str());
+	fflush(stdout);
+}
+
+
+bool LScreen::checkKeyIn(char* val)
+{
+	int c = 0;
+	int cprev = 0;
+
+	while  ( read(0, &c, 1) == 1 )
+	{
+		if ( c == '\n' )
+		{
+			*val = cprev;
+			fprintf(stdout, "\033[1T");
+			fflush(stdout);
+			reprompt();
+			return true;
+		}
+		cprev = c;
+	}
+	return false;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LScreen.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LScreen.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,49 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+#ifndef LSCREEN_H_
+#define LSCREEN_H_
+#include <stdarg.h>
+#include <string>
+using namespace std;
+
+namespace linuxAsyncClient {
+#define SCREEN_BUFF_SIZE 1024
+/*========================================
+ Class Screen
+ =======================================*/
+class LScreen{
+public:
+	LScreen();
+	~LScreen();
+	void clear(void);
+	void display(const char* format, ...);
+	void prompt(const char* format, ...);
+	bool checkKeyIn(char* val);
+
+private:
+	void reprompt(void);
+	void getSize(void);
+	void vdisplay(const char* format, va_list args);
+	void vprompt(const char* format, va_list args);
+	char _buffer[SCREEN_BUFF_SIZE];
+	int _hight;
+	int _width;
+	string _prompt;
+};
+
+}  /* end of namespace */
+
+#endif /* LSCREEN_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LSubscribeManager.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LSubscribeManager.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,406 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "LMqttsnClientApp.h"
+#include "LTimer.h"
+#include "LScreen.h"
+#include "LGwProxy.h"
+#include "LMqttsnClient.h"
+#include "LSubscribeManager.h"
+
+using namespace std;
+using namespace linuxAsyncClient;
+
+extern void setUint16(uint8_t* pos, uint16_t val);
+extern uint16_t getUint16(const uint8_t* pos);
+extern LMqttsnClient* theClient;
+extern SUBSCRIBE_LIST;
+extern LScreen* theScreen;
+#define SUB_DONE   1
+#define SUB_READY  0
+/*========================================
+ Class SubscribeManager
+ =======================================*/
+LSubscribeManager::LSubscribeManager()
+{
+    _first = 0;
+    _last = 0;
+}
+
+LSubscribeManager::~LSubscribeManager()
+{
+    SubElement* elm = _first;
+    SubElement* sav = 0;
+    while (elm)
+    {
+        sav = elm->next;
+        if (elm != 0)
+        {
+            free(elm);
+        }
+        elm = sav;
+    }
+}
+
+void LSubscribeManager::onConnect(void)
+{
+    DISPLAY("\033[0m\033[0;32m Attempting OnConnect.....\033[0m\033[0;37m\n");
+    if (_first == 0)
+    {
+        for (uint8_t i = 0; theOnPublishList[i].topic != 0; i++)
+        {
+            if ( theOnPublishList[i].type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+            {
+                subscribe(theOnPublishList[i].id, theOnPublishList[i].pubCallback, theOnPublishList[i].qos);
+            }
+            else
+            {
+                subscribe(theOnPublishList[i].topic, theOnPublishList[i].pubCallback, theOnPublishList[i].qos);
+            }
+        }
+    }
+    else
+    {
+        SubElement* elm = _first;
+        SubElement* pelm;
+        do
+        {
+            pelm = elm;
+            if (elm->msgType == MQTTSN_TYPE_SUBSCRIBE)
+            {
+                elm->done = SUB_READY;
+                elm->retryCount = MQTTSN_RETRY_COUNT;
+                subscribe(elm->topicName, elm->callback, elm->qos);
+            }
+            elm = pelm->next;
+        } while (pelm->next);
+    }
+
+    while (!theClient->getSubscribeManager()->isDone())
+    {
+        theClient->getGwProxy()->getMessage();
+    }
+    DISPLAY("\033[0m\033[0;32m OnConnect complete\033[0m\033[0;37m\n");
+    DISPLAY("\033[0m\033[0;32m Test is Ready.\033[0m\033[0;37m\n");
+}
+
+bool LSubscribeManager::isDone(void)
+{
+    SubElement* elm = _first;
+    SubElement* prevelm;
+    while (elm)
+    {
+        prevelm = elm;
+        if (elm->done == SUB_READY)
+        {
+            return false;
+        }
+        elm = prevelm->next;
+    }
+    return true;
+}
+
+void LSubscribeManager::send(SubElement* elm)
+{
+    if (elm->done == SUB_DONE)
+    {
+        return;
+    }
+    uint8_t msg[MQTTSN_MAX_MSG_LENGTH + 1];
+    if (elm->topicType == MQTTSN_TOPIC_TYPE_PREDEFINED)
+    {
+        msg[0] = 7;
+        setUint16(msg + 5, elm->topicId);
+    }
+    else
+    {
+        msg[0] = 5 + strlen(elm->topicName);
+        strcpy((char*) msg + 5, elm->topicName);
+    }
+    msg[1] = elm->msgType;
+    msg[2] = elm->qos | elm->topicType;
+    if (elm->retryCount == MQTTSN_RETRY_COUNT)
+    {
+        elm->msgId = theClient->getGwProxy()->getNextMsgId();
+    }
+
+    if ((elm->retryCount < MQTTSN_RETRY_COUNT) && elm->msgType == MQTTSN_TYPE_SUBSCRIBE)
+    {
+        msg[2] = msg[2] | MQTTSN_FLAG_DUP;
+    }
+
+    setUint16(msg + 3, elm->msgId);
+
+    theClient->getGwProxy()->connect();
+    theClient->getGwProxy()->writeMsg(msg);
+    theClient->getGwProxy()->setPingReqTimer();
+    elm->sendUTC = time(NULL);
+    elm->retryCount--;
+}
+
+void LSubscribeManager::subscribe(const char* topicName, TopicCallback onPublish, uint8_t qos)
+{
+    MQTTSN_topicTypes topicType;
+    if ( strlen(topicName) > 2 )
+    {
+        topicType = MQTTSN_TOPIC_TYPE_NORMAL;
+    }
+    else
+    {
+        topicType = MQTTSN_TOPIC_TYPE_SHORT;
+    }
+    SubElement* elm = add(MQTTSN_TYPE_SUBSCRIBE, topicName, topicType, 0,  qos, onPublish);
+    send(elm);
+}
+
+void LSubscribeManager::subscribe(uint16_t topicId, TopicCallback onPublish, uint8_t qos)
+{
+    SubElement* elm = add(MQTTSN_TYPE_SUBSCRIBE, 0, MQTTSN_TOPIC_TYPE_PREDEFINED, topicId,  qos, onPublish);
+    send(elm);
+}
+
+void LSubscribeManager::unsubscribe(const char* topicName)
+{
+    MQTTSN_topicTypes topicType;
+    if ( strlen(topicName) > 2 )
+    {
+        topicType = MQTTSN_TOPIC_TYPE_NORMAL;
+    }
+    else
+    {
+        topicType = MQTTSN_TOPIC_TYPE_SHORT;
+    }
+    SubElement* elm = add(MQTTSN_TYPE_UNSUBSCRIBE, topicName, topicType, 0, 0, 0);
+    send(elm);
+}
+
+void LSubscribeManager::unsubscribe( uint16_t topicId)
+{
+    SubElement* elm = add(MQTTSN_TYPE_UNSUBSCRIBE, 0, MQTTSN_TOPIC_TYPE_PREDEFINED, topicId, 0, 0);
+    send(elm);
+}
+
+void LSubscribeManager::checkTimeout(void)
+{
+    SubElement* elm = _first;
+
+    while (elm)
+    {
+        if (elm->sendUTC + MQTTSN_TIME_RETRY < time(NULL))
+        {
+            if (elm->retryCount >= 0)
+            {
+                send(elm);
+            }
+            else
+            {
+                if ( elm->done == SUB_READY )
+                {
+                    if (elm->msgType == MQTTSN_TYPE_SUBSCRIBE)
+                    {
+                        DISPLAY("\033[0m\033[0;31m\n!!!!!! SUBSCRIBE  Error !!!!! Topic : %s\033[0m\033[0;37m\n\n", (char*)elm->topicName);
+                    }else{
+                        DISPLAY("\033[0m\033[0;31m\n!!!!!! UNSUBSCRIBE  Error !!!!! Topic : %s\033[0m\033[0;37m\n\n", (char*)elm->topicName);
+                    }
+                    elm->done = SUB_DONE;
+                }
+            }
+        }
+        elm = elm->next;
+    }
+}
+
+void LSubscribeManager::responce(const uint8_t* msg)
+{
+    if (msg[0] == MQTTSN_TYPE_SUBACK)
+    {
+        uint16_t topicId = getUint16(msg + 2);
+        uint16_t msgId = getUint16(msg + 4);
+        uint8_t rc = msg[6];
+
+        SubElement* elm = getElement(msgId);
+        if (elm)
+        {
+            if ( rc == MQTTSN_RC_ACCEPTED )
+            {
+                theClient->getGwProxy()->getTopicTable()->add((char*) elm->topicName, elm->topicType, topicId, elm->callback);
+                getElement(msgId)->done = SUB_DONE;
+                DISPLAY("\033[0m\033[0;32m Topic \"%s\" Id : %d was Subscribed. \033[0m\033[0;37m\n\n", getElement(msgId)->topicName, topicId);
+            }
+            else
+            {
+                DISPLAY("\033[0m\033[0;31m SUBACK Invalid messageId. %s\033[0m\033[0;37m\n\n", getElement(msgId)->topicName);
+                remove(elm);
+            }
+        }
+    }
+    else if (msg[0] == MQTTSN_TYPE_UNSUBACK)
+    {
+        uint16_t msgId = getUint16(msg + 1);
+        SubElement* elm = getElement(msgId);
+        if (elm)
+        {
+            //theClient->getGwProxy()->getTopicTable()->setCallback(elm->topicName, 0);
+            DISPLAY("\033[0m\033[0;32m Topic  \"%s\"  was Unsubscribed. \033[0m\033[0;37m\n\n", getElement(msgId)->topicName);
+            remove(elm);
+        }
+        else
+        {
+            DISPLAY("\033[0m\033[0;31m UNSUBACK Invalid messageId. \033[0m\033[0;37m\n\n");
+        }
+    }
+}
+
+/* SubElement operations */
+
+SubElement* LSubscribeManager::add(uint8_t msgType, const char* topicName, MQTTSN_topicTypes topicType, uint16_t topicId,
+        uint8_t qos, TopicCallback callback)
+{
+    SubElement* elm = 0;
+    if (topicName )
+    {
+        elm = getElement(topicName, msgType);
+    }
+    else
+    {
+        elm = getElement(topicId, topicType);
+    }
+
+    if ( elm  == 0 )
+    {
+        elm = (SubElement*) calloc(1, sizeof(SubElement));
+        if (elm == 0)
+        {
+            return 0;
+        }
+        if (_last == 0)
+        {
+            _first = elm;
+            _last = elm;
+        }
+        else
+        {
+            elm->prev = _last;
+            _last->next = elm;
+            _last = elm;
+        }
+    }
+
+    elm->msgType = msgType;
+    elm->callback = callback;
+    elm->topicName = topicName;
+    elm->topicId = topicId;
+    elm->topicType = topicType;
+
+    if (qos == 1)
+    {
+        elm->qos = MQTTSN_FLAG_QOS_1;
+    }
+    else if (qos == 2)
+    {
+        elm->qos = MQTTSN_FLAG_QOS_2;
+    }
+    else
+    {
+        elm->qos = MQTTSN_FLAG_QOS_0;
+    }
+    elm->msgId = 0;
+    elm->retryCount = MQTTSN_RETRY_COUNT;
+    elm->done = SUB_READY;
+    elm->sendUTC = 0;
+
+    return elm;
+}
+
+void LSubscribeManager::remove(SubElement* elm)
+{
+    if (elm)
+    {
+        if (elm->prev == 0)
+        {
+            _first = elm->next;
+            if (elm->next != 0)
+            {
+                elm->next->prev = 0;
+                _last = elm->next;
+            }
+            free(elm);
+        }
+        else
+        {
+            if ( elm->next == 0 )
+            {
+                _last = elm->prev;
+            }
+            elm->prev->next = elm->next;
+            free(elm);
+        }
+    }
+}
+
+SubElement* LSubscribeManager::getElement(uint16_t msgId)
+{
+    SubElement* elm = _first;
+    while (elm)
+    {
+        if (elm->msgId == msgId)
+        {
+            return elm;
+        }
+        else
+        {
+            elm = elm->next;
+        }
+    }
+    return 0;
+}
+
+SubElement* LSubscribeManager::getElement(const char* topicName, uint8_t msgType)
+{
+    SubElement* elm = _first;
+    while (elm)
+    {
+        if ( elm->msgType == msgType &&  strncmp(elm->topicName, topicName, strlen(topicName)) == 0 )
+        {
+            return elm;
+        }
+        else
+        {
+            elm = elm->next;
+        }
+    }
+    return 0;
+}
+
+SubElement* LSubscribeManager::getElement(uint16_t topicId, MQTTSN_topicTypes topicType)
+{
+    SubElement* elm = _first;
+    while (elm)
+    {
+        if (elm->topicId == topicId && elm->topicType == topicType)
+        {
+            return elm;
+        }
+        else
+        {
+            elm = elm->next;
+        }
+    }
+    return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LSubscribeManager.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LSubscribeManager.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,78 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef SUBSCRIBEMANAGER_H_
+#define SUBSCRIBEMANAGER_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "LMqttsnClientApp.h"
+#include "LRegisterManager.h"
+#include "LTimer.h"
+#include "LTopicTable.h"
+
+using namespace std;
+
+namespace linuxAsyncClient {
+
+typedef struct SubElement{
+    TopicCallback callback;
+    const char* topicName;
+    uint16_t  msgId;
+    time_t    sendUTC;
+    uint16_t  topicId;
+    uint8_t   msgType;
+    MQTTSN_topicTypes   topicType;
+    uint8_t   qos;
+
+    int       retryCount;
+    uint8_t   done;
+
+    SubElement* prev;
+    SubElement* next;
+} SubElement;
+
+/*========================================
+       Class LSubscribeManager
+ =======================================*/
+class LSubscribeManager{
+public:
+    LSubscribeManager();
+    ~LSubscribeManager();
+    void onConnect(void);
+    void subscribe(const char* topicName, TopicCallback onPublish, uint8_t qos);
+    void subscribe(uint16_t topicId, TopicCallback onPublish, uint8_t qos);
+    void unsubscribe(const char* topicName);
+    void unsubscribe(uint16_t topicId);
+    void responce(const uint8_t* msg);
+    void checkTimeout(void);
+    bool isDone(void);
+private:
+    void send(SubElement* elm);
+    SubElement* getFirstElement(void);
+    SubElement* getElement(uint16_t msgId);
+    SubElement* getElement(uint16_t topicId, MQTTSN_topicTypes topicType);
+    SubElement* getElement(const char* topicName, uint8_t msgType);
+	SubElement* add(uint8_t msgType, const char* topicName, MQTTSN_topicTypes topicType, uint16_t topicId, uint8_t qos, TopicCallback callback);
+	void remove(SubElement* elm);
+	SubElement* _first;
+	SubElement* _last;
+};
+ 
+} /* end of namespace */
+#endif /* SUBSCRIBEMANAGER_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTaskManager.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTaskManager.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,177 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "LMqttsnClientApp.h"
+#include "LSubscribeManager.h"
+#include "LTimer.h"
+#include "LMqttsnClient.h"
+#include "LTaskManager.h"
+#include "LScreen.h"
+
+using namespace std;
+using namespace linuxAsyncClient;
+
+extern LMqttsnClient* theClient;
+extern LScreen* theScreen;
+extern bool theClientMode;
+/*=====================================
+           TaskManager
+ ======================================*/
+LTaskManager::LTaskManager(void){
+	_tasks = 0;
+	_tests = 0;
+	_index = 0;
+}
+
+LTaskManager::~LTaskManager(void){
+    
+}
+
+void LTaskManager::add(TaskList* task){
+    _tasks = task;
+}
+
+void LTaskManager::add(TestList* test){
+    _tests = test;
+}
+
+void LTaskManager::run(void){
+	int i = 0;
+	char c = 0;
+	bool cancelFlg = false;
+
+	if ( !theClientMode )
+	{
+			theClient->getGwProxy()->getMessage();
+
+			for (i = 0; _tests[i].testTask > 0; i++)
+			{
+				PROMPT("Execute \"%s\" ? ( y/n ) : ", _tests[i].testLabel);
+				while (true)
+				{
+					if (CHECKKEYIN(&c))
+					{
+						if ( toupper(c) == 'N' )
+						{
+
+							DISPLAY("\033[0m\033[0;32m\n**** %s is canceled ****\033[0m\033[0;37m\n\n", _tests[i].testLabel);
+							theScreen->prompt("");
+							cancelFlg = true;
+							break;
+						}
+						else if ( toupper(c) == 'Y' )
+						{
+							DISPLAY("\033[0m\033[0;32m\n\n**** %s start ****\033[0m\033[0;37m\n", _tests[i].testLabel);
+							theScreen->prompt("");
+							(_tests[i].testTask)();
+							cancelFlg = false;
+							break;
+						}
+					}
+					else
+					{
+						theClient->getGwProxy()->getMessage();
+					}
+				}
+
+				while ( true )
+				{
+					do
+					{
+						theClient->getGwProxy()->getMessage();
+					}
+					while(theClient->getPublishManager()->isMaxFlight() ||
+						   !theClient->getSubscribeManager()->isDone() ||
+						   !theClient->getRegisterManager()->isDone());
+
+					if (theClient->getPublishManager()->isDone())
+					{
+						break;
+					}
+				}
+				if ( !cancelFlg )
+				{
+					DISPLAY("\033[0m\033[0;32m\n**** %s complete ****\033[0m\033[0;37m\n\n", _tests[i].testLabel);
+				}
+			}
+			DISPLAY("\033[0m\033[0;32m\n\n#########  All tests complete!  ###########\033[0m\033[0;37m\n\n");
+	}
+	else
+	{
+		while (true)
+		{
+			theClient->getGwProxy()->getMessage();
+			for (_index = 0; _tasks[_index].callback > 0; _index++)
+			{
+				if ((_tasks[_index].prevTime + _tasks[_index].interval <= time(NULL)) &&
+					 _tasks[_index].count == 0)
+				{
+					_tasks[_index].prevTime = time(NULL);
+					(_tasks[_index].callback)();
+				}
+			}
+
+			do
+			{
+				theClient->getGwProxy()->getMessage();
+			}
+			while(theClient->getPublishManager()->isMaxFlight() ||
+				   !theClient->getSubscribeManager()->isDone() ||
+				   !theClient->getRegisterManager()->isDone());
+
+			if (theClient->getPublishManager()->isDone())
+			{
+				break;
+			}
+		}
+	}
+}
+
+uint8_t LTaskManager::getIndex(void){
+	return _index;
+}
+
+void LTaskManager::done(uint8_t index){
+	if (_tasks )
+	{
+		if (_tasks[index].count > 0)
+		{
+			_tasks[index].count--;
+		}
+	}
+	if (_tests )
+		{
+			if (_tests[index].count > 0)
+			{
+				_tests[index].count--;
+			}
+		}
+}
+
+void LTaskManager::suspend(uint8_t index){
+	if ( _tasks )
+	{
+		_tasks[index].count++;
+	}
+	if ( _tests )
+	{
+		_tests[index].count++;
+	}
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTaskManager.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTaskManager.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,66 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef TASKMANAGER_H_
+#define TASKMANAGER_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "LMqttsnClientApp.h"
+#include "LTimer.h"
+
+using namespace std;
+
+namespace linuxAsyncClient {
+
+struct TaskList{
+    void     (*callback)(void);
+	time_t   interval;
+    time_t    prevTime;
+    uint8_t  count;
+};
+
+struct TestList {
+	const char* testLabel;
+	void     (*testTask)(void);
+	uint8_t  count;
+};
+
+/*========================================
+       Class TaskManager
+ =======================================*/
+class LTaskManager{
+public:
+    LTaskManager();
+    ~LTaskManager();
+    void add(TaskList* task);
+    void add(TestList* test);
+    void run(void);
+    void done(uint8_t index);
+    void suspend(uint8_t index);
+    uint8_t getIndex(void);
+private:
+    TaskList* _tasks;
+    TestList* _tests;
+    uint8_t   _index;
+
+};
+
+} /* end of namespace */
+#endif /* TASKMANAGER_H_ */
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTimer.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTimer.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,80 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "LMqttsnClientApp.h"
+#include "LTimer.h"
+
+//using namespace std;
+using namespace linuxAsyncClient;
+
+/*=====================================
+        Class Timer
+ =====================================*/
+
+LTimer::LTimer(){
+	_startTime.tv_sec = 0;
+	_millis = 0;
+}
+
+LTimer::~LTimer(){
+
+}
+
+void LTimer::start(uint32_t msec){
+  gettimeofday(&_startTime, 0);
+  _millis = msec;
+}
+
+bool LTimer::isTimeUp(void){
+  return isTimeUp(_millis);
+}
+
+bool LTimer::isTimeUp(uint32_t msec){
+    struct timeval curTime;
+    uint32_t secs, usecs;
+    if (_startTime.tv_sec == 0){
+        return false;
+    }else{
+        gettimeofday(&curTime, 0);
+        secs  = (curTime.tv_sec  - _startTime.tv_sec) * 1000;
+        usecs = (curTime.tv_usec - _startTime.tv_usec) / 1000.0;
+        return ((secs + usecs) > (uint32_t)msec);
+    }
+}
+
+void LTimer::stop(){
+  _startTime.tv_sec = 0;
+  _millis = 0;
+}
+
+uint32_t LTimer::getRemain(void)
+{
+    struct timeval curTime;
+    uint32_t secs, usecs;
+    if (_millis <= 0){
+        return 0;
+    }else{
+        gettimeofday(&curTime, 0);
+        secs  = (curTime.tv_sec  - _startTime.tv_sec) * 1000;
+        usecs = (curTime.tv_usec - _startTime.tv_usec) / 1000.0;
+        secs = _millis - (secs + usecs);
+        return secs;
+    }
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTimer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTimer.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,47 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef TIMER_H_
+#define TIMER_H_
+
+#include <time.h>
+
+#include "LMqttsnClientApp.h"
+
+namespace linuxAsyncClient {
+
+/*============================================
+                LTimer
+ ============================================*/
+class LTimer{
+public:
+    LTimer();
+    ~LTimer();
+    void start(uint32_t msec = 0);
+    bool isTimeUp(uint32_t msec);
+    bool isTimeUp(void);
+    void stop(void);
+    void changeUTC(void){};
+    uint32_t getRemain(void);
+    static void setUnixTime(uint32_t utc){};
+private:
+    struct timeval _startTime;
+    uint32_t _millis;
+};
+
+} /* end of namespace */
+
+#endif /* TIMER_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTopicTable.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTopicTable.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,287 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "LMqttsnClientApp.h"
+#include "LTopicTable.h"
+
+using namespace std;
+using namespace linuxAsyncClient;
+/*=====================================
+        Class Topic
+ ======================================*/
+LTopic::LTopic(){
+    _topicStr = 0;
+    _callback = 0;
+    _topicId = 0;
+    _topicType = MQTTSN_TOPIC_TYPE_NORMAL;
+    _next = 0;
+    _malocFlg = 0;
+}
+
+LTopic::~LTopic(){
+	if (_malocFlg){
+		free(_topicStr);
+	}
+}
+
+TopicCallback LTopic::getCallback(void){
+	return _callback;
+}
+
+int LTopic::execCallback(uint8_t* payload, uint16_t payloadlen){
+    if(_callback != 0){
+        return _callback(payload, payloadlen);
+    }
+    return 0;
+}
+
+
+uint8_t LTopic::hasWildCard(uint8_t* pos){
+	*pos = strlen(_topicStr) - 1;
+    if (*(_topicStr + *pos) == '#'){
+        return MQTTSN_TOPIC_MULTI_WILDCARD;
+    }else{
+    	for(uint8_t p = 0; p < strlen(_topicStr); p++){
+    		if (*(_topicStr + p) == '+'){
+    			*pos = p;
+    			return MQTTSN_TOPIC_SINGLE_WILDCARD;
+    		}
+    	}
+    }
+    return 0;
+}
+
+bool LTopic::isMatch(const char* topic){
+    uint8_t pos;
+
+	if ( strlen(topic) < strlen(_topicStr)){
+		return false;
+	}
+
+	uint8_t wc = hasWildCard(&pos);
+
+	if (wc == MQTTSN_TOPIC_SINGLE_WILDCARD){
+		if ( strncmp(_topicStr, topic, pos - 1) == 0){
+			if (*(_topicStr + pos + 1) == '/'){
+				for(uint8_t p = pos; p < strlen(topic); p++){
+					if (*(topic + p) == '/'){
+						if (strcmp(_topicStr + pos + 1, topic + p ) == 0){
+							return true;
+						}
+					}
+				}
+			}else{
+				for(uint8_t p = pos + 1;p < strlen(topic); p++){
+					if (*(topic + p) == '/'){
+						return false;
+					}
+				}
+			}
+			return true;
+		}
+	}else if (wc == MQTTSN_TOPIC_MULTI_WILDCARD){
+		if (strncmp(_topicStr, topic, pos) == 0){
+			return true;
+		}
+	}else if (strcmp(_topicStr, topic) == 0){
+		return true;
+	}
+	return false;
+}
+
+
+/*=====================================
+        Class TopicTable
+ ======================================*/
+LTopicTable::LTopicTable(){
+	_first = 0;
+	_last = 0;
+}
+
+LTopicTable::~LTopicTable(){
+	clearTopic();
+}
+
+
+LTopic* LTopicTable::getTopic(const char* topic){
+	LTopic* p = _first;
+	while(p){
+		if (p->_topicStr != 0 && strcmp(p->_topicStr, topic) == 0){
+			return p;
+		}
+		p = p->_next;
+	}
+	return 0;
+}
+
+LTopic* LTopicTable::getTopic(uint16_t topicId, MQTTSN_topicTypes topicType){
+	LTopic* p = _first;
+	while(p){
+		if (p->_topicId == topicId && p->_topicType == topicType){
+			return p;
+		}
+		p = p->_next;
+	}
+	return 0;
+}
+
+uint16_t LTopicTable::getTopicId(const char* topic){
+	LTopic* p = getTopic(topic);
+	if (p){
+		return p->_topicId;
+	}
+	return 0;
+}
+
+
+char* LTopicTable::getTopicName(LTopic* topic){
+	return topic->_topicStr;
+}
+
+
+void LTopicTable::setTopicId(const char* topic, uint16_t id, MQTTSN_topicTypes type){
+    LTopic* tp = getTopic(topic);
+    if (tp){
+        tp->_topicId = id;
+    }else{
+    	add(topic, type, id, 0);
+    }
+}
+
+
+bool LTopicTable::setCallback(const char* topic, TopicCallback callback){
+	LTopic* p = getTopic(topic);
+	if (p){
+		p->_callback = callback;
+		return true;
+	}
+	return false;
+}
+
+
+bool LTopicTable::setCallback(uint16_t topicId, MQTTSN_topicTypes topicType, TopicCallback callback){
+	LTopic* p = getTopic(topicId, topicType);
+	if (p){
+		p->_callback = callback;
+		return true;
+	}
+	return false;
+}
+
+
+int LTopicTable::execCallback(uint16_t  topicId, uint8_t* payload, uint16_t payloadlen, MQTTSN_topicTypes topicType){
+	LTopic* p = getTopic(topicId, topicType);
+	if (p){;
+		return p->execCallback(payload, payloadlen);
+	}
+	return 0;
+}
+
+
+LTopic* LTopicTable::add(const char* topicName, MQTTSN_topicTypes type, uint16_t id, TopicCallback callback, uint8_t alocFlg)
+{
+	LTopic* elm;
+
+    if (topicName){
+	    elm = getTopic(topicName);
+    }else{
+        elm = getTopic(id, type);
+    }
+    
+	if (elm == 0){
+		elm = new LTopic();
+		if(elm == 0){
+			goto exit;
+		}
+		if ( _last == 0){
+			_first = elm;
+			_last = elm;
+		}
+		else
+		{
+			elm->_prev = _last;
+			_last->_next = elm;
+			_last = elm;
+		}
+
+		elm->_topicStr =  const_cast <char*>(topicName);
+		elm->_topicId = id;
+		elm->_topicType = type;
+		elm->_callback = callback;
+		elm->_malocFlg = alocFlg;
+		elm->_prev = 0;
+	}else{
+		elm->_callback = callback;
+	}
+exit:
+	return elm;
+}
+
+void LTopicTable::remove(uint16_t topicId, MQTTSN_topicTypes type)
+{
+	LTopic* elm = getTopic(topicId, type);
+
+	if (elm){
+		if (elm->_prev == 0)
+		{
+			_first = elm->_next;
+			if (elm->_next == 0)
+			{
+				_last = 0;
+			}
+			else
+			{
+				elm->_next->_prev = 0;
+				_last = elm->_next;
+			}
+		}
+		else
+		{
+			if ( elm->_next == 0 )
+			{
+				_last = elm->_prev;
+			}
+			elm->_prev->_next = elm->_next;
+		}
+		delete elm;
+	}
+}
+
+LTopic* LTopicTable::match(const char* topicName){
+	LTopic* elm = _first;
+	while(elm){
+		if (elm->isMatch(topicName)){
+			break;
+		}
+		elm = elm->_next;
+	}
+	return elm;
+}
+
+
+void LTopicTable::clearTopic(void){
+	LTopic* p = _first;
+	while(p){
+		_first = p->_next;
+		delete p;
+		p = _first;
+	}
+	_last = 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTopicTable.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/LTopicTable.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,82 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef TOPICTABLE_H_
+#define TOPICTABLE_H_
+
+#include <stdio.h>
+
+#include "LMqttsnClientApp.h"
+#include "Payload.h"
+
+#define MQTTSN_TOPIC_MULTI_WILDCARD   1
+#define MQTTSN_TOPIC_SINGLE_WILDCARD  2
+
+namespace linuxAsyncClient {
+/*=====================================
+        Class LTopic
+ ======================================*/
+typedef int (*TopicCallback)(uint8_t*, uint16_t);
+
+class LTopic {
+	friend class LTopicTable;
+public:
+    LTopic();
+    ~LTopic();
+    int      execCallback(uint8_t* payload, uint16_t payloadlen);
+    uint8_t  hasWildCard(uint8_t* pos);
+    bool     isMatch(const char* topic);
+    TopicCallback getCallback(void);
+private:
+    uint16_t  _topicId;
+    MQTTSN_topicTypes   _topicType;
+    char*     _topicStr;
+    TopicCallback  _callback;
+    uint8_t  _malocFlg;
+    LTopic*    _prev;
+    LTopic*    _next;
+};
+
+/*=====================================
+        Class LTopicTable
+ ======================================*/
+class LTopicTable {
+public:
+	LTopicTable();
+      ~LTopicTable();
+      uint16_t getTopicId(const char* topic);
+      char*    getTopicName(LTopic* topic);
+      LTopic*   getTopic(const char* topic);
+      LTopic*   getTopic(uint16_t topicId, MQTTSN_topicTypes topicType);
+      void     setTopicId(const char* topic, uint16_t id, MQTTSN_topicTypes topicType);
+      bool     setCallback(const char* topic, TopicCallback callback);
+      bool     setCallback(uint16_t topicId, MQTTSN_topicTypes type, TopicCallback callback);
+      int      execCallback(uint16_t topicId, uint8_t* payload, uint16_t payloadlen, MQTTSN_topicTypes topicType);
+      LTopic*  add(const char* topic, MQTTSN_topicTypes type, uint16_t id = 0, TopicCallback callback = 0, uint8_t alocFlg = 0);
+      //LTopic*  add(uint16_t topicId, uint16_t id, MQTTSN_topicTypes type, TopicCallback callback, uint8_t alocFlg);
+      LTopic*  match(const char* topic);
+      void     clearTopic(void);
+      void     remove(uint16_t topicId, MQTTSN_topicTypes type);
+
+private:
+    LTopic*  _first;
+    LTopic*  _last;
+
+};
+
+} /* end of namespace */
+
+#endif /* TOPICTABLE_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/Payload.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/Payload.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,348 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "LMqttsnClientApp.h"
+#include "Payload.h"
+
+using namespace std;
+using namespace linuxAsyncClient;
+
+
+extern uint16_t getUint16(const uint8_t* pos);
+extern uint32_t getUint32(const uint8_t* pos);
+extern float    getFloat32(const uint8_t* pos);
+
+extern void setUint16(uint8_t* pos, uint16_t val);
+extern void setUint32(uint8_t* pos, uint32_t val);
+extern void setFloat32(uint8_t* pos, float val);
+
+/*=====================================
+        Class Payload
+  =====================================*/
+Payload::Payload(){
+	_buff = _pos = 0;
+	_len = 0;
+	_elmCnt = 0;
+	_memDlt = 0;
+}
+
+Payload::Payload(uint16_t len){
+	_buff = (uint8_t*)calloc(len, sizeof(uint8_t));
+	if(_buff == 0){
+		exit(-1);
+	}
+	_pos = _buff;
+	_elmCnt = 0;
+	_len = len;
+	_memDlt = 1;
+}
+
+Payload::~Payload(){
+	if(_memDlt){
+		free(_buff);
+	}
+}
+
+void Payload::init(){
+	_pos = _buff;
+	_elmCnt = 0;
+}
+
+uint16_t Payload::getAvailableLength(){
+	return _len - (_pos - _buff);
+}
+
+uint16_t Payload::getLen(){
+	return _pos - _buff;
+}
+
+uint8_t* Payload::getRowData(){
+	return _buff;
+}
+
+/*======================
+ *     setter
+ ======================*/
+int8_t Payload::set_uint32(uint32_t val){
+	if(getAvailableLength() < 6){
+		return -1;
+	}
+	if(val < 128){
+		*_pos++ = (uint8_t)val;
+	}else if(val < 256){
+		*_pos++ = MSGPACK_UINT8;
+		*_pos++ = (uint8_t)val;
+	}else if(val < 65536){
+		*_pos++ = MSGPACK_UINT16;
+		setUint16(_pos,(uint16_t) val);
+		_pos += 2;
+	}else{
+		*_pos++ = MSGPACK_UINT32;
+		setUint32(_pos, val);
+		_pos += 4;
+	}
+	_elmCnt++;
+	return 0;
+}
+
+int8_t Payload::set_int32(int32_t val){
+	if(getAvailableLength() < 6){
+			return -1;
+	}
+	if((val > -32) && (val < 0)){
+		*_pos++ = val | MSGPACK_NEGINT;
+	}else if((val >= 0) && (val < 128)){
+		*_pos++ = val;
+	}else if(val > -128 && val < 128){
+		*_pos++ = MSGPACK_INT8;
+		*_pos++ = (uint8_t)val;
+	}else if(val > -32768 && val < 32768){
+		*_pos++ = MSGPACK_INT16;
+		setUint16(_pos, (uint16_t)val);
+		_pos += 2;
+	}else{
+		*_pos++ = MSGPACK_INT32;
+		setUint32(_pos, (uint32_t)val);
+		_pos += 4;
+	}
+	_elmCnt++;
+	return 0;
+}
+
+int8_t Payload::set_float(float val){
+	if(getAvailableLength() < 6){
+			return -1;
+	}
+	*_pos++ = MSGPACK_FLOAT32;
+	setFloat32(_pos, val);
+	_pos += 4;
+	_elmCnt++;
+	return 0;
+}
+
+int8_t Payload::set_str(char* val){
+	return set_str((const char*) val);
+}
+
+int8_t Payload::set_str(const char* val){
+	if(getAvailableLength() < strlen(val) + 3){
+		return -1;
+	}else if(strlen(val) < 32){
+		*_pos++ = (uint8_t)strlen(val) | MSGPACK_FIXSTR;
+	}else if(strlen(val) < 256){
+		*_pos++ = MSGPACK_STR8;
+		*_pos++ = (uint8_t)strlen(val);
+	}else if(strlen(val) < 65536){
+		*_pos++ = MSGPACK_STR16;
+		setUint16(_pos, (uint16_t)strlen(val));
+		_pos += 2;
+	}
+	memcpy(_pos, val, strlen(val));
+	_pos += strlen(val);
+	return 0;
+}
+
+int8_t Payload::set_array(uint8_t val){
+	if(getAvailableLength() < (uint16_t)val+ 1){
+		return -1;
+	}
+	if(val < 16){
+		*_pos++ = MSGPACK_ARRAY15 | val;
+	}else{
+		*_pos++ = MSGPACK_ARRAY16;
+		setUint16(_pos,(uint16_t)val);
+		_pos += 2;
+	}
+	_elmCnt++;
+	return 0;
+}
+
+int8_t Payload::set_bool(bool val){
+	if (getAvailableLength() < 1){
+			return -1;
+	}
+	if (val){
+		*_pos++ = MSGPACK_TRUE;
+	}else {
+		*_pos++ = MSGPACK_FALSE;
+	}
+	_elmCnt++;
+	return 0;
+}
+/*======================
+ *     getter
+ ======================*/
+uint8_t Payload::getArray(uint8_t index){
+	uint8_t rc = 0;
+	uint8_t* val = getBufferPos(index);
+	if(val != 0){
+		if(*val == MSGPACK_ARRAY15){
+			rc = *val & 0x0F;
+		}else if(*val == MSGPACK_ARRAY16){
+			rc = (uint8_t)getUint16(val + 1);
+		}
+	}
+	return rc;
+}
+
+bool Payload::get_bool(uint8_t index){
+	uint8_t* val = getBufferPos(index);
+	if (*val == MSGPACK_FALSE){
+		return false;
+	}else{
+		return true;
+	}
+}
+
+uint32_t Payload::get_uint32(uint8_t index){
+	uint32_t rc = 0;
+	uint8_t* val = getBufferPos(index);
+	if(val != 0){
+		if(*val == MSGPACK_UINT32){
+			rc = getUint32(val + 1);
+		}else if(*val == MSGPACK_UINT16){
+			rc = (uint32_t)getUint16(val + 1);
+		}else if(*val == MSGPACK_UINT8){
+			rc = (uint32_t)*(val + 1);
+		}else if(*val < 128){
+			rc = (uint32_t)*val;
+		}
+	}
+	return rc;
+}
+
+int32_t Payload::get_int32(uint8_t index){
+	int32_t rc = 0;
+	uint8_t* val = getBufferPos(index);
+	if(val != 0){
+		if(*val == MSGPACK_INT32){
+			rc = (int32_t) getUint32(val + 1);
+		}else if(*val == MSGPACK_INT16){
+			uint16_t d16 = getUint16(val + 1);
+			if(d16 >= 32768){
+				rc = d16 - 65536;
+			}else{
+				rc = (int32_t)d16;
+			}
+		}else if(*val == MSGPACK_INT8){
+			rc = (int32_t)*(val + 1);
+		}else if((*val & MSGPACK_NEGINT) == MSGPACK_NEGINT){
+			*val &= ~MSGPACK_NEGINT;
+			rc = ((int32_t)*val) * -1;
+		}else{
+			rc = (int32_t) *val;
+		}
+	}
+	return rc;
+}
+
+float Payload::get_float(uint8_t index){
+	uint8_t* val = getBufferPos(index);
+	if(val != 0){
+		if(*val == MSGPACK_FLOAT32){
+			return getFloat32(val + 1);
+		}
+	}
+	return 0;
+}
+
+const char* Payload::get_str(uint8_t index, uint16_t* len){
+	uint8_t* val = getBufferPos(index);
+	if(val != 0){
+		if(*val == MSGPACK_STR16){
+			*len = getUint16(val + 1);
+			return (const char*)(val + 3);
+		}else if(*val == MSGPACK_STR8){
+			*len = *(val + 1);
+			return (const char*)(val + 2);
+		}else if( (*val & 0xf0) == MSGPACK_FIXSTR ){
+			*len = *val & 0x0f;
+			return (const char*)(val + 1);
+		}
+	}
+	*len = 0;
+	return (const char*) 0;
+
+}
+
+
+uint8_t* Payload::getBufferPos(uint8_t index){
+	uint8_t* bpos = 0;
+	uint8_t* pos = _buff;
+
+	for(uint8_t i = 0; i <= index; i++){
+		bpos = pos;
+		switch(*pos){
+		case MSGPACK_FALSE:
+		case MSGPACK_TRUE:
+			pos++;
+			break;
+		case MSGPACK_UINT8:
+		case MSGPACK_INT8:
+			pos += 2;
+			break;
+		case MSGPACK_UINT16:
+		case MSGPACK_INT16:
+		case MSGPACK_ARRAY16:
+			pos += 3;
+			break;
+		case MSGPACK_UINT32:
+		case MSGPACK_INT32:
+		case MSGPACK_FLOAT32:
+			pos += 5;
+			break;
+		case MSGPACK_STR8:
+			pos += *(pos + 1) + 2;
+			break;
+		case MSGPACK_STR16:
+			pos += getUint16(pos + 1) + 3;
+			break;
+		default:
+			if((*pos < MSGPACK_POSINT) ||
+				((*pos & 0xf0) == MSGPACK_NEGINT) ||
+				((*pos & 0xf0) == MSGPACK_ARRAY15)) {
+				pos++;
+			}else if((*pos & 0xf0) == MSGPACK_FIXSTR){
+				pos += (*pos & 0x0f) + 1;
+			}
+		}
+		/*
+		if((pos - _buff) >= _len){
+			return 0;
+		}
+		*/
+	}
+	return bpos;
+}
+
+void Payload::setRowData(uint8_t* payload, uint16_t payloadLen){
+    if(_memDlt){
+			free(_buff);
+			_memDlt = 0;
+	}
+	_buff = payload;
+	_len = payloadLen;
+	_pos = _buff + _len;
+}
+
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/Payload.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/Payload.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,87 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef PAYLOAD_H_
+#define PAYLOAD_H_
+
+#include "LMqttsnClientApp.h"
+
+#define MSGPACK_FALSE    0xc2
+#define MSGPACK_TRUE     0xc3
+#define MSGPACK_POSINT   0x80
+#define MSGPACK_NEGINT   0xe0
+#define MSGPACK_UINT8    0xcc
+#define MSGPACK_UINT16   0xcd
+#define MSGPACK_UINT32   0xce
+#define MSGPACK_INT8     0xd0
+#define MSGPACK_INT16    0xd1
+#define MSGPACK_INT32    0xd2
+#define MSGPACK_FLOAT32  0xca
+#define MSGPACK_FIXSTR   0xa0
+#define MSGPACK_STR8     0xd9
+#define MSGPACK_STR16    0xda
+#define MSGPACK_ARRAY15  0x90
+#define MSGPACK_ARRAY16  0xdc
+#define MSGPACK_MAX_ELEMENTS   50   // Less than 256
+
+namespace linuxAsyncClient {
+/*=====================================
+        Class Payload
+  =====================================*/
+class Payload{
+public:
+	Payload();
+	Payload(uint16_t len);
+	~Payload();
+
+/*---------------------------------------------
+  getLen() and getRowData() are
+  minimum required functions of Payload class.
+----------------------------------------------*/
+	uint16_t getLen();       // get data length
+	uint8_t* getRowData();   // get data pointer
+
+/*--- Functions for MessagePack ---*/
+	void init(void);
+	int8_t set_bool(bool val);
+	int8_t set_uint32(uint32_t val);
+	int8_t set_int32(int32_t val);
+	int8_t set_float(float val);
+	int8_t set_str(char* val);
+	int8_t set_str(const char* val);
+	int8_t set_array(uint8_t val);
+
+	bool    get_bool(uint8_t index);
+	uint8_t getArray(uint8_t index);
+	uint32_t get_uint32(uint8_t index);
+	int32_t  get_int32(uint8_t index);
+    float    get_float(uint8_t index);
+    const char* get_str(uint8_t index, uint16_t* len);
+
+	void 	 setRowData(uint8_t* payload, uint16_t payloadLen);
+	uint16_t getAvailableLength();
+private:
+	uint8_t* getBufferPos(uint8_t index);
+	uint8_t* _buff;
+	uint16_t _len;
+	uint8_t  _elmCnt;
+	uint8_t* _pos;
+	uint8_t  _memDlt;
+};
+
+} /* linuxAsyncClient */
+
+#endif /* PAYLOAD_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/Util.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/GatewayTester/src/Util.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,134 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "LMqttsnClientApp.h"
+using namespace std;
+/*=====================================
+        Global functions
+ ======================================*/
+#ifndef CPU_BIGENDIANN
+
+/*--- For Little endianness ---*/
+
+uint16_t getUint16(const uint8_t* pos){
+	uint16_t val = ((uint16_t)*pos++ << 8);
+	return val += *pos;
+}
+
+void setUint16(uint8_t* pos, uint16_t val){
+    *pos++ = (val >> 8) & 0xff;
+	*pos   = val & 0xff;
+}
+
+uint32_t getUint32(const uint8_t* pos){
+    uint32_t val = uint32_t(*pos++) <<  24;
+	val += uint32_t(*pos++) << 16;
+	val += uint32_t(*pos++) <<  8;
+	return val += *pos++;
+}
+
+void setUint32(uint8_t* pos, uint32_t val){
+	*pos++ = (val >> 24) & 0xff;
+	*pos++ = (val >> 16) & 0xff;
+	*pos++ = (val >>  8) & 0xff;
+	*pos   =  val & 0xff;
+}
+
+float getFloat32(const uint8_t* pos){
+	union{
+		float flt;
+		uint8_t d[4];
+	}val;
+    val.d[3] = *pos++;
+	val.d[2] = *pos++;
+	val.d[1] = *pos++;
+	val.d[0] = *pos;
+	return val.flt;
+}
+
+void setFloat32(uint8_t* pos, float flt){
+	union{
+		float flt;
+		uint8_t d[4];
+	}val;
+	val.flt = flt;
+    *pos++ = val.d[3];
+    *pos++ = val.d[2];
+    *pos++ = val.d[1];
+    *pos   = val.d[0];
+}
+
+#else
+
+/*--- For Big endianness ---*/
+
+uint16_t getUint16(const uint8_t* pos){
+  uint16_t val = *pos++;
+  return val += ((uint16_t)*pos++ << 8);
+}
+
+void setUint16(uint8_t* pos, uint16_t val){
+	*pos++ =  val & 0xff;
+	*pos   = (val >>  8) & 0xff;
+}
+
+uint32_t getUint32(const uint8_t* pos){
+    long val = uint32_t(*(pos + 3)) << 24;
+    val += uint32_t(*(pos + 2)) << 16;
+	val += uint32_t(*(pos + 1)) <<  8;
+	return val += *pos;
+}
+
+void setUint32(uint8_t* pos, uint32_t val){
+    *pos++ =  val & 0xff;
+    *pos++ = (val >>  8) & 0xff;
+    *pos++ = (val >> 16) & 0xff;
+    *pos   = (val >> 24) & 0xff;
+}
+
+float getFloat32(const uint8_t* pos){
+	union{
+		float flt;
+		uint8_t d[4];
+	}val;
+
+    val.d[0] = *pos++;
+	val.d[1] = *pos++;
+	val.d[2] = *pos++;
+	val.d[3] = *pos;
+	return val.flt;
+}
+
+void setFloat32(uint8_t* pos, float flt){
+	union{
+		float flt;
+		uint8_t d[4];
+	}val;
+	val.flt = flt;
+    *pos++ = val.d[0];
+    *pos++ = val.d[1];
+    *pos++ = val.d[2];
+    *pos   = val.d[3];
+}
+
+#endif  // CPU_LITTLEENDIANN
+
+
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/README.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/README.md	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,112 @@
+# MQTT-SN Transparent / Aggrigating Gateway
+
+**MQTT-SN** requires a MQTT-SN Gateway which acts as a protocol converter to convert **MQTT-SN messages to MQTT messages**. MQTT-SN client over SensorNetwork can not communicate directly with MQTT broker(TCP/IP).   
+This Gateway can run as a transparent or aggrigating Gateway by specifying the gateway.conf.
+
+### **step1. Build the gateway**   
+````
+$ git clone -b experiment https://github.com/eclipse/paho.mqtt-sn.embedded-c   
+$ cd paho.mqtt-sn.embedded-c/MQTTSNGateway       
+$ make   
+$ make install   
+$ make clean    
+````      
+MQTT-SNGateway, MQTT-SNLogmonitor and *.conf files are copied into ../ directory.    
+If you want to install the gateway into specific directories, enter a command line as follows:
+````
+$ make install INSTALL_DIR=/path/to/your_directory CONFIG_DIR=/path/to/your_directory
+````
+
+    
+### **step2. Execute the Gateway.**     
+
+````    
+$ cd ../   
+$ ./MQTT-SNGateway [-f Config file name]
+````   
+
+
+### **How to Change the configuration of the gateway**    
+**../gateway.conf**   Contents are follows: 
+   
+<pre><dev>    
+
+# config file of MQTT-SN Gateway
+#
+
+BrokerName=iot.eclipse.org
+BrokerPortNo=1883
+BrokerSecurePortNo=8883
+
+#
+# When AggregatingGateway=YES or ClientAuthentication=YES,
+# All clients must be specified by the ClientList File  
+#
+
+ClientAuthentication=NO
+AggregatingGateway=NO
+QoS-1=NO
+Forwarder=NO
+
+#ClientsList=/path/to/your_clients.conf
+
+PredefinedTopic=NO
+#PredefinedTopicList=/path/to/your_predefinedTopic.conf
+
+#RootCAfile=/etc/ssl/certs/ca-certificates.crt
+#RootCApath=/etc/ssl/certs/
+#CertsFile=/path/to/certKey.pem
+#PrivateKey=/path/to/privateKey.pem
+
+GatewayID=1
+GatewayName=PahoGateway-01
+KeepAlive=900
+#LoginID=your_ID
+#Password=your_Password
+
+
+# UDP
+GatewayPortNo=10000
+MulticastIP=225.1.1.1
+MulticastPortNo=1883
+
+# XBee
+Baudrate=38400
+SerialDevice=/dev/ttyUSB0
+ApiMode=2
+
+# LOG
+ShearedMemory=NO;
+
+</dev></pre>    
+
+**BrokerName** to specify a domain name of the Broker, and **BrokerPortNo** is a port No of the Broker. **BrokerSecurePortNo** is for TLS connection.       
+**MulticastIP** and **MulticastPortNo** is a multicast address for GWSEARCH messages. Gateway is waiting GWSEARCH  and when receiving it send GWINFO message via MulticastIP address. Clients can get the gateway address (Gateway IP address and **GatewayPortNo**) from GWINFO message by means of std::recvfrom().
+Client should know the MulticastIP and MulticastPortNo to send a SEARCHGW message.    
+**GatewayId** is used by GWINFO message.    
+**KeepAlive** is a duration of ADVERTISE message in seconds.    
+when **AggregatingGateway** or **ClientAuthentication** is **YES**, All clients which connect to the gateway must be declared by a **ClientsList** file.       
+Format of the file is ClientId and SensorNetwork Address. e.g. IP address and Port No etc, in CSV. more detail see clients.conf.    
+When **QoS-1** is **YES**, QoS-1 PUBLISH is available. All clients which send QoS-1 PUBLISH must be specified by Client.conf file. 
+When **PredefinedTopic** is **YES**, **Pre-definedTopicId**s  specified by **PredefinedTopicList** are effective. This file defines Pre-definedTopics of the clients. In this file, ClientID,TopicName and TopicID are declared in CSV format.    
+When **Forwarder** is **YES**, Forwarder Encapsulation Message is available. Connectable Forwarders must be declared by a **ClientsList** file.     
+ 
+
+### ** How to monitor the gateway from remote. **
+
+Uncomment line32 in MQTTSNGWDefined.h.
+
+`//#define RINGBUFFER     // print out Packets log into shared memory./"`    
+````    
+$ make   
+$ make install 
+$ make clean
+````
+restart the gateway.    
+open ssh terminal and execute LogMonitor.
+
+`$ ./MQTT-SNLogmonitor`    
+
+Now you can get the Log on your terminal.
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/clients.conf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/clients.conf	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,47 @@
+#***********************************************************************
+# Copyright (c) 2016, Tomoaki Yamaguchi
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+# The Eclipse Public License is available at
+#    http://www.eclipse.org/legal/epl-v10.html
+# and the Eclipse Distribution License is available at
+#   http://www.eclipse.org/org/documents/edl-v10.php.
+#***********************************************************************
+#
+# File format is:
+#     Lines bigning with # are comment line.
+#     ClientId, SensorNetAddress, "unstableLine", "secureConnection"
+#     in case of UDP, SensorNetAddress format is portNo@IPAddress.
+#     if the SensorNetwork is not stable, write "unstableLine".
+#     if Broker's Connection is SSL, write "secureConnection".
+#     if the client is a forwarder, "forwarder" is required.
+#     if the client send PUBLISH QoS-1, "QoS-1" is required.
+#
+# Ex:
+#     #Client List
+#     ClientId1,11200@192.168.10.10
+#     ClientID2,35000@192.168.50.200,unstableLine
+#     ClientID3,40000@192.168.200.50,secureConnection
+#     ClientID4,41000@192.168.200.52,unstableLine,secureConnection
+#     ClientID5,41000@192.168.200.53,unstableLine,secureConnection,QoS-1 
+#     ClientID6,41000@192.168.200.54,unstableLine,secureConnection,forwarder
+#
+# SensorNetwork address format is defined by SensorNetAddress::setAddress(string* data) function.
+#
+GatewayTester, 172.16.1.11:20020
+ClientPUB,172.16.1.11:2010
+Client01,172.16.1.11:12001
+Client02,172.16.1.11:12002
+Client03,172.16.1.11:13003
+
+QoS-1_Client01,172.16.1.11:20001,QoS-1
+QoS-1_Client02,172.16.1.11:20002,QoS-1
+QoS-1_Client03,172.16.1.11:20003,QoS-1
+
+Forwarder01,172.16.1.11:22002,forwarder
+Forwarder02,172.16.1.11:22003,forwarder
+Forwarder03,172.16.1.11:22004,forwarder
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/gateway.conf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/gateway.conf	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,60 @@
+#**************************************************************************
+# Copyright (c) 2016-2018, Tomoaki Yamaguchi
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+# The Eclipse Public License is available at
+#    http://www.eclipse.org/legal/epl-v10.html
+# and the Eclipse Distribution License is available at
+#   http://www.eclipse.org/org/documents/edl-v10.php.
+#***************************************************************************
+#
+# config file of MQTT-SN Gateway
+#
+
+BrokerName=iot.eclipse.org
+BrokerPortNo=1883
+BrokerSecurePortNo=8883
+
+#
+# When AggregatingGateway=YES or ClientAuthentication=YES,
+# All clients must be specified by the ClientList File  
+#
+
+ClientAuthentication=NO
+AggregatingGateway=NO
+QoS-1=NO
+Forwarder=NO
+
+#ClientsList=/path/to/your_clients.conf
+
+PredefinedTopic=NO
+#PredefinedTopicList=/path/to/your_predefinedTopic.conf
+
+#RootCAfile=/etc/ssl/certs/ca-certificates.crt
+#RootCApath=/etc/ssl/certs/
+#CertsFile=/path/to/certKey.pem
+#PrivateKey=/path/to/privateKey.pem
+
+GatewayID=1
+GatewayName=PahoGateway-01
+KeepAlive=900
+#LoginID=your_ID
+#Password=your_Password
+
+
+# UDP
+GatewayPortNo=10000
+MulticastIP=225.1.1.1
+MulticastPortNo=1883
+
+# XBee
+Baudrate=38400
+SerialDevice=/dev/ttyUSB0
+ApiMode=2
+
+# LOG
+ShearedMemory=NO;
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/predefinedTopic.conf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/predefinedTopic.conf	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,36 @@
+#***********************************************************************
+# Copyright (c) 2017, Tomoaki Yamaguchi
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+# The Eclipse Public License is available at
+#    http://www.eclipse.org/legal/epl-v10.html
+# and the Eclipse Distribution License is available at
+#   http://www.eclipse.org/org/documents/edl-v10.php.
+#***********************************************************************
+#
+#  pre-defined-topics are defined by this file.
+#  A format of this file is in CSV as follows:
+#
+#     ClientID, TopicName, TopicID
+#
+#     Topics is common to all clients, ClientID should be *.
+
+#
+#  pre-defined-topics for Clients
+#
+
+*,ty4tw/predefinedTopic1, 1
+GatewayTestClient,ty4tw/predefinedTopic2, 2
+GatewayTestClient,ty4tw/predefinedTopic3, 3
+
+#
+#  pre-defined-topics for QoS-1 clients.
+# 
+
+
+QoS-1_Client03,ty4tw/proxy/predefTopic4, 1
+QoS-1_Client03,ty4tw/proxy/predefTopic5, 2
+QoS-1_Client03,ty4tw/proxy/predefTopic6, 3
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWConnectionHandler.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWConnectionHandler.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,99 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include "MQTTGWConnectionHandler.h"
+#include "MQTTGWPacket.h"
+
+using namespace std;
+using namespace MQTTSNGW;
+
+MQTTGWConnectionHandler::MQTTGWConnectionHandler(Gateway* gateway)
+{
+	_gateway = gateway;
+}
+
+MQTTGWConnectionHandler::~MQTTGWConnectionHandler()
+{
+
+}
+
+void MQTTGWConnectionHandler::handleConnack(Client* client, MQTTGWPacket* packet)
+{
+	uint8_t rc = MQTT_SERVER_UNAVAILABLE;
+	Connack resp;
+	packet->getCONNACK(&resp);
+
+	/* convert MQTT ReturnCode to MQTT-SN one */
+	if (resp.rc == MQTT_CONNECTION_ACCEPTED)
+	{
+		rc = MQTTSN_RC_ACCEPTED;
+	}
+	else if (resp.rc == MQTT_UNACCEPTABLE_PROTOCOL_VERSION)
+	{
+		rc = MQTTSN_RC_NOT_SUPPORTED;
+		WRITELOG(" ClientID : %s Requested Protocol version is not supported.\n", client->getClientId());
+	}
+	else if (resp.rc == MQTT_IDENTIFIER_REJECTED)
+	{
+		rc = MQTTSN_RC_NOT_SUPPORTED;
+		WRITELOG(" ClientID : %s ClientID is collect UTF-8 but not allowed by the Server.\n",
+				client->getClientId());
+	}
+	else if (resp.rc == MQTT_SERVER_UNAVAILABLE)
+	{
+		rc = MQTTSN_RC_REJECTED_CONGESTED;
+		WRITELOG(" ClientID : %s The Network Connection has been made but the MQTT service is unavailable.\n",
+				client->getClientId());
+	}
+	else if (resp.rc == MQTT_BAD_USERNAME_OR_PASSWORD)
+	{
+		rc = MQTTSN_RC_NOT_SUPPORTED;
+		WRITELOG(" Gateway Configuration Error: The data in the user name or password is malformed.\n");
+	}
+	else if (resp.rc == MQTT_NOT_AUTHORIZED)
+	{
+		rc = MQTTSN_RC_NOT_SUPPORTED;
+		WRITELOG(" Gateway Configuration Error: The Client is not authorized to connect.\n");
+	}
+
+	MQTTSNPacket* snPacket = new MQTTSNPacket();
+	snPacket->setCONNACK(rc);
+
+	Event* ev1 = new Event();
+	ev1->setClientSendEvent(client, snPacket);
+	client->connackSended(rc);  // update the client's status
+	_gateway->getClientSendQue()->post(ev1);
+}
+
+void MQTTGWConnectionHandler::handlePingresp(Client* client, MQTTGWPacket* packet)
+{
+	MQTTSNPacket* snPacket = new MQTTSNPacket();
+	snPacket->setPINGRESP();
+	Event* ev1 = new Event();
+	ev1->setClientSendEvent(client, snPacket);
+	client->updateStatus(snPacket);
+	_gateway->getClientSendQue()->post(ev1);
+}
+
+void MQTTGWConnectionHandler::handleDisconnect(Client* client, MQTTGWPacket* packet)
+{
+		MQTTSNPacket* snPacket = new MQTTSNPacket();
+		snPacket->setDISCONNECT(0);
+		client->disconnected();
+		client->getNetwork()->close();
+		Event* ev1 = new Event();
+		ev1->setClientSendEvent(client, snPacket);
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWConnectionHandler.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWConnectionHandler.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,39 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#ifndef MQTTGWCONNECTIONHANDLER_H_
+#define MQTTGWCONNECTIONHANDLER_H_
+
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGWPacket.h"
+#include "MQTTSNGateway.h"
+
+namespace MQTTSNGW
+{
+
+class MQTTGWConnectionHandler
+{
+public:
+	MQTTGWConnectionHandler(Gateway* gateway);
+	~MQTTGWConnectionHandler();
+	void handleConnack(Client* client, MQTTGWPacket* packet);
+	void handlePingresp(Client* client, MQTTGWPacket* packet);
+	void handleDisconnect(Client* client, MQTTGWPacket* packet);
+private:
+	Gateway* _gateway;
+};
+
+}
+#endif /* MQTTGWCONNECTIONHANDLER_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWPacket.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWPacket.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,645 @@
+/**************************************************************************************
+ * Copyright (c) 2009, 2014 IBM Corp. Tomoaki YAMAGUCHI
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Tomoaki Yamaguchi - modify codes for MATT-SN Gateway
+ **************************************************************************************/
+
+#include "MQTTGWPacket.h"
+#include <string>
+#include <string.h>
+
+using namespace MQTTSNGW;
+
+int readInt(char** ptr);
+void writeInt(unsigned char** pptr, int msgId);
+
+#define MAX_NO_OF_REMAINING_LENGTH_BYTES    3
+/**
+ * List of the predefined MQTT v3 packet names.
+ */
+static const char* mqtt_packet_names[] =
+{ "RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL", "PUBCOMP", "SUBSCRIBE", "SUBACK",
+		"UNSUBSCRIBE", "UNSUBACK", "PINGREQ", "PINGRESP", "DISCONNECT" };
+
+/**
+ * Encodes the message length according to the MQTT algorithm
+ * @param buf the buffer into which the encoded data is written
+ * @param length the length to be encoded
+ * @return the number of bytes written to buffer
+ */
+int MQTTPacket_encode(char* buf, int length)
+{
+	int rc = 0;
+	do
+	{
+		char d = length % 128;
+		length /= 128;
+		/* if there are more digits to encode, set the top bit of this digit */
+		if (length > 0)
+			d |= 0x80;
+		buf[rc++] = d;
+	} while (length > 0);
+	return rc;
+}
+
+/**
+ * Calculates an integer from two bytes read from the input buffer
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the integer value calculated
+ */
+int readInt(char** pptr)
+{
+	char* ptr = *pptr;
+	int len = 256 * ((unsigned char) (*ptr)) + (unsigned char) (*(ptr + 1));
+	*pptr += 2;
+	return len;
+}
+
+/**
+ * Reads a "UTF" string from the input buffer.  UTF as in the MQTT v3 spec which really means
+ * a length delimited string.  So it reads the two byte length then the data according to
+ * that length.  The end of the buffer is provided too, so we can prevent buffer overruns caused
+ * by an incorrect length.
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @param enddata pointer to the end of the buffer not to be read beyond
+ * @param len returns the calculcated value of the length bytes read
+ * @return an allocated C string holding the characters read, or NULL if the length read would
+ * have caused an overrun.
+ *
+ */
+char* readUTFlen(char** pptr, char* enddata, int* len)
+{
+	char* string = NULL;
+
+	if (enddata - (*pptr) > 1) /* enough length to read the integer? */
+	{
+		*len = readInt(pptr);
+		if (&(*pptr)[*len] <= enddata)
+		{
+			string = (char*)calloc(*len + 1, 1);
+			memcpy(string, *pptr, (size_t)*len);
+			string[*len] = '\0';
+			*pptr += *len;
+		}
+	}
+	return string;
+}
+
+/**
+ * Reads a "UTF" string from the input buffer.  UTF as in the MQTT v3 spec which really means
+ * a length delimited string.  So it reads the two byte length then the data according to
+ * that length.  The end of the buffer is provided too, so we can prevent buffer overruns caused
+ * by an incorrect length.
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @param enddata pointer to the end of the buffer not to be read beyond
+ * @return an allocated C string holding the characters read, or NULL if the length read would
+ * have caused an overrun.
+ */
+char* readUTF(char** pptr, char* enddata)
+{
+	int len;
+	return readUTFlen(pptr, enddata, &len);
+}
+
+/**
+ * Reads one character from the input buffer.
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the character read
+ */
+unsigned char readChar(char** pptr)
+{
+	unsigned char c = **pptr;
+	(*pptr)++;
+	return c;
+}
+
+/**
+ * Writes one character to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param c the character to write
+ */
+void writeChar(unsigned char** pptr, char c)
+{
+	**pptr = c;
+	(*pptr)++;
+}
+
+/**
+ * Writes an integer as 2 bytes to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param anInt the integer to write
+ */
+void writeInt(unsigned char** pptr, int anInt)
+{
+	**pptr = (unsigned char)(anInt / 256);
+	(*pptr)++;
+	**pptr = (unsigned char)(anInt % 256);
+	(*pptr)++;
+}
+
+/**
+ * Writes a "UTF" string to an output buffer.  Converts C string to length-delimited.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param string the C string to write
+ */
+void writeUTF(unsigned char** pptr, const char* string)
+{
+	int len = (int)strlen(string);
+	writeInt(pptr, len);
+	memcpy(*pptr, string, (size_t)len);
+	*pptr += len;
+}
+
+/**
+ * Lapper class of MQTTPacket
+ *
+ */
+MQTTGWPacket::MQTTGWPacket()
+{
+	_data = 0;
+	_header.byte = 0;
+	_remainingLength = 0;
+}
+
+MQTTGWPacket::~MQTTGWPacket()
+{
+	if (_data)
+	{
+		free(_data);
+	}
+}
+
+int MQTTGWPacket::recv(Network* network)
+{
+	int len = 0;
+	int multiplier = 1;
+	unsigned char c;
+
+	/* read First Byte of Packet */
+	int rc = network->recv((unsigned char*)&_header.byte, 1);
+	if ( rc <= 0)
+	{
+		return rc;
+	}
+	/* read RemainingLength */
+	do
+	{
+		if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
+		{
+			return -2;
+		}
+		if (network->recv(&c, 1) == -1)
+		{
+			return -1;
+		}
+		_remainingLength += (c & 127) * multiplier;
+		multiplier *= 128;
+	} while ((c & 128) != 0);
+
+	if ( _remainingLength > 0 )
+	{
+		/* allocate buffer */
+		_data = (unsigned char*)calloc(_remainingLength, 1);
+		if ( !_data )
+		{
+			return -3;
+		}
+
+		/* read Payload */
+		int remlen = network->recv(_data, _remainingLength);
+
+		if (remlen == -1 )
+		{
+			return -1;
+		}
+		else if ( remlen != _remainingLength )
+		{
+			return -2;
+		}
+	}
+	return 1 + len + _remainingLength;
+}
+
+int MQTTGWPacket::send(Network* network)
+{
+	unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE];
+	memset(buf, 0, MQTTSNGW_MAX_PACKET_SIZE);
+	int len = getPacketData(buf);
+	return network->send(buf, len);
+
+}
+
+int MQTTGWPacket::getAck(Ack* ack)
+{
+	if (PUBACK != _header.bits.type && PUBREC != _header.bits.type && PUBREL != _header.bits.type
+			&& PUBCOMP != _header.bits.type && UNSUBACK != _header.bits.type)
+	{
+		return 0;
+	}
+	char* ptr = (char*) _data;
+	ack->header.byte = _header.byte;
+	ack->msgId = readInt((char**) &ptr);
+	return 1;
+}
+
+int MQTTGWPacket::getCONNACK(Connack* resp)
+{
+	if (_header.bits.type != CONNACK)
+	{
+		return 0;
+	}
+	char* ptr = (char*) _data;
+	resp->header.byte = _header.byte;
+	resp->flags.all = *ptr++;
+	resp->rc = readChar(&ptr);
+	return 1;
+}
+
+int MQTTGWPacket::getSUBACK(unsigned short* msgId, unsigned char* rc)
+{
+	if (_header.bits.type != SUBACK)
+	{
+		return 0;
+	}
+	char *ptr = (char*) _data;
+	*msgId = readInt((char**) &ptr);
+	*rc = readChar(&ptr);
+	return 1;
+}
+
+int MQTTGWPacket::getPUBLISH(Publish* pub)
+{
+	if (_header.bits.type != PUBLISH)
+	{
+		return 0;
+	}
+	char* ptr = (char*) _data;
+	pub->header = _header;
+	pub->topiclen = readInt((char**) &ptr);
+	pub->topic = (char*) _data + 2;
+	ptr += pub->topiclen;
+	if (_header.bits.qos > 0)
+	{
+		pub->msgId = readInt(&ptr);
+		pub->payloadlen = _remainingLength - pub->topiclen - 4;
+	}
+	else
+	{
+		pub->msgId = 0;
+		pub->payloadlen = _remainingLength - pub->topiclen - 2;
+	}
+	pub->payload = ptr;
+	return 1;
+}
+
+int MQTTGWPacket::setCONNECT(Connect* connect, unsigned char* username, unsigned char* password)
+{
+	clearData();
+	_header = connect->header;
+
+	_remainingLength = ((connect->version == 3) ? 12 : 10) + (int)strlen(connect->clientID) + 2;
+	if (connect->flags.bits.will)
+	{
+		_remainingLength += (int)strlen(connect->willTopic) + 2 + (int)strlen(connect->willMsg) + 2;
+	}
+	if ( connect->flags.bits.username )
+	{
+		_remainingLength += (int)strlen((char*) username) + 2;
+	}
+	if (connect->flags.bits.password)
+	{
+		_remainingLength += (int)strlen((char*) password) + 2;
+	}
+
+	_data = (unsigned char*)calloc(_remainingLength, 1);
+	unsigned char* ptr = _data;
+
+	if (connect->version == 3)
+	{
+		writeUTF(&ptr, "MQIsdp");
+		writeChar(&ptr, (char) 3);
+	}
+	else if (connect->version == 4)
+	{
+		writeUTF(&ptr, "MQTT");
+		writeChar(&ptr, (char) 4);
+	}
+	else
+	{
+		return 0;
+	}
+
+	writeChar(&ptr, connect->flags.all);
+	writeInt(&ptr, connect->keepAliveTimer);
+	writeUTF(&ptr, connect->clientID);
+	if (connect->flags.bits.will)
+	{
+		writeUTF(&ptr, connect->willTopic);
+		writeUTF(&ptr, connect->willMsg);
+	}
+
+	if (connect->flags.bits.username)
+	{
+		writeUTF(&ptr, (const char*) username);
+	}
+	if (connect->flags.bits.password)
+	{
+		writeUTF(&ptr, (const char*) password);
+	}
+	return 1;
+}
+
+int MQTTGWPacket::setSUBSCRIBE(const char* topic, unsigned char qos, unsigned short msgId)
+{
+	clearData();
+	_header.byte = 0;
+	_header.bits.type = SUBSCRIBE;
+	_header.bits.qos = 1;          // Reserved
+	_remainingLength = (int)strlen(topic) + 5;
+	_data = (unsigned char*)calloc(_remainingLength, 1);
+	if (_data)
+	{
+		unsigned char* ptr = _data;
+		writeInt(&ptr, msgId);
+		writeUTF(&ptr, topic);
+		writeChar(&ptr, (char) qos);
+		return 1;
+	}
+	clearData();
+	return 0;
+}
+
+int MQTTGWPacket::setUNSUBSCRIBE(const char* topic, unsigned short msgid)
+{
+	clearData();
+	_header.byte = 0;
+	_header.bits.type = UNSUBSCRIBE;
+	_header.bits.qos = 1;
+	_remainingLength = (int)strlen(topic) + 4;
+	_data = (unsigned char*)calloc(_remainingLength, 1);
+	if (_data)
+	{
+		unsigned char* ptr = _data;
+		writeInt(&ptr, msgid);
+		writeUTF(&ptr, topic);
+		return 1;
+	}
+	clearData();
+	return 0;
+
+}
+
+int MQTTGWPacket::setPUBLISH(Publish* pub)
+{
+	clearData();
+	_header.byte = pub->header.byte;
+	_header.bits.type = PUBLISH;
+	_remainingLength = 4 + pub->topiclen + pub->payloadlen;
+	_data = (unsigned char*)calloc(_remainingLength, 1);
+	if (_data)
+	{
+		unsigned char* ptr = _data;
+		writeInt(&ptr, pub->topiclen);
+		memcpy(ptr, pub->topic, pub->topiclen);
+		ptr += pub->topiclen;
+		if ( _header.bits.qos > 0 )
+		{
+			writeInt(&ptr, pub->msgId);
+		}
+		else
+		{
+			_remainingLength -= 2;
+		}
+		memcpy(ptr, pub->payload, pub->payloadlen);
+		return 1;
+	}
+	else
+	{
+		clearData();
+		return 0;
+	}
+}
+
+int MQTTGWPacket::setAck(unsigned char msgType, unsigned short msgid)
+{
+	clearData();
+	_remainingLength = 2;
+	_header.bits.type = msgType;
+	_header.bits.qos = (msgType == PUBREL) ? 1 : 0;
+
+	_data = (unsigned char*)calloc(_remainingLength, 1);
+	if (_data)
+	{
+		unsigned char* data = _data;
+		writeInt(&data, msgid);
+		return 1;
+	}
+	return 0;
+}
+
+int MQTTGWPacket::setHeader(unsigned char msgType)
+{
+	clearData();
+	if (msgType < CONNECT || msgType > DISCONNECT)
+	{
+		return 0;
+	}
+	_header.bits.type = msgType;
+	return 0;
+}
+
+int MQTTGWPacket::getType(void)
+{
+	return _header.bits.type;
+}
+
+const char* MQTTGWPacket::getName(void)
+{
+	return getType() > DISCONNECT ? "UNKNOWN" : mqtt_packet_names[getType()];
+}
+
+int MQTTGWPacket::getPacketData(unsigned char* buf)
+{
+	unsigned char* ptr = buf;
+	*ptr++ = _header.byte;
+	int len = MQTTPacket_encode((char*)ptr, _remainingLength);
+	ptr += len;
+	memcpy(ptr, _data, _remainingLength);
+	return 1 + len + _remainingLength;
+}
+
+int MQTTGWPacket::getPacketLength(void)
+{
+	char buf[4];
+	return 1 + MQTTPacket_encode(buf, _remainingLength) + _remainingLength;
+}
+
+void MQTTGWPacket::clearData(void)
+{
+	if (_data)
+	{
+		free(_data);
+	}
+	_header.byte = 0;
+	_remainingLength = 0;
+}
+
+char* MQTTGWPacket::getMsgId(char* pbuf)
+{
+	int type = getType();
+
+	switch ( type )
+	{
+	case PUBLISH:
+		Publish pub;
+		pub.msgId = 0;
+		getPUBLISH(&pub);
+		if ( _header.bits.dup )
+		{
+			sprintf(pbuf, "+%04X", pub.msgId);
+		}
+		else
+		{
+			sprintf(pbuf, " %04X", pub.msgId);
+		}
+		break;
+	case SUBSCRIBE:
+	case UNSUBSCRIBE:
+	case PUBACK:
+	case PUBREC:
+	case PUBREL:
+	case PUBCOMP:
+	case SUBACK:
+	case UNSUBACK:
+		sprintf(pbuf, " %02X%02X", _data[0], _data[1]);
+		break;
+	default:
+		sprintf(pbuf, "    ");
+		break;
+	}
+	if ( strcmp(pbuf, " 0000") == 0 )
+	{
+		sprintf(pbuf, "    ");
+	}
+	return pbuf;
+}
+
+int MQTTGWPacket::getMsgId(void)
+{
+	int type = getType();
+	int msgId = 0;
+
+	switch ( type )
+	{
+	case PUBLISH:
+		Publish pub;
+		pub.msgId = 0;
+		getPUBLISH(&pub);
+		msgId = pub.msgId;
+		break;
+	case PUBACK:
+	case PUBREC:
+	case PUBREL:
+	case PUBCOMP:
+	case SUBSCRIBE:
+	case UNSUBSCRIBE:
+	case SUBACK:
+	case UNSUBACK:
+		msgId = 256 * (unsigned char)_data[0] + (unsigned char)_data[1];
+		break;
+	default:
+		break;
+	}
+	return msgId;
+}
+
+void MQTTGWPacket::setMsgId(int msgId)
+{
+	int type = getType();
+	unsigned char* ptr = 0;
+
+	switch ( type )
+	{
+	case PUBLISH:
+		Publish pub;
+		pub.topiclen = 0;
+		pub.msgId = 0;
+		getPUBLISH(&pub);
+		pub.msgId = msgId;
+		ptr = _data + pub.topiclen;
+		writeInt(&ptr, pub.msgId);
+		*ptr++ = (unsigned char)(msgId / 256);
+		*ptr = (unsigned char)(msgId % 256);
+		break;
+	case SUBSCRIBE:
+	case UNSUBSCRIBE:
+	case PUBACK:
+	case PUBREC:
+	case PUBREL:
+	case PUBCOMP:
+	case SUBACK:
+	case UNSUBACK:
+		ptr = _data;
+		*ptr++ = (unsigned char)(msgId / 256);
+		*ptr = (unsigned char)(msgId % 256);
+		break;
+	default:
+		break;
+	}
+}
+
+char* MQTTGWPacket::print(char* pbuf)
+{
+	uint8_t packetData[MQTTSNGW_MAX_PACKET_SIZE];
+	char* ptr = pbuf;
+	char** pptr = &pbuf;
+	int len = getPacketData(packetData);
+	int size = len > SIZE_OF_LOG_PACKET ? SIZE_OF_LOG_PACKET : len;
+	for (int i = 0; i < size; i++)
+	{
+		sprintf(*pptr, " %02X", packetData[i]);
+		*pptr += 3;
+	}
+	**pptr = 0;
+	return ptr;
+}
+
+MQTTGWPacket& MQTTGWPacket::operator =(MQTTGWPacket& packet)
+{
+	clearData();
+	this->_header.byte = packet._header.byte;
+	this->_remainingLength = packet._remainingLength;
+	_data = (unsigned char*)calloc(_remainingLength, 1);
+	if (_data)
+	{
+		memcpy(this->_data, packet._data, _remainingLength);
+	}
+	else
+	{
+		clearData();
+	}
+	return *this;
+}
+
+UTF8String MQTTGWPacket::getTopic(void)
+{
+	UTF8String str = {0, nullptr};
+	if ( _header.bits.type == SUBSCRIBE || _header.bits.type == UNSUBSCRIBE )
+	{
+		char* ptr = (char*)(_data + 2);
+		str.len = readInt(&ptr);
+		str.data = (char*)(_data + 4);
+	}
+	return str;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWPacket.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWPacket.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,240 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Ian Craggs, Allan Stockdill-Mander - SSL updates
+ *    Ian Craggs - MQTT 3.1.1 support
+ *    Tomoaki Yamaguchi - modify codes for MATT-SN Gateway
+ *******************************************************************************/
+
+#ifndef MQTTGWPACKET_H_
+#define MQTTGWPACKET_H_
+
+#include "Network.h"
+
+namespace MQTTSNGW
+{
+
+typedef void* (*pf)(unsigned char, char*, size_t);
+
+#define BAD_MQTT_PACKET -4
+
+enum msgTypes
+{
+	CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL,
+	PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK,
+	PINGREQ, PINGRESP, DISCONNECT
+};
+
+
+/**
+ * Bitfields for the MQTT header byte.
+ */
+typedef union
+{
+	/*unsigned*/ char byte;	/**< the whole byte */
+#if defined(REVERSED)
+	struct
+	{
+		unsigned int type : 4;	/**< message type nibble */
+		bool dup : 1;			/**< DUP flag bit */
+		unsigned int qos : 2;	/**< QoS value, 0, 1 or 2 */
+		bool retain : 1;		/**< retained flag bit */
+	} bits;
+#else
+	struct
+	{
+		bool retain : 1;		/**< retained flag bit */
+		unsigned int qos : 2;	/**< QoS value, 0, 1 or 2 */
+		bool dup : 1;			/**< DUP flag bit */
+		unsigned int type : 4;	/**< message type nibble */
+	} bits;
+#endif
+} Header;
+
+
+/**
+ * Data for a connect packet.
+ */
+
+enum MQTT_connackCodes{
+	MQTT_CONNECTION_ACCEPTED ,
+	MQTT_UNACCEPTABLE_PROTOCOL_VERSION,
+	MQTT_IDENTIFIER_REJECTED,
+	MQTT_SERVER_UNAVAILABLE,
+	MQTT_BAD_USERNAME_OR_PASSWORD,
+	MQTT_NOT_AUTHORIZED
+};
+
+typedef struct
+{
+	Header header;	/**< MQTT header byte */
+	union
+	{
+		unsigned char all;	/**< all connect flags */
+#if defined(REVERSED)
+		struct
+		{
+			bool username : 1;			/**< 3.1 user name */
+			bool password : 1; 			/**< 3.1 password */
+			bool willRetain : 1;		/**< will retain setting */
+			unsigned int willQoS : 2;	/**< will QoS value */
+			bool will : 1;			/**< will flag */
+			bool cleanstart : 1;	/**< cleansession flag */
+			int : 1;	/**< unused */
+		} bits;
+#else
+		struct
+		{
+			int : 1;	/**< unused */
+			bool cleanstart : 1;	/**< cleansession flag */
+			bool will : 1;			/**< will flag */
+			unsigned int willQoS : 2;	/**< will QoS value */
+			bool willRetain : 1;		/**< will retain setting */
+			bool password : 1; 			/**< 3.1 password */
+			bool username : 1;			/**< 3.1 user name */
+		} bits;
+#endif
+	} flags;	/**< connect flags byte */
+
+	char *Protocol, /**< MQTT protocol name */
+		*clientID,	/**< string client id */
+        *willTopic,	/**< will topic */
+        *willMsg;	/**< will payload */
+
+	int keepAliveTimer;		/**< keepalive timeout value in seconds */
+	unsigned char version;	/**< MQTT version number */
+} Connect;
+
+#define MQTTPacket_Connect_Initializer {{0}, 0, nullptr, nullptr, nullptr, nullptr, 0, 0}
+#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 }
+#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \
+        MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} }
+
+
+
+/**
+ * Data for a willMessage.
+ */
+typedef struct
+{
+	char* topic;
+	char* msg;
+	int retained;
+	int qos;
+}willMessages;
+
+/**
+ * Data for a connack packet.
+ */
+typedef struct
+{
+	Header header; /**< MQTT header byte */
+	union
+	{
+		unsigned char all;	/**< all connack flags */
+#if defined(REVERSED)
+		struct
+		{
+			unsigned int reserved : 7;	/**< message type nibble */
+			bool sessionPresent : 1;    /**< was a session found on the server? */
+		} bits;
+#else
+		struct
+		{
+			bool sessionPresent : 1;    /**< was a session found on the server? */
+			unsigned int reserved : 7;	/**< message type nibble */
+		} bits;
+#endif
+	} flags;	 /**< connack flags byte */
+	char rc; /**< connack return code */
+} Connack;
+
+
+/**
+ * Data for a publish packet.
+ */
+typedef struct
+{
+	Header header;	/**< MQTT header byte */
+	char* topic;	/**< topic string */
+	int topiclen;
+	int msgId;		/**< MQTT message id */
+	char* payload;	/**< binary payload, length delimited */
+	int payloadlen;	/**< payload length */
+} Publish;
+
+#define MQTTPacket_Publish_Initializer {{0}, nullptr, 0, 0, nullptr, 0}
+
+/**
+ * Data for one of the ack packets.
+ */
+typedef struct
+{
+	Header header;	/**< MQTT header byte */
+	int msgId;		/**< MQTT message id */
+} Ack;
+
+/**
+ * UTF8String.
+ */
+typedef struct
+{
+	unsigned char len;
+	char*  data;
+} UTF8String;
+
+/**
+ * Class MQTT Packet
+ */
+class MQTTGWPacket
+{
+public:
+	MQTTGWPacket();
+	~MQTTGWPacket();
+	int recv(Network* network);
+	int send(Network* network);
+	int getType(void);
+	int getPacketData(unsigned char* buf);
+	int getPacketLength(void);
+	const char* getName(void);
+
+	int getAck(Ack* ack);
+	int getCONNACK(Connack* resp);
+	int getSUBACK(unsigned short* msgId, unsigned char* rc);
+	int getPUBLISH(Publish* pub);
+
+	int setCONNECT(Connect* conect, unsigned char* username, unsigned char* password);
+	int setPUBLISH(Publish* pub);
+	int setAck(unsigned char msgType, unsigned short msgid);
+	int setHeader(unsigned char msgType);
+	int setSUBSCRIBE(const char* topic, unsigned char qos, unsigned short msgId);
+	int setUNSUBSCRIBE(const char* topics, unsigned short msgid);
+
+	UTF8String getTopic(void);
+	char* getMsgId(char* buf);
+	int getMsgId(void);
+	void setMsgId(int msgId);
+	char* print(char* buf);
+	MQTTGWPacket& operator =(MQTTGWPacket& packet);
+
+private:
+	void  clearData(void);
+	Header	 _header;
+	int _remainingLength;
+	unsigned char* _data;
+};
+
+}
+
+#endif /* MQTTGWPACKET_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWPublishHandler.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWPublishHandler.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,323 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ *    Tieto Poland Sp. z o.o. - Gateway improvements
+ **************************************************************************************/
+
+#include "MQTTGWPublishHandler.h"
+#include "MQTTSNGateway.h"
+#include "MQTTSNPacket.h"
+#include <string>
+
+using namespace std;
+using namespace MQTTSNGW;
+
+char* currentDateTime(void);
+
+MQTTGWPublishHandler::MQTTGWPublishHandler(Gateway* gateway)
+{
+	_gateway = gateway;
+}
+
+MQTTGWPublishHandler::~MQTTGWPublishHandler()
+{
+
+}
+
+void MQTTGWPublishHandler::handlePublish(Client* client, MQTTGWPacket* packet)
+{
+	if ( !client->isActive() && !client->isSleep() && !client->isAwake())
+	{
+		WRITELOG("%s     The client is neither active nor sleep %s%s\n", ERRMSG_HEADER, client->getStatus(), ERRMSG_FOOTER);
+		return;
+	}
+
+	/* client is sleeping. save PUBLISH */
+	if ( client->isSleep() )
+	{
+		Publish pub;
+		packet->getPUBLISH(&pub);
+
+		WRITELOG(FORMAT_Y_G_G, currentDateTime(), packet->getName(),
+		RIGHTARROW, client->getClientId(), "is sleeping. a message was saved.");
+
+		if (pub.header.bits.qos == 1)
+		{
+			replyACK(client, &pub, PUBACK);
+		}
+		else if ( pub.header.bits.qos == 2)
+		{
+			replyACK(client, &pub, PUBREC);
+		}
+
+		MQTTGWPacket* msg = new MQTTGWPacket();
+		*msg = *packet;
+		if ( msg->getType() == 0 )
+		{
+			WRITELOG("%s MQTTGWPublishHandler::handlePublish can't allocate memories for Packet.%s\n", ERRMSG_HEADER,ERRMSG_FOOTER);
+			delete msg;
+			return;
+		}
+		client->setClientSleepPacket(msg);
+		return;
+	}
+
+	Publish pub;
+	packet->getPUBLISH(&pub);
+
+	MQTTSNPacket* snPacket = new MQTTSNPacket();
+
+	/* create MQTTSN_topicid */
+	MQTTSN_topicid topicId;
+	uint16_t id = 0;
+
+	if (pub.topiclen <= 2)
+	{
+		topicId.type = MQTTSN_TOPIC_TYPE_SHORT;
+		*(topicId.data.short_name) = *pub.topic;
+		*(topicId.data.short_name + 1) = *(pub.topic + 1);
+	}
+	else
+	{
+        topicId.data.long_.len = pub.topiclen;
+        topicId.data.long_.name = pub.topic;
+        Topic* tp = client->getTopics()->getTopicByName(&topicId);
+
+        if ( tp )
+        {
+            topicId.type = tp->getType();
+            topicId.data.long_.len = pub.topiclen;
+            topicId.data.long_.name = pub.topic;
+            topicId.data.id = tp->getTopicId();
+        }
+		else
+		{
+			/* This message might be subscribed with wild card. */
+		    topicId.type = MQTTSN_TOPIC_TYPE_NORMAL;
+			Topic* topic = client->getTopics()->match(&topicId);
+			if (topic == nullptr)
+			{
+				WRITELOG(" Invalid Topic. PUBLISH message is canceled.\n");
+				if (pub.header.bits.qos == 1)
+				{
+					replyACK(client, &pub, PUBACK);
+				}
+				else if ( pub.header.bits.qos == 2 )
+				{
+					replyACK(client, &pub, PUBREC);
+				}
+
+				delete snPacket;
+				return;
+			}
+
+			/* add the Topic and get a TopicId */
+			topic = client->getTopics()->add(&topicId);
+			id = topic->getTopicId();
+
+			if (id > 0)
+			{
+				/* create REGISTER */
+				MQTTSNPacket* regPacket = new MQTTSNPacket();
+
+				MQTTSNString topicName = MQTTSNString_initializer;
+				topicName.lenstring.len = topicId.data.long_.len;
+				topicName.lenstring.data = topicId.data.long_.name;
+
+				uint16_t regackMsgId = client->getNextSnMsgId();
+				regPacket->setREGISTER(id, regackMsgId, &topicName);
+
+				/* send REGISTER */
+				Event* evrg = new Event();
+				evrg->setClientSendEvent(client, regPacket);
+				_gateway->getClientSendQue()->post(evrg);
+
+				/* send PUBLISH */
+				topicId.data.id = id;
+				snPacket->setPUBLISH((uint8_t) pub.header.bits.dup, (int) pub.header.bits.qos,
+						(uint8_t) pub.header.bits.retain, (uint16_t) pub.msgId, topicId, (uint8_t*) pub.payload,
+						pub.payloadlen);
+				client->getWaitREGACKPacketList()->setPacket(snPacket, regackMsgId);
+				return;
+			}
+			else
+			{
+				WRITELOG("%sMQTTGWPublishHandler Can't create a Topic.%s\n", ERRMSG_HEADER,ERRMSG_FOOTER);
+				delete snPacket;
+				return;
+			}
+		}
+	}
+
+	snPacket->setPUBLISH((uint8_t) pub.header.bits.dup, (int) pub.header.bits.qos, (uint8_t) pub.header.bits.retain,
+			(uint16_t) pub.msgId, topicId, (uint8_t*) pub.payload, pub.payloadlen);
+	Event* ev1 = new Event();
+	ev1->setClientSendEvent(client, snPacket);
+	_gateway->getClientSendQue()->post(ev1);
+
+}
+
+void MQTTGWPublishHandler::replyACK(Client* client, Publish* pub, int type)
+{
+	MQTTGWPacket* pubAck = new MQTTGWPacket();
+	pubAck->setAck(type, (uint16_t)pub->msgId);
+	Event* ev1 = new Event();
+	ev1->setBrokerSendEvent(client, pubAck);
+	_gateway->getBrokerSendQue()->post(ev1);
+}
+
+void MQTTGWPublishHandler::handlePuback(Client* client, MQTTGWPacket* packet)
+{
+	Ack ack;
+	packet->getAck(&ack);
+	TopicIdMapElement* topicId = client->getWaitedPubTopicId((uint16_t)ack.msgId);
+	if (topicId)
+	{
+		MQTTSNPacket* mqttsnPacket = new MQTTSNPacket();
+		mqttsnPacket->setPUBACK(topicId->getTopicId(), (uint16_t)ack.msgId, 0);
+
+		client->eraseWaitedPubTopicId((uint16_t)ack.msgId);
+		Event* ev1 = new Event();
+		ev1->setClientSendEvent(client, mqttsnPacket);
+		_gateway->getClientSendQue()->post(ev1);
+		return;
+	}
+	WRITELOG(" PUBACK from the Broker is invalid. PacketID : %04X  ClientID : %s \n", (uint16_t)ack.msgId, client->getClientId());
+}
+
+void MQTTGWPublishHandler::handleAck(Client* client, MQTTGWPacket* packet, int type)
+{
+	Ack ack;
+	packet->getAck(&ack);
+
+	if ( client->isActive() || client->isAwake() )
+	{
+		MQTTSNPacket* mqttsnPacket = new MQTTSNPacket();
+		if (type == PUBREC)
+		{
+			mqttsnPacket->setPUBREC((uint16_t) ack.msgId);
+		}
+		else if (type == PUBREL)
+		{
+			mqttsnPacket->setPUBREL((uint16_t) ack.msgId);
+		}
+		else if (type == PUBCOMP)
+		{
+			mqttsnPacket->setPUBCOMP((uint16_t) ack.msgId);
+		}
+
+		Event* ev1 = new Event();
+		ev1->setClientSendEvent(client, mqttsnPacket);
+		_gateway->getClientSendQue()->post(ev1);
+	}
+	else if ( client->isSleep() )
+	{
+		if (type == PUBREL)
+		{
+			MQTTGWPacket* pubComp = new MQTTGWPacket();
+			pubComp->setAck(PUBCOMP, (uint16_t)ack.msgId);
+			Event* ev1 = new Event();
+			ev1->setBrokerSendEvent(client, pubComp);
+			_gateway->getBrokerSendQue()->post(ev1);
+		}
+	}
+}
+
+
+
+void MQTTGWPublishHandler::handleAggregatePuback(Client* client, MQTTGWPacket* packet)
+{
+	uint16_t msgId = packet->getMsgId();
+	uint16_t clientMsgId = 0;
+	Client* newClient = _gateway->getAdapterManager()->convertClient(msgId, &clientMsgId);
+	if ( newClient != nullptr )
+	{
+		packet->setMsgId((int)clientMsgId);
+		handlePuback(newClient, packet);
+	}
+}
+
+void MQTTGWPublishHandler::handleAggregateAck(Client* client, MQTTGWPacket* packet, int type)
+{
+	uint16_t msgId = packet->getMsgId();
+	uint16_t clientMsgId = 0;
+	Client* newClient = _gateway->getAdapterManager()->convertClient(msgId, &clientMsgId);
+	if ( newClient != nullptr )
+	{
+		packet->setMsgId((int)clientMsgId);
+		handleAck(newClient, packet,type);
+	}
+}
+
+void MQTTGWPublishHandler::handleAggregatePubrel(Client* client, MQTTGWPacket* packet)
+{
+	Publish pub;
+	packet->getPUBLISH(&pub);
+	replyACK(client, &pub, PUBCOMP);
+}
+
+void MQTTGWPublishHandler::handleAggregatePublish(Client* client, MQTTGWPacket* packet)
+{
+	Publish pub;
+	packet->getPUBLISH(&pub);
+
+	WRITELOG(FORMAT_Y_G_G, currentDateTime(), packet->getName(),
+	RIGHTARROW, client->getClientId(), "is sleeping. a message was saved.");
+
+	if (pub.header.bits.qos == 1)
+	{
+		replyACK(client, &pub, PUBACK);
+	}
+	else if ( pub.header.bits.qos == 2)
+	{
+		replyACK(client, &pub, PUBREC);
+	}
+
+
+
+	string* topicName = new string(pub.topic, pub.topiclen);
+	Topic topic = Topic(topicName, MQTTSN_TOPIC_TYPE_NORMAL);
+	AggregateTopicElement* list = _gateway->getAdapterManager()->createClientList(&topic);
+	if ( list != nullptr )
+	{
+		ClientTopicElement* p = list->getFirstElement();
+
+		while ( p )
+		{
+			Client* devClient = p->getClient();
+			if ( devClient != nullptr )
+			{
+				MQTTGWPacket* msg = new MQTTGWPacket();
+				*msg = *packet;
+				if ( msg->getType() == 0 )
+				{
+					WRITELOG("%s MQTTGWPublishHandler::handleAggregatePublish can't allocate memories for Packet.%s\n", ERRMSG_HEADER,ERRMSG_FOOTER);
+					delete msg;
+					break;
+				}
+				Event* ev = new Event();
+				ev->setBrokerRecvEvent(devClient, msg);
+				_gateway->getPacketEventQue()->post(ev);
+			}
+			else
+			{
+				break;
+			}
+
+			p = list->getNextElement(p);
+		}
+		delete list;
+	}
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWPublishHandler.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWPublishHandler.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,50 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#ifndef MQTTGWPUBLISHHANDLER_H_
+#define MQTTGWPUBLISHHANDLER_H_
+
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGWPacket.h"
+#include "MQTTSNGateway.h"
+
+namespace MQTTSNGW
+{
+
+class MQTTGWPublishHandler
+{
+public:
+	MQTTGWPublishHandler(Gateway* gateway);
+	~MQTTGWPublishHandler();
+	void handlePublish(Client* client, MQTTGWPacket* packet);
+	void handlePuback(Client* client, MQTTGWPacket* packet);
+	void handleAck(Client* client, MQTTGWPacket* packet, int type);
+
+	void handleAggregatePublish(Client* client, MQTTGWPacket* packet);
+	void handleAggregatePuback(Client* client, MQTTGWPacket* packet);
+	void handleAggregateAck(Client* client, MQTTGWPacket* packet, int type);
+	void handleAggregatePubrel(Client* client, MQTTGWPacket* packet);
+
+private:
+	void replyACK(Client* client, Publish* pub, int type);
+
+	Gateway* _gateway;
+};
+
+}
+
+
+
+#endif /* MQTTGWPUBLISHHANDLER_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWSubscribeHandler.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,99 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include "MQTTGWSubscribeHandler.h"
+#include "MQTTGWPacket.h"
+
+using namespace std;
+using namespace MQTTSNGW;
+
+MQTTGWSubscribeHandler::MQTTGWSubscribeHandler(Gateway* gateway)
+{
+	_gateway = gateway;
+}
+
+MQTTGWSubscribeHandler::~MQTTGWSubscribeHandler()
+{
+
+}
+
+void MQTTGWSubscribeHandler::handleSuback(Client* client, MQTTGWPacket* packet)
+{
+	uint16_t msgId;
+	uint8_t rc;
+	uint8_t returnCode;
+	int qos = 0;
+
+	packet->getSUBACK(&msgId, &rc);
+	TopicIdMapElement* topicId = client->getWaitedSubTopicId(msgId);
+
+	if (topicId)
+	{
+		MQTTSNPacket* snPacket = new MQTTSNPacket();
+
+		if (rc == 0x80)
+		{
+			returnCode = MQTTSN_RC_REJECTED_INVALID_TOPIC_ID;
+		}
+		else
+		{
+			returnCode = MQTTSN_RC_ACCEPTED;
+			qos = rc;
+		}
+		snPacket->setSUBACK(qos, topicId->getTopicId(), msgId, returnCode);
+		Event* evt = new Event();
+		evt->setClientSendEvent(client, snPacket);
+		_gateway->getClientSendQue()->post(evt);
+        client->eraseWaitedSubTopicId(msgId);
+	}
+}
+
+void MQTTGWSubscribeHandler::handleUnsuback(Client* client, MQTTGWPacket* packet)
+{
+	Ack ack;
+	packet->getAck(&ack);
+	MQTTSNPacket* snPacket = new MQTTSNPacket();
+	snPacket->setUNSUBACK(ack.msgId);
+	Event* evt = new Event();
+	evt->setClientSendEvent(client, snPacket);
+	_gateway->getClientSendQue()->post(evt);
+}
+
+void MQTTGWSubscribeHandler::handleAggregateSuback(Client* client, MQTTGWPacket* packet)
+{
+	uint16_t msgId = packet->getMsgId();
+	uint16_t clientMsgId = 0;
+	Client* newClient = _gateway->getAdapterManager()->getAggregater()->convertClient(msgId, &clientMsgId);
+	if (  newClient != nullptr )
+	{
+		packet->setMsgId((int)clientMsgId);
+		handleSuback(newClient, packet);
+	}
+}
+
+void MQTTGWSubscribeHandler::handleAggregateUnsuback(Client* client, MQTTGWPacket* packet)
+{
+	uint16_t msgId = packet->getMsgId();
+	uint16_t clientMsgId = 0;
+	Client* newClient = _gateway->getAdapterManager()->getAggregater()->convertClient(msgId, &clientMsgId);
+	if (  newClient != nullptr )
+	{
+		packet->setMsgId((int)clientMsgId);
+		handleUnsuback(newClient, packet);
+	}
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWSubscribeHandler.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTGWSubscribeHandler.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,43 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#ifndef MQTTGWSUBSCRIBEHANDLER_H_
+#define MQTTGWSUBSCRIBEHANDLER_H_
+
+#include "MQTTSNGWDefines.h"
+#include "MQTTGWPacket.h"
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWClient.h"
+
+namespace MQTTSNGW
+{
+
+class MQTTGWSubscribeHandler
+{
+public:
+	MQTTGWSubscribeHandler(Gateway* gateway);
+	~MQTTGWSubscribeHandler();
+	void handleSuback(Client* clnode, MQTTGWPacket* packet);
+	void handleUnsuback(Client* clnode, MQTTGWPacket* packet);
+	void handleAggregateSuback(Client* client, MQTTGWPacket* packet);
+	void handleAggregateUnsuback(Client* client, MQTTGWPacket* packet);
+
+private:
+	Gateway* _gateway;
+};
+
+}
+
+#endif /* MQTTGWSUBSCRIBEHANDLER_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,202 @@
+/**************************************************************************************
+ * Copyright (c) 2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include "MQTTSNAggregateConnectionHandler.h"
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWPacket.h"
+#include "MQTTGWPacket.h"
+#include <string.h>
+
+using namespace std;
+using namespace MQTTSNGW;
+
+/*=====================================
+ Class MQTTSNAggregateConnectionHandler
+ =====================================*/
+MQTTSNAggregateConnectionHandler::MQTTSNAggregateConnectionHandler(Gateway* gateway)
+{
+	_gateway = gateway;
+}
+
+MQTTSNAggregateConnectionHandler::~MQTTSNAggregateConnectionHandler()
+{
+
+}
+
+
+/*
+ *  CONNECT
+ */
+void MQTTSNAggregateConnectionHandler::handleConnect(Client* client, MQTTSNPacket* packet)
+{
+	MQTTSNPacket_connectData data;
+	if ( packet->getCONNECT(&data) == 0 )
+	{
+		return;
+	}
+
+	/* return CONNACK when the client is sleeping */
+	if ( client->isSleep() || client->isAwake() )
+	{
+		MQTTSNPacket* packet = new MQTTSNPacket();
+		packet->setCONNACK(MQTTSN_RC_ACCEPTED);
+		Event* ev = new Event();
+		ev->setClientSendEvent(client, packet);
+		_gateway->getClientSendQue()->post(ev);
+		sendStoredPublish(client);
+		return;
+	}
+
+	//* clear ConnectData of Client */
+	Connect* connectData = client->getConnectData();
+	memset(connectData, 0, sizeof(Connect));
+
+	client->disconnected();
+
+	Topics* topics = client->getTopics();
+
+	/* CONNECT was not sent yet. prepare Connect data */
+
+
+	client->setSessionStatus(false);
+	if (data.cleansession)
+	{
+		/* reset the table of msgNo and TopicId pare */
+		client->clearWaitedPubTopicId();
+		client->clearWaitedSubTopicId();
+
+		/* renew the TopicList */
+		if (topics)
+		{
+			_gateway->getAdapterManager()->removeAggregateTopicList(topics, client);
+			topics->eraseNormal();
+		}
+		client->setSessionStatus(true);
+	}
+
+	if (data.willFlag)
+	{
+		/* create & send WILLTOPICREQ message to the client */
+		MQTTSNPacket* reqTopic = new MQTTSNPacket();
+		reqTopic->setWILLTOPICREQ();
+		Event* evwr = new Event();
+		evwr->setClientSendEvent(client, reqTopic);
+
+		/* Send WILLTOPICREQ to the client */
+		_gateway->getClientSendQue()->post(evwr);
+	}
+	else
+	{
+		/* create CONNACK & send it to the client */
+		MQTTSNPacket* packet = new MQTTSNPacket();
+		packet->setCONNACK(MQTTSN_RC_ACCEPTED);
+		Event* ev = new Event();
+		ev->setClientSendEvent(client, packet);
+		_gateway->getClientSendQue()->post(ev);
+		client->connackSended(MQTTSN_RC_ACCEPTED);
+		sendStoredPublish(client);
+		return;
+	}
+}
+
+
+/*
+ *  WILLMSG
+ */
+void MQTTSNAggregateConnectionHandler::handleWillmsg(Client* client, MQTTSNPacket* packet)
+{
+	if ( !client->isWaitWillMsg() )
+	{
+		DEBUGLOG("     MQTTSNConnectionHandler::handleWillmsg  WaitWillMsgFlg is off.\n");
+		return;
+	}
+
+	MQTTSNString willmsg  = MQTTSNString_initializer;
+	//Connect* connectData = client->getConnectData();
+
+	if( client->isConnectSendable() )
+	{
+		/* save WillMsg in the client */
+		if ( packet->getWILLMSG(&willmsg) == 0 )
+		{
+			return;
+		}
+		client->setWillMsg(willmsg);
+
+			/* Send CONNACK to the client */
+		MQTTSNPacket* packet = new MQTTSNPacket();
+		packet->setCONNACK(MQTTSN_RC_ACCEPTED);
+		Event* ev = new Event();
+		ev->setClientSendEvent(client, packet);
+		_gateway->getClientSendQue()->post(ev);
+
+		sendStoredPublish(client);
+		return;
+	}
+}
+
+/*
+ *  DISCONNECT
+ */
+void MQTTSNAggregateConnectionHandler::handleDisconnect(Client* client, MQTTSNPacket* packet)
+{
+    MQTTSNPacket* snMsg = new MQTTSNPacket();
+    snMsg->setDISCONNECT(0);
+    Event* evt = new Event();
+    evt->setClientSendEvent(client, snMsg);
+    _gateway->getClientSendQue()->post(evt);
+}
+
+/*
+ *  PINGREQ
+ */
+void MQTTSNAggregateConnectionHandler::handlePingreq(Client* client, MQTTSNPacket* packet)
+{
+	if ( ( client->isSleep() || client->isAwake() ) &&  client->getClientSleepPacket() )
+	{
+	    sendStoredPublish(client);
+		client->holdPingRequest();
+	}
+	else
+	{
+        /* create and send PINGRESP to the PacketHandler */
+	    client->resetPingRequest();
+
+        MQTTGWPacket* pingresp = new MQTTGWPacket();
+
+        pingresp->setHeader(PINGRESP);
+
+        Event* evt = new Event();
+        evt->setBrokerRecvEvent(client, pingresp);
+        _gateway->getPacketEventQue()->post(evt);
+	}
+}
+
+void MQTTSNAggregateConnectionHandler::sendStoredPublish(Client* client)
+{
+    MQTTGWPacket* msg = nullptr;
+
+    while  ( ( msg = client->getClientSleepPacket() ) != nullptr )
+    {
+        // ToDo:  This version can't re-send PUBLISH when PUBACK is not returned.
+        client->deleteFirstClientSleepPacket();  // pop the que to delete element.
+
+        Event* ev = new Event();
+        ev->setBrokerRecvEvent(client, msg);
+        _gateway->getPacketEventQue()->post(ev);
+    }
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNAggregateConnectionHandler.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,48 @@
+/**************************************************************************************
+ * Copyright (c) 2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef MQTTSNGATEWAY_SRC_MQTTSNAGGREGATECONNECTIONHANDLER_H_
+#define MQTTSNGATEWAY_SRC_MQTTSNAGGREGATECONNECTIONHANDLER_H_
+
+#include "MQTTSNGWDefines.h"
+
+namespace MQTTSNGW
+{
+class Gateway;
+class Client;
+class MQTTSNPacket;
+
+class MQTTSNAggregateConnectionHandler
+{
+public:
+	MQTTSNAggregateConnectionHandler(Gateway* gateway);
+	~MQTTSNAggregateConnectionHandler(void);
+
+	void handleConnect(Client* client, MQTTSNPacket* packet);
+	void handleWillmsg(Client* client, MQTTSNPacket* packet);
+	void handleDisconnect(Client* client, MQTTSNPacket* packet);
+	void handlePingreq(Client* client, MQTTSNPacket* packet);
+
+private:
+	void sendStoredPublish(Client* client);
+
+	char _pbuf[MQTTSNGW_MAX_PACKET_SIZE * 3];
+	Gateway* _gateway;
+};
+
+}
+
+#endif /* MQTTSNGATEWAY_SRC_MQTTSNAGGREGATECONNECTIONHANDLER_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAdapter.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAdapter.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,321 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#include "Timer.h"
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWAdapter.h"
+#include "SensorNetwork.h"
+#include "MQTTSNGWProcess.h"
+#include "MQTTSNGWClient.h"
+
+#include <string.h>
+using namespace MQTTSNGW;
+
+
+/*=====================================
+     Class Adapter
+ =====================================*/
+Adapter:: Adapter(Gateway* gw)
+{
+	_gateway = gw;
+	_proxy = new Proxy(gw);
+	_proxySecure = new Proxy(gw);
+}
+
+Adapter::~Adapter(void)
+{
+    if (  _proxy )
+    {
+        delete _proxy;
+    }
+
+    if (  _proxySecure )
+   {
+	   delete _proxySecure;
+   }
+}
+
+
+void Adapter::setup(const char* adpterName, AdapterType adapterType)
+{
+    _isSecure = false;
+    if ( _gateway->hasSecureConnection() )
+    {
+		_isSecure = true;
+    }
+
+    MQTTSNString id = MQTTSNString_initializer;
+	MQTTSNString idSecure = MQTTSNString_initializer;
+
+	string name = string(adpterName);
+	id.cstring = const_cast<char*>(name.c_str());
+	string nameSecure = string(adpterName) + "-S";
+	idSecure.cstring = const_cast<char*>(nameSecure.c_str());
+
+	Client*  client = _gateway->getClientList()->createClient(0, &id, true, false, TRANSPEARENT_TYPE);
+	setClient(client, false);
+	client->setAdapterType(adapterType);
+
+	client = _gateway->getClientList()->createClient(0, &idSecure, true, true, TRANSPEARENT_TYPE);
+	setClient(client, true);
+	client->setAdapterType(adapterType);
+}
+
+
+Client* Adapter::getClient(SensorNetAddress* addr)
+{
+	Client* client = _gateway->getClientList()->getClient(addr);
+	if ( !client )
+	{
+		return nullptr;
+	}
+	else if ( client->isQoSm1() )
+	{
+		return client;
+	}
+	else
+	{
+		return nullptr;
+	}
+}
+
+const char*  Adapter::getClientId(SensorNetAddress* addr)
+{
+    Client* client = getClient(addr);
+    if ( !client )
+    {
+    	return nullptr;
+    }
+    else if ( client->isQoSm1() )
+    {
+    	return client->getClientId();
+    }
+    else
+    {
+    	return nullptr;
+    }
+}
+
+bool Adapter::isSecure(SensorNetAddress* addr)
+{
+	Client* client = getClient(addr);
+	if ( !client )
+	{
+		return false;
+	}
+	else if ( client->isSecureNetwork() )
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+void Adapter::setClient(Client* client, bool secure)
+{
+    if ( secure )
+    {
+        _clientSecure = client;
+    }
+    else
+    {
+        _client = client;
+    }
+}
+
+Client* Adapter::getClient(void)
+{
+    return _client;
+}
+
+Client* Adapter::getSecureClient(void)
+{
+    return _clientSecure;
+}
+
+void Adapter::checkConnection(void)
+{
+    _proxy->checkConnection(_client);
+
+    if ( _isSecure )
+    {
+        _proxySecure->checkConnection(_clientSecure);
+    }
+}
+
+void Adapter::send(MQTTSNPacket* packet, Client* client)
+{
+    Proxy* proxy = _proxy;
+    if ( client->isSecureNetwork() && !_isSecure )
+    {
+        if ( _isSecure )
+        {
+            proxy = _proxySecure;
+        }
+        else
+        {
+            WRITELOG("%s %s  No Secure connections %s 's packet is discarded.%s\n", ERRMSG_HEADER, client->getClientId() , ERRMSG_FOOTER);
+            return;
+        }
+    }
+
+    proxy->recv(packet, client);
+
+}
+
+void Adapter::resetPingTimer(bool secure)
+{
+    if ( secure )
+    {
+    	_proxySecure->resetPingTimer();
+    }
+    else
+    {
+    	_proxy->resetPingTimer();
+    }
+}
+
+bool Adapter::isActive(void)
+{
+    return _isActive;
+}
+
+void Adapter::savePacket(Client* client, MQTTSNPacket* packet)
+{
+	if ( client->isSecureNetwork())
+	{
+		_proxySecure->savePacket(client, packet);
+	}
+	else
+	{
+		_proxy->savePacket(client, packet);
+	}
+}
+
+
+Client* Adapter::getAdapterClient(Client* client)
+{
+	if ( client->isSecureNetwork() )
+	{
+		return _client;
+	}
+	else
+	{
+		return _client;
+	}
+}
+
+/*=====================================
+     Class Proxy
+ =====================================*/
+Proxy::Proxy(Gateway* gw)
+{
+	_gateway = gw;
+	_suspendedPacketEventQue = new EventQue();
+}
+Proxy::~Proxy(void)
+{
+	if ( _suspendedPacketEventQue )
+	{
+		delete _suspendedPacketEventQue;
+	}
+}
+
+void Proxy::checkConnection(Client* client)
+{
+    if ( client->isDisconnect()  || ( client->isConnecting() && _responseTimer.isTimeup()) )
+    {
+        client->connectSended();
+        _responseTimer.start(QOSM1_PROXY_RESPONSE_DURATION * 1000UL);
+        MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer;
+        options.clientID.cstring = client->getClientId();
+        options.duration = QOSM1_PROXY_KEEPALIVE_DURATION;
+
+        MQTTSNPacket* packet = new MQTTSNPacket();
+        packet->setCONNECT(&options);
+        Event* ev = new Event();
+        ev->setClientRecvEvent(client, packet);
+        _gateway->getPacketEventQue()->post(ev);
+    }
+    else if (  (client->isActive() && _keepAliveTimer.isTimeup() ) || (_isWaitingResp  && _responseTimer.isTimeup() ) )
+    {
+            MQTTSNPacket* packet = new MQTTSNPacket();
+            MQTTSNString clientId = MQTTSNString_initializer;
+            packet->setPINGREQ(&clientId);
+            Event* ev = new Event();
+            ev->setClientRecvEvent(client, packet);
+            _gateway->getPacketEventQue()->post(ev);
+            _responseTimer.start(QOSM1_PROXY_RESPONSE_DURATION * 1000UL);
+            _isWaitingResp = true;
+
+            if ( ++_retryCnt > QOSM1_PROXY_MAX_RETRY_CNT )
+            {
+                client->disconnected();
+            }
+            resetPingTimer();
+    }
+}
+
+
+void Proxy::resetPingTimer(void)
+{
+    _keepAliveTimer.start(QOSM1_PROXY_KEEPALIVE_DURATION * 1000UL);
+}
+
+void Proxy::recv(MQTTSNPacket* packet, Client* client)
+{
+    if ( packet->getType() == MQTTSN_CONNACK )
+    {
+       if ( packet->isAccepted() )
+       {
+            _responseTimer.stop();
+            _retryCnt = 0;
+            resetPingTimer();
+            sendSuspendedPacket();
+       }
+    }
+    else if ( packet->getType() == MQTTSN_PINGRESP )
+    {
+        _isWaitingResp = false;
+        _responseTimer.stop();
+         _retryCnt = 0;
+         resetPingTimer();
+    }
+    else if ( packet->getType() == MQTTSN_DISCONNECT )
+    {
+        // blank
+    }
+}
+
+void Proxy::savePacket(Client* client, MQTTSNPacket* packet)
+{
+	MQTTSNPacket* pk = new MQTTSNPacket(*packet);
+	Event* ev = new Event();
+	ev->setClientRecvEvent(client, pk);
+	_suspendedPacketEventQue->post(ev);
+}
+
+void Proxy::sendSuspendedPacket(void)
+{
+	while ( _suspendedPacketEventQue->size() )
+	{
+		Event* ev = _suspendedPacketEventQue->wait();
+		_gateway->getPacketEventQue()->post(ev);
+	}
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAdapter.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAdapter.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,99 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef MQTTSNGATEWAY_SRC_MQTTSNGWADAPTER_H_
+#define MQTTSNGATEWAY_SRC_MQTTSNGWADAPTER_H_
+
+#include <stdint.h>
+#include "Timer.h"
+namespace MQTTSNGW
+{
+class Gateway;
+class Client;
+class Proxy;
+class SensorNetAddress;
+class MQTTSNPacket;
+class MQTTSNGWPacket;
+class EventQue;
+class Timer;
+
+/* When you add a new type, Client::setAdapterType() and Client::isAdapter() functions must be modified. */
+typedef enum{
+	Atype_QoSm1Proxy, Atype_Aggregater
+}AdapterType;
+
+/*=====================================
+     Class Adapter
+ =====================================*/
+class Adapter
+{
+public:
+	Adapter(Gateway* gw);
+    ~Adapter(void);
+
+    void setup(const char* adpterName, AdapterType adapterType);
+    const char* getClientId(SensorNetAddress* addr);
+    void setClient(Client* client, bool secure);
+    Client* getClient(SensorNetAddress* addr);
+    Client* getClient(void);
+    Client* getSecureClient(void);
+    Client* getAdapterClient(Client* client);
+    void resetPingTimer(bool secure);
+    void checkConnection(void);
+    void send(MQTTSNPacket* packet, Client* client);
+    bool isActive(void);
+    bool isSecure(SensorNetAddress* addr);
+    void savePacket(Client* client, MQTTSNPacket* packet);
+
+private:
+    Gateway* _gateway {nullptr};
+    Proxy* _proxy {nullptr};
+    Proxy* _proxySecure {nullptr};
+    Client* _client {nullptr};
+    Client* _clientSecure {nullptr};
+    bool _isActive {false};
+    bool _isSecure{false};
+};
+
+
+/*=====================================
+     Class Proxy
+ =====================================*/
+class Proxy
+{
+public:
+    Proxy(Gateway* gw);
+    ~Proxy(void);
+
+    void setKeepAlive(uint16_t secs);
+    void checkConnection(Client* client);
+    void resetPingTimer(void);
+    void recv(MQTTSNPacket* packet, Client* client);
+    void savePacket(Client* client, MQTTSNPacket* packet);
+
+private:
+    void sendSuspendedPacket(void);
+    Gateway* _gateway;
+    EventQue* _suspendedPacketEventQue {nullptr};
+    Timer  _keepAliveTimer;
+    Timer  _responseTimer;
+    bool   _isWaitingResp {false};
+    int _retryCnt {0};
+};
+
+}
+
+#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWADAPTER_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAdapterManager.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,188 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGateway.h"
+#include "SensorNetwork.h"
+#include "MQTTSNGWProcess.h"
+#include "MQTTSNGWVersion.h"
+#include "MQTTSNGWClientRecvTask.h"
+#include "MQTTSNGWClientSendTask.h"
+#include "MQTTSNGWClient.h"
+#include "MQTTSNGWAggregater.h"
+#include "MQTTSNGWQoSm1Proxy.h"
+#include <string.h>
+using namespace MQTTSNGW;
+
+char* currentDateTime(void);
+
+/*=====================================
+ Class AdapterManager
+ =====================================*/
+AdapterManager::AdapterManager(Gateway* gw)
+{
+	_gateway = gw;
+	_forwarders = new ForwarderList();
+	_qosm1Proxy = new QoSm1Proxy(gw);
+	_aggregater = new Aggregater(gw);
+}
+
+
+void AdapterManager::initialize(void)
+{
+    _aggregater->initialize();
+    _forwarders->initialize(_gateway);
+    _qosm1Proxy->initialize();
+}
+
+
+AdapterManager::~AdapterManager(void)
+{
+    if ( _forwarders )
+    {
+        delete _forwarders;
+    }
+    if ( _qosm1Proxy )
+    {
+        delete _qosm1Proxy;
+    }
+    if ( _aggregater )
+    {
+        delete _aggregater;
+    }
+}
+
+ForwarderList* AdapterManager::getForwarderList(void)
+{
+    return _forwarders;
+}
+
+QoSm1Proxy* AdapterManager::getQoSm1Proxy(void)
+{
+    return _qosm1Proxy;
+}
+
+Aggregater* AdapterManager::getAggregater(void)
+{
+    return _aggregater;
+}
+
+bool AdapterManager::isAggregatedClient(Client* client)
+{
+	if ( !_aggregater->isActive() || client->isQoSm1() || client->isAggregater() || client->isQoSm1Proxy())
+	{
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+}
+
+Client* AdapterManager::getClient(Client& client)
+{
+	bool secure = client.isSecureNetwork();
+	Client* newClient = &client;
+	if ( client.isQoSm1() )
+	{
+		newClient = _qosm1Proxy->getAdapterClient(&client);
+		_qosm1Proxy->resetPingTimer(secure);
+	}
+	else if ( client.isAggregated() )
+
+	{
+		newClient = _aggregater->getAdapterClient(&client);
+		_aggregater->resetPingTimer(secure);
+	}
+
+	return newClient;
+}
+
+int AdapterManager::unicastToClient(Client* client, MQTTSNPacket* packet, ClientSendTask* task)
+{
+	char pbuf[SIZE_OF_LOG_PACKET * 3];
+	Forwarder* fwd = client->getForwarder();
+	int rc = 0;
+
+	if ( fwd )
+	{
+		MQTTSNGWEncapsulatedPacket encap(packet);
+		WirelessNodeId* wnId = fwd->getWirelessNodeId(client);
+		encap.setWirelessNodeId(wnId);
+		WRITELOG(FORMAT_Y_W_G, currentDateTime(), encap.getName(), RIGHTARROW, fwd->getId(), encap.print(pbuf));
+		task->log(client, packet);
+		rc = encap.unicast(_gateway->getSensorNetwork(),fwd->getSensorNetAddr());
+	}
+	else
+	{
+		task->log(client, packet);
+		if ( client->isQoSm1Proxy() )
+		{
+			_qosm1Proxy->send(packet, client);
+		}
+		else if ( client->isAggregater() )
+		{
+			_aggregater->send(packet, client);
+		}
+		else
+		{
+			rc = packet->unicast(_gateway->getSensorNetwork(), client->getSensorNetAddress());
+		}
+	}
+	return rc;
+}
+
+void AdapterManager::checkConnection(void)
+{
+	if ( _aggregater->isActive())
+	{
+		_aggregater->checkConnection();
+	}
+
+	if ( _qosm1Proxy->isActive())
+	{
+		_qosm1Proxy->checkConnection();
+	}
+}
+
+Client* AdapterManager::convertClient(uint16_t msgId, uint16_t* clientMsgId)
+{
+	return _aggregater->convertClient(msgId, clientMsgId);
+}
+
+bool AdapterManager::isAggregaterActive(void)
+{
+	return _aggregater->isActive();
+}
+
+AggregateTopicElement* AdapterManager::createClientList(Topic* topic)
+{
+	return _aggregater->createClientList(topic);
+}
+
+int AdapterManager::addAggregateTopic(Topic* topic, Client* client)
+{
+	return _aggregater->addAggregateTopic(topic, client);
+}
+
+void AdapterManager::removeAggregateTopic(Topic* topic, Client* client)
+{
+	 _aggregater->removeAggregateTopic(topic, client);
+}
+
+void AdapterManager::removeAggregateTopicList(Topics* topics, Client* client)
+{
+	 _aggregater->removeAggregateTopicList(topics, client);
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAdapterManager.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAdapterManager.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,70 @@
+/**************************************************************************************
+ * Copyright (c) 2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef MQTTSNGATEWAY_SRC_MQTTSNGWADAPTERMANAGER_H_
+#define MQTTSNGATEWAY_SRC_MQTTSNGWADAPTERMANAGER_H_
+
+#include "MQTTSNGWAggregater.h"
+#include "MQTTSNGWQoSm1Proxy.h"
+namespace MQTTSNGW
+{
+class Gateway;
+class Client;
+class QoSm1Proxy;
+class Aggregater;
+class ForwarderList;
+class Forwarder;
+class MQTTSNPacket;
+class MQTTSNGWPacket;
+class ClientRecvTask;
+class ClientSendTask;
+
+/*=====================================
+     Class AdapterManager
+ =====================================*/
+class AdapterManager
+{
+public:
+	AdapterManager(Gateway* gw);
+    ~AdapterManager(void);
+    void initialize(void);
+    ForwarderList* getForwarderList(void);
+    QoSm1Proxy* getQoSm1Proxy(void);
+    Aggregater* getAggregater(void);
+    void checkConnection(void);
+
+    bool isAggregatedClient(Client* client);
+    Client* getClient(Client& client);
+    Client* convertClient(uint16_t msgId, uint16_t* clientMsgId);
+    int unicastToClient(Client* client, MQTTSNPacket* packet, ClientSendTask* task);
+    bool isAggregaterActive(void);
+    AggregateTopicElement* createClientList(Topic* topic);
+    int addAggregateTopic(Topic* topic, Client* client);
+    void removeAggregateTopic(Topic* topic, Client* client);
+    void removeAggregateTopicList(Topics* topics, Client* client);
+
+private:
+    Gateway* _gateway {nullptr};
+    ForwarderList* _forwarders {nullptr};
+    QoSm1Proxy*  _qosm1Proxy {nullptr};
+    Aggregater* _aggregater {nullptr};
+};
+
+
+
+
+}
+#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWADAPTERMANAGER_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,161 @@
+/**************************************************************************************
+ * Copyright (c) 2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#include "MQTTSNGWAggregateTopicTable.h"
+#include "MQTTSNGWClient.h"
+
+/*=====================================
+ Class ClientTopicElement
+ =====================================*/
+ClientTopicElement::ClientTopicElement(Client* client)
+{
+	_client = client;
+}
+
+ClientTopicElement::~ClientTopicElement()
+{
+
+}
+
+Client* ClientTopicElement::getClient(void)
+{
+	return _client;
+}
+
+/*=====================================
+ Class AggregateTopicElement
+ =====================================*/
+AggregateTopicElement::AggregateTopicElement(void)
+{
+
+}
+
+AggregateTopicElement::AggregateTopicElement(Topic* topic, Client* client)
+{
+	ClientTopicElement* elm = new ClientTopicElement(client);
+	if ( elm != nullptr )
+	{
+		_head = elm;
+		_tail = elm;
+	}
+}
+
+AggregateTopicElement::~AggregateTopicElement(void)
+{
+	_mutex.lock();
+	if ( _head != nullptr )
+	{
+		ClientTopicElement* p = _tail;
+		while ( p )
+		{
+			ClientTopicElement* pPrev = p;
+			delete p;
+			p = pPrev->_prev;
+		}
+		_head = _tail = nullptr;
+	}
+	_mutex.unlock();
+}
+
+ClientTopicElement* AggregateTopicElement::add(Client* client)
+{
+	ClientTopicElement* elm = new ClientTopicElement(client);
+	if ( elm == nullptr )
+	{
+		return nullptr;
+	}
+	_mutex.lock();
+	if ( _head == nullptr )
+	{
+		_head = elm;
+		_tail = elm;
+	}
+	else
+	{
+		ClientTopicElement* p = find(client);
+		if ( p == nullptr )
+		{
+			 p = _tail;
+			_tail = elm;
+			elm->_prev = p;
+			p->_next = elm;
+		}
+		else
+		{
+			delete elm;
+			elm = nullptr;
+		}
+	}
+	_mutex.unlock();
+	return elm;
+}
+
+ClientTopicElement* AggregateTopicElement::find(Client* client)
+{
+	ClientTopicElement* p = _head;
+	while ( p )
+	{
+		if ( p->_client == client)
+		{
+			break;
+		}
+		p = p->_next;
+	}
+	return p;
+}
+
+ClientTopicElement* AggregateTopicElement::getFirstElement(void)
+{
+	return _head;
+}
+
+ClientTopicElement* AggregateTopicElement::getNextElement(ClientTopicElement* elm)
+{
+	return elm->_next;
+}
+
+
+/*=====================================
+ Class AggregateTopicTable
+ ======================================*/
+
+AggregateTopicTable::AggregateTopicTable()
+{
+
+}
+
+AggregateTopicTable::~AggregateTopicTable()
+{
+
+}
+
+AggregateTopicElement* AggregateTopicTable::add(Topic* topic, Client* client)
+{
+	//ToDo: AggregateGW
+	return 0;
+}
+
+void AggregateTopicTable::remove(Topic* topic, Client* client)
+{
+	//ToDo: AggregateGW
+}
+
+AggregateTopicElement* AggregateTopicTable::getClientList(Topic* client)
+{
+	// ToDo: AggregateGW
+	return 0;
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAggregateTopicTable.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,98 @@
+/**************************************************************************************
+ * Copyright (c) 2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef MQTTSNGATEWAY_SRC_MQTTSNGWAGGREGATETOPICTABLE_H_
+#define MQTTSNGATEWAY_SRC_MQTTSNGWAGGREGATETOPICTABLE_H_
+
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGWProcess.h"
+#include <stdint.h>
+namespace MQTTSNGW
+{
+
+class Client;
+class Topic;
+class AggregateTopicElement;
+class ClientTopicElement;
+class Mutex;
+
+/*=====================================
+ Class AggregateTopicTable
+ ======================================*/
+class AggregateTopicTable
+{
+public:
+	AggregateTopicTable();
+	~AggregateTopicTable();
+
+	AggregateTopicElement* add(Topic* topic, Client* client);
+	AggregateTopicElement* getClientList(Topic* client);
+	void remove(Topic* topic, Client* client);
+	void clear(void);
+private:
+	AggregateTopicElement* _head {nullptr};
+	AggregateTopicElement* _tail {nullptr};
+	int _cnt {0};
+	int _maxSize {MAX_MESSAGEID_TABLE_SIZE};
+};
+
+/*=====================================
+ Class AggregateTopicElement
+ =====================================*/
+class AggregateTopicElement
+{
+    friend class AggregateTopicTable;
+public:
+    AggregateTopicElement(void);
+    AggregateTopicElement(Topic* topic, Client* client);
+    ~AggregateTopicElement(void);
+
+    ClientTopicElement* add(Client* client);
+    ClientTopicElement* getFirstElement(void);
+    ClientTopicElement* getNextElement(ClientTopicElement* elm);
+    void erase(ClientTopicElement* elm);
+    ClientTopicElement* find(Client* client);
+
+private:
+    Mutex _mutex;
+    Topic* _topic {nullptr};
+    ClientTopicElement* _head {nullptr};
+    ClientTopicElement* _tail {nullptr};
+};
+
+/*=====================================
+ Class ClientTopicElement
+ =====================================*/
+class ClientTopicElement
+{
+    friend class AggregateTopicTable;
+    friend class AggregateTopicElement;
+public:
+    ClientTopicElement(Client* client);
+    ~ClientTopicElement(void);
+    Client* getClient(void);
+
+private:
+    Client* _client {nullptr};
+    ClientTopicElement* _next {nullptr};
+    ClientTopicElement* _prev {nullptr};
+};
+
+}
+
+
+
+#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWAGGREGATETOPICTABLE_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAggregater.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAggregater.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,145 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#include "MQTTSNGWAggregater.h"
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWClient.h"
+#include "MQTTSNGWAdapter.h"
+#include "MQTTSNGWAdapterManager.h"
+#include "MQTTSNGWMessageIdTable.h"
+#include "MQTTSNGWTopic.h"
+#include <stdio.h>
+#include <string.h>
+#include <string>
+
+using namespace MQTTSNGW;
+
+Aggregater::Aggregater(Gateway* gw) : Adapter(gw)
+{
+	_gateway = gw;
+}
+
+Aggregater::~Aggregater(void)
+{
+
+}
+
+void Aggregater::initialize(void)
+{
+    char param[MQTTSNGW_PARAM_MAX];
+
+    if (_gateway->getParam("AggregatingGateway", param) == 0 )
+    {
+        if (!strcasecmp(param, "YES") )
+        {
+           /* Create Aggregated Clients */
+        	_gateway->getClientList()->setClientList(AGGREGATER_TYPE);
+
+        	string name = _gateway->getGWParams()->gatewayName;
+        	setup(name.c_str(), Atype_Aggregater);
+        	_isActive = true;
+        }
+    }
+
+    //testMessageIdTable();
+
+}
+
+bool Aggregater::isActive(void)
+{
+	return _isActive;
+}
+
+uint16_t Aggregater::msgId(void)
+{
+	return Adapter::getSecureClient()->getNextPacketId();
+}
+
+Client* Aggregater::convertClient(uint16_t msgId, uint16_t* clientMsgId)
+{
+	return _msgIdTable.getClientMsgId(msgId, clientMsgId);
+}
+
+
+uint16_t Aggregater::addMessageIdTable(Client* client, uint16_t msgId)
+{
+	/* set Non secure client`s nextMsgId. otherwise Id is duplicated.*/
+
+	MessageIdElement* elm = _msgIdTable.add(this, client, msgId);
+	if ( elm == nullptr )
+	{
+		return 0;
+	}
+	else
+	{
+		return elm->_msgId;
+	}
+}
+
+uint16_t Aggregater::getMsgId(Client* client, uint16_t clientMsgId)
+{
+	return _msgIdTable.getMsgId(client, clientMsgId);
+}
+
+void Aggregater::removeAggregateTopic(Topic* topic, Client* client)
+{
+      // ToDo: AggregateGW this method called when the client disconnect and erase it`s Topics. this method call */
+}
+
+void Aggregater::removeAggregateTopicList(Topics* topics, Client* client)
+{
+      // ToDo: AggregateGW this method called when the client disconnect and erase it`s Topics. this method call */
+}
+
+int Aggregater::addAggregateTopic(Topic* topic, Client* client)
+{
+	// ToDo: AggregateGW  */
+	return 0;
+}
+
+AggregateTopicElement* Aggregater::createClientList(Topic* topic)
+{
+	// ToDo: AggregateGW  */
+	return 0;
+}
+
+bool Aggregater::testMessageIdTable(void)
+{
+	Client* client = new Client();
+	uint16_t msgId = 0;
+
+	printf("msgId=%d\n", addMessageIdTable(client,1));
+	printf("msgId=%d\n", addMessageIdTable(client,2));
+	printf("msgId=%d\n", addMessageIdTable(client,3));
+	printf("msgId=%d\n", addMessageIdTable(client,1));
+	printf("msgId=%d\n", addMessageIdTable(client,2));
+	printf("msgId=%d\n", addMessageIdTable(client,3));
+	printf("msgId=%d\n", addMessageIdTable(client,4));
+	printf("msgId=%d\n", addMessageIdTable(client,4));
+	printf("msgId=%d\n", addMessageIdTable(client,4));
+
+	convertClient(1,&msgId);
+	printf("msgId=%d\n",msgId);
+	convertClient(2,&msgId);
+	printf("msgId=%d\n",msgId);
+	convertClient(5,&msgId);
+	printf("msgId=%d\n",msgId);
+	convertClient(4,&msgId);
+	printf("msgId=%d\n",msgId);
+	convertClient(3,&msgId);
+	printf("msgId=%d\n",msgId);
+			return true;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAggregater.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWAggregater.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,76 @@
+/**************************************************************************************
+ * Copyright (c) 2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef MQTTSNGATEWAY_SRC_MQTTSNGWAGGREGATER_H_
+#define MQTTSNGATEWAY_SRC_MQTTSNGWAGGREGATER_H_
+
+#include "MQTTSNGWAdapter.h"
+#include "MQTTSNGWMessageIdTable.h"
+#include "MQTTSNGWAggregateTopicTable.h"
+namespace MQTTSNGW
+{
+class Gateway;
+class Adapter;
+class Client;
+class SensorNetAddress;
+class MessageIdTable;
+class AggregateTopicTable;
+class Topics;
+
+/*=====================================
+     Class Aggregater
+ =====================================*/
+class Aggregater : public Adapter
+{
+	friend class MessageIdTable;
+public:
+    Aggregater(Gateway* gw);
+    ~Aggregater(void);
+
+    void initialize(void);
+
+    const char* getClientId(SensorNetAddress* addr);
+	Client* getClient(SensorNetAddress* addr);
+	Client* convertClient(uint16_t msgId, uint16_t* clientMsgId);
+	uint16_t addMessageIdTable(Client* client, uint16_t msgId);
+	uint16_t getMsgId(Client* client, uint16_t clientMsgId);
+
+
+	AggregateTopicElement* createClientList(Topic* topic);
+	int addAggregateTopic(Topic* topic, Client* client);
+	void removeAggregateTopic(Topic* topic, Client* client);
+	void removeAggregateTopicList(Topics* topics, Client* client);
+	bool isActive(void);
+
+	bool testMessageIdTable(void);
+
+private:
+	uint16_t msgId(void);
+    Gateway* _gateway {nullptr};
+    MessageIdTable _msgIdTable;
+    AggregateTopicTable _topicTable;
+
+    bool _isActive {false};
+    bool _isSecure {false};
+};
+
+
+
+}
+
+
+
+#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWAGGREGATER_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,220 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include "MQTTSNGWBrokerRecvTask.h"
+#include "MQTTSNGWClient.h"
+#include "MQTTSNGWClientList.h"
+#include <unistd.h>
+
+using namespace std;
+using namespace MQTTSNGW;
+
+char* currentDateTime(void);
+
+/*=====================================
+ Class BrokerRecvTask
+ =====================================*/
+BrokerRecvTask::BrokerRecvTask(Gateway* gateway)
+{
+	_gateway = gateway;
+	_gateway->attach((Thread*)this);
+	_light = nullptr;
+}
+
+BrokerRecvTask::~BrokerRecvTask()
+{
+
+}
+
+/**
+ *  Initialize attributs of this class
+ */
+void BrokerRecvTask::initialize(int argc, char** argv)
+{
+	_light = _gateway->getLightIndicator();
+}
+
+/**
+ *  receive a MQTT messge from the broker and post a event.
+ */
+void BrokerRecvTask::run(void)
+{
+	struct timeval timeout;
+	MQTTGWPacket* packet = nullptr;
+	int rc;
+	Event* ev = nullptr;
+	fd_set rset;
+	fd_set wset;
+
+	while (true)
+	{
+		_light->blueLight(false);
+		if (CHK_SIGINT)
+		{
+			WRITELOG("%s BrokerRecvTask   stopped.\n", currentDateTime());
+			return;
+		}
+		timeout.tv_sec = 0;
+		timeout.tv_usec = 500000;    // 500 msec
+		FD_ZERO(&rset);
+		FD_ZERO(&wset);
+		int maxSock = 0;
+		int sockfd = 0;
+
+		/* Prepare sockets list to read */
+		Client* client = _gateway->getClientList()->getClient(0);
+
+		while ( client )
+		{
+			if (client->getNetwork()->isValid())
+			{
+				sockfd = client->getNetwork()->getSock();
+				FD_SET(sockfd, &rset);
+				FD_SET(sockfd, &wset);
+				if (sockfd > maxSock)
+				{
+					maxSock = sockfd;
+				}
+			}
+			client = client->getNextClient();
+		}
+
+		if (maxSock == 0)
+		{
+			usleep(500 * 1000);
+		}
+		else
+		{
+			/* Check sockets is ready to read */
+			int activity = select(maxSock + 1, &rset, 0, 0, &timeout);
+			if (activity > 0)
+			{
+				client = _gateway->getClientList()->getClient(0);
+
+				while ( client )
+				{
+					_light->blueLight(false);
+					if (client->getNetwork()->isValid())
+					{
+						int sockfd = client->getNetwork()->getSock();
+						if (FD_ISSET(sockfd, &rset))
+						{
+							packet = new MQTTGWPacket();
+							rc = 0;
+							/* read sockets */
+							_light->blueLight(true);
+							rc = packet->recv(client->getNetwork());
+							if ( rc > 0 )
+							{
+								if ( log(client, packet) == -1 )
+								{
+									delete packet;
+									goto nextClient;
+								}
+
+								/* post a BrokerRecvEvent */
+								ev = new Event();
+								ev->setBrokerRecvEvent(client, packet);
+								_gateway->getPacketEventQue()->post(ev);
+							}
+							else
+							{
+								if ( rc == 0 )  // Disconnected
+								{
+									client->getNetwork()->close();
+									delete packet;
+
+									/* delete client when the client is not authorized & session is clean */
+									_gateway->getClientList()->erase(client);
+
+									if ( client )
+									{
+										client = client->getNextClient();
+									}
+									continue;
+								}
+								else if (rc == -1)
+								{
+									WRITELOG("%s BrokerRecvTask can't receive a packet from the broker errno=%d %s%s\n", ERRMSG_HEADER, errno, client->getClientId(), ERRMSG_FOOTER);
+								}
+								else if ( rc == -2 )
+								{
+									WRITELOG("%s BrokerRecvTask receive invalid length of packet from the broker.  DISCONNECT  %s %s\n", ERRMSG_HEADER, client->getClientId(),ERRMSG_FOOTER);
+								}
+								else if ( rc == -3 )
+								{
+									WRITELOG("%s BrokerRecvTask can't get memories for the packet %s%s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER);
+								}
+
+								delete packet;
+
+								if ( (rc == -1 || rc == -2) && client->isActive() )
+								{
+									/* disconnect the client */
+									packet = new MQTTGWPacket();
+									packet->setHeader(DISCONNECT);
+									ev = new Event();
+									ev->setBrokerRecvEvent(client, packet);
+									_gateway->getPacketEventQue()->post(ev);
+								}
+							}
+						}
+					}
+					nextClient:
+					client = client->getNextClient();
+				}
+			}
+		}
+	}
+}
+
+/**
+ *  write message content into stdout or Ringbuffer
+ */
+int BrokerRecvTask::log(Client* client, MQTTGWPacket* packet)
+{
+	char pbuf[(SIZE_OF_LOG_PACKET + 5 )* 3];
+	char msgId[6];
+	int rc = 0;
+
+	switch (packet->getType())
+	{
+	case CONNACK:
+		WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), LEFTARROWB, client->getClientId(), packet->print(pbuf));
+		break;
+	case PUBLISH:
+		WRITELOG(FORMAT_W_MSGID_Y_W_NL, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROWB, client->getClientId(), packet->print(pbuf));
+		break;
+	case PUBACK:
+	case PUBREC:
+	case PUBREL:
+	case PUBCOMP:
+		WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROWB, client->getClientId(), packet->print(pbuf));
+		break;
+	case SUBACK:
+	case UNSUBACK:
+		WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROWB, client->getClientId(), packet->print(pbuf));
+		break;
+	case PINGRESP:
+		WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), LEFTARROWB, client->getClientId(), packet->print(pbuf));
+		break;
+	default:
+		WRITELOG("Type=%x\n", packet->getType());
+		rc = -1;
+		break;
+	}
+	return rc;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWBrokerRecvTask.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,48 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#ifndef MQTTSNGWBROKERRECVTASK_H_
+#define MQTTSNGWBROKERRECVTASK_H_
+
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGateway.h"
+
+namespace MQTTSNGW
+{
+
+/*=====================================
+ Class BrokerRecvTask
+ =====================================*/
+class BrokerRecvTask: public Thread
+{
+MAGIC_WORD_FOR_THREAD;
+	;
+public:
+	BrokerRecvTask(Gateway* gateway);
+	~BrokerRecvTask();
+	void initialize(int argc, char** argv);
+	void run(void);
+
+private:
+	int log(Client*, MQTTGWPacket*);
+
+	Gateway* _gateway;
+	LightIndicator* _light;
+};
+
+}
+
+
+#endif /* MQTTSNGWBROKERRECVTASK_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,181 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include <MQTTSNGWAdapterManager.h>
+#include "MQTTSNGWBrokerSendTask.h"
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWClient.h"
+#include "MQTTGWPacket.h"
+#include <string.h>
+
+using namespace std;
+using namespace MQTTSNGW;
+
+char* currentDateTime();
+#define ERRMSG_FORMAT "\n%s   \x1b[0m\x1b[31merror:\x1b[0m\x1b[37m Can't Xmit to the Broker. errno=%d\n"
+
+/*=====================================
+ Class BrokerSendTask
+ =====================================*/
+BrokerSendTask::BrokerSendTask(Gateway* gateway)
+{
+	_gateway = gateway;
+	_gateway->attach((Thread*)this);
+	_gwparams = nullptr;
+	_light = nullptr;
+}
+
+BrokerSendTask::~BrokerSendTask()
+{
+
+}
+
+/**
+ *  Initialize attributs of this class
+ */
+void BrokerSendTask::initialize(int argc, char** argv)
+{
+	_gwparams = _gateway->getGWParams();
+	_light = _gateway->getLightIndicator();
+}
+
+/**
+ *  connect to the broker and send MQTT messges
+ */
+void BrokerSendTask::run()
+{
+	Event* ev = nullptr;
+	MQTTGWPacket* packet = nullptr;
+	Client* client = nullptr;
+	AdapterManager* adpMgr = _gateway->getAdapterManager();
+	int rc = 0;
+
+	while (true)
+	{
+		ev = _gateway->getBrokerSendQue()->wait();
+
+		if ( ev->getEventType() == EtStop )
+		{
+			WRITELOG("%s BrokerSendTask   stopped.\n", currentDateTime());
+			delete ev;
+			return;
+		}
+
+		if ( ev->getEventType() == EtBrokerSend)
+		{
+			client = ev->getClient();
+			packet = ev->getMQTTGWPacket();
+
+			/* Check Client is managed by Adapters */
+			client = adpMgr->getClient(*client);
+
+			if ( packet->getType() == CONNECT && client->getNetwork()->isValid() )
+			{
+				client->getNetwork()->close();
+			}
+
+			if ( !client->getNetwork()->isValid() )
+			{
+				/* connect to the broker and send a packet */
+
+				if (client->isSecureNetwork())
+				{
+					rc = client->getNetwork()->connect((const char*)_gwparams->brokerName, (const char*)_gwparams->portSecure, (const char*)_gwparams->rootCApath,
+							(const char*)_gwparams->rootCAfile, (const char*)_gwparams->certKey, (const char*)_gwparams->privateKey);
+				}
+				else
+				{
+					rc = client->getNetwork()->connect((const char*)_gwparams->brokerName, (const char*)_gwparams->port);
+				}
+
+				if ( !rc )
+				{
+					/* disconnect the broker and the client */
+					WRITELOG("%s BrokerSendTask: %s can't connect to the broker. errno=%d %s %s\n",
+							ERRMSG_HEADER, client->getClientId(), errno, strerror(errno), ERRMSG_FOOTER);
+					delete ev;
+					client->getNetwork()->close();
+					continue;
+				}
+			}
+
+			/* send a packet */
+			_light->blueLight(true);
+			if ( (rc = packet->send(client->getNetwork())) > 0 )
+			{
+				if ( packet->getType() == CONNECT )
+				{
+					client->connectSended();
+				}
+				log(client, packet);
+			}
+			else
+			{
+				WRITELOG("%s BrokerSendTask: %s can't send a packet to the broker. errno=%d %s %s\n",
+						ERRMSG_HEADER, client->getClientId(), rc == -1 ? errno : 0, strerror(errno), ERRMSG_FOOTER);
+				client->getNetwork()->close();
+
+				/* Disconnect the client */
+				packet = new MQTTGWPacket();
+				packet->setHeader(DISCONNECT);
+				Event* ev1 = new Event();
+				ev1->setBrokerRecvEvent(client, packet);
+				_gateway->getPacketEventQue()->post(ev1);
+			}
+
+			_light->blueLight(false);
+		}
+		delete ev;
+	}
+}
+
+
+/**
+ *  write message content into stdout or Ringbuffer
+ */
+void BrokerSendTask::log(Client* client, MQTTGWPacket* packet)
+{
+	char pbuf[(SIZE_OF_LOG_PACKET + 5 )* 3];
+	char msgId[6];
+
+	switch (packet->getType())
+	{
+	case CONNECT:
+		WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), RIGHTARROWB, client->getClientId(), packet->print(pbuf));
+		break;
+	case PUBLISH:
+		WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROWB, client->getClientId(), packet->print(pbuf));
+		break;
+	case SUBSCRIBE:
+	case UNSUBSCRIBE:
+	case PUBACK:
+	case PUBREC:
+	case PUBREL:
+	case PUBCOMP:
+		WRITELOG(FORMAT_W_MSGID_Y_W, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROWB, client->getClientId(), packet->print(pbuf));
+		break;
+	case PINGREQ:
+		WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), RIGHTARROWB, client->getClientId(), packet->print(pbuf));
+		break;
+	case DISCONNECT:
+		WRITELOG(FORMAT_Y_Y_W, currentDateTime(), packet->getName(), RIGHTARROWB, client->getClientId(), packet->print(pbuf));
+		break;
+	default:
+		break;
+	}
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWBrokerSendTask.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,47 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#ifndef MQTTSNGWBROKERSENDTASK_H_
+#define MQTTSNGWBROKERSENDTASK_H_
+
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWClient.h"
+
+namespace MQTTSNGW
+{
+class Adapter;
+
+/*=====================================
+     Class BrokerSendTask
+ =====================================*/
+class BrokerSendTask : public Thread
+{
+	MAGIC_WORD_FOR_THREAD;
+	friend AdapterManager;
+public:
+	BrokerSendTask(Gateway* gateway);
+	~BrokerSendTask();
+	void initialize(int argc, char** argv);
+	void run();
+private:
+	void log(Client*, MQTTGWPacket*);
+	Gateway* _gateway;
+	GatewayParams* _gwparams;
+	LightIndicator* _light;
+};
+
+}
+#endif /* MQTTSNGWBROKERSENDTASK_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClient.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClient.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,694 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ *    Tieto Poland Sp. z o.o. - Gateway improvements
+ **************************************************************************************/
+
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGWClientList.h"
+#include "MQTTSNGateway.h"
+#include "SensorNetwork.h"
+#include <string>
+#include <string.h>
+#include <stdio.h>
+
+#include "MQTTSNGWForwarder.h"
+
+using namespace MQTTSNGW;
+char* currentDateTime(void);
+
+
+/*=====================================
+ Class Client
+ =====================================*/
+static const char* theClientStatus[] = { "Disconnected", "TryConnecting", "Connecting", "Active", "Asleep", "Awake", "Lost" };
+
+Client::Client(bool secure)
+{
+	_packetId = 0;
+	_snMsgId = 0;
+	_status = Cstat_Disconnected;
+	_keepAliveMsec = 0;
+	_topics = new Topics();
+	_clientId = nullptr;
+	_willTopic = nullptr;
+	_willMsg = nullptr;
+	_connectData = MQTTPacket_Connect_Initializer;
+	_network = new Network(secure);
+	_secureNetwork = secure;
+	_sensorNetype = true;
+	_connAck = nullptr;
+	_waitWillMsgFlg = false;
+	_sessionStatus = false;
+	_prevClient = nullptr;
+	_nextClient = nullptr;
+	_clientSleepPacketQue.setMaxSize(MAX_SAVED_PUBLISH);
+	_proxyPacketQue.setMaxSize(MAX_SAVED_PUBLISH);
+	_hasPredefTopic = false;
+	_holdPingRequest = false;
+	_forwarder = nullptr;
+	_clientType = Ctype_Regular;
+}
+
+Client::~Client()
+{
+	if ( _topics )
+	{
+		delete _topics;
+	}
+
+	if ( _clientId )
+	{
+		free(_clientId);
+	}
+
+	if ( _willTopic )
+	{
+		free(_willTopic);
+	}
+
+	if ( _willMsg )
+	{
+		free(_willMsg);
+	}
+
+	if (_connAck)
+	{
+		delete _connAck;
+	}
+
+	if (_network)
+	{
+		delete _network;
+	}
+}
+
+TopicIdMapElement* Client::getWaitedPubTopicId(uint16_t msgId)
+{
+	return _waitedPubTopicIdMap.getElement(msgId);
+}
+
+TopicIdMapElement* Client::getWaitedSubTopicId(uint16_t msgId)
+{
+	return _waitedSubTopicIdMap.getElement(msgId);
+}
+
+MQTTGWPacket* Client::getClientSleepPacket()
+{
+	return _clientSleepPacketQue.getPacket();
+}
+
+void Client::deleteFirstClientSleepPacket()
+{
+	_clientSleepPacketQue.pop();
+}
+
+int Client::setClientSleepPacket(MQTTGWPacket* packet)
+{
+	int rc = _clientSleepPacketQue.post(packet);
+	if ( rc )
+	{
+		WRITELOG("%s    %s is sleeping. the packet was saved.\n", currentDateTime(), _clientId);
+	}
+	else
+	{
+		WRITELOG("%s    %s is sleeping but discard the packet.\n", currentDateTime(), _clientId);
+	}
+	return rc;
+}
+
+MQTTSNPacket* Client::getProxyPacket(void)
+{
+    return _proxyPacketQue.getPacket();
+}
+
+void Client::deleteFirstProxyPacket()
+{
+    _proxyPacketQue.pop();
+}
+
+int Client::setProxyPacket(MQTTSNPacket* packet)
+{
+    int rc = _proxyPacketQue.post(packet);
+    if ( rc )
+    {
+        WRITELOG("%s    %s is Disconnected. the packet was saved.\n", currentDateTime(), _clientId);
+    }
+    else
+    {
+        WRITELOG("%s    %s is Disconnected and discard the packet.\n", currentDateTime(), _clientId);
+    }
+    return rc;
+}
+
+Connect* Client::getConnectData(void)
+{
+	return &_connectData;
+}
+
+void Client::eraseWaitedPubTopicId(uint16_t msgId)
+{
+	_waitedPubTopicIdMap.erase(msgId);
+}
+
+void Client::eraseWaitedSubTopicId(uint16_t msgId)
+{
+	_waitedSubTopicIdMap.erase(msgId);
+}
+
+void Client::clearWaitedPubTopicId(void)
+{
+	_waitedPubTopicIdMap.clear();
+}
+
+void Client::clearWaitedSubTopicId(void)
+{
+	_waitedSubTopicIdMap.clear();
+}
+
+void Client::setWaitedPubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type)
+{
+	_waitedPubTopicIdMap.add(msgId, topicId, type);
+}
+void Client::setWaitedSubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type)
+{
+	_waitedSubTopicIdMap.add(msgId, topicId, type);
+}
+
+bool Client::checkTimeover(void)
+{
+	return (_status == Cstat_Active && _keepAliveTimer.isTimeup());
+}
+
+void Client::setKeepAlive(MQTTSNPacket* packet)
+{
+	MQTTSNPacket_connectData param;
+	if (packet->getCONNECT(&param))
+	{
+		_keepAliveMsec = param.duration * 1000UL;
+		_keepAliveTimer.start(_keepAliveMsec * 1.5);
+	}
+}
+
+void Client::setForwarder(Forwarder* forwarder)
+{
+    _forwarder = forwarder;
+    _clientType = Ctype_Forwarded;
+}
+
+Forwarder* Client::getForwarder(void)
+{
+    return _forwarder;
+}
+
+void Client::setSessionStatus(bool status)
+{
+	_sessionStatus = status;
+}
+
+bool Client::erasable(void)
+{
+	return _sessionStatus && !_hasPredefTopic  && _forwarder == nullptr;
+}
+
+void Client::updateStatus(MQTTSNPacket* packet)
+{
+	if (((_status == Cstat_Disconnected) || (_status == Cstat_Lost)) && packet->getType() == MQTTSN_CONNECT)
+	{
+		setKeepAlive(packet);
+	}
+	else if (_status == Cstat_Active)
+	{
+		switch (packet->getType())
+		{
+		case MQTTSN_PINGREQ:
+		case MQTTSN_PUBLISH:
+		case MQTTSN_SUBSCRIBE:
+		case MQTTSN_UNSUBSCRIBE:
+		case MQTTSN_PUBACK:
+		case MQTTSN_PUBCOMP:
+		case MQTTSN_PUBREL:
+		case MQTTSN_PUBREC:
+			if ( _clientType != Ctype_Proxy )
+			{
+			    _keepAliveTimer.start(_keepAliveMsec * 1.5);
+			}
+			break;
+		case MQTTSN_DISCONNECT:
+			uint16_t duration;
+			packet->getDISCONNECT(&duration);
+			if (duration)
+			{
+				_status = Cstat_Asleep;
+			}
+			else
+			{
+				disconnected();
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	else if (_status == Cstat_Awake || _status == Cstat_Asleep)
+	{
+		switch (packet->getType())
+		{
+		case MQTTSN_CONNECT:
+			_status = Cstat_Active;
+			break;
+		case MQTTSN_DISCONNECT:
+			disconnected();
+			break;
+		case MQTTSN_PINGREQ:
+			_status = Cstat_Awake;
+			break;
+		case MQTTSN_PINGRESP:
+			_status = Cstat_Asleep;
+			break;
+		default:
+			break;
+		}
+	}
+	DEBUGLOG("Client Status = %s\n", theClientStatus[_status]);
+}
+
+void Client::updateStatus(ClientStatus stat)
+{
+	_status = stat;
+}
+
+void Client::connectSended()
+{
+	_status = Cstat_Connecting;
+}
+
+void Client::connackSended(int rc)
+{
+	if (rc == MQTTSN_RC_ACCEPTED)
+	{
+		_status = Cstat_Active;
+	}
+	else
+	{
+		disconnected();
+	}
+}
+
+void Client::disconnected(void)
+{
+	_status = Cstat_Disconnected;
+	_waitWillMsgFlg = false;
+}
+
+void Client::tryConnect(void)
+{
+    _status = Cstat_TryConnecting;
+}
+
+bool Client::isConnectSendable(void)
+{
+	if ( _status == Cstat_Lost || _status == Cstat_TryConnecting )
+	{
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+}
+
+uint16_t Client::getNextPacketId(void)
+{
+	_packetId++;
+	if ( _packetId == 0xffff )
+	{
+		_packetId = 1;
+	}
+	return _packetId;
+}
+
+uint8_t Client::getNextSnMsgId(void)
+{
+	_snMsgId++;
+	if (_snMsgId == 0)
+	{
+		_snMsgId++;
+	}
+	return _snMsgId;
+}
+
+Topics* Client::getTopics(void)
+{
+	return _topics;
+}
+
+Network* Client::getNetwork(void)
+{
+	return _network;
+}
+
+void Client::setClientAddress(SensorNetAddress* sensorNetAddr)
+{
+	_sensorNetAddr = *sensorNetAddr;
+}
+
+SensorNetAddress* Client::getSensorNetAddress(void)
+{
+	return &_sensorNetAddr;
+}
+
+void Client::setSensorNetType(bool stable)
+{
+	_sensorNetype = stable;
+}
+
+void Client::setTopics(Topics* topics)
+{
+  _topics = topics;
+}
+
+ClientStatus Client::getClientStatus(void)
+{
+    return _status;
+}
+
+void Client::setWaitWillMsgFlg(bool flg)
+{
+	_waitWillMsgFlg = flg;
+}
+
+bool Client::isWaitWillMsg(void)
+{
+	return _waitWillMsgFlg;
+}
+
+bool Client::isDisconnect(void)
+{
+	return (_status == Cstat_Disconnected);
+}
+
+bool Client::isActive(void)
+{
+	return (_status == Cstat_Active);
+}
+
+bool Client::isSleep(void)
+{
+	return (_status == Cstat_Asleep);
+}
+
+bool Client::isAwake(void)
+{
+	return (_status == Cstat_Awake);
+}
+
+bool Client::isConnecting(void)
+{
+    return (_status == Cstat_Connecting);
+}
+
+bool Client::isSecureNetwork(void)
+{
+	return _secureNetwork;
+}
+
+bool Client::isSensorNetStable(void)
+{
+	return _sensorNetype;
+}
+
+WaitREGACKPacketList* Client::getWaitREGACKPacketList()
+{
+	return &_waitREGACKList;
+}
+
+Client* Client::getNextClient(void)
+{
+	return _nextClient;
+}
+
+void Client::setClientId(MQTTSNString id)
+{
+	if ( _clientId )
+	{
+		free(_clientId);
+	}
+
+	if ( id.cstring )
+	{
+	    _clientId = (char*)calloc(strlen(id.cstring) + 1, 1);
+	    memcpy(_clientId, id.cstring, strlen(id.cstring));
+	}
+	else
+	{
+        /* save clientId into (char*)_clientId NULL terminated */
+        _clientId = (char*)calloc(MQTTSNstrlen(id) + 1, 1);
+        unsigned char* ptr = (unsigned char*)_clientId;
+        writeMQTTSNString((unsigned char**)&ptr, id);
+	}
+}
+
+void Client::setWillTopic(MQTTSNString willTopic)
+{
+	if ( _willTopic )
+	{
+		free(_willTopic);
+	}
+
+	_willTopic = (char*)calloc(MQTTSNstrlen(willTopic) + 1, 1);
+	/* save willTopic into (char*)_willTopic  with NULL termination */
+	unsigned char* ptr = (unsigned char*)_willTopic;
+	writeMQTTSNString((unsigned char**)&ptr, willTopic);
+}
+
+void Client::setWillMsg(MQTTSNString willMsg)
+{
+	if ( _willMsg)
+	{
+		free(_willMsg);
+	}
+
+	_willMsg = (char*)calloc(MQTTSNstrlen(willMsg) + 1, 1);
+	/* save willMsg into (char*)_willMsg  with NULL termination */
+	unsigned char* ptr = (unsigned char*)_willMsg;
+	writeMQTTSNString((unsigned char**)&ptr, willMsg);
+}
+
+char* Client::getClientId(void)
+{
+	return _clientId;
+}
+
+char* Client::getWillTopic(void)
+{
+	return _willTopic;
+}
+
+char* Client::getWillMsg(void)
+{
+	return _willMsg;
+}
+
+const char* Client::getStatus(void)
+{
+	return theClientStatus[_status];
+}
+
+bool Client::isQoSm1Proxy(void)
+{
+	return _clientType == Ctype_Proxy;
+}
+
+bool Client::isForwarded(void)
+{
+    return _clientType == Ctype_Forwarded;
+}
+
+bool Client::isAggregated(void)
+{
+    return _clientType == Ctype_Aggregated;
+}
+
+bool Client::isAggregater(void)
+{
+    return _clientType == Ctype_Aggregater;
+}
+
+void Client::setAdapterType(AdapterType type)
+{
+    switch ( type )
+    {
+    case Atype_QoSm1Proxy:
+    	_clientType = Ctype_Proxy;
+    	break;
+    case Atype_Aggregater:
+    	_clientType = Ctype_Aggregater;
+    	break;
+    default:
+    	throw Exception("Client::setAdapterType(): Invalid Type.");
+    	break;
+    }
+}
+
+bool Client::isAdapter(void)
+{
+	return _clientType == Ctype_Proxy || _clientType == Ctype_Aggregater;
+}
+
+bool Client::isQoSm1(void)
+{
+    return _clientType == Ctype_QoS_1;
+}
+
+void Client::setQoSm1(void)
+{
+    _clientType =  Ctype_QoS_1;
+}
+
+void Client::setAggregated(void)
+{
+	_clientType = Ctype_Aggregated;
+}
+
+void Client::holdPingRequest(void)
+{
+    _holdPingRequest = true;
+}
+
+void Client::resetPingRequest(void)
+{
+    _holdPingRequest = false;
+}
+
+bool Client::isHoldPringReqest(void)
+{
+    return _holdPingRequest;
+}
+
+
+
+/*=====================================
+ Class WaitREGACKPacket
+ =====================================*/
+waitREGACKPacket::waitREGACKPacket(MQTTSNPacket* packet, uint16_t REGACKMsgId)
+{
+	_packet = packet;
+	_msgId = REGACKMsgId;
+	_next = nullptr;
+	_prev = nullptr;
+}
+
+waitREGACKPacket::~waitREGACKPacket()
+{
+	delete _packet;
+}
+
+/*=====================================
+ Class WaitREGACKPacketList
+ =====================================*/
+
+WaitREGACKPacketList::WaitREGACKPacketList()
+{
+	_first = nullptr;
+	_end = nullptr;
+	_cnt = 0;
+}
+
+WaitREGACKPacketList::~WaitREGACKPacketList()
+{
+	waitREGACKPacket* p = _first;
+	while (p)
+	{
+		waitREGACKPacket* q = p->_next;
+		delete p;
+		p = q;
+	}
+}
+
+int WaitREGACKPacketList::setPacket(MQTTSNPacket* packet, uint16_t REGACKMsgId)
+{
+	waitREGACKPacket* elm = new waitREGACKPacket(packet, REGACKMsgId);
+	if (elm == nullptr)
+	{
+		return 0;
+	}
+
+	if (_first == nullptr)
+	{
+		_first = elm;
+		_end = elm;
+	}
+	else
+	{
+		_end->_next = elm;
+		elm->_prev = _end;
+		_end = elm;
+	}
+	_cnt++;
+	return 1;
+}
+
+MQTTSNPacket* WaitREGACKPacketList::getPacket(uint16_t REGACKMsgId)
+{
+	waitREGACKPacket* p = _first;
+	while (p)
+	{
+		if (p->_msgId == REGACKMsgId)
+		{
+			return p->_packet;
+		}
+		p = p->_next;
+	}
+	return nullptr;
+}
+
+void WaitREGACKPacketList::erase(uint16_t REGACKMsgId)
+{
+	waitREGACKPacket* p = _first;
+	while (p)
+	{
+		if (p->_msgId == REGACKMsgId)
+		{
+			if (p->_prev == nullptr)
+			{
+				_first = p->_next;
+
+			}
+			else
+			{
+				p->_prev->_next = p->_next;
+			}
+			if (p->_next == nullptr)
+			{
+				_end = p->_prev;
+			}
+			else
+			{
+				p->_next->_prev = p->_prev;
+			}
+			_cnt--;
+            break;
+            // Do not delete element. Element is deleted after sending to Client.
+		}
+		p = p->_next;
+	}
+}
+
+uint8_t WaitREGACKPacketList::getCount(void)
+{
+    return _cnt;
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClient.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClient.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,305 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ *    Tieto Poland Sp. z o.o. - Gateway improvements
+ **************************************************************************************/
+
+#ifndef MQTTSNGWCLIENT_H_
+#define MQTTSNGWCLIENT_H_
+
+#include <Timer.h>    // Timer class
+#include "MQTTSNGWProcess.h"
+#include "MQTTGWPacket.h"
+#include "MQTTSNGWPacket.h"
+#include "MQTTSNPacket.h"
+#include "Network.h"
+#include "SensorNetwork.h"
+#include "MQTTSNPacket.h"
+#include "MQTTSNGWEncapsulatedPacket.h"
+#include "MQTTSNGWForwarder.h"
+#include "MQTTSNGWTopic.h"
+#include "MQTTSNGWClientList.h"
+#include "MQTTSNGWAdapter.h"
+
+namespace MQTTSNGW
+{
+
+#define MQTTSN_TOPIC_MULTI_WILDCARD   '#'
+#define MQTTSN_TOPIC_SINGLE_WILDCARD  '+'
+
+/*=====================================
+ Class PacketQue
+ =====================================*/
+template<class T> class PacketQue
+{
+public:
+    PacketQue()
+    {
+        _que = new Que<T>;
+    }
+
+
+    ~PacketQue()
+    {
+        clear();
+        delete _que;
+    }
+
+    T* getPacket()
+    {
+        T* packet;
+        if (_que->size() > 0)
+        {
+            _mutex.lock();
+            packet = _que->front();
+            _mutex.unlock();
+            return packet;
+        }
+        else
+        {
+            return 0;
+        }
+    }
+
+    int
+    post(T* packet)
+    {
+        int rc;
+        _mutex.lock();
+        rc = _que->post(packet);
+        _mutex.unlock();
+        return rc;
+    }
+
+    void pop()
+    {
+        if (_que->size() > 0)
+        {
+            _mutex.lock();
+            _que->pop();
+            _mutex.unlock();
+        }
+    }
+
+    void clear()
+    {
+        _mutex.lock();
+        while (_que->size() > 0)
+        {
+            delete _que->front();
+            _que->pop();
+        }
+        _mutex.unlock();
+    }
+
+    void setMaxSize(int size)
+    {
+        _que->setMaxSize(size);
+    }
+
+private:
+    Que<T>* _que;
+    Mutex _mutex;
+};
+
+
+
+/*=====================================
+ Class WaitREGACKPacket
+ =====================================*/
+class waitREGACKPacket
+{
+    friend class WaitREGACKPacketList;
+public:
+    waitREGACKPacket(MQTTSNPacket* packet, uint16_t REGACKMsgId);
+    ~waitREGACKPacket();
+
+private:
+    uint16_t _msgId;
+    MQTTSNPacket* _packet;
+    waitREGACKPacket* _next;
+    waitREGACKPacket* _prev;
+};
+
+/*=====================================
+ Class WaitREGACKPacketList
+ =====================================*/
+class WaitREGACKPacketList
+{
+public:
+    WaitREGACKPacketList();
+    ~WaitREGACKPacketList();
+    int setPacket(MQTTSNPacket* packet, uint16_t REGACKMsgId);
+    MQTTSNPacket* getPacket(uint16_t REGACKMsgId);
+    void erase(uint16_t REGACKMsgId);
+    uint8_t getCount(void);
+
+private:
+    uint8_t _cnt;
+    waitREGACKPacket* _first;
+    waitREGACKPacket* _end;
+};
+
+
+
+/*=====================================
+ Class Client
+ =====================================*/
+typedef enum
+{
+    Cstat_Disconnected = 0, Cstat_TryConnecting, Cstat_Connecting, Cstat_Active, Cstat_Asleep, Cstat_Awake, Cstat_Lost
+} ClientStatus;
+
+typedef enum
+{
+    Ctype_Regular = 0, Ctype_Forwarded, Ctype_QoS_1, Ctype_Aggregated, Ctype_Proxy, Ctype_Aggregater
+}ClientType;
+
+class Forwarder;
+
+class Client
+{
+    friend class ClientList;
+public:
+    Client(bool secure = false);
+    Client(uint8_t maxInflightMessages, bool secure);
+    ~Client();
+
+    Connect* getConnectData(void);
+    TopicIdMapElement* getWaitedPubTopicId(uint16_t msgId);
+    TopicIdMapElement* getWaitedSubTopicId(uint16_t msgId);
+    MQTTGWPacket* getClientSleepPacket(void);
+    void deleteFirstClientSleepPacket(void);
+
+    MQTTSNPacket* getProxyPacket(void);
+    void deleteFirstProxyPacket(void);
+    WaitREGACKPacketList* getWaitREGACKPacketList(void);
+
+    void eraseWaitedPubTopicId(uint16_t msgId);
+    void eraseWaitedSubTopicId(uint16_t msgId);
+    void clearWaitedPubTopicId(void);
+    void clearWaitedSubTopicId(void);
+
+    int  setClientSleepPacket(MQTTGWPacket*);
+    int setProxyPacket(MQTTSNPacket* packet);
+    void setWaitedPubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type);
+    void setWaitedSubTopicId(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type);
+
+    bool checkTimeover(void);
+    void updateStatus(MQTTSNPacket*);
+    void updateStatus(ClientStatus);
+    void connectSended(void);
+    void connackSended(int rc);
+    void disconnected(void);
+    bool isConnectSendable(void);
+    void tryConnect(void);
+    ClientStatus getClientStatus(void);
+
+    uint16_t getNextPacketId(void);
+    uint8_t getNextSnMsgId(void);
+    Topics* getTopics(void);
+    void setTopics(Topics* topics);
+    void setKeepAlive(MQTTSNPacket* packet);
+
+    SensorNetAddress* getSensorNetAddress(void);
+    Network* getNetwork(void);
+    void setClientAddress(SensorNetAddress* sensorNetAddr);
+    void setSensorNetType(bool stable);
+
+    Forwarder* getForwarder(void);
+    void setForwarder(Forwarder* forwader);
+
+    void setAdapterType(AdapterType type);
+    void setQoSm1(void);
+    void setAggregated(void);
+    bool isQoSm1Proxy(void);
+    bool isForwarded(void);
+    bool isAggregated(void);
+    bool isAggregater(void);
+    bool isQoSm1(void);
+    bool isAdapter(void);
+
+    void setClientId(MQTTSNString id);
+    void setWillTopic(MQTTSNString willTopic);
+    void setWillMsg(MQTTSNString willmsg);
+    char* getClientId(void);
+    char* getWillTopic(void);
+    char* getWillMsg(void);
+    const char* getStatus(void);
+    void setWaitWillMsgFlg(bool);
+    void setSessionStatus(bool);  // true: clean session
+    bool erasable(void);
+
+    bool isDisconnect(void);
+    bool isConnecting(void);
+    bool isActive(void);
+    bool isSleep(void);
+    bool isAwake(void);
+    bool isSecureNetwork(void);
+    bool isSensorNetStable(void);
+    bool isWaitWillMsg(void);
+
+    void holdPingRequest(void);
+    void resetPingRequest(void);
+    bool isHoldPringReqest(void);
+
+    Client* getNextClient(void);
+
+private:
+    PacketQue<MQTTGWPacket> _clientSleepPacketQue;
+    PacketQue<MQTTSNPacket> _proxyPacketQue;
+
+    WaitREGACKPacketList    _waitREGACKList;
+
+    Topics* _topics;
+    TopicIdMap _waitedPubTopicIdMap;
+    TopicIdMap _waitedSubTopicIdMap;
+
+    Connect _connectData;
+    MQTTSNPacket* _connAck;
+
+    char* _clientId;
+    char* _willTopic;
+    char* _willMsg;
+
+    bool _holdPingRequest;
+
+    Timer _keepAliveTimer;
+    uint32_t _keepAliveMsec;
+
+    ClientStatus _status;
+    bool _waitWillMsgFlg;
+
+    uint16_t _packetId;
+    uint8_t _snMsgId;
+
+    Network* _network;      // Broker
+    bool  _secureNetwork;    // SSL
+    bool _sensorNetype;     // false: unstable network like a G3
+    SensorNetAddress _sensorNetAddr;
+
+    Forwarder* _forwarder;
+    ClientType _clientType;
+
+    bool _sessionStatus;
+    bool _hasPredefTopic;
+
+    Client* _nextClient;
+    Client* _prevClient;
+};
+
+
+
+}
+#endif /* MQTTSNGWCLIENT_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientList.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientList.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,483 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ *    Tieto Poland Sp. z o.o. - Gateway improvements
+ **************************************************************************************/
+#include "MQTTSNGWClientList.h"
+#include "MQTTSNGateway.h"
+#include <string.h>
+#include <string>
+
+using namespace MQTTSNGW;
+extern Gateway* theGateway;
+/*=====================================
+ Class ClientList
+ =====================================*/
+const char* common_topic = "*";
+
+ClientList::ClientList()
+{
+    _clientCnt = 0;
+    _authorize = false;
+    _firstClient = nullptr;
+    _endClient = nullptr;
+}
+
+ClientList::~ClientList()
+{
+    _mutex.lock();
+    Client* cl = _firstClient;
+    Client* ncl;
+
+    while (cl != nullptr)
+    {
+        ncl = cl->_nextClient;
+        delete cl;
+        cl = ncl;
+    };
+    _mutex.unlock();
+}
+
+void ClientList::initialize(bool aggregate)
+{
+    if (theGateway->getGWParams()->clientAuthentication )
+    {
+		int type = TRANSPEARENT_TYPE;
+		if ( aggregate )
+		{
+			type = AGGREGATER_TYPE;
+		}
+		setClientList(type);
+        _authorize = true;
+    }
+}
+
+void ClientList::setClientList(int type)
+{
+	char param[MQTTSNGW_PARAM_MAX];
+	string fileName;
+	GatewayParams* params = theGateway->getGWParams();
+	if (theGateway->getParam("ClientsList", param) == 0)
+	{
+		fileName = string(param);
+	}
+	else
+	{
+		fileName = params->configDir + string(CLIENT_LIST);
+	}
+
+	if (!createList(fileName.c_str(), type))
+	{
+		throw Exception("ClientList::initialize(): No client list defined by the configuration.");
+	}
+
+	if ( params->clientListName == nullptr )
+	{
+		params->clientListName = strdup(fileName.c_str());
+	}
+}
+
+void ClientList::setPredefinedTopics(bool aggrecate)
+{
+	char param[MQTTSNGW_PARAM_MAX];
+
+	string fileName;
+	GatewayParams* params = theGateway->getGWParams();
+
+	if (theGateway->getParam("PredefinedTopicList", param) == 0)
+	{
+		fileName = string(param);
+	}
+	else
+	{
+		fileName = params->configDir + string(PREDEFINEDTOPIC_FILE);
+	}
+
+	if ( readPredefinedList(fileName.c_str(), aggrecate) )
+	{
+		params->predefinedTopicFileName = strdup(fileName.c_str());
+	}
+}
+
+/**
+ * Create ClientList from a client list file.
+ * @param File name of the client list
+ * @return true: Reject client connection that is not registered in the client list
+ *
+ * File format is:
+ *     Lines bigning with # are comment line.
+ *     ClientId, SensorNetAddress, "unstableLine", "secureConnection"
+ *     in case of UDP, SensorNetAddress format is portNo@IPAddress.
+ *     if the SensorNetwork is not stable, write unstableLine.
+ *     if BrokerConnection is SSL, write secureConnection.
+ *     if the client send PUBLISH QoS-1, QoS-1 is required.
+ *
+ * Ex:
+ *     #Client List
+ *     ClientId1,11200@192.168.10.10
+ *     ClientID2,35000@192.168.50.200,unstableLine
+ *     ClientID3,40000@192.168.200.50,secureConnection
+ *     ClientID4,41000@192.168.200.51,unstableLine,secureConnection
+ *      ClientID5,41000@192.168.200.51,unstableLine,secureConnection,QoS-1
+ */
+
+bool ClientList::createList(const char* fileName, int type)
+{
+    FILE* fp;
+    char buf[MAX_CLIENTID_LENGTH + 256];
+    size_t pos;
+    bool secure;
+    bool stable;
+    bool qos_1;
+    bool forwarder;
+    bool rc = true;
+    SensorNetAddress netAddr;
+    MQTTSNString clientId = MQTTSNString_initializer;
+
+    if ((fp = fopen(fileName, "r")) != 0)
+    {
+        while (fgets(buf, MAX_CLIENTID_LENGTH + 254, fp) != 0)
+        {
+            if (*buf == '#')
+            {
+                continue;
+            }
+            string data = string(buf);
+            while ((pos = data.find_first_of("  \t\n")) != string::npos)
+            {
+                data.erase(pos, 1);
+            }
+            if (data.empty())
+            {
+                continue;
+            }
+            pos = data.find_first_of(",");
+            string id = data.substr(0, pos);
+            clientId.cstring = strdup(id.c_str());
+            string addr = data.substr(pos + 1);
+
+            if (netAddr.setAddress(&addr) == 0)
+            {
+                qos_1 = (data.find("QoS-1") != string::npos);
+                forwarder = (data.find("forwarder") != string::npos);
+                secure = (data.find("secureConnection") != string::npos);
+                stable = !(data.find("unstableLine") != string::npos);
+                if ( (qos_1 && type == QOSM1PROXY_TYPE) || (!qos_1 && type == AGGREGATER_TYPE) )
+                {
+                	createClient(&netAddr, &clientId, stable, secure, type);
+                }
+                else if ( forwarder && type == FORWARDER_TYPE)
+                {
+                	theGateway->getAdapterManager()->getForwarderList()->addForwarder(&netAddr, &clientId);
+                }
+                else if (type == TRANSPEARENT_TYPE )
+                {
+                	createClient(&netAddr, &clientId, stable, secure, type);
+                }
+            }
+            else
+            {
+                WRITELOG("Invalid address     %s\n", data.c_str());
+                rc = false;
+            }
+            free(clientId.cstring);
+        }
+        fclose(fp);
+    }
+    return rc;
+}
+
+bool ClientList::readPredefinedList(const char* fileName, bool aggregate)
+{
+    FILE* fp;
+    char buf[MAX_CLIENTID_LENGTH + 256];
+    size_t pos0, pos1;
+    MQTTSNString clientId = MQTTSNString_initializer;;
+    bool rc = false;
+
+    if ((fp = fopen(fileName, "r")) != 0)
+    {
+        while (fgets(buf, MAX_CLIENTID_LENGTH + 254, fp) != 0)
+        {
+            if (*buf == '#')
+            {
+                continue;
+            }
+            string data = string(buf);
+            while ((pos0 = data.find_first_of("  \t\n")) != string::npos)
+            {
+                data.erase(pos0, 1);
+            }
+            if (data.empty())
+            {
+                continue;
+            }
+
+            pos0 = data.find_first_of(",");
+            pos1 = data.find(",", pos0 + 1) ;
+            string id = data.substr(0, pos0);
+            clientId.cstring = strdup(id.c_str());
+            string topicName = data.substr(pos0 + 1, pos1 - pos0 -1);
+            uint16_t topicID = stoul(data.substr(pos1 + 1));
+            createPredefinedTopic( &clientId, topicName,  topicID, aggregate);
+            free(clientId.cstring);
+        }
+        fclose(fp);
+        rc = true;
+    }
+    else
+    {
+        WRITELOG("ClientList can not open the Predefined Topic List.     %s\n", fileName);
+        return false;
+    }
+    return rc;
+}
+
+void ClientList::erase(Client*& client)
+{
+    if ( !_authorize && client->erasable())
+    {
+        _mutex.lock();
+        Client* prev = client->_prevClient;
+        Client* next = client->_nextClient;
+
+        if (prev)
+        {
+            prev->_nextClient = next;
+        }
+        else
+        {
+            _firstClient = next;
+
+        }
+        if (next)
+        {
+            next->_prevClient = prev;
+        }
+        else
+        {
+            _endClient = prev;
+        }
+        _clientCnt--;
+        Forwarder* fwd = client->getForwarder();
+        if ( fwd )
+        {
+            fwd->eraseClient(client);
+        }
+        delete client;
+        client = nullptr;
+        _mutex.unlock();
+    }
+}
+
+Client* ClientList::getClient(SensorNetAddress* addr)
+{
+    if ( addr )
+    {
+        _mutex.lock();
+        Client* client = _firstClient;
+
+        while (client != nullptr)
+        {
+            if (client->getSensorNetAddress()->isMatch(addr) )
+            {
+                _mutex.unlock();
+                return client;
+            }
+            client = client->_nextClient;
+        }
+        _mutex.unlock();
+    }
+    return 0;
+}
+
+Client* ClientList::getClient(int index)
+{
+   Client* client = _firstClient;
+   int p = 0;
+   while ( client != nullptr )
+   {
+       if ( p == index )
+       {
+           return client;
+       }
+       else
+       {
+           client = client->_nextClient;
+           p++;
+       }
+   }
+   return nullptr;
+}
+
+
+Client* ClientList::getClient(MQTTSNString* clientId)
+{
+    _mutex.lock();
+    Client* client = _firstClient;
+    const char* clID =clientId->cstring;
+
+    if (clID == nullptr )
+    {
+        clID = clientId->lenstring.data;
+    }
+
+    while (client != nullptr)
+    {
+        if (strncmp((const char*)client->getClientId(), clID, MQTTSNstrlen(*clientId)) == 0 )
+        {
+            _mutex.unlock();
+            return client;
+        }
+        client = client->_nextClient;
+    }
+    _mutex.unlock();
+    return 0;
+}
+
+Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, int type)
+{
+	return createClient(addr, clientId, false, false, type);
+}
+
+Client* ClientList::createClient(SensorNetAddress* addr, MQTTSNString* clientId, bool unstableLine, bool secure, int type)
+{
+    Client* client = nullptr;
+
+    /*  anonimous clients */
+    if ( _clientCnt > MAX_CLIENTS )
+    {
+        return 0;  // full of clients
+    }
+
+    client = getClient(addr);
+    if ( client )
+    {
+        return client;
+    }
+
+    /* creat a new client */
+    client = new Client(secure);
+    if ( addr )
+    {
+        client->setClientAddress(addr);
+    }
+    client->setSensorNetType(unstableLine);
+    if ( MQTTSNstrlen(*clientId) )
+    {
+        client->setClientId(*clientId);
+    }
+    else
+    {
+        MQTTSNString  dummyId MQTTSNString_initializer;;
+        dummyId.cstring = strdup("");
+        client->setClientId(dummyId);
+         free(dummyId.cstring);
+    }
+
+    if ( type == AGGREGATER_TYPE )
+    {
+    	client->setAggregated();
+    }
+    else if ( type == QOSM1PROXY_TYPE )
+    {
+        client->setQoSm1();
+    }
+
+    _mutex.lock();
+
+    /* add the list */
+    if ( _firstClient == nullptr )
+    {
+        _firstClient = client;
+        _endClient = client;
+    }
+    else
+    {
+        _endClient->_nextClient = client;
+        client->_prevClient = _endClient;
+        _endClient = client;
+    }
+    _clientCnt++;
+    _mutex.unlock();
+    return client;
+}
+
+Client* ClientList::createPredefinedTopic( MQTTSNString* clientId, string topicName, uint16_t topicId, bool aggregate)
+{
+	if ( clientId->cstring == common_topic )
+	{
+		_gateway->getTopics()->add((const char*)topicName.c_str(), topicId);
+		return 0;
+	}
+	else
+	{
+		Client* client = getClient(clientId);
+
+		if ( _authorize && client == nullptr )
+		{
+			return 0;
+		}
+
+		/*  anonimous clients */
+		if ( _clientCnt > MAX_CLIENTS )
+		{
+			return nullptr;  // full of clients
+		}
+
+		if ( client == nullptr )
+		{
+			/* creat a new client */
+			client = new Client();
+			client->setClientId(*clientId);
+			if ( aggregate )
+			{
+				client->setAggregated();
+			}
+			_mutex.lock();
+
+			/* add the list */
+			if ( _firstClient == nullptr )
+			{
+				_firstClient = client;
+				_endClient = client;
+			}
+			else
+			{
+				_endClient->_nextClient = client;
+				client->_prevClient = _endClient;
+				_endClient = client;
+			}
+			_clientCnt++;
+			_mutex.unlock();
+		}
+
+		// create Topic & Add it
+		client->getTopics()->add((const char*)topicName.c_str(), topicId);
+		client->_hasPredefTopic = true;
+		return client;
+	}
+}
+
+uint16_t ClientList::getClientCount()
+{
+    return _clientCnt;
+}
+
+bool ClientList::isAuthorized()
+{
+    return _authorize;
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientList.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientList.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,72 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ *    Tieto Poland Sp. z o.o. - Gateway improvements
+ **************************************************************************************/
+
+#ifndef MQTTSNGATEWAY_SRC_MQTTSNGWCLIENTLIST_H_
+#define MQTTSNGATEWAY_SRC_MQTTSNGWCLIENTLIST_H_
+
+#include "MQTTSNGWClient.h"
+#include "MQTTSNGateway.h"
+
+namespace MQTTSNGW
+{
+#define TRANSPEARENT_TYPE 0
+#define QOSM1PROXY_TYPE 1
+#define AGGREGATER_TYPE 2
+#define FORWARDER_TYPE  3
+
+class Client;
+
+/*=====================================
+ Class ClientList
+ =====================================*/
+class ClientList
+{
+public:
+    ClientList();
+    ~ClientList();
+
+    void initialize(bool aggregate);
+    void setClientList(int type);
+    void setPredefinedTopics(bool aggregate);
+    void erase(Client*&);
+    Client* createClient(SensorNetAddress* addr, MQTTSNString* clientId,int type);
+    Client* createClient(SensorNetAddress* addr, MQTTSNString* clientId, bool unstableLine, bool secure, int type);
+    bool createList(const char* fileName, int type);
+    Client* getClient(SensorNetAddress* addr);
+    Client* getClient(MQTTSNString* clientId);
+    Client* getClient(int index);
+    uint16_t getClientCount(void);
+    Client* getClient(void);
+    bool isAuthorized();
+
+private:
+    bool readPredefinedList(const char* fileName, bool _aggregate);
+    Gateway* _gateway {nullptr};
+    Client* createPredefinedTopic( MQTTSNString* clientId, string topicName, uint16_t toipcId, bool _aggregate);
+    Client* _firstClient;
+    Client* _endClient;
+    Mutex _mutex;
+    uint16_t _clientCnt;
+    bool _authorize {false};
+};
+
+
+}
+
+
+
+#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWCLIENTLIST_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientRecvTask.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,304 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include "MQTTSNGWClientRecvTask.h"
+#include "MQTTSNPacket.h"
+#include "MQTTSNGWQoSm1Proxy.h"
+#include "MQTTSNGWEncapsulatedPacket.h"
+#include <cstring>
+
+//#include "MQTTSNGWForwarder.h"
+
+using namespace MQTTSNGW;
+char* currentDateTime(void);
+/*=====================================
+ Class ClientRecvTask
+ =====================================*/
+ClientRecvTask::ClientRecvTask(Gateway* gateway)
+{
+	_gateway = gateway;
+	_gateway->attach((Thread*)this);
+	_sensorNetwork = _gateway->getSensorNetwork();
+}
+
+ClientRecvTask::~ClientRecvTask()
+{
+
+}
+
+/**
+ * Initialize SensorNetwork
+ */
+void ClientRecvTask::initialize(int argc, char** argv)
+{
+	if ( _sensorNetwork->initialize() < 0 )
+	{
+		throw Exception(" Can't open the sensor network.\n");
+	}
+}
+
+/*
+ * Receive a packet from clients via sensor netwwork
+ * and generate a event to execute the packet handling  procedure
+ * of MQTTSNPacketHandlingTask.
+ */
+void ClientRecvTask::run()
+{
+	Event* ev = nullptr;
+	AdapterManager* adpMgr = _gateway->getAdapterManager();
+	QoSm1Proxy* qosm1Proxy = adpMgr->getQoSm1Proxy();
+	bool isAggrActive = adpMgr->isAggregaterActive();
+	ClientList* clientList = _gateway->getClientList();
+	EventQue* packetEventQue = _gateway->getPacketEventQue();
+
+	char buf[128];
+
+	while (true)
+	{
+		Client* client = nullptr;
+	    Forwarder* fwd = nullptr;
+	    WirelessNodeId nodeId;
+
+		MQTTSNPacket* packet = new MQTTSNPacket();
+		int packetLen = packet->recv(_sensorNetwork);
+
+		if (CHK_SIGINT)
+		{
+			WRITELOG("%s ClientRecvTask   stopped.\n", currentDateTime());
+			delete packet;
+			return;
+		}
+
+		if (packetLen < 2 )
+		{
+			delete packet;
+			continue;
+		}
+
+		if ( packet->getType() <= MQTTSN_ADVERTISE || packet->getType() == MQTTSN_GWINFO )
+		{
+			delete packet;
+			continue;
+		}
+
+		if ( packet->getType() == MQTTSN_SEARCHGW )
+		{
+			/* write log and post Event */
+			log(0, packet, 0);
+			ev = new Event();
+			ev->setBrodcastEvent(packet);
+			packetEventQue->post(ev);
+			continue;
+		}
+
+
+		SensorNetAddress* senderAddr = _gateway->getSensorNetwork()->getSenderAddress();
+
+		if ( packet->getType() == MQTTSN_ENCAPSULATED )
+		{
+			fwd = _gateway->getAdapterManager()->getForwarderList()->getForwarder(senderAddr);
+
+			if ( fwd != nullptr )
+			{
+				MQTTSNString fwdName = MQTTSNString_initializer;
+				fwdName.cstring = const_cast<char *>( fwd->getName() );
+				log(0, packet, &fwdName);
+
+				/* get the packet from the encapsulation message */
+				MQTTSNGWEncapsulatedPacket  encap;
+				encap.desirialize(packet->getPacketData(), packet->getPacketLength());
+				nodeId.setId( encap.getWirelessNodeId() );
+				client = fwd->getClient(&nodeId);
+				packet = encap.getMQTTSNPacket();
+			}
+		}
+		else
+		{
+			/*   Check the client belonging to QoS-1Proxy  ?    */
+
+			if ( qosm1Proxy->isActive() )
+			{
+				 const char* clientName = qosm1Proxy->getClientId(senderAddr);
+
+				if ( clientName )
+				{
+					if ( !packet->isQoSMinusPUBLISH() )
+					{
+						client = qosm1Proxy->getClient();
+						log(clientName, packet);
+						WRITELOG("%s %s  %s can send only PUBLISH with QoS-1.%s\n", ERRMSG_HEADER, clientName, senderAddr->sprint(buf), ERRMSG_FOOTER);
+						delete packet;
+						continue;
+					}
+				}
+			}
+		}
+
+		client = _gateway->getClientList()->getClient(senderAddr);
+
+		if ( client )
+		{
+			/* write log and post Event */
+			log(client, packet, 0);
+			ev = new Event();
+			ev->setClientRecvEvent(client,packet);
+			packetEventQue->post(ev);
+		}
+		else
+		{
+			/* new client */
+ 		    if (packet->getType() == MQTTSN_CONNECT)
+			{
+				MQTTSNPacket_connectData data;
+				memset(&data, 0, sizeof(MQTTSNPacket_connectData));
+				if ( !packet->getCONNECT(&data) )
+				{
+					log(0, packet, &data.clientID);
+					WRITELOG("%s CONNECT message form %s is incorrect.%s\n", ERRMSG_HEADER, senderAddr->sprint(buf), ERRMSG_FOOTER);
+					delete packet;
+					continue;
+				}
+
+				client = clientList->getClient(&data.clientID);
+
+				if ( fwd )
+				{
+				    if ( client == nullptr )
+				    {
+				        /* create a new client */
+				        client = clientList->createClient(0, &data.clientID, isAggrActive);
+				    }
+				    /* Add to af forwarded client list of forwarder. */
+                    fwd->addClient(client, &nodeId);
+				}
+				else
+				{
+                    if ( client )
+                    {
+                        /* Client exists. Set SensorNet Address of it. */
+                        client->setClientAddress(senderAddr);
+                    }
+                    else
+                    {
+                        /* create a new client */
+                        client = clientList->createClient(senderAddr, &data.clientID, isAggrActive);
+                    }
+				}
+
+				log(client, packet, &data.clientID);
+
+				if (!client)
+				{
+	                WRITELOG("%s Client(%s) was rejected. CONNECT message has been discarded.%s\n", ERRMSG_HEADER, senderAddr->sprint(buf), ERRMSG_FOOTER);
+					delete packet;
+					continue;
+				}
+
+				/* post Client RecvEvent */
+				ev = new Event();
+				ev->setClientRecvEvent(client, packet);
+				packetEventQue->post(ev);
+			}
+ 		    else
+			{
+				log(client, packet, 0);
+				if ( packet->getType() == MQTTSN_ENCAPSULATED )
+				{
+					WRITELOG("%s Forwarder(%s) is not declared by ClientList file. message has been discarded.%s\n", ERRMSG_HEADER, _sensorNetwork->getSenderAddress()->sprint(buf), ERRMSG_FOOTER);
+				}
+				else
+				{
+					WRITELOG("%s Client(%s) is not connecting. message has been discarded.%s\n", ERRMSG_HEADER, senderAddr->sprint(buf), ERRMSG_FOOTER);
+				}
+				delete packet;
+			}
+		}
+	}
+}
+
+void ClientRecvTask::log(Client* client, MQTTSNPacket* packet, MQTTSNString* id)
+{
+	const char* clientId;
+	char cstr[MAX_CLIENTID_LENGTH + 1];
+
+	if ( id )
+	{
+	    if ( id->cstring )
+	    {
+	        strncpy(cstr, id->cstring, strlen(id->cstring) );
+	        clientId = cstr;
+	    }
+	    else
+	    {
+            memset((void*)cstr, 0, id->lenstring.len + 1);
+            strncpy(cstr, id->lenstring.data, id->lenstring.len );
+            clientId = cstr;
+	    }
+	}
+	else if ( client )
+	{
+		clientId = client->getClientId();
+	}
+	else
+	{
+		clientId = UNKNOWNCL;
+	}
+
+	log(clientId,  packet);
+}
+
+void ClientRecvTask::log(const char* clientId, MQTTSNPacket* packet)
+{
+    char pbuf[ SIZE_OF_LOG_PACKET * 3 + 1];
+    char msgId[6];
+
+    switch (packet->getType())
+    {
+    case MQTTSN_SEARCHGW:
+        WRITELOG(FORMAT_Y_G_G_NL, currentDateTime(), packet->getName(), LEFTARROW, CLIENT, packet->print(pbuf));
+        break;
+    case MQTTSN_CONNECT:
+    case MQTTSN_PINGREQ:
+        WRITELOG(FORMAT_Y_G_G_NL, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf));
+        break;
+    case MQTTSN_DISCONNECT:
+    case MQTTSN_WILLTOPICUPD:
+    case MQTTSN_WILLMSGUPD:
+    case MQTTSN_WILLTOPIC:
+    case MQTTSN_WILLMSG:
+        WRITELOG(FORMAT_Y_G_G, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf));
+        break;
+    case MQTTSN_PUBLISH:
+    case MQTTSN_REGISTER:
+    case MQTTSN_SUBSCRIBE:
+    case MQTTSN_UNSUBSCRIBE:
+        WRITELOG(FORMAT_G_MSGID_G_G_NL, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROW, clientId, packet->print(pbuf));
+        break;
+    case MQTTSN_REGACK:
+    case MQTTSN_PUBACK:
+    case MQTTSN_PUBREC:
+    case MQTTSN_PUBREL:
+    case MQTTSN_PUBCOMP:
+        WRITELOG(FORMAT_G_MSGID_G_G, currentDateTime(), packet->getName(), packet->getMsgId(msgId), LEFTARROW, clientId, packet->print(pbuf));
+        break;
+    case MQTTSN_ENCAPSULATED:
+            WRITELOG(FORMAT_Y_G_G, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf));
+            break;
+    default:
+        WRITELOG(FORMAT_W_NL, currentDateTime(), packet->getName(), LEFTARROW, clientId, packet->print(pbuf));
+        break;
+    }
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientRecvTask.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,49 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#ifndef MQTTSNGWCLIENTRECVTASK_H_
+#define MQTTSNGWCLIENTRECVTASK_H_
+
+#include "SensorNetwork.h"
+#include "MQTTSNGateway.h"
+
+namespace MQTTSNGW
+{
+class AdapterManager;
+
+/*=====================================
+     Class ClientRecvTask
+ =====================================*/
+class ClientRecvTask:public Thread
+{
+	MAGIC_WORD_FOR_THREAD;
+	friend AdapterManager;
+public:
+	ClientRecvTask(Gateway*);
+	~ClientRecvTask(void);
+	virtual void initialize(int argc, char** argv);
+	void run(void);
+
+private:
+	void log(Client*, MQTTSNPacket*, MQTTSNString* id);
+	void log(const char* clientId, MQTTSNPacket* packet);
+
+	Gateway*       _gateway;
+	SensorNetwork* _sensorNetwork;
+};
+
+}
+
+#endif /* MQTTSNGWCLIENTRECVTASK_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientSendTask.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,123 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#include "MQTTSNGWClientSendTask.h"
+#include "MQTTSNGWPacket.h"
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWEncapsulatedPacket.h"
+#include "MQTTSNGWQoSm1Proxy.h"
+
+using namespace MQTTSNGW;
+using namespace std;
+char* currentDateTime(void);
+/*=====================================
+ Class ClientSendTask
+ =====================================*/
+ClientSendTask::ClientSendTask(Gateway* gateway)
+{
+	_gateway = gateway;
+	_gateway->attach((Thread*)this);
+	_sensorNetwork = _gateway->getSensorNetwork();
+}
+
+ClientSendTask::~ClientSendTask()
+{
+
+}
+
+void ClientSendTask::run()
+{
+	Client* client = nullptr;
+	MQTTSNPacket* packet = nullptr;
+	AdapterManager* adpMgr = _gateway->getAdapterManager();
+	int rc = 0;
+
+	while (true)
+	{
+		Event* ev = _gateway->getClientSendQue()->wait();
+
+		if (ev->getEventType() == EtStop)
+		{
+			WRITELOG("%s ClientSendTask   stopped.\n", currentDateTime());
+			delete ev;
+			break;
+		}
+		if (ev->getEventType() == EtClientSend)
+		{
+			client = ev->getClient();
+			packet = ev->getMQTTSNPacket();
+			rc = adpMgr->unicastToClient(client, packet, this);
+		}
+		else if (ev->getEventType() == EtBroadcast)
+		{
+			packet = ev->getMQTTSNPacket();
+			log(client, packet);
+			rc = packet->broadcast(_sensorNetwork);
+		}
+		else if (ev->getEventType() == EtSensornetSend)
+		{
+			packet = ev->getMQTTSNPacket();
+			log(client, packet);
+			rc = packet->unicast(_sensorNetwork, ev->getSensorNetAddress());
+		}
+
+		if ( rc < 0 )
+		{
+			WRITELOG("%s ClientSendTask can't send a packet to the client %s%s.\n",
+				ERRMSG_HEADER, (client ? (const char*)client->getClientId() : UNKNOWNCL ), ERRMSG_FOOTER);
+		}
+		delete ev;
+	}
+}
+
+void ClientSendTask::log(Client* client, MQTTSNPacket* packet)
+{
+	char pbuf[SIZE_OF_LOG_PACKET * 3 + 1];
+	char msgId[6];
+	const char* clientId = client ? (const char*)client->getClientId() : UNKNOWNCL ;
+
+	switch (packet->getType())
+	{
+	case MQTTSN_ADVERTISE:
+	case MQTTSN_GWINFO:
+		WRITELOG(FORMAT_Y_W_G, currentDateTime(), packet->getName(), RIGHTARROW, CLIENTS, packet->print(pbuf));
+		break;
+	case MQTTSN_CONNACK:
+	case MQTTSN_DISCONNECT:
+	case MQTTSN_WILLTOPICREQ:
+	case MQTTSN_WILLMSGREQ:
+	case MQTTSN_WILLTOPICRESP:
+	case MQTTSN_WILLMSGRESP:
+	case MQTTSN_PINGRESP:
+		WRITELOG(FORMAT_Y_W_G, currentDateTime(), packet->getName(), RIGHTARROW, clientId, packet->print(pbuf));
+		break;
+	case MQTTSN_REGISTER:
+	case MQTTSN_PUBLISH:
+		WRITELOG(FORMAT_W_MSGID_W_G, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROW, clientId,	packet->print(pbuf));
+		break;
+	case MQTTSN_REGACK:
+	case MQTTSN_PUBACK:
+	case MQTTSN_PUBREC:
+	case MQTTSN_PUBREL:
+	case MQTTSN_PUBCOMP:
+	case MQTTSN_SUBACK:
+	case MQTTSN_UNSUBACK:
+		WRITELOG(FORMAT_W_MSGID_W_G, currentDateTime(), packet->getName(), packet->getMsgId(msgId), RIGHTARROW, clientId,	packet->print(pbuf));
+		break;
+	default:
+		break;
+	}
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientSendTask.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWClientSendTask.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,47 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#ifndef MQTTSNGWCLIENTSENDTASK_H_
+#define MQTTSNGWCLIENTSENDTASK_H_
+
+#include "MQTTSNGateway.h"
+#include "SensorNetwork.h"
+
+namespace MQTTSNGW
+{
+class AdapterManager;
+
+/*=====================================
+ Class ClientSendTask
+ =====================================*/
+class ClientSendTask: public Thread
+{
+	MAGIC_WORD_FOR_THREAD;
+	friend AdapterManager;
+public:
+	ClientSendTask(Gateway* gateway);
+	~ClientSendTask(void);
+	void run(void);
+
+private:
+	void log(Client* client, MQTTSNPacket* packet);
+
+	Gateway* _gateway;
+	SensorNetwork* _sensorNetwork;
+};
+
+}
+
+#endif /* MQTTSNGWCLIENTSENDTASK_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWConnectionHandler.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,305 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include "MQTTSNGWConnectionHandler.h"
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWPacket.h"
+#include "MQTTGWPacket.h"
+#include <string.h>
+
+using namespace std;
+using namespace MQTTSNGW;
+
+/*=====================================
+ Class MQTTSNConnectionHandler
+ =====================================*/
+MQTTSNConnectionHandler::MQTTSNConnectionHandler(Gateway* gateway)
+{
+	_gateway = gateway;
+}
+
+MQTTSNConnectionHandler::~MQTTSNConnectionHandler()
+{
+
+}
+
+/*
+ *  ADVERTISE
+ */
+void MQTTSNConnectionHandler::sendADVERTISE()
+{
+	MQTTSNPacket* adv = new MQTTSNPacket();
+	adv->setADVERTISE(_gateway->getGWParams()->gatewayId, _gateway->getGWParams()->keepAlive);
+	Event* ev1 = new Event();
+	ev1->setBrodcastEvent(adv);  //broadcast
+	_gateway->getClientSendQue()->post(ev1);
+}
+
+/*
+ *  SEARCHGW
+ */
+void MQTTSNConnectionHandler::handleSearchgw(MQTTSNPacket* packet)
+{
+	if (packet->getType() == MQTTSN_SEARCHGW)
+	{
+		MQTTSNPacket* gwinfo = new MQTTSNPacket();
+		gwinfo->setGWINFO(_gateway->getGWParams()->gatewayId);
+		Event* ev1 = new Event();
+		ev1->setBrodcastEvent(gwinfo);
+		_gateway->getClientSendQue()->post(ev1);
+	}
+}
+
+/*
+ *  CONNECT
+ */
+void MQTTSNConnectionHandler::handleConnect(Client* client, MQTTSNPacket* packet)
+{
+	MQTTSNPacket_connectData data;
+	if ( packet->getCONNECT(&data) == 0 )
+	{
+		return;
+	}
+
+	/* return CONNACK when the client is sleeping */
+	if ( client->isSleep() || client->isAwake() )
+	{
+		MQTTSNPacket* packet = new MQTTSNPacket();
+		packet->setCONNACK(MQTTSN_RC_ACCEPTED);
+		Event* ev = new Event();
+		ev->setClientSendEvent(client, packet);
+		_gateway->getClientSendQue()->post(ev);
+
+		sendStoredPublish(client);
+		return;
+	}
+
+	//* clear ConnectData of Client */
+	Connect* connectData = client->getConnectData();
+	memset(connectData, 0, sizeof(Connect));
+	if ( !client->isAdapter() )
+	{
+	    client->disconnected();
+	}
+
+	Topics* topics = client->getTopics();
+
+	/* CONNECT was not sent yet. prepare Connect data */
+	connectData->header.bits.type = CONNECT;
+	connectData->clientID = client->getClientId();
+	connectData->version = _gateway->getGWParams()->mqttVersion;
+	connectData->keepAliveTimer = data.duration;
+	connectData->flags.bits.will = data.willFlag;
+
+	if ((const char*) _gateway->getGWParams()->loginId != nullptr && (const char*) _gateway->getGWParams()->password != 0)
+	{
+		connectData->flags.bits.password = 1;
+		connectData->flags.bits.username = 1;
+	}
+
+	client->setSessionStatus(false);
+	if (data.cleansession)
+	{
+		connectData->flags.bits.cleanstart = 1;
+		/* reset the table of msgNo and TopicId pare */
+		client->clearWaitedPubTopicId();
+		client->clearWaitedSubTopicId();
+
+		/* renew the TopicList */
+		if (topics)
+		{
+			topics->eraseNormal();;
+		}
+		client->setSessionStatus(true);
+	}
+
+	if (data.willFlag)
+	{
+		/* create & send WILLTOPICREQ message to the client */
+		MQTTSNPacket* reqTopic = new MQTTSNPacket();
+		reqTopic->setWILLTOPICREQ();
+		Event* evwr = new Event();
+		evwr->setClientSendEvent(client, reqTopic);
+
+		/* Send WILLTOPICREQ to the client */
+		_gateway->getClientSendQue()->post(evwr);
+	}
+	else
+	{
+		/* CONNECT message was not qued in.
+		 * create CONNECT message & send it to the broker */
+		MQTTGWPacket* mqMsg = new MQTTGWPacket();
+		mqMsg->setCONNECT(client->getConnectData(), (unsigned char*)_gateway->getGWParams()->loginId, (unsigned char*)_gateway->getGWParams()->password);
+		Event* ev1 = new Event();
+		ev1->setBrokerSendEvent(client, mqMsg);
+		_gateway->getBrokerSendQue()->post(ev1);
+	}
+}
+
+/*
+ *  WILLTOPIC
+ */
+void MQTTSNConnectionHandler::handleWilltopic(Client* client, MQTTSNPacket* packet)
+{
+	int willQos;
+	uint8_t willRetain;
+	MQTTSNString willTopic = MQTTSNString_initializer;
+
+	if ( packet->getWILLTOPIC(&willQos, &willRetain, &willTopic) == 0 )
+	{
+		return;
+	}
+	client->setWillTopic(willTopic);
+	Connect* connectData = client->getConnectData();
+
+	/* add the connectData for MQTT CONNECT message */
+	connectData->willTopic = client->getWillTopic();
+	connectData->flags.bits.willQoS = willQos;
+	connectData->flags.bits.willRetain = willRetain;
+
+	/* Send WILLMSGREQ to the client */
+	client->setWaitWillMsgFlg(true);
+	MQTTSNPacket* reqMsg = new MQTTSNPacket();
+	reqMsg->setWILLMSGREQ();
+	Event* evt = new Event();
+	evt->setClientSendEvent(client, reqMsg);
+	_gateway->getClientSendQue()->post(evt);
+}
+
+/*
+ *  WILLMSG
+ */
+void MQTTSNConnectionHandler::handleWillmsg(Client* client, MQTTSNPacket* packet)
+{
+	if ( !client->isWaitWillMsg() )
+	{
+		DEBUGLOG("     MQTTSNConnectionHandler::handleWillmsg  WaitWillMsgFlg is off.\n");
+		return;
+	}
+
+	MQTTSNString willmsg  = MQTTSNString_initializer;
+	Connect* connectData = client->getConnectData();
+
+	if( client->isConnectSendable() )
+	{
+		/* save WillMsg in the client */
+		if ( packet->getWILLMSG(&willmsg) == 0 )
+		{
+			return;
+		}
+		client->setWillMsg(willmsg);
+
+		/* create CONNECT message */
+		MQTTGWPacket* mqttPacket =  new MQTTGWPacket();
+		connectData->willMsg = client->getWillMsg();
+		mqttPacket->setCONNECT(connectData, (unsigned char*)_gateway->getGWParams()->loginId, (unsigned char*)_gateway->getGWParams()->password);
+
+		/* Send CONNECT to the broker */
+		Event* evt = new Event();
+		evt->setBrokerSendEvent(client, mqttPacket);
+		client->setWaitWillMsgFlg(false);	
+		_gateway->getBrokerSendQue()->post(evt);
+	}
+}
+
+/*
+ *  DISCONNECT
+ */
+void MQTTSNConnectionHandler::handleDisconnect(Client* client, MQTTSNPacket* packet)
+{
+    uint16_t duration = 0;
+
+    if ( packet->getDISCONNECT(&duration) != 0 )
+    {
+        if ( duration == 0 )
+        {
+            MQTTGWPacket* mqMsg = new MQTTGWPacket();
+            mqMsg->setHeader(DISCONNECT);
+            Event* ev = new Event();
+            ev->setBrokerSendEvent(client, mqMsg);
+            _gateway->getBrokerSendQue()->post(ev);
+        }
+    }
+
+    MQTTSNPacket* snMsg = new MQTTSNPacket();
+    snMsg->setDISCONNECT(0);
+    Event* evt = new Event();
+    evt->setClientSendEvent(client, snMsg);
+    _gateway->getClientSendQue()->post(evt);
+}
+
+/*
+ *  WILLTOPICUPD
+ */
+void MQTTSNConnectionHandler::handleWilltopicupd(Client* client, MQTTSNPacket* packet)
+{
+	/* send NOT_SUPPORTED responce to the client */
+	MQTTSNPacket* respMsg = new MQTTSNPacket();
+	respMsg->setWILLTOPICRESP(MQTTSN_RC_NOT_SUPPORTED);
+	Event* evt = new Event();
+	evt->setClientSendEvent(client, respMsg);
+	_gateway->getClientSendQue()->post(evt);
+}
+
+/*
+ *  WILLMSGUPD
+ */
+void MQTTSNConnectionHandler::handleWillmsgupd(Client* client, MQTTSNPacket* packet)
+{
+	/* send NOT_SUPPORTED responce to the client */
+	MQTTSNPacket* respMsg = new MQTTSNPacket();
+	respMsg->setWILLMSGRESP(MQTTSN_RC_NOT_SUPPORTED);
+	Event* evt = new Event();
+	evt->setClientSendEvent(client, respMsg);
+	_gateway->getClientSendQue()->post(evt);
+}
+
+/*
+ *  PINGREQ
+ */
+void MQTTSNConnectionHandler::handlePingreq(Client* client, MQTTSNPacket* packet)
+{
+	if ( ( client->isSleep() || client->isAwake() ) &&  client->getClientSleepPacket() )
+	{
+	    sendStoredPublish(client);
+		client->holdPingRequest();
+	}
+	else
+	{
+        /* send PINGREQ to the broker */
+	    client->resetPingRequest();
+        MQTTGWPacket* pingreq = new MQTTGWPacket();
+        pingreq->setHeader(PINGREQ);
+        Event* evt = new Event();
+        evt->setBrokerSendEvent(client, pingreq);
+        _gateway->getBrokerSendQue()->post(evt);
+	}
+}
+
+void MQTTSNConnectionHandler::sendStoredPublish(Client* client)
+{
+    MQTTGWPacket* msg = nullptr;
+
+    while  ( ( msg = client->getClientSleepPacket() ) != nullptr )
+    {
+        // ToDo:  This version can't re-send PUBLISH when PUBACK is not returned.
+        client->deleteFirstClientSleepPacket();  // pop the que to delete element.
+
+        Event* ev = new Event();
+        ev->setBrokerRecvEvent(client, msg);
+        _gateway->getPacketEventQue()->post(ev);
+    }
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWConnectionHandler.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWConnectionHandler.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,47 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#ifndef MQTTSNGWCONNECTIONHANDLER_H_
+#define MQTTSNGWCONNECTIONHANDLER_H_
+
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWPacket.h"
+
+namespace MQTTSNGW
+{
+
+class MQTTSNConnectionHandler
+{
+public:
+	MQTTSNConnectionHandler(Gateway* gateway);
+	~MQTTSNConnectionHandler();
+	void sendADVERTISE(void);
+	void handleSearchgw(MQTTSNPacket* packet);
+	void handleConnect(Client* client, MQTTSNPacket* packet);
+	void handleWilltopic(Client* client, MQTTSNPacket* packet);
+	void handleWillmsg(Client* client, MQTTSNPacket* packet);
+	void handleDisconnect(Client* client, MQTTSNPacket* packet);
+	void handleWilltopicupd(Client* client, MQTTSNPacket* packet);
+	void handleWillmsgupd(Client* client, MQTTSNPacket* packet);
+	void handlePingreq(Client* client, MQTTSNPacket* packet);
+private:
+	void sendStoredPublish(Client* client);
+
+	Gateway* _gateway;
+};
+
+}
+
+#endif /* MQTTSNGWCONNECTIONHANDLER_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWDefines.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWDefines.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,72 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef MQTTSNGWDEFINES_H_
+#define MQTTSNGWDEFINES_H_
+
+namespace MQTTSNGW
+{
+/*=================================
+ *    Config Parametrs
+ ==================================*/
+#define CONFIG_DIRECTORY "./"
+#define CONFIG_FILE      "gateway.conf"
+#define CLIENT_LIST      "clients.conf"
+#define PREDEFINEDTOPIC_FILE      "predefinedTopic.conf"
+#define FORWARDER_LIST     "forwarders.conf"
+
+/*==========================================================
+ *    Gateway default parameters
+ ===========================================================*/
+#define DEFAULT_KEEP_ALIVE_TIME     (900)  // 900 secs = 15 mins
+#define DEFAULT_MQTT_VERSION          (4)  // Defualt MQTT version
+
+/*=================================
+ *    MQTT-SN Parametrs
+ ==================================*/
+#define MAX_CLIENTS                 (100)  // Number of Clients can be handled.
+#define MAX_CLIENTID_LENGTH          (64)  // Max length of clientID
+#define MAX_INFLIGHTMESSAGES         (10)  // Number of inflight messages
+#define MAX_MESSAGEID_TABLE_SIZE    (500)  // Number of MessageIdTable size
+#define MAX_SAVED_PUBLISH            (20)  // Max number of PUBLISH message for Asleep state
+#define MAX_TOPIC_PAR_CLIENT     (50)    // Max Topic count for a client. it should be less than 256
+#define MQTTSNGW_MAX_PACKET_SIZE   (1024)  // Max Packet size  (5+2+TopicLen+PayloadLen + Foward Encapsulation)
+#define SIZE_OF_LOG_PACKET          (500)  // Length of the packet log in bytes
+
+#define QOSM1_PROXY_KEEPALIVE_DURATION   900       // Secs
+#define QOSM1_PROXY_RESPONSE_DURATION     10       // Secs
+#define QOSM1_PROXY_MAX_RETRY_CNT        3
+/*=================================
+ *    Data Type
+ ==================================*/
+typedef unsigned char  uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int   uint32_t;
+
+/*=================================
+ *    Log controls
+ ==================================*/
+//#define DEBUG          // print out log for debug
+//#define DEBUG_NWSTACK  // print out SensorNetwork log
+
+#ifdef  DEBUG
+#define DEBUGLOG(...) printf(__VA_ARGS__)
+#else
+#define DEBUGLOG(...)
+#endif
+
+}
+#endif /* MQTTSNGWDEFINES_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,179 @@
+/**************************************************************************************
+ * Copyright (c) 2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#include "MQTTSNGWPacket.h"
+#include "MQTTSNGWEncapsulatedPacket.h"
+#include "MQTTSNPacket.h"
+#include <string.h>
+
+using namespace MQTTSNGW;
+using namespace std;
+
+WirelessNodeId::WirelessNodeId()
+    :
+    _len{0},
+    _nodeId{0}
+{
+
+}
+
+WirelessNodeId::~WirelessNodeId()
+{
+    if ( _nodeId )
+    {
+        free(_nodeId);
+    }
+}
+
+void WirelessNodeId::setId(uint8_t* id, uint8_t len)
+{
+    if ( _nodeId )
+     {
+         free(_nodeId);
+     }
+    uint8_t* buf = (uint8_t*)malloc(len);
+    if ( buf )
+    {
+        memcpy(buf, id, len);
+        _len = len;
+        _nodeId = buf;
+    }
+    else
+    {
+        _nodeId = nullptr;
+        _len = 0;
+    }
+}
+
+void WirelessNodeId::setId(WirelessNodeId* id)
+{
+    setId(id->_nodeId, id->_len);
+}
+
+bool WirelessNodeId::operator ==(WirelessNodeId& id)
+{
+    if ( _len == id._len )
+    {
+        return memcmp(_nodeId, id._nodeId, _len) == 0;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+/*
+ *    Class MQTTSNGWEncapsulatedPacket
+ */
+MQTTSNGWEncapsulatedPacket::MQTTSNGWEncapsulatedPacket()
+    :  _mqttsn{0},
+       _ctrl{0}
+{
+
+}
+
+MQTTSNGWEncapsulatedPacket::MQTTSNGWEncapsulatedPacket(MQTTSNPacket* packet)
+    :  _mqttsn{packet},
+       _ctrl{0}
+{
+
+}
+
+MQTTSNGWEncapsulatedPacket::~MQTTSNGWEncapsulatedPacket()
+{
+    /*  Do not delete the MQTTSNPacket.  MQTTSNPacket is deleted by delete Event */
+}
+
+int MQTTSNGWEncapsulatedPacket::unicast(SensorNetwork* network, SensorNetAddress* sendTo)
+{
+    uint8_t buf[MQTTSNGW_MAX_PACKET_SIZE];
+    int len = serialize(buf);
+    return network->unicast(buf, len, sendTo);
+}
+
+int MQTTSNGWEncapsulatedPacket::serialize(uint8_t* buf)
+{
+    int len = 0;
+    buf[0] = _id._len + 3;
+    buf[1] = MQTTSN_ENCAPSULATED;
+    buf[2] = _ctrl;
+    memcpy( buf + 3, _id._nodeId, _id._len);
+    if ( _mqttsn )
+    {
+        len = _mqttsn->getPacketLength();
+        memcpy(buf + buf[0], _mqttsn->getPacketData(), len);
+    }
+    return  buf[0] + len;
+}
+
+int MQTTSNGWEncapsulatedPacket::desirialize(unsigned char* buf, unsigned short len)
+{
+    if ( _mqttsn )
+    {
+        delete _mqttsn;
+        _mqttsn = nullptr;
+    }
+
+    _ctrl = buf[2];
+    _id.setId(buf + 3, buf[0] - 3);
+
+    _mqttsn = new MQTTSNPacket;
+    _mqttsn->desirialize(buf + buf[0], len - buf[0]);
+    return buf[0];
+}
+
+int MQTTSNGWEncapsulatedPacket::getType(void)
+{
+    return MQTTSN_ENCAPSULATED;
+}
+
+const char* MQTTSNGWEncapsulatedPacket::getName()
+{
+    return MQTTSNPacket_name(MQTTSN_ENCAPSULATED);
+}
+
+MQTTSNPacket* MQTTSNGWEncapsulatedPacket::getMQTTSNPacket(void)
+{
+    return _mqttsn;
+}
+
+WirelessNodeId* MQTTSNGWEncapsulatedPacket::getWirelessNodeId(void)
+{
+    return &_id;
+}
+
+void MQTTSNGWEncapsulatedPacket::setWirelessNodeId(WirelessNodeId* id)
+{
+    _id.setId(id);
+}
+
+char* MQTTSNGWEncapsulatedPacket::print(char* pbuf)
+{
+    char* ptr = pbuf;
+    char** pptr = &pbuf;
+
+    uint8_t buf[MQTTSNGW_MAX_PACKET_SIZE];
+    int len = serialize(buf);
+    int size = len > SIZE_OF_LOG_PACKET ? SIZE_OF_LOG_PACKET : len;
+
+    for (int i = 1; i < size; i++)
+    {
+        sprintf(*pptr, " %02X", *(buf + i));
+        *pptr += 3;
+    }
+    **pptr = 0;
+    return ptr;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWEncapsulatedPacket.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,65 @@
+/**************************************************************************************
+ * Copyright (c) 2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef MQTTSNGATEWAY_SRC_MQTTSNGWENCAPSULATEDPACKET_H_
+#define MQTTSNGATEWAY_SRC_MQTTSNGWENCAPSULATEDPACKET_H_
+
+namespace MQTTSNGW
+{
+
+class WirelessNodeId
+{
+    friend class MQTTSNGWEncapsulatedPacket;
+public:
+    WirelessNodeId();
+    ~WirelessNodeId();
+    void setId(uint8_t* id, uint8_t len);
+    void setId(WirelessNodeId* id);
+    bool operator ==(WirelessNodeId& id);
+private:
+    uint8_t _len;
+    uint8_t* _nodeId;
+};
+
+class MQTTSNGWEncapsulatedPacket
+{
+public:
+    MQTTSNGWEncapsulatedPacket();
+    MQTTSNGWEncapsulatedPacket(MQTTSNPacket* packet);
+    ~MQTTSNGWEncapsulatedPacket();
+    int unicast(SensorNetwork* network, SensorNetAddress* sendTo);
+    int serialize(uint8_t* buf);
+    int desirialize(unsigned char* buf, unsigned short len);
+    int getType(void);
+    unsigned char* getPacketData(void);
+    int getPacketLength(void);
+    const char* getName();
+    MQTTSNPacket* getMQTTSNPacket(void);
+    void setWirelessNodeId(WirelessNodeId* id);
+    WirelessNodeId* getWirelessNodeId(void);
+    char* print(char* buf);
+
+private:
+    MQTTSNPacket* _mqttsn;
+    WirelessNodeId _id;
+    uint8_t _ctrl;
+};
+
+}
+
+
+
+#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWENCAPSULATEDPACKET_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWForwarder.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWForwarder.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,288 @@
+/**************************************************************************************
+ * Copyright (c) 2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#include "MQTTSNGWForwarder.h"
+#include "SensorNetwork.h"
+
+#include <string.h>
+
+using namespace MQTTSNGW;
+using namespace std;
+
+/*=====================================
+     Class ForwarderList
+ =====================================*/
+
+ForwarderList::ForwarderList()
+{
+    _head = nullptr;
+}
+
+ForwarderList::~ForwarderList()
+{
+    if ( _head )
+    {
+        Forwarder* p = _head;
+        while ( p )
+        {
+            Forwarder* next = p->_next;
+            delete p;
+            p = next;
+        }
+    }
+}
+
+
+void ForwarderList::initialize(Gateway* gw)
+{
+    char param[MQTTSNGW_PARAM_MAX];
+    string fileName;
+
+    if (gw->getParam("Forwarder", param) == 0 )
+    {
+        if (!strcasecmp(param, "YES") )
+        {
+        	gw->getClientList()->setClientList(FORWARDER_TYPE);
+        }
+    }
+}
+
+
+Forwarder* ForwarderList::getForwarder(SensorNetAddress* addr)
+{
+    Forwarder* p = _head;
+    while ( p )
+    {
+        if ( p->_sensorNetAddr.isMatch(addr) )
+        {
+            break;
+        }
+        p = p->_next;
+    }
+    return p;
+}
+
+Forwarder* ForwarderList::addForwarder(SensorNetAddress* addr,  MQTTSNString* forwarderId)
+{
+    Forwarder* fdr = new Forwarder(addr, forwarderId);
+    if ( _head == nullptr )
+    {
+        _head = fdr;
+    }
+    else
+    {
+        Forwarder* p = _head;
+        while ( p )
+        {
+            if ( p->_next == nullptr )
+            {
+                p->_next = fdr;
+                break;
+            }
+            else
+            {
+                p = p->_next;
+            }
+        }
+    }
+    return fdr;
+}
+
+Forwarder::Forwarder()
+{
+    _headClient = nullptr;
+    _next = nullptr;
+}
+
+/*=====================================
+     Class ForwarderList
+ =====================================*/
+
+Forwarder::Forwarder(SensorNetAddress* addr,  MQTTSNString* forwarderId)
+{
+    _forwarderName = string(forwarderId->cstring);
+    _sensorNetAddr = *addr;
+    _headClient = nullptr;
+    _next = nullptr;
+}
+
+Forwarder::~Forwarder(void)
+{
+    if ( _headClient )
+    {
+        ForwarderElement* p = _headClient;
+        while ( p )
+        {
+            ForwarderElement* next = p->_next;
+            delete p;
+            p = next;
+        }
+    }
+}
+
+const char* Forwarder::getId(void)
+{
+    return _forwarderName.c_str();
+}
+
+void Forwarder::addClient(Client* client, WirelessNodeId* id)
+{
+    ForwarderElement* p = _headClient;
+    ForwarderElement* prev = nullptr;
+
+    client->setForwarder(this);
+
+    if ( p != nullptr )
+    {
+        while ( p )
+        {
+            if ( p->_client == client )
+            {
+                client->setForwarder(this);
+                return;
+            }
+            prev = p;
+            p = p->_next;
+        }
+    }
+
+    ForwarderElement* fclient = new ForwarderElement();
+
+    fclient->setClient(client);
+    fclient->setWirelessNodeId(id);
+
+    if ( prev )
+    {
+        prev->_next = fclient;
+    }
+    else
+    {
+        _headClient = fclient;
+    }
+}
+
+Client* Forwarder::getClient(WirelessNodeId* id)
+{
+    Client* cl = nullptr;
+    _mutex.lock();
+    ForwarderElement* p = _headClient;
+    while ( p )
+    {
+        if ( *(p->_wirelessNodeId) == *id )
+        {
+            cl = p->_client;
+            break;
+        }
+        else
+        {
+            p = p->_next;
+        }
+    }
+    _mutex.unlock();
+    return cl;
+}
+
+const char* Forwarder::getName(void)
+{
+    return _forwarderName.c_str();
+}
+
+WirelessNodeId* Forwarder::getWirelessNodeId(Client* client)
+{
+    WirelessNodeId* nodeId = nullptr;
+    _mutex.lock();
+    ForwarderElement* p = _headClient;
+    while ( p )
+    {
+        if ( p->_client == client )
+        {
+            nodeId = p->_wirelessNodeId;
+            break;
+        }
+        else
+        {
+            p = p->_next;
+        }
+    }
+    _mutex.unlock();
+    return nodeId;
+}
+
+void Forwarder::eraseClient(Client* client)
+{
+    ForwarderElement* prev = nullptr;
+    _mutex.lock();
+    ForwarderElement* p = _headClient;
+
+    while ( p )
+    {
+        if ( p->_client == client )
+        {
+            if ( prev )
+            {
+                prev->_next = p->_next;
+            }
+            else
+            {
+                _headClient = p->_next;
+            }
+            delete p;
+            break;
+        }
+        else
+        {
+            p = p->_next;
+        }
+    }
+    _mutex.unlock();
+}
+
+SensorNetAddress* Forwarder::getSensorNetAddr(void)
+{
+    return &_sensorNetAddr;
+}
+
+/*
+ *    Class ForwardedClient
+ */
+
+ForwarderElement::ForwarderElement()
+    : _client{0}
+    , _wirelessNodeId{0}
+    , _next{0}
+{
+}
+
+ForwarderElement::~ForwarderElement()
+{
+    if (_wirelessNodeId)
+    {
+        delete _wirelessNodeId;
+    }
+}
+
+void ForwarderElement::setClient(Client* client)
+{
+    _client = client;
+}
+
+void ForwarderElement::setWirelessNodeId(WirelessNodeId* id)
+{
+    if ( _wirelessNodeId == nullptr )
+    {
+        _wirelessNodeId = new WirelessNodeId();
+    }
+    _wirelessNodeId->setId(id);
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWForwarder.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWForwarder.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,99 @@
+/**************************************************************************************
+ * Copyright (c) 2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef MQTTSNGATEWAY_SRC_MQTTSNGWFORWARDER_H_
+#define MQTTSNGATEWAY_SRC_MQTTSNGWFORWARDER_H_
+
+#include "MQTTSNGWClient.h"
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWEncapsulatedPacket.h"
+#include "SensorNetwork.h"
+
+
+namespace MQTTSNGW
+{
+class Gateway;
+class Client;
+class WirelessNodeId;
+
+/*=====================================
+     Class ForwarderElement
+ =====================================*/
+class ForwarderElement
+{
+    friend class Forwarder;
+public:
+    ForwarderElement();
+    ~ForwarderElement();
+
+    void setClient(Client* client);
+    void setWirelessNodeId(WirelessNodeId* id);
+private:
+    Client* _client;
+    WirelessNodeId* _wirelessNodeId;
+    ForwarderElement* _next;
+};
+
+/*=====================================
+     Class Forwarder
+ =====================================*/
+class Forwarder
+{
+    friend class ForwarderList;
+public:
+    Forwarder(void);
+    Forwarder(SensorNetAddress* addr,  MQTTSNString* forwarderId);
+    ~Forwarder();
+
+    void initialize(void);
+    const char* getId(void);
+    void addClient(Client* client, WirelessNodeId* id);
+    Client* getClient(WirelessNodeId* id);
+    WirelessNodeId* getWirelessNodeId(Client* client);
+    void eraseClient(Client* client);
+    SensorNetAddress* getSensorNetAddr(void);
+    const char* getName(void);
+
+private:
+    string _forwarderName;
+    SensorNetAddress _sensorNetAddr;
+    ForwarderElement* _headClient{nullptr};
+    Forwarder* _next {nullptr};
+    Mutex _mutex;
+};
+
+/*=====================================
+     Class ForwarderList
+ =====================================*/
+class ForwarderList
+{
+public:
+    ForwarderList();
+    ~ForwarderList();
+
+    void initialize(Gateway* gw);
+    Forwarder* getForwarder(SensorNetAddress* addr);
+    Forwarder* addForwarder(SensorNetAddress* addr,  MQTTSNString* forwarderId);
+
+private:
+    Forwarder* _head;
+};
+
+}
+
+
+
+#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWFORWARDER_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWLogmonitor.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWLogmonitor.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,50 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#define RINGBUFFER
+
+#include "MQTTSNGWProcess.h"
+#include "MQTTSNGWLogmonitor.h"
+#include <stdio.h>
+
+using namespace std;
+using namespace MQTTSNGW;
+
+Logmonitor::Logmonitor()
+{
+	theProcess = this;
+}
+
+Logmonitor::~Logmonitor()
+{
+
+}
+
+void Logmonitor::run()
+{
+	while (true)
+	{
+		const char* data = getLog();
+		if ( *data == 0 )
+		{
+			break;
+		}
+		else
+		{
+			printf("%s", data);
+		}
+	}
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWLogmonitor.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWLogmonitor.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,33 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#ifndef MQTTSNGWLOGMONITOR_H_
+#define MQTTSNGWLOGMONITOR_H_
+
+#include "MQTTSNGWProcess.h"
+
+namespace MQTTSNGW
+{
+class Logmonitor: public Process
+{
+public:
+	Logmonitor();
+	~Logmonitor();
+	void run();
+};
+
+}
+
+#endif /* MQTTSNGWLOGMONITOR_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWMessageIdTable.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,218 @@
+/**************************************************************************************
+ * Copyright (c) 2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include "MQTTSNGWMessageIdTable.h"
+#include "MQTTSNGWClient.h"
+
+using namespace MQTTSNGW;
+
+/*===============================
+ * Class MessageIdTable
+ ===============================*/
+MessageIdTable::MessageIdTable()
+{
+
+}
+
+MessageIdTable::~MessageIdTable()
+{
+	_mutex.lock();
+	if ( _head != nullptr )
+	{
+		MessageIdElement* p = _tail;
+		while ( p )
+		{
+			MessageIdElement* pPrev = p;
+			delete p;
+			_cnt--;
+			p = pPrev->_prev;
+		}
+		_head = _tail = nullptr;
+	}
+	_mutex.unlock();
+}
+
+MessageIdElement* MessageIdTable::add(Aggregater* aggregater, Client* client, uint16_t clientMsgId)
+{
+	if ( _cnt > _maxSize )
+	{
+		return nullptr;
+	}
+
+	MessageIdElement* elm = new MessageIdElement(0, client, clientMsgId);
+	if ( elm == nullptr )
+	{
+		return nullptr;
+	}
+	_mutex.lock();
+	if ( _head == nullptr )
+	{
+		elm->_msgId = aggregater->msgId();
+		_head = elm;
+		_tail = elm;
+		_cnt++;
+	}
+	else
+	{
+		MessageIdElement* p = find(client, clientMsgId);
+		if ( p == nullptr )
+		{
+			elm->_msgId = aggregater->msgId();
+			 p = _tail;
+			_tail = elm;
+			elm->_prev = p;
+			p->_next = elm;
+			_cnt++;
+		}
+		else
+		{
+			delete elm;
+			elm = nullptr;
+		}
+	}
+	_mutex.unlock();
+	return elm;
+}
+
+MessageIdElement* MessageIdTable::find(uint16_t msgId)
+{
+	MessageIdElement* p = _head;
+	while ( p )
+	{
+		if ( p->_msgId == msgId)
+		{
+			break;
+		}
+		p = p->_next;
+	}
+	return p;
+}
+
+MessageIdElement* MessageIdTable::find(Client* client, uint16_t clientMsgId)
+{
+	MessageIdElement* p = _head;
+	while ( p )
+	{
+		if ( p->_clientMsgId == clientMsgId && p->_client == client)
+		{
+			break;
+		}
+		p = p->_next;
+	}
+	return p;
+}
+
+
+Client* MessageIdTable::getClientMsgId(uint16_t msgId, uint16_t* clientMsgId)
+{
+	Client* clt = nullptr;
+	*clientMsgId = 0;
+	_mutex.lock();
+	MessageIdElement* p = find(msgId);
+	if ( p != nullptr )
+	{
+		clt = p->_client;
+		*clientMsgId = p->_clientMsgId;
+		clear(p);
+	}
+	_mutex.unlock();
+	return clt;
+}
+
+void MessageIdTable::erase(uint16_t msgId)
+{
+	_mutex.lock();
+	MessageIdElement* p = find(msgId);
+	clear(p);
+	_mutex.unlock();
+}
+
+void MessageIdTable::clear(MessageIdElement* elm)
+{
+	if ( elm == nullptr )
+	{
+		return;
+	}
+
+	if ( elm->_prev == nullptr )
+	{
+		_head = elm->_next;
+		if ( _head == nullptr)
+		{
+			_tail = nullptr;
+		}
+		else
+		{
+			_head->_prev = nullptr;
+		}
+		delete elm;
+		_cnt--;
+		return;
+	}
+	else
+	{
+		elm->_prev->_next = elm->_next;
+		if ( elm->_next == nullptr )
+		{
+			_tail = elm->_prev;
+		}
+		else
+		{
+			elm->_next->_prev = elm->_prev;
+		}
+		delete elm;
+		_cnt--;
+		return;
+	}
+}
+
+
+uint16_t MessageIdTable::getMsgId(Client* client, uint16_t clientMsgId)
+{
+	uint16_t msgId = 0;
+	MessageIdElement* p = find(client, clientMsgId);
+	if ( p != nullptr )
+	{
+		msgId = p->_msgId;
+	}
+	return msgId;
+}
+
+/*===============================
+ * Class MessageIdElement
+ ===============================*/
+MessageIdElement::MessageIdElement(void)
+	: _msgId{0}
+	, _clientMsgId {0}
+	, _client {nullptr}
+	, _next {nullptr}
+	, _prev {nullptr}
+{
+
+}
+
+MessageIdElement::MessageIdElement(uint16_t msgId, Client* client, uint16_t clientMsgId)
+	: MessageIdElement()
+{
+	_msgId = msgId;
+	_client = client;
+	_clientMsgId = clientMsgId;
+}
+
+MessageIdElement::~MessageIdElement(void)
+{
+
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWMessageIdTable.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWMessageIdTable.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,78 @@
+/**************************************************************************************
+ * Copyright (c) 2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef MQTTSNGATEWAY_SRC_MQTTSNGWMESSAGEIDTABLE_H_
+#define MQTTSNGATEWAY_SRC_MQTTSNGWMESSAGEIDTABLE_H_
+
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGWProcess.h"
+
+#include <stdint.h>
+namespace MQTTSNGW
+{
+
+class Client;
+class MessageIdElement;
+class Meutex;
+class Aggregater;
+/*=====================================
+ Class MessageIdTable
+ ======================================*/
+class MessageIdTable
+{
+public:
+	MessageIdTable();
+	~MessageIdTable();
+
+	MessageIdElement* add(Aggregater* aggregater, Client* client, uint16_t clientMsgId);
+	Client* getClientMsgId(uint16_t msgId, uint16_t* clientMsgId);
+	uint16_t getMsgId(Client* client, uint16_t clientMsgId);
+	void erase(uint16_t msgId);
+	void clear(MessageIdElement* elm);
+private:
+	MessageIdElement* find(uint16_t msgId);
+	MessageIdElement* find(Client* client, uint16_t clientMsgId);
+	MessageIdElement* _head {nullptr};
+	MessageIdElement* _tail {nullptr};
+	int _cnt {0};
+	int _maxSize {MAX_MESSAGEID_TABLE_SIZE};
+	Mutex _mutex;
+};
+
+/*=====================================
+ Class MessageIdElement
+ =====================================*/
+class MessageIdElement
+{
+    friend class MessageIdTable;
+    friend class Aggregater;
+public:
+    MessageIdElement(void);
+    MessageIdElement(uint16_t msgId, Client* client, uint16_t clientMsgId);
+    ~MessageIdElement(void);
+
+private:
+    uint16_t _msgId;
+    uint16_t _clientMsgId;
+    Client*  _client;
+    MessageIdElement* _next;
+    MessageIdElement* _prev;
+};
+
+
+}
+
+#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWMESSAGEIDTABLE_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPacket.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPacket.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,584 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWPacket.h"
+#include "MQTTSNPacket.h"
+#include "SensorNetwork.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+using namespace std;
+using namespace MQTTSNGW;
+int readInt(char** pptr);
+void writeInt(unsigned char** pptr, int msgId);
+
+MQTTSNPacket::MQTTSNPacket(void)
+{
+	_buf = nullptr;
+	_bufLen = 0;
+}
+
+MQTTSNPacket::MQTTSNPacket(MQTTSNPacket& packet)
+{
+	_buf = (unsigned char*)malloc(packet._bufLen);
+	if (_buf)
+	{
+		_bufLen = packet._bufLen;
+		memcpy(_buf, packet._buf, _bufLen);
+	}
+	else
+	{
+		_buf = nullptr;
+		_bufLen = 0;
+	}
+}
+
+MQTTSNPacket::~MQTTSNPacket()
+{
+	if (_buf)
+	{
+		free(_buf);
+	}
+}
+
+int MQTTSNPacket::unicast(SensorNetwork* network, SensorNetAddress* sendTo)
+{
+	return network->unicast(_buf, _bufLen, sendTo);
+}
+
+int MQTTSNPacket::broadcast(SensorNetwork* network)
+{
+	return network->broadcast(_buf, _bufLen);
+}
+
+int MQTTSNPacket::serialize(uint8_t* buf)
+{
+	buf = _buf;
+	return _bufLen;
+}
+
+int MQTTSNPacket::desirialize(unsigned char* buf, unsigned short len)
+{
+	if ( _buf )
+	{
+		free(_buf);
+	}
+
+	_buf = (unsigned char*)calloc(len, sizeof(unsigned char));
+	if ( _buf )
+	{
+		memcpy(_buf, buf, len);
+		_bufLen = len;
+	}
+	else
+	{
+		_bufLen = 0;
+	}
+	return _bufLen;
+}
+
+int MQTTSNPacket::recv(SensorNetwork* network)
+{
+	uint8_t buf[MQTTSNGW_MAX_PACKET_SIZE];
+	int len = network->read((uint8_t*) buf, MQTTSNGW_MAX_PACKET_SIZE);
+	if (len > 1)
+	{
+		len = desirialize(buf, len);
+	}
+	else
+	{
+		len = 0;
+	}
+	return len;
+
+}
+
+int MQTTSNPacket::getType(void)
+{
+	if ( _bufLen == 0 )
+	{
+		return 0;
+	}
+	int value = 0;
+	int p = MQTTSNPacket_decode(_buf, _bufLen, &value);
+	return _buf[p];
+}
+
+bool MQTTSNPacket::isQoSMinusPUBLISH(void)
+{
+    if ( _bufLen == 0 )
+    {
+        return false;;
+    }
+    int value = 0;
+    int p = MQTTSNPacket_decode(_buf, _bufLen, &value);
+    return (  (_buf[p] == MQTTSN_PUBLISH) && ((_buf[p + 1] & 0x60 ) == 0x60 ));
+}
+
+unsigned char* MQTTSNPacket::getPacketData(void)
+{
+	return _buf;
+}
+
+int MQTTSNPacket::getPacketLength(void)
+{
+	return _bufLen;
+}
+
+const char* MQTTSNPacket::getName()
+{
+	return MQTTSNPacket_name(getType());
+}
+
+int MQTTSNPacket::setADVERTISE(uint8_t gatewayid, uint16_t duration)
+{
+	unsigned char buf[5];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_advertise(buf, buflen, (unsigned char) gatewayid,
+			(unsigned short) duration);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setGWINFO(uint8_t gatewayId)
+{
+	unsigned char buf[3];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_gwinfo(buf, buflen, (unsigned char) gatewayId, 0, 0);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setConnect(void)
+{
+	unsigned char buf[40];
+	int buflen = sizeof(buf);
+	MQTTSNPacket_connectData data;
+	data.clientID.cstring = (char*)"client01";
+	int len = MQTTSNSerialize_connect(buf, buflen, &data);
+	return desirialize(buf, len);
+}
+
+bool MQTTSNPacket::isAccepted(void)
+{
+    return  ( getType() == MQTTSN_CONNACK)  && (_buf[2] == MQTTSN_RC_ACCEPTED);
+}
+
+int MQTTSNPacket::setCONNACK(uint8_t returnCode)
+{
+	unsigned char buf[3];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_connack(buf, buflen, (int) returnCode);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setWILLTOPICREQ(void)
+{
+	unsigned char buf[2];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_willtopicreq(buf, buflen);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setWILLMSGREQ(void)
+{
+	unsigned char buf[2];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_willmsgreq(buf, buflen);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setREGISTER(uint16_t topicId, uint16_t msgId, MQTTSNString* topicName)
+{
+	unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_register(buf, buflen, (unsigned short) topicId, (unsigned short) msgId,
+			topicName);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setREGACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode)
+{
+	unsigned char buf[7];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_regack(buf, buflen, (unsigned short) topicId, (unsigned short) msgId,
+			(unsigned char) returnCode);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setPUBLISH(uint8_t dup, int qos, uint8_t retained, uint16_t msgId, MQTTSN_topicid topic,
+		uint8_t* payload, uint16_t payloadlen)
+{
+	unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_publish(buf, buflen, (unsigned char) dup, qos, (unsigned char) retained,
+			(unsigned short) msgId, topic, (unsigned char*) payload, (int) payloadlen);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setPUBACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode)
+{
+	unsigned char buf[7];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_puback(buf, buflen, (unsigned short) topicId, (unsigned short) msgId,
+			(unsigned char) returnCode);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setPUBREC(uint16_t msgId)
+{
+	unsigned char buf[4];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_pubrec(buf, buflen, (unsigned short) msgId);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setPUBREL(uint16_t msgId)
+{
+	unsigned char buf[4];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_pubrel(buf, buflen, (unsigned short) msgId);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setPUBCOMP(uint16_t msgId)
+{
+	unsigned char buf[4];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_pubcomp(buf, buflen, (unsigned short) msgId);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setSUBACK(int qos, uint16_t topicId, uint16_t msgId, uint8_t returnCode)
+{
+	unsigned char buf[8];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_suback(buf, buflen, qos, (unsigned short) topicId,
+			(unsigned short) msgId, (unsigned char) returnCode);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setUNSUBACK(uint16_t msgId)
+{
+	unsigned char buf[4];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_unsuback(buf, buflen, (unsigned short) msgId);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setPINGRESP(void)
+{
+	unsigned char buf[32];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_pingresp(buf, buflen);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setDISCONNECT(uint16_t duration)
+{
+	unsigned char buf[4];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_disconnect(buf, buflen, (int) duration);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setWILLTOPICRESP(uint8_t returnCode)
+{
+	unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_willtopicresp(buf, buflen, (int) returnCode);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setWILLMSGRESP(uint8_t returnCode)
+{
+	unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE];
+	int buflen = sizeof(buf);
+	int len = MQTTSNSerialize_willmsgresp(buf, buflen, (int) returnCode);
+	return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setCONNECT(MQTTSNPacket_connectData* options)
+{
+    unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE];
+    int buflen = sizeof(buf);
+    int len = MQTTSNSerialize_connect(buf, buflen, options);
+    return desirialize(buf, len);
+}
+
+int MQTTSNPacket::setPINGREQ(MQTTSNString* clientId)
+{
+    unsigned char buf[MQTTSNGW_MAX_PACKET_SIZE];
+    int buflen = sizeof(buf);
+    int len = MQTTSNSerialize_pingreq( buf, buflen, *clientId);
+    return desirialize(buf, len);
+}
+
+int MQTTSNPacket::getSERCHGW(uint8_t* radius)
+{
+	return MQTTSNDeserialize_searchgw((unsigned char*) radius, (unsigned char*) _buf, _bufLen);
+}
+
+int MQTTSNPacket::getCONNECT(MQTTSNPacket_connectData* data)
+{
+	return MQTTSNDeserialize_connect(data, _buf, _bufLen);
+}
+
+int MQTTSNPacket::getCONNACK(uint8_t* returnCode)
+{
+	return MQTTSNSerialize_connack(_buf, _bufLen, (int) *returnCode);
+}
+
+int MQTTSNPacket::getWILLTOPIC(int* willQoS, uint8_t* willRetain, MQTTSNString* willTopic)
+{
+	return MQTTSNDeserialize_willtopic((int*) willQoS, (unsigned char*) willRetain, willTopic, _buf, _bufLen);
+}
+
+int MQTTSNPacket::getWILLMSG(MQTTSNString* willmsg)
+{
+	return MQTTSNDeserialize_willmsg(willmsg, _buf, _bufLen);
+}
+
+int MQTTSNPacket::getREGISTER(uint16_t* topicId, uint16_t* msgId, MQTTSNString* topicName)
+{
+	return MQTTSNDeserialize_register((unsigned short*) topicId, (unsigned short*) msgId, topicName,
+			_buf, _bufLen);
+}
+
+int MQTTSNPacket::getREGACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode)
+{
+	return MQTTSNDeserialize_regack((unsigned short*) topicId, (unsigned short*) msgId, (unsigned char*) returnCode, _buf, _bufLen);
+}
+
+int MQTTSNPacket::getPUBLISH(uint8_t* dup, int* qos, uint8_t* retained, uint16_t* msgId, MQTTSN_topicid* topic,
+		uint8_t** payload, int* payloadlen)
+{
+	return MQTTSNDeserialize_publish((unsigned char*) dup, qos, (unsigned char*) retained, (unsigned short*) msgId,
+			topic, (unsigned char**) payload, (int*) payloadlen, _buf, _bufLen);
+}
+
+int MQTTSNPacket::getPUBACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode)
+{
+	return MQTTSNDeserialize_puback((unsigned short*) topicId, (unsigned short*) msgId, (unsigned char*) returnCode,
+			_buf, _bufLen);
+}
+
+int MQTTSNPacket::getACK(uint16_t* msgId)
+{
+	unsigned char type;
+	return MQTTSNDeserialize_ack(&type, (unsigned short*) msgId, _buf, _bufLen);
+}
+
+int MQTTSNPacket::getSUBSCRIBE(uint8_t* dup, int* qos, uint16_t* msgId, MQTTSN_topicid* topicFilter)
+{
+	return MQTTSNDeserialize_subscribe((unsigned char*) dup, qos, (unsigned short*) msgId, topicFilter,	_buf, _bufLen);
+}
+
+int MQTTSNPacket::getUNSUBSCRIBE(uint16_t* msgId, MQTTSN_topicid* topicFilter)
+{
+	return MQTTSNDeserialize_unsubscribe((unsigned short*) msgId, topicFilter, _buf, _bufLen);
+}
+
+int MQTTSNPacket::getPINGREQ(void)
+{
+	if (getType() == MQTTSN_PINGRESP && _bufLen > 2 )
+	{
+		return _bufLen - 2;
+	}
+	return 0;
+}
+
+int MQTTSNPacket::getDISCONNECT(uint16_t* duration)
+{
+	int dur = 0;
+	int rc = MQTTSNDeserialize_disconnect(&dur, _buf, _bufLen);
+	*duration = (uint16_t)dur;
+	return rc;
+}
+
+int MQTTSNPacket::getWILLTOPICUPD(uint8_t* willQoS, uint8_t* willRetain, MQTTSNString* willTopic)
+{
+	return MQTTSNDeserialize_willtopicupd((int*) willQoS, (unsigned char*) willRetain, willTopic, _buf, _bufLen);
+}
+
+int MQTTSNPacket::getWILLMSGUPD(MQTTSNString* willMsg)
+{
+	return MQTTSNDeserialize_willmsgupd(willMsg, _buf, _bufLen);
+}
+
+char* MQTTSNPacket::print(char* pbuf)
+{
+	char* ptr = pbuf;
+	char** pptr = &pbuf;
+	int size = _bufLen > SIZE_OF_LOG_PACKET ? SIZE_OF_LOG_PACKET : _bufLen;
+
+	for (int i = 0; i < size; i++)
+	{
+		sprintf(*pptr, " %02X", *(_buf + i));
+		*pptr += 3;
+	}
+	**pptr = 0;
+	return ptr;
+}
+
+char* MQTTSNPacket::getMsgId(char* pbuf)
+{
+	int value = 0;
+	int p = 0;
+
+	switch ( getType() )
+	{
+	case MQTTSN_PUBLISH:
+		p = MQTTSNPacket_decode(_buf, _bufLen, &value);
+		if ( _buf[p + 1] & 0x80 )
+		{
+			sprintf(pbuf, "+%02X%02X", _buf[p + 4], _buf[p + 5]);
+		}
+		else
+		{
+			sprintf(pbuf, " %02X%02X", _buf[p + 4], _buf[p + 5]);
+		}
+		break;
+	case MQTTSN_PUBACK:
+	case MQTTSN_REGISTER:
+	case MQTTSN_REGACK:
+		sprintf(pbuf, " %02X%02X", _buf[4], _buf[5]);
+		break;
+	case MQTTSN_PUBREC:
+	case MQTTSN_PUBREL:
+	case MQTTSN_PUBCOMP:
+	case MQTTSN_UNSUBACK:
+		sprintf(pbuf, " %02X%02X", _buf[2], _buf[3]);
+		break;
+	case MQTTSN_SUBSCRIBE:
+	case MQTTSN_UNSUBSCRIBE:
+		p = MQTTSNPacket_decode(_buf, _bufLen, &value);
+		sprintf(pbuf, " %02X%02X", _buf[p + 2], _buf[p + 3]);
+		break;
+	case MQTTSN_SUBACK:
+		sprintf(pbuf, " %02X%02X", _buf[5], _buf[6]);
+		break;
+	default:
+		sprintf(pbuf, "    ");
+		break;
+	}
+	if ( strcmp(pbuf, " 0000") == 0 )
+	{
+		sprintf(pbuf, "    ");
+	}
+	return pbuf;
+}
+
+int MQTTSNPacket::getMsgId(void)
+{
+	int value = 0;
+	int p = 0;
+	int msgId = 0;
+	char* ptr = 0;
+
+	switch ( getType() )
+	{
+	case MQTTSN_PUBLISH:
+		p = MQTTSNPacket_decode(_buf, _bufLen, &value);
+		ptr = (char*)_buf + p + 4;
+		msgId = readInt((char**)&ptr);
+		break;
+	case MQTTSN_PUBACK:
+	case MQTTSN_REGISTER:
+	case MQTTSN_REGACK:
+		ptr = (char*)_buf + 4;
+		msgId = readInt((char**)&ptr);
+		break;
+	case MQTTSN_PUBREC:
+	case MQTTSN_PUBREL:
+	case MQTTSN_PUBCOMP:
+	case MQTTSN_UNSUBACK:
+		ptr = (char*)_buf + 2;
+		msgId = readInt((char**)&ptr);
+		break;
+	case MQTTSN_SUBSCRIBE:
+	case MQTTSN_UNSUBSCRIBE:
+		p = MQTTSNPacket_decode(_buf, _bufLen, &value);
+		ptr = (char*)_buf + p + 2;
+		msgId = readInt((char**)&ptr);
+		break;
+	case MQTTSN_SUBACK:
+		ptr = (char*)_buf + 5;
+		msgId = readInt((char**)&ptr);
+		break;
+	default:
+		break;
+	}
+	return msgId;
+}
+
+void MQTTSNPacket::setMsgId(uint16_t msgId)
+{
+	int value = 0;
+	int p = 0;
+	//unsigned char* ptr = 0;
+
+	switch ( getType() )
+	{
+	case MQTTSN_PUBLISH:
+		p = MQTTSNPacket_decode(_buf, _bufLen, &value);
+		_buf[p + 4] = (unsigned char)(msgId / 256);
+		_buf[p + 5] = (unsigned char)(msgId % 256);
+		//ptr = _buf + p + 4;
+		//writeInt(&ptr, msgId);
+		break;
+	case MQTTSN_PUBACK:
+	case MQTTSN_REGISTER:
+	case MQTTSN_REGACK:
+		_buf[4] = (unsigned char)(msgId / 256);
+		_buf[5] = (unsigned char)(msgId % 256);
+		//ptr = _buf + 4;
+		//writeInt(&ptr, msgId);
+		break;
+	case MQTTSN_PUBREC:
+	case MQTTSN_PUBREL:
+	case MQTTSN_PUBCOMP:
+	case MQTTSN_UNSUBACK:
+		_buf[2] = (unsigned char)(msgId / 256);
+		_buf[3] = (unsigned char)(msgId % 256);
+		//ptr = _buf + 2;
+		//writeInt(&ptr, msgId);
+		break;
+	case MQTTSN_SUBSCRIBE:
+	case MQTTSN_UNSUBSCRIBE:
+		p = MQTTSNPacket_decode(_buf, _bufLen, &value);
+		_buf[p + 2] = (unsigned char)(msgId / 256);
+		_buf[p + 3] = (unsigned char)(msgId % 256);
+		//ptr = _buf + p + 2;
+		//writeInt(&ptr, msgId);
+break;
+	case MQTTSN_SUBACK:
+		_buf[5] = (unsigned char)(msgId / 256);
+		_buf[6] = (unsigned char)(msgId % 256);
+		//ptr = _buf + 5;
+		//writeInt(&ptr, msgId);
+break;
+	default:
+		break;
+	}
+}
+
+bool MQTTSNPacket::isDuplicate(void)
+{
+	int value = 0;
+	int p = MQTTSNPacket_decode(_buf, _bufLen, &value);
+	return ( _buf[p + 1] & 0x80 );
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPacket.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPacket.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,98 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#ifndef MQTTSNGWPACKET_H_
+#define MQTTSNGWPACKET_H_
+
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNPacket.h"
+#include "SensorNetwork.h"
+
+namespace MQTTSNGW
+{
+
+class MQTTSNPacket
+{
+public:
+	MQTTSNPacket(void);
+	MQTTSNPacket(MQTTSNPacket &packet);
+	~MQTTSNPacket(void);
+	int unicast(SensorNetwork* network, SensorNetAddress* sendTo);
+	int broadcast(SensorNetwork* network);
+	int recv(SensorNetwork* network);
+	int serialize(uint8_t* buf);
+	int desirialize(unsigned char* buf, unsigned short len);
+	int getType(void);
+	unsigned char* getPacketData(void);
+	int getPacketLength(void);
+	const char* getName();
+
+													int setConnect(void);   // Debug
+	int setADVERTISE(uint8_t gatewayid, uint16_t duration);
+	int setGWINFO(uint8_t gatewayId);
+	int setCONNACK(uint8_t returnCode);
+	int setWILLTOPICREQ(void);
+	int setWILLMSGREQ(void);
+	int setREGISTER(uint16_t topicId, uint16_t msgId, MQTTSNString* TopicName);
+	int setREGACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode);
+	int setPUBLISH(uint8_t dup, int qos, uint8_t retained, uint16_t msgId,
+			MQTTSN_topicid topic, uint8_t* payload, uint16_t payloadlen);
+	int setPUBACK(uint16_t topicId, uint16_t msgId, uint8_t returnCode);
+	int setPUBREC(uint16_t msgId);
+	int setPUBREL(uint16_t msgId);
+	int setPUBCOMP(uint16_t msgId);
+	int setSUBACK(int qos, uint16_t topicId, uint16_t msgId, uint8_t returnCode);
+	int setUNSUBACK(uint16_t msgId);
+	int setPINGRESP(void);
+	int setDISCONNECT(uint16_t duration);
+	int setWILLTOPICRESP(uint8_t returnCode);
+	int setWILLMSGRESP(uint8_t returnCode);
+
+	int setCONNECT(MQTTSNPacket_connectData* options);
+	int setPINGREQ(MQTTSNString* clientId);
+
+	int getSERCHGW(uint8_t* radius);
+	int getCONNECT(MQTTSNPacket_connectData* option);
+	int getCONNACK(uint8_t* returnCode);
+	int getWILLTOPIC(int* willQoS, uint8_t* willRetain, MQTTSNString* willTopic);
+	int getWILLMSG(MQTTSNString* willmsg);
+	int getREGISTER(uint16_t* topicId, uint16_t* msgId, MQTTSNString* topicName);
+	int getREGACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode);
+	int getPUBLISH(uint8_t* dup, int* qos, uint8_t* retained, uint16_t* msgId,
+			MQTTSN_topicid* topic, unsigned char** payload, int* payloadlen);
+	int getPUBACK(uint16_t* topicId, uint16_t* msgId, uint8_t* returnCode);
+	int getACK(uint16_t* msgId);
+	int getSUBSCRIBE(uint8_t* dup, int* qos, uint16_t* msgId, MQTTSN_topicid* topicFilter);
+	int getUNSUBSCRIBE(uint16_t* msgId, MQTTSN_topicid* topicFilter);
+	int getPINGREQ(void);
+	int getDISCONNECT(uint16_t* duration);
+	int getWILLTOPICUPD(uint8_t* willQoS, uint8_t* willRetain, MQTTSNString* willTopic);
+	int getWILLMSGUPD(MQTTSNString* willMsg);
+
+	bool isAccepted(void);
+	bool isDuplicate(void);
+	bool isQoSMinusPUBLISH(void);
+	char* getMsgId(char* buf);
+	int getMsgId(void);
+	void setMsgId(uint16_t msgId);
+	char* print(char* buf);
+
+private:
+	unsigned char* _buf;    // Ptr to a packet data
+	int            _bufLen; // length of the packet data
+};
+
+}
+#endif /* MQTTSNGWPACKET_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,366 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ *    Tieto Poland Sp. z o.o. - Gateway improvements
+ **************************************************************************************/
+
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGWPacketHandleTask.h"
+#include "MQTTSNGWProcess.h"
+#include "MQTTGWPacket.h"
+#include "MQTTSNGWClient.h"
+#include "MQTTSNGWProcess.h"
+#include "MQTTSNGWAdapterManager.h"
+#include "MQTTGWConnectionHandler.h"
+#include "MQTTGWPublishHandler.h"
+#include "MQTTGWSubscribeHandler.h"
+#include "MQTTSNGWConnectionHandler.h"
+#include "MQTTSNGWPublishHandler.h"
+#include "MQTTSNGWSubscribeHandler.h"
+#include "Timer.h"
+#include "MQTTSNAggregateConnectionHandler.h"
+
+#include <string.h>
+
+using namespace std;
+using namespace MQTTSNGW;
+
+#define EVENT_QUE_TIME_OUT  2000      // 2000 msecs
+char* currentDateTime(void);
+/*=====================================
+ Class PacketHandleTask
+ =====================================*/
+
+PacketHandleTask::PacketHandleTask(Gateway* gateway)
+{
+	_gateway = gateway;
+	_gateway->attach((Thread*)this);
+	_mqttConnection = new MQTTGWConnectionHandler(_gateway);
+	_mqttPublish = new MQTTGWPublishHandler(_gateway);
+	_mqttSubscribe = new MQTTGWSubscribeHandler(_gateway);
+	_mqttsnConnection = new MQTTSNConnectionHandler(_gateway);
+	_mqttsnPublish = new MQTTSNPublishHandler(_gateway);
+	_mqttsnSubscribe = new MQTTSNSubscribeHandler(_gateway);
+
+	_mqttsnAggrConnection = new MQTTSNAggregateConnectionHandler(_gateway);
+}
+
+/**
+ *  Destructor is called by Gateway's destructor indirectly.
+ */
+PacketHandleTask::~PacketHandleTask()
+{
+	if ( _mqttConnection )
+	{
+		delete _mqttConnection;
+	}
+	if ( _mqttPublish )
+	{
+		delete _mqttPublish;
+	}
+	if ( _mqttSubscribe )
+	{
+		delete _mqttSubscribe;
+	}
+	if ( _mqttsnConnection )
+	{
+		delete _mqttsnConnection;
+	}
+	if ( _mqttsnPublish )
+	{
+		delete _mqttsnPublish;
+	}
+	if ( _mqttsnSubscribe )
+	{
+		delete _mqttsnSubscribe;
+	}
+
+	if ( _mqttsnAggrConnection )
+	{
+		delete _mqttsnAggrConnection;
+	}
+}
+
+void PacketHandleTask::run()
+{
+	Event* ev = nullptr;
+	EventQue* eventQue = _gateway->getPacketEventQue();
+    AdapterManager* adpMgr = _gateway->getAdapterManager();
+
+	Client* client = nullptr;
+	MQTTSNPacket* snPacket = nullptr;
+	MQTTGWPacket* brPacket = nullptr;
+	char msgId[6];
+	memset(msgId, 0, 6);
+
+	_advertiseTimer.start(_gateway->getGWParams()->keepAlive * 1000UL);
+
+	while (true)
+	{
+		/* wait Event */
+		ev = eventQue->timedwait(EVENT_QUE_TIME_OUT);
+
+		if (ev->getEventType() == EtStop)
+		{
+			WRITELOG("%s PacketHandleTask stopped.\n", currentDateTime());
+			delete ev;
+			return;
+		}
+
+		if (ev->getEventType() == EtTimeout)
+		{
+			/*------ Check Keep Alive Timer & send Advertise ------*/
+			if (_advertiseTimer.isTimeup())
+			{
+				_mqttsnConnection->sendADVERTISE();
+				_advertiseTimer.start(_gateway->getGWParams()->keepAlive * 1000UL);
+			}
+
+			/*------ Check Adapters   Connect or PINGREQ ------*/
+			adpMgr->checkConnection();
+		}
+
+		/*------    Handle SEARCHGW Message     ---------*/
+		else if (ev->getEventType() == EtBroadcast)
+		{
+			snPacket = ev->getMQTTSNPacket();
+			_mqttsnConnection->handleSearchgw(snPacket);
+		}
+
+		/*------    Handle Messages form Clients      ---------*/
+		else if (ev->getEventType() == EtClientRecv)
+		{
+			client = ev->getClient();
+			snPacket = ev->getMQTTSNPacket();
+
+			DEBUGLOG("     PacketHandleTask gets %s %s from the client.\n", snPacket->getName(), snPacket->getMsgId(msgId));
+
+			if ( adpMgr->isAggregatedClient(client) )
+			{
+				aggregatePacketHandler(client, snPacket);
+			}
+			else
+			{
+				transparentPacketHandler(client, snPacket);
+			}
+
+
+			/* Reset the Timer for PINGREQ. */
+			client->updateStatus(snPacket);
+		}
+		/*------  Handle Messages form Broker      ---------*/
+		else if ( ev->getEventType() == EtBrokerRecv )
+		{
+			client = ev->getClient();
+			brPacket = ev->getMQTTGWPacket();
+			DEBUGLOG("     PacketHandleTask gets %s %s from the broker.\n", brPacket->getName(), brPacket->getMsgId(msgId));
+
+
+			if ( client->isAggregater() )
+			{
+				aggregatePacketHandler(client, brPacket);
+			}
+			else
+			{
+				transparentPacketHandler(client, brPacket);
+			}
+		}
+		delete ev;
+	}
+}
+
+
+
+void PacketHandleTask::aggregatePacketHandler(Client*client, MQTTSNPacket* packet)
+{
+	switch (packet->getType())
+	{
+	case MQTTSN_CONNECT:
+		_mqttsnAggrConnection->handleConnect(client, packet);
+		break;
+	case MQTTSN_WILLTOPIC:
+		_mqttsnConnection->handleWilltopic(client, packet);
+		break;
+	case MQTTSN_WILLMSG:
+		_mqttsnAggrConnection->handleWillmsg(client, packet);
+		break;
+	case MQTTSN_DISCONNECT:
+		_mqttsnAggrConnection->handleDisconnect(client, packet);
+		break;
+	case MQTTSN_WILLMSGUPD:
+		_mqttsnConnection->handleWillmsgupd(client, packet);
+		break;
+	case MQTTSN_PINGREQ:
+		_mqttsnAggrConnection->handlePingreq(client, packet);
+		break;
+	case MQTTSN_PUBLISH:
+		_mqttsnPublish->handleAggregatePublish(client, packet);
+		break;
+	case MQTTSN_PUBACK:
+		_mqttsnPublish->handleAggregateAck(client, packet, MQTTSN_PUBACK);
+		break;
+	case MQTTSN_PUBREC:
+		_mqttsnPublish->handleAggregateAck(client, packet, MQTTSN_PUBREC);
+		break;
+	case MQTTSN_PUBREL:
+		_mqttsnPublish->handleAggregateAck(client, packet, MQTTSN_PUBREL);
+		break;
+	case MQTTSN_PUBCOMP:
+		_mqttsnPublish->handleAggregateAck(client, packet, MQTTSN_PUBCOMP);
+		break;
+	case MQTTSN_REGISTER:
+		_mqttsnPublish->handleRegister(client, packet);
+		break;
+	case MQTTSN_REGACK:
+	    _mqttsnPublish->handleRegAck(client, packet);
+		break;
+	case MQTTSN_SUBSCRIBE:
+		_mqttsnSubscribe->handleAggregateSubscribe(client, packet);
+		break;
+	case MQTTSN_UNSUBSCRIBE:
+		_mqttsnSubscribe->handleAggregateUnsubscribe(client, packet);
+		break;
+	default:
+		break;
+	}
+}
+
+
+void PacketHandleTask::aggregatePacketHandler(Client*client, MQTTGWPacket* packet)
+{
+	switch (packet->getType())
+	{
+	case CONNACK:
+		_mqttConnection->handleConnack(client, packet);
+		break;
+	case PINGRESP:
+		_mqttConnection->handlePingresp(client, packet);
+		break;
+	case PUBLISH:
+		_mqttPublish->handleAggregatePublish(client, packet);
+		break;
+	case PUBACK:
+		_mqttPublish->handleAggregatePuback(client, packet);
+		break;
+	case PUBREC:
+		_mqttPublish->handleAggregateAck(client, packet, PUBREC);
+		break;
+	case PUBREL:
+		_mqttPublish->handleAggregatePubrel(client, packet);
+		break;
+	case PUBCOMP:
+		_mqttPublish->handleAggregateAck(client, packet, PUBCOMP);
+		break;
+	case SUBACK:
+		_mqttSubscribe->handleAggregateSuback(client, packet);
+		break;
+	case UNSUBACK:
+		_mqttSubscribe->handleAggregateUnsuback(client, packet);
+		break;
+	default:
+		break;
+	}
+}
+
+void PacketHandleTask::transparentPacketHandler(Client*client, MQTTSNPacket* packet)
+{
+	switch (packet->getType())
+	{
+	case MQTTSN_CONNECT:
+		_mqttsnConnection->handleConnect(client, packet);
+		break;
+	case MQTTSN_WILLTOPIC:
+		_mqttsnConnection->handleWilltopic(client, packet);
+		break;
+	case MQTTSN_WILLMSG:
+		_mqttsnConnection->handleWillmsg(client, packet);
+		break;
+	case MQTTSN_DISCONNECT:
+		_mqttsnConnection->handleDisconnect(client, packet);
+		break;
+	case MQTTSN_WILLMSGUPD:
+		_mqttsnConnection->handleWillmsgupd(client, packet);
+		break;
+	case MQTTSN_PINGREQ:
+		_mqttsnConnection->handlePingreq(client, packet);
+		break;
+	case MQTTSN_PUBLISH:
+		_mqttsnPublish->handlePublish(client, packet);
+		break;
+	case MQTTSN_PUBACK:
+		_mqttsnPublish->handlePuback(client, packet);
+		break;
+	case MQTTSN_PUBREC:
+		_mqttsnPublish->handleAck(client, packet, PUBREC);
+		break;
+	case MQTTSN_PUBREL:
+		_mqttsnPublish->handleAck(client, packet, PUBREL);
+		break;
+	case MQTTSN_PUBCOMP:
+		_mqttsnPublish->handleAck(client, packet, PUBCOMP);
+		break;
+	case MQTTSN_REGISTER:
+		_mqttsnPublish->handleRegister(client, packet);
+		break;
+	case MQTTSN_REGACK:
+	    _mqttsnPublish->handleRegAck(client, packet);
+		break;
+	case MQTTSN_SUBSCRIBE:
+		_mqttsnSubscribe->handleSubscribe(client, packet);
+		break;
+	case MQTTSN_UNSUBSCRIBE:
+		_mqttsnSubscribe->handleUnsubscribe(client, packet);
+		break;
+	default:
+		break;
+	}
+}
+
+
+void PacketHandleTask::transparentPacketHandler(Client*client, MQTTGWPacket* packet)
+{
+	switch (packet->getType())
+	{
+	case CONNACK:
+		_mqttConnection->handleConnack(client, packet);
+		break;
+	case PINGRESP:
+		_mqttConnection->handlePingresp(client, packet);
+		break;
+	case PUBLISH:
+		_mqttPublish->handlePublish(client, packet);
+		break;
+	case PUBACK:
+		_mqttPublish->handlePuback(client, packet);
+		break;
+	case PUBREC:
+		_mqttPublish->handleAck(client, packet, PUBREC);
+		break;
+	case PUBREL:
+		_mqttPublish->handleAck(client, packet, PUBREL);
+		break;
+	case PUBCOMP:
+		_mqttPublish->handleAck(client, packet, PUBCOMP);
+		break;
+	case SUBACK:
+		_mqttSubscribe->handleSuback(client, packet);
+		break;
+	case UNSUBACK:
+		_mqttSubscribe->handleUnsuback(client, packet);
+		break;
+	default:
+		break;
+	}
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPacketHandleTask.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,79 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef MQTTSNGWPACKETHANDLETASK_H_
+#define MQTTSNGWPACKETHANDLETASK_H_
+
+#include "Timer.h"
+#include "MQTTSNGWProcess.h"
+namespace MQTTSNGW
+{
+class Gateway;
+class Client;
+class MQTTSNPacket;
+class MQTTGWPacket;
+class Timer;
+class MQTTGWConnectionHandler;
+class MQTTGWPublishHandler;
+class MQTTGWSubscribeHandler;
+class MQTTSNConnectionHandler;
+class MQTTSNPublishHandler;
+class MQTTSNSubscribeHandler;
+
+class MQTTSNAggregateConnectionHandler;
+
+#define ERRNO_APL_01  11    // Task Initialize Error
+
+class Thread;
+class Timer;
+/*=====================================
+        Class PacketHandleTask
+ =====================================*/
+class PacketHandleTask : public Thread
+{
+	MAGIC_WORD_FOR_THREAD;
+	friend class MQTTGWAggregatePublishHandler;
+	friend class MQTTGWAggregateSubscribeHandler;
+	friend class MQTTSNAggregateConnectionHandler;
+	friend class MQTTSNAggregatePublishHandler;
+	friend class MQTTSNAggregateSubscribeHandler;
+public:
+	PacketHandleTask(Gateway* gateway);
+	~PacketHandleTask();
+	void run();
+private:
+	void aggregatePacketHandler(Client*client, MQTTSNPacket* packet);
+	void aggregatePacketHandler(Client*client, MQTTGWPacket* packet);
+	void transparentPacketHandler(Client*client, MQTTSNPacket* packet);
+	void transparentPacketHandler(Client*client, MQTTGWPacket* packet);
+
+	Gateway* _gateway {nullptr};
+	Timer _advertiseTimer;
+	Timer _sendUnixTimer;
+	MQTTGWConnectionHandler* _mqttConnection {nullptr};
+	MQTTGWPublishHandler*    _mqttPublish {nullptr};
+	MQTTGWSubscribeHandler*  _mqttSubscribe {nullptr};
+	MQTTSNConnectionHandler* _mqttsnConnection {nullptr};
+	MQTTSNPublishHandler*    _mqttsnPublish {nullptr};
+	MQTTSNSubscribeHandler*  _mqttsnSubscribe {nullptr};
+
+	MQTTSNAggregateConnectionHandler* _mqttsnAggrConnection {nullptr};
+};
+
+
+}
+
+#endif /* MQTTSNGWPACKETHANDLETASK_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWProcess.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWProcess.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,418 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <Timer.h>
+#include <exception>
+#include <getopt.h>
+#include <unistd.h>
+#include "MQTTSNGWProcess.h"
+#include "Threading.h"
+
+using namespace std;
+using namespace MQTTSNGW;
+
+char* currentDateTime(void);
+
+/*=====================================
+ Global Variables & Functions
+ ======================================*/
+Process* MQTTSNGW::theProcess = nullptr;
+MultiTaskProcess* MQTTSNGW::theMultiTaskProcess = nullptr;
+
+/*
+ *  Save the type of signal
+ */
+volatile int theSignaled = 0;
+
+static void signalHandler(int sig)
+{
+	theSignaled = sig;
+}
+
+/*=====================================
+ Class Process
+ ====================================*/
+Process::Process()
+{
+	_argc = 0;
+	_argv = 0;
+	_configDir = CONFIG_DIRECTORY;
+	_configFile = CONFIG_FILE;
+	_log = 0;
+}
+
+Process::~Process()
+{
+	if (_rb )
+	{
+		delete _rb;
+	}
+	if ( _rbsem )
+	{
+		delete _rbsem;
+	}
+}
+
+void Process::run()
+{
+
+}
+
+void Process::initialize(int argc, char** argv)
+{
+	char param[MQTTSNGW_PARAM_MAX];
+	_argc = argc;
+	_argv = argv;
+	signal(SIGINT, signalHandler);
+	signal(SIGTERM, signalHandler);
+	signal(SIGHUP, signalHandler);
+
+	int opt;
+	while ((opt = getopt(_argc, _argv, "f:")) != -1)
+	{
+		if ( opt == 'f' )
+		{
+			string config = string(optarg);
+			size_t pos = 0;
+			if ( (pos = config.find_last_of("/")) == string::npos )
+			{
+				_configFile = optarg;
+			}
+			else
+			{
+				_configFile = config.substr(pos + 1, config.size() - pos - 1);;
+				_configDir = config.substr(0, pos + 1);
+			}
+		}
+	}
+	_rbsem = new Semaphore(MQTTSNGW_RB_SEMAPHOR_NAME, 0);
+	_rb = new RingBuffer(_configDir.c_str());
+
+	if (getParam("ShearedMemory", param) == 0)
+	{
+		if (!strcasecmp(param, "YES"))
+		{
+			_log = 1;
+		}
+		else
+		{
+			_log = 0;
+		}
+	}
+}
+
+void Process::putLog(const char* format, ...)
+{
+	_mt.lock();
+	va_list arg;
+	va_start(arg, format);
+	vsprintf(_rbdata, format, arg);
+	va_end(arg);
+	if (strlen(_rbdata))
+	{
+		if ( _log > 0 )
+		{
+			_rb->put(_rbdata);
+			_rbsem->post();
+		}
+		else
+		{
+			printf("%s", _rbdata);
+		}
+	}
+	_mt.unlock();
+}
+
+int Process::getArgc()
+{
+	return _argc;
+}
+
+char** Process::getArgv()
+{
+	return _argv;
+}
+
+int Process::getParam(const char* parameter, char* value)
+{
+	char str[MQTTSNGW_PARAM_MAX];
+	char param[MQTTSNGW_PARAM_MAX];
+	FILE *fp;
+
+	int i = 0, j = 0;
+	string configPath = _configDir + _configFile;
+
+	if ((fp = fopen(configPath.c_str(), "r")) == NULL)
+	{
+		WRITELOG("No config file:[%s]\n", configPath.c_str());
+		return -1;
+	}
+
+	while (true)
+	{
+		if (fgets(str, MQTTSNGW_PARAM_MAX - 1, fp) == NULL)
+		{
+			fclose(fp);
+			return -3;
+		}
+		if (!strncmp(str, parameter, strlen(parameter)))
+		{
+			while (str[i++] != '=')
+			{
+				;
+			}
+			while (str[i] != '\n')
+			{
+				param[j++] = str[i++];
+			}
+			param[j] = '\0';
+
+			for (i = strlen(param) - 1; i >= 0 && isspace(param[i]); i--)
+				;
+			param[i + 1] = '\0';
+			for (i = 0; isspace(param[i]); i++)
+				;
+			if (i > 0)
+			{
+				j = 0;
+				while (param[i])
+					param[j++] = param[i++];
+				param[j] = '\0';
+			}
+			strcpy(value, param);
+			fclose(fp);
+			return 0;
+		}
+	}
+	fclose(fp);
+	return -2;
+}
+
+const char* Process::getLog()
+{
+	int len = 0;
+	_mt.lock();
+	while ((len = _rb->get(_rbdata, PROCESS_LOG_BUFFER_SIZE)) == 0)
+	{
+		_rbsem->timedwait(1000);
+		if ( checkSignal() == SIGINT)
+		{
+			break;
+		}
+	}
+	*(_rbdata + len) = 0;
+	_mt.unlock();
+	return _rbdata;
+}
+
+void Process::resetRingBuffer()
+{
+	_rb->reset();
+}
+
+int Process::checkSignal(void)
+{
+	return theSignaled;
+}
+
+const string* Process::getConfigDirName(void)
+{
+	return &_configDir;
+}
+
+const string* Process::getConfigFileName(void)
+{
+	return &_configFile;
+}
+
+/*=====================================
+ Class MultiTaskProcess
+ ====================================*/
+MultiTaskProcess::MultiTaskProcess()
+{
+	theMultiTaskProcess = this;
+	_threadCount = 0;
+	_stopCount = 0;
+}
+
+MultiTaskProcess::~MultiTaskProcess()
+{
+	for (int i = 0; i < _threadCount; i++)
+	{
+		_threadList[i]->stop();
+	}
+}
+
+void MultiTaskProcess::initialize(int argc, char** argv)
+{
+	Process::initialize(argc, argv);
+	for (int i = 0; i < _threadCount; i++)
+	{
+		_threadList[i]->initialize(argc, argv);
+	}
+
+}
+
+void MultiTaskProcess::run(void)
+{
+	for (int i = 0; i < _threadCount; i++)
+	{
+		_threadList[i]->start();
+	}
+
+	try
+	{
+		while(true)
+		{
+			if (theProcess->checkSignal() == SIGINT)
+			{
+				return;
+			}
+			sleep(1);
+		}
+	}
+	catch(Exception* ex)
+	{
+		ex->writeMessage();
+	}
+	catch(...)
+	{
+		throw;
+	}
+}
+
+void MultiTaskProcess::waitStop(void)
+{
+	while (_stopCount < _threadCount)
+	{
+		sleep(1);
+	}
+}
+
+void MultiTaskProcess::threadStoped(void)
+{
+	_mutex.lock();
+	_stopCount++;
+	_mutex.unlock();
+
+}
+
+void MultiTaskProcess::attach(Thread* thread)
+{
+	_mutex.lock();
+	if (_threadCount < MQTTSNGW_MAX_TASK)
+	{
+		_threadList[_threadCount] = thread;
+		_threadCount++;
+	}
+	else
+	{
+		_mutex.unlock();
+		throw Exception("Full of Threads");
+	}
+	_mutex.unlock();
+}
+
+int MultiTaskProcess::getParam(const char* parameter, char* value)
+{
+	_mutex.lock();
+	int rc = Process::getParam(parameter, value);
+	_mutex.unlock();
+	if (rc == -1)
+	{
+		throw Exception("No config file.");
+	}
+	return rc;
+}
+
+/*=====================================
+ Class Exception
+ ======================================*/
+Exception::Exception(const string& message)
+{
+	_message = message;
+	_exNo = 0;
+	_fileName = 0;
+	_functionName = 0;
+	_line = 0;
+}
+
+Exception::Exception(const int exNo, const string& message)
+{
+	_message = message;
+	_exNo = exNo;
+	_fileName = nullptr;
+	_functionName = nullptr;
+	_line = 0;
+}
+
+Exception::Exception(const int exNo, const string& message, const char* file,
+		const char* function, const int line)
+{
+	_message = message;
+	_exNo = exNo;
+	_fileName = file;
+	_functionName = function;
+	_line = line;
+}
+
+Exception::~Exception() throw ()
+{
+
+}
+
+const char* Exception::what() const throw ()
+{
+	return _message.c_str();
+}
+
+const char* Exception::getFileName()
+{
+	return _fileName;
+}
+
+const char* Exception::getFunctionName()
+{
+	return _functionName;
+}
+
+const int Exception::getLineNo()
+{
+	return _line;
+}
+
+const int Exception::getExceptionNo()
+{
+	return _exNo;
+}
+
+void Exception::writeMessage()
+{
+	if (getExceptionNo() == 0 )
+	{
+		WRITELOG("%s %s\n", currentDateTime(), what());
+	}
+	else
+	{
+		WRITELOG("%s:%-6d   %s  line %-4d %s() : %s\n", currentDateTime(), getExceptionNo(),
+			getFileName(), getLineNo(), getFunctionName(), what());
+	}
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWProcess.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWProcess.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,985 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef MQTTSNGWPROCESS_H_
+#define MQTTSNGWPROCESS_H_
+
+#include <exception>
+#include <string>
+#include <signal.h>
+#include "MQTTSNGWDefines.h"
+#include "Threading.h"
+
+using namespace std;
+
+namespace MQTTSNGW
+{
+
+/*=================================
+ *    Parameters
+ ==================================*/
+#define MQTTSNGW_MAX_TASK           10  // number of Tasks
+#define PROCESS_LOG_BUFFER_SIZE  16384  // Ring buffer size for Logs
+#define MQTTSNGW_PARAM_MAX         128  // Max length of config records.
+
+/*=================================
+ *    Macros
+ ==================================*/
+#define WRITELOG theProcess->putLog
+#define CHK_SIGINT (theProcess->checkSignal() == SIGINT)
+#define UNUSED(x) ((void)(x))
+/*=================================
+ Class Process
+ ==================================*/
+class Process
+{
+public:
+	Process();
+	virtual ~Process();
+	virtual void initialize(int argc, char** argv);
+	virtual void run(void);
+	void putLog(const char* format, ...);
+	void resetRingBuffer(void);
+	int  getArgc(void);
+	char** getArgv(void);
+	int getParam(const char* parameter, char* value);
+	const char* getLog(void);
+	int checkSignal(void);
+	const string* getConfigDirName(void);
+	const string* getConfigFileName(void);
+private:
+	int _argc;
+	char** _argv;
+	string  _configDir;
+	string  _configFile;
+	RingBuffer* _rb;
+	Semaphore*  _rbsem;
+	Mutex _mt;
+	int  _log;
+	char _rbdata[PROCESS_LOG_BUFFER_SIZE + 1];
+};
+
+/*=====================================
+ Class MultiTaskProcess
+ ====================================*/
+class MultiTaskProcess: public Process
+{
+public:
+	MultiTaskProcess(void);
+	~MultiTaskProcess();
+	void initialize(int argc, char** argv);
+	int getParam(const char* parameter, char* value);
+	void run(void);
+	void waitStop(void);
+	void threadStoped(void);
+	void attach(Thread* thread);
+
+private:
+	Thread* _threadList[MQTTSNGW_MAX_TASK];
+	Mutex _mutex;
+	int _threadCount;
+	int _stopCount;
+};
+
+/*=====================================
+ Class Exception
+ =====================================*/
+class Exception: public exception
+{
+public:
+	Exception(const string& message);
+	Exception(const int exNo, const string& message);
+	Exception(const int exNo, const string& message,
+			const char* file, const char* func, const int line);
+	virtual ~Exception() throw ();
+	const char* getFileName();
+	const char* getFunctionName();
+	const int getLineNo();
+	const int getExceptionNo();
+	virtual const char* what() const throw ();
+	void writeMessage();
+
+private:
+	int _exNo;
+	string _message;
+	const char* _fileName;
+	const char* _functionName;
+	int _line;
+};
+
+
+/*=====================================
+ Class QueElement
+ ====================================*/
+template<class T>
+class QueElement
+{
+	template<class U> friend class Que;
+public:
+	QueElement(T* t)
+	{
+		_element = t;
+		_next = nullptr;
+		_prev = nullptr;
+	}
+
+	~QueElement()
+	{
+	}
+
+private:
+	T* _element;
+	QueElement<T>* _next;
+	QueElement<T>* _prev;
+};
+
+/*=====================================
+ Class Que
+ ====================================*/
+template<class T>
+class Que
+{
+public:
+	Que()
+	{
+		_head = nullptr;
+		_tail = nullptr;
+		_cnt = 0;
+		_maxSize = 0;
+	}
+
+	~Que()
+	{
+		QueElement<T>* elm = _head;
+		while (elm)
+		{
+			QueElement<T>* next = elm->_next;
+			delete elm->_element;
+			delete elm;
+			elm = next;
+		}
+	}
+
+	void pop(void)
+	{
+		if ( _head )
+		{
+			QueElement<T>* head = _head;
+			if ( _head == _tail )
+			{
+				_head = _tail = nullptr;
+			}
+			else
+			{
+				_head = head->_next;
+				head->_prev = nullptr;
+			}
+			delete head;
+			_cnt--;
+		}
+	}
+
+	T* front(void)
+	{
+		{
+			if ( _head )
+			{
+				return _head->_element;
+			}
+			else
+			{
+				return 0;
+			}
+		}
+	}
+
+	int post(T* t)
+	{
+		if ( t && ( _maxSize == 0 || _cnt < _maxSize ))
+		{
+			QueElement<T>* elm = new QueElement<T>(t);
+			if ( _head )
+			{
+				if ( _tail == _head )
+				{
+					elm->_prev = _tail;
+					_tail = elm;
+					_head->_next = elm;
+				}
+				else
+				{
+				_tail->_next = elm;
+				elm->_prev = _tail;
+				_tail = elm;
+				}
+			}
+			else
+			{
+				_head = elm;
+				_tail = elm;
+			}
+			_cnt++;
+			return _cnt;
+		}
+		return 0;
+	}
+
+	int size(void)
+	{
+		return _cnt;
+	}
+
+	void setMaxSize(int maxSize)
+	{
+		_maxSize = maxSize;
+	}
+
+private:
+	int _cnt;
+	int _maxSize;
+	QueElement<T>* _head;
+	QueElement<T>* _tail;
+};
+
+/*=====================================
+ Class Tree23
+ ====================================*/
+#define TREE23_INSERT_ACTIVE  (-2)
+#define TREE23_DELETE_ACTIVE  (-1)
+#define TREE23_BI_NODE        (2)
+#define TREE23_TRI_NODE       (3)
+
+template <typename K, typename V>
+class Tree23Elm{
+	template<typename T, typename U> friend class Tree23;
+public:
+	Tree23Elm()
+	{
+		_key = 0;
+		_val = 0;
+	}
+
+	Tree23Elm(K* key, V* val)
+	{
+		_key = key;
+		_val = val;
+	}
+
+	~Tree23Elm()
+	{
+
+	}
+
+	int compare(Tree23Elm<K, V>* elm)
+	{
+		return _key->compare(elm->_key);
+	}
+private:
+	K* _key;
+	V* _val;
+};
+
+
+template <typename K, typename V>
+class Tree23Node{
+	template<typename S, typename W> friend class Tree23;
+public:
+	Tree23Node(const int type)
+	{
+		_type = type;
+		_telm0 = _telm1 = NULL;
+		_left = _midle = _right = NULL;
+	}
+
+	Tree23Node(const int type, Tree23Node<K, V>* midle)
+	{
+		_type = type;
+		_telm0 = _telm1 = NULL;
+		_left = _right = NULL;
+		_midle = midle;
+	}
+
+	Tree23Node(const int type, Tree23Elm<K, V>* telm)
+	{
+		_type = type;
+		_telm0 = telm;
+		_telm1 = NULL;
+		_left = _midle = _right = NULL;
+	}
+
+	Tree23Node(const int type, Tree23Elm<K, V>* telm, Tree23Node<K, V>* left, Tree23Node<K, V>* right)
+	{
+		_type = type;
+		_telm0 = telm;
+		_telm1 = NULL;
+		_left = left;
+		_midle = NULL;
+		_right = right;
+	}
+
+	Tree23Node(const int type, Tree23Elm<K, V>* telm0, Tree23Elm<K, V>* telm1, Tree23Node<K, V>* left, Tree23Node<K, V>* midle, Tree23Node<K, V>* right)
+	{
+		_type = type;
+		_telm0 = telm0;
+		_telm1 = telm1;
+		_left = left;
+		_midle = midle;
+		_right = right;
+	}
+
+	~Tree23Node()
+	{
+
+	}
+
+private:
+	int   _type;
+	Tree23Elm<K, V>* _telm0;
+	Tree23Elm<K, V>* _telm1;
+	Tree23Node<K, V>* _left;
+	Tree23Node<K, V>* _midle;
+	Tree23Node<K, V>* _right;
+};
+
+template <typename K, typename V>
+class Tree23{
+public:
+	Tree23()
+	{
+		_root = NULL;
+	}
+
+	~Tree23()
+	{
+		if ( _root )
+		{
+			delete _root;
+		}
+	}
+
+	void add(K* key, V* val)
+	{
+		_root = add( _root, new Tree23Elm<K, V>(key, val));
+		_root->_type = abs(_root->_type);
+	}
+
+	Tree23Node<K, V>* add(Tree23Node<K, V>* n, Tree23Elm<K, V>* elm)
+	{
+		if ( n == 0 )
+		{
+			return new Tree23Node<K, V>(TREE23_INSERT_ACTIVE, elm);
+		}
+
+		int cmp0 = elm->compare(n->_telm0);
+		int cmp1 = 0;
+		switch ( n->_type )
+		{
+		case 2:
+			if ( cmp0 < 0 )
+			{
+				n->_left = add(n->_left, elm);
+				return addLeft2(n);
+			}
+			else if ( cmp0 == 0 )
+			{
+				n->_telm0 = elm;
+				return n;
+			}
+			else
+			{
+				n->_right = add(n->_right, elm);
+				return addRight2(n);
+			}
+			break;
+		case 3:
+			cmp1 = elm->compare(n->_telm1);
+			if ( cmp0 < 0 )
+			{
+				n->_left = add(n->_left, elm);
+				return addLeft3(n);
+			}
+			else if ( cmp0 == 0 )
+			{
+				n->_telm0 = elm;
+				return n;
+			}
+			else if ( cmp1 < 0 )
+			{
+				n->_midle = add(n->_midle, elm);
+				return addMidle3(n);
+			}
+			else if ( cmp1 == 0 )
+			{
+				n->_telm1 = elm;
+				return n;
+			}
+			else
+			{
+				n->_right = add(n->_right, elm);
+				return addRight3(n);
+			}
+			break;
+		default:
+			break;
+		}
+		return 0;
+	}
+
+	void remove(K* k)
+	{
+		_root = remove(_root, k);
+		if ( _root != NULL && _root->_type == TREE23_DELETE_ACTIVE )
+		{
+			_root = _root->_midle;
+		}
+	}
+
+	Tree23Node<K, V>* remove(Tree23Node<K, V>* node, K* k)
+	{
+		if ( node == NULL )
+		{
+			return NULL;
+		}
+		int cmp0 = k->compare(node->_telm0->_key);
+		int cmp1 = 0;
+		switch ( node->_type )
+		{
+		case 2:
+			if ( cmp0 < 0 )
+			{
+				node->_left = remove( node->_left, k);
+				return removeLeft2(node);
+			}
+			else if ( cmp0 == 0 )
+			{
+				if ( node->_left == NULL)
+				{
+					return new Tree23Node<K, V>(TREE23_DELETE_ACTIVE);
+				}
+				Tree23Elm<K, V>* maxLeft = new Tree23Elm<K, V>();
+				node->_left = removeMax(node->_left, maxLeft);
+				node->_telm0 = maxLeft;
+				return removeLeft2(node);
+			}
+			else
+			{
+				node->_right = remove(node->_right, k);
+				return removeRight2(node);
+			}
+		case 3:
+			cmp1 = k->compare(node->_telm1->_key);
+			if ( cmp0 < 0 )
+			{
+				node->_left = remove(node->_left, k);
+				return removeLeft3(node);
+			}
+			else if ( cmp0 == 0 )
+			{
+				if ( node->_left == NULL )
+				{
+					return new Tree23Node<K, V>(TREE23_BI_NODE, node->_telm1);
+				}
+				Tree23Elm<K, V>* maxLeft = new Tree23Elm<K, V>();
+				node->_left = removeMax(node->_left, maxLeft);
+				node->_telm0 = maxLeft;
+				return removeLeft3(node);
+			}
+			else if ( cmp1 < 0 )
+			{
+				node->_midle = remove(node->_midle, k);
+				return removeMidle3(node);
+			}
+			else if ( cmp1 == 0 )
+			{
+				if ( node->_midle == NULL )
+				{
+					return new Tree23Node<K, V>(TREE23_BI_NODE, node->_telm0);
+				}
+				Tree23Elm<K, V>* maxMidle = new Tree23Elm<K, V>();
+				node->_midle = removeMax(node->_midle, maxMidle);
+				node->_telm1 = maxMidle;
+				return removeMidle3(node);
+			}
+			else
+			{
+				node->_right = remove(node->_right, k);
+				return removeRight3(node);
+			}
+		default:
+			break;
+		}
+		return NULL;
+	}
+
+	bool find(K* key)
+	{
+		Tree23Node<K, V>* node = _root;
+		while (node != NULL)
+		{
+			int cmp0 = key->compare(node->_telm0->_key);
+			int cmp1 = 0;
+			switch (node->_type)
+			{
+			case 2:
+				if ( cmp0 <  0 ) node = node->_left;
+				else if ( cmp0 == 0 )
+				{
+				return true;
+				}
+				else
+				{
+					node = node->_right;
+				}
+				break;
+			case 3:
+				cmp1 = key->compare(node->_telm1->_key);
+				if ( cmp0 <  0 )
+				{
+					node = node->_left;
+				}
+				else if ( cmp0 == 0 )
+				{
+					return true;
+				}
+				else if ( cmp1 <  0 )
+				{
+					node = node->_midle;
+				}
+				else if ( cmp1 == 0 )
+				{
+					return true;
+				}
+				else
+				{
+					node = node->_right;
+				}
+				break;
+			default:
+				break;
+			}
+		}
+		return false;
+	}
+
+
+	V* getVal(K* key)
+	{
+		Tree23Node<K, V>* node = _root;
+		while (node != NULL)
+		{
+			int cmp0 = key->compare(node->_telm0->_key);
+			int cmp1 = 0;
+			switch (node->_type)
+			{
+			case 2:
+				if ( cmp0 <  0 )
+				{
+					node = node->_left;
+				}
+				else if ( cmp0 == 0 )
+				{
+					return node->_telm0->_val;
+				}
+				else
+				{
+					node = node->_right;
+				}
+				break;
+			case 3:
+				cmp1 = key->compare(node->_telm1->_key);
+				if ( cmp0 < 0 )
+				{
+					node = node->_left;
+				}
+				else if ( cmp0 == 0 )
+				{
+					return node->_telm0->_val;
+				}
+				else if ( cmp1 <  0 )
+				{
+					node = node->_midle;
+				}
+				else if ( cmp1 == 0 )
+				{
+					return node->_telm1->_val;
+				}
+				else
+				{
+					node = node->_right;
+				}
+				break;
+			default:
+				break;
+			}
+		}
+		return NULL;
+	}
+
+private:
+	Tree23Node<K, V>* addLeft2(Tree23Node<K, V>* node)
+	{
+		Tree23Node<K, V>* n = node->_left;
+		if ( n != NULL && n->_type == TREE23_INSERT_ACTIVE )
+		{
+			return new Tree23Node<K, V>(TREE23_TRI_NODE, n->_telm0, node->_telm0, n->_left, n->_right, node->_right);
+		}
+		return node;
+	}
+
+	Tree23Node<K, V>* addLeft3(Tree23Node<K, V>* node)
+	{
+		Tree23Node<K, V>* n = node->_left;
+		if ( n != NULL && n->_type == TREE23_INSERT_ACTIVE)
+		{
+			n->_type = TREE23_BI_NODE;
+			Tree23Node<K, V>* nn = new Tree23Node<K, V>(TREE23_BI_NODE, node->_telm1, node->_midle, node->_right);
+			return new Tree23Node<K, V>(TREE23_INSERT_ACTIVE, node->_telm0, n, nn);
+		}
+		return node;
+	}
+
+	Tree23Node<K, V>* addRight2(Tree23Node<K, V>* node)
+	{
+		Tree23Node<K, V>* n = node->_right;
+		if (n != NULL &&  n->_type == TREE23_INSERT_ACTIVE)
+		{
+			return new Tree23Node<K, V>(TREE23_TRI_NODE, node->_telm0, n->_telm0, node->_left, n->_left, n->_right);
+		}
+		return node;
+	}
+
+	Tree23Node<K, V>* addRight3(Tree23Node<K, V>* node)
+	{
+		Tree23Node<K, V>* n = node->_right;
+		if (n != NULL &&  n->_type == TREE23_INSERT_ACTIVE) {
+			n->_type = TREE23_BI_NODE;
+			Tree23Node<K, V>* nn = new Tree23Node<K, V>(TREE23_BI_NODE, node->_telm0, node->_left, node->_midle);
+			return new Tree23Node<K, V>(TREE23_INSERT_ACTIVE, node->_telm1, nn, n);
+		}
+		return node;
+	}
+
+	Tree23Node<K, V>* addMidle3(Tree23Node<K, V>* node)
+	{
+		Tree23Node<K, V>* n = node->_midle;
+		if ( n != NULL && n->_type == TREE23_INSERT_ACTIVE )
+		{
+			n->_left = new Tree23Node<K, V>(TREE23_BI_NODE, node->_telm0, node->_left, n->_left);
+			n->_right = new Tree23Node<K, V>(TREE23_BI_NODE, node->_telm1, n->_right, node->_right);
+			return n;
+		}
+		return node;
+	}
+
+
+	Tree23Node<K, V>* removeMax(Tree23Node<K, V>* node, Tree23Elm<K, V>* elm)
+	{
+		if (node->_right == NULL)
+		{
+			switch (node->_type)
+			{
+				case 2:
+					elm->_key = node->_telm0->_key;
+					elm->_val = node->_telm0->_val;
+					return new Tree23Node<K, V>(TREE23_DELETE_ACTIVE);
+				case 3:
+					elm->_key = node->_telm1->_key;
+					elm->_val = node->_telm1->_val;
+					return new Tree23Node<K, V>(TREE23_BI_NODE, node->_telm0);
+				default:
+					break;
+			}
+		}
+		else
+		{
+			node->_right = removeMax(node->_right, elm);
+			switch (node->_type)
+			{
+			case 2:
+				return removeRight2(node);
+			case 3:
+				return removeRight3(node);
+			default:
+			   break;
+			}
+		}
+		return NULL;
+	}
+
+
+	Tree23Node<K, V>* removeLeft2(Tree23Node<K, V>* node)
+	{
+		Tree23Node<K, V>* n  = node->_left;
+		if ( n != NULL && n->_type == TREE23_DELETE_ACTIVE )
+		{
+			Tree23Node<K, V>* r = node->_right;
+			Tree23Node<K, V>* midle;
+			Tree23Node<K, V>* left;
+			Tree23Node<K, V>* right;
+
+			switch ( r->_type )
+			{
+			case 2:
+				midle = new Tree23Node<K, V>(TREE23_TRI_NODE, node->_telm0, r->_telm0, n->_midle, r->_left, r->_right);
+				return new Tree23Node<K, V>(TREE23_DELETE_ACTIVE, midle);
+			case 3:
+				left = new Tree23Node<K, V>(TREE23_BI_NODE, node->_telm0, n->_midle, r->_left);
+				right = new Tree23Node<K, V>(TREE23_BI_NODE, r->_telm1, r->_midle, r->_right);
+				return new Tree23Node<K, V>(TREE23_BI_NODE, r->_telm0, left, right);
+			default:
+				break;
+			}
+		}
+		return node;
+	}
+
+	Tree23Node<K, V>* removeRight2(Tree23Node<K, V>* node)
+	{
+		Tree23Node<K, V>* n  = node->_right;
+		if ( n != NULL && n->_type == TREE23_DELETE_ACTIVE )
+		{
+			Tree23Node<K, V>* l = node->_left;
+			Tree23Node<K, V>* midle;
+			Tree23Node<K, V>* left;
+			Tree23Node<K, V>* right;
+
+			switch (l->_type)
+			{
+			case 2:
+				midle = new Tree23Node<K, V>(TREE23_TRI_NODE, l->_telm0, node->_telm0, l->_left, l->_right, n->_midle);
+				return new Tree23Node<K, V>(-1, midle);
+			case 3:
+				right = new Tree23Node<K, V>(TREE23_BI_NODE, node->_telm0, l->_right, n->_midle);
+				left = new Tree23Node<K, V>(TREE23_BI_NODE, l->_telm0, l->_left, l->_midle);
+				return new Tree23Node<K, V>(TREE23_BI_NODE, l->_telm1, left, right);
+			default:
+				break;
+			}
+		}
+		return node;
+	}
+
+	Tree23Node<K, V>* removeLeft3(Tree23Node<K, V>* node)
+	{
+		Tree23Node<K, V>* n  = node->_left;
+		if ( n != NULL && n->_type == TREE23_DELETE_ACTIVE )
+		{
+			Tree23Node<K, V>* m = node->_midle;
+			Tree23Node<K, V>* r = node->_right;
+			Tree23Node<K, V>* left;
+			Tree23Node<K, V>* midle;
+
+			switch (m->_type) {
+			case 2:
+				left = new Tree23Node<K, V>(TREE23_TRI_NODE, node->_telm0, m->_telm0, n->_midle, m->_left, m->_right);
+				return new Tree23Node<K, V>(TREE23_BI_NODE, node->_telm1, left, r);
+			case 3:
+				left = new Tree23Node<K, V>(TREE23_BI_NODE, node->_telm0, n->_midle, m->_left);
+				midle = new Tree23Node<K, V>(TREE23_BI_NODE, m->_telm1, m->_midle, m->_right);
+				return new Tree23Node<K, V>(TREE23_TRI_NODE, m->_telm0, node->_telm1, left, midle, r);
+			default:
+				break;
+			}
+		}
+		return node;
+	}
+
+	Tree23Node<K, V>* removeMidle3(Tree23Node<K, V>* node)
+	{
+		Tree23Node<K, V>* n  = node->_midle;
+	        if ( n != NULL && n->_type == TREE23_DELETE_ACTIVE )
+	        {
+	        	Tree23Node<K, V>* l = node->_left;
+	        	Tree23Node<K, V>* r = node->_right;
+	        	Tree23Node<K, V>* midle;
+	        	Tree23Node<K, V>* right;
+	            switch (r->_type)
+	            {
+				case 2:
+					right = new Tree23Node<K, V>(TREE23_TRI_NODE, node->_telm1, r->_telm0, n->_midle, r->_left, r->_right);
+					return new Tree23Node<K, V>(TREE23_BI_NODE, node->_telm0, l, right);
+				case 3:
+					midle = new Tree23Node<K, V>(TREE23_BI_NODE, node->_telm1, n->_midle, r->_left);
+					right = new Tree23Node<K, V>(TREE23_BI_NODE, r->_telm1, r->_midle, r->_right);
+					return new Tree23Node<K, V>(TREE23_TRI_NODE, node->_telm0, r->_telm0, l, midle, right);
+				default:
+					break;
+	            }
+	        }
+	        return node;
+	}
+
+	Tree23Node<K, V>* removeRight3(Tree23Node<K, V>* node)
+	{
+		Tree23Node<K, V>* n = node->_right;
+	        if ( n != NULL && n->_type == TREE23_DELETE_ACTIVE )
+	        {
+	        	Tree23Node<K, V>* l = node->_left;
+				Tree23Node<K, V>* m = node->_midle;
+				Tree23Node<K, V>* midle;
+				Tree23Node<K, V>* right;
+	            switch (m->_type)
+	            {
+				case 2:
+					right = new Tree23Node<K, V>(TREE23_TRI_NODE, m->_telm0, node->_telm1, m->_left, m->_right, n->_midle);
+					return new Tree23Node<K, V>(TREE23_BI_NODE, node->_telm0, l, right);
+				case 3:
+					right = new Tree23Node<K, V>(TREE23_BI_NODE, node->_telm1, m->_right, n->_midle);
+					midle = new Tree23Node<K, V>(TREE23_BI_NODE, m->_telm0, m->_left, m->_midle);
+					return new Tree23Node<K, V>(TREE23_TRI_NODE, node->_telm0, m->_telm1, l, midle, right);
+				default:
+					break;
+	            }
+	        }
+	        return node;
+	}
+
+
+	Tree23Node<K, V>* _root;
+};
+
+/*=====================================
+ Class List
+ =====================================*/
+template <typename T>
+class ListElm
+{
+	template<typename U> friend class List;
+public:
+	ListElm()
+	{
+		_elm = nullptr;
+		_prev = _next = nullptr;
+	}
+	ListElm(T* elm)
+	{
+		_elm = elm;
+		_prev = _next = nullptr;
+	}
+	T* getContent(void)
+	{
+		return _elm;
+	}
+	~ListElm(){}
+
+private:
+	ListElm<T>* getNext(void){return _next;}
+	T* _elm;
+	ListElm<T>* _prev;
+	ListElm<T>* _next;
+};
+
+
+template <typename T>
+class List{
+public:
+	List()
+	{
+		_head = _tail = nullptr;
+		_size = 0;
+	}
+	~List()
+	{
+		clear();
+	}
+
+	int add(T* t)
+	{
+		ListElm<T>* elm = new ListElm<T>(t);
+		if ( elm == nullptr )
+		{
+			return 0;
+		}
+		if ( _head == nullptr )
+		{
+			_head = elm;
+			_tail = elm;
+		}
+		else
+		{
+			elm->_prev = _tail;
+			_tail->_next = elm;
+			_tail = elm;
+		}
+		_size++;
+		return 1;
+	}
+
+	void erase(ListElm<T>* elm)
+	{
+		if ( _head == elm )
+		{
+			_head = elm->_next;
+			_size--;
+			delete elm;
+		}
+		else if ( _tail == elm )
+		{
+			_tail = elm->_prev;
+			elm->_prev->_next = nullptr;
+			_size--;
+			delete elm;
+		}
+		else
+		{
+			elm->_prev->_next = elm->_next;
+			elm->_next->_prev = elm->_prev;
+			_size--;
+			delete elm;
+		}
+	}
+	void clear(void)
+	{
+		ListElm<T>* p = _head;
+		while ( p )
+		{
+			ListElm<T>* q = p->_next;
+			delete p;
+			p = q;
+		}
+		_head = nullptr;
+		_tail = nullptr;
+		_size = 0;
+	}
+
+	ListElm<T>* getElm(void)
+	{
+		return _head;
+	}
+
+	ListElm<T>* getNext(ListElm<T>* elm)
+	{
+		return elm->getNext();
+	}
+
+	int getSize(void)
+	{
+		return _size;
+	}
+
+
+private:
+	ListElm<T>* _head;
+	ListElm<T>* _tail;
+	int _size;
+};
+
+
+extern Process* theProcess;
+extern MultiTaskProcess* theMultiTaskProcess;
+
+}
+#endif /* MQTTSNGWPROCESS_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPublishHandler.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,293 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ *    Tieto Poland Sp. z o.o. - Gateway improvements
+ **************************************************************************************/
+
+#include "MQTTSNGWPublishHandler.h"
+#include "MQTTSNGWPacket.h"
+#include "MQTTGWPacket.h"
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWClient.h"
+#include "MQTTSNGWQoSm1Proxy.h"
+#include <string.h>
+using namespace std;
+using namespace MQTTSNGW;
+
+MQTTSNPublishHandler::MQTTSNPublishHandler(Gateway* gateway)
+{
+	_gateway = gateway;
+}
+
+MQTTSNPublishHandler::~MQTTSNPublishHandler()
+{
+
+}
+
+MQTTGWPacket* MQTTSNPublishHandler::handlePublish(Client* client, MQTTSNPacket* packet)
+{
+	uint8_t dup;
+	int qos;
+	uint8_t retained;
+	uint16_t msgId;
+	uint8_t* payload;
+    MQTTSN_topicid topicid;
+	int payloadlen;
+	Publish pub = MQTTPacket_Publish_Initializer;
+
+	char  shortTopic[2];
+
+	if ( !_gateway->getAdapterManager()->getQoSm1Proxy()->isActive() )
+	{
+	    if ( client->isQoSm1() )
+	    {
+	        _gateway->getAdapterManager()->getQoSm1Proxy()->savePacket(client, packet);
+
+	        return nullptr;
+	    }
+	}
+
+	if ( packet->getPUBLISH(&dup, &qos, &retained, &msgId, &topicid, &payload, &payloadlen) ==0 )
+	{
+		return nullptr;
+	}
+	pub.msgId = msgId;
+	pub.header.bits.dup = dup;
+	pub.header.bits.qos = ( qos == 3 ? 0 : qos );
+	pub.header.bits.retain = retained;
+
+	Topic* topic = nullptr;
+
+	if( topicid.type ==  MQTTSN_TOPIC_TYPE_SHORT )
+	{
+		shortTopic[0] = topicid.data.short_name[0];
+		shortTopic[1] = topicid.data.short_name[1];
+		pub.topic = shortTopic;
+		pub.topiclen = 2;
+	}
+	else
+	{
+	    topic = client->getTopics()->getTopicById(&topicid);
+	    if ( !topic )
+	    {
+	    	topic = _gateway->getTopics()->getTopicById(&topicid);
+	    	if ( topic )
+	    	{
+	    		topic = client->getTopics()->add(topic->getTopicName()->c_str(), topic->getTopicId());
+	    	}
+	    }
+
+	    if( !topic && qos == 3 )
+	    {
+	        WRITELOG("%s Invalid TopicId.%s %s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER);
+	        return nullptr;
+	    }
+
+		if( !topic && msgId && qos > 0 && qos < 3 )
+		{
+			/* Reply PubAck with INVALID_TOPIC_ID to the client */
+			MQTTSNPacket* pubAck = new MQTTSNPacket();
+			pubAck->setPUBACK( topicid.data.id, msgId, MQTTSN_RC_REJECTED_INVALID_TOPIC_ID);
+			Event* ev1 = new Event();
+			ev1->setClientSendEvent(client, pubAck);
+			_gateway->getClientSendQue()->post(ev1);
+			return nullptr;
+		}
+		if ( topic )
+		{
+			pub.topic = (char*)topic->getTopicName()->data();
+			pub.topiclen = topic->getTopicName()->length();
+		}
+	}
+	/* Save a msgId & a TopicId pare for PUBACK */
+	if( msgId && qos > 0 && qos < 3)
+	{
+		client->setWaitedPubTopicId(msgId, topicid.data.id, topicid.type);
+	}
+
+	pub.payload = (char*)payload;
+	pub.payloadlen = payloadlen;
+
+	MQTTGWPacket* publish = new MQTTGWPacket();
+	publish->setPUBLISH(&pub);
+
+	if ( _gateway->getAdapterManager()->isAggregaterActive() && client->isAggregated() )
+	{
+		return publish;
+	}
+	else
+	{
+		Event* ev1 = new Event();
+		ev1->setBrokerSendEvent(client, publish);
+		_gateway->getBrokerSendQue()->post(ev1);
+		return nullptr;
+	}
+}
+
+void MQTTSNPublishHandler::handlePuback(Client* client, MQTTSNPacket* packet)
+{
+	uint16_t topicId;
+	uint16_t msgId;
+	uint8_t rc;
+
+	if ( client->isActive() )
+	{
+		if ( packet->getPUBACK(&topicId, &msgId, &rc) == 0 )
+		{
+			return;
+		}
+
+		if ( rc == MQTTSN_RC_ACCEPTED)
+		{
+			if ( !_gateway->getAdapterManager()->getAggregater()->isActive() )
+			{
+				MQTTGWPacket* pubAck = new MQTTGWPacket();
+				pubAck->setAck(PUBACK, msgId);
+				Event* ev1 = new Event();
+				ev1->setBrokerSendEvent(client, pubAck);
+				_gateway->getBrokerSendQue()->post(ev1);
+			}
+		}
+		else if ( rc == MQTTSN_RC_REJECTED_INVALID_TOPIC_ID)
+		{
+			WRITELOG("  PUBACK   %d : Invalid Topic ID\n", msgId);
+		}
+	}
+}
+
+void MQTTSNPublishHandler::handleAck(Client* client, MQTTSNPacket* packet, uint8_t packetType)
+{
+	uint16_t msgId;
+
+	if ( client->isActive() )
+	{
+		if ( packet->getACK(&msgId) == 0 )
+		{
+			return;
+		}
+		MQTTGWPacket* ackPacket = new MQTTGWPacket();
+		ackPacket->setAck(packetType, msgId);
+		Event* ev1 = new Event();
+		ev1->setBrokerSendEvent(client, ackPacket);
+		_gateway->getBrokerSendQue()->post(ev1);
+	}
+}
+
+void MQTTSNPublishHandler::handleRegister(Client* client, MQTTSNPacket* packet)
+{
+	uint16_t id;
+	uint16_t msgId;
+	MQTTSNString topicName  = MQTTSNString_initializer;;
+	MQTTSN_topicid topicid;
+
+	if ( client->isActive() || client->isAwake())
+	{
+		if ( packet->getREGISTER(&id, &msgId, &topicName) == 0 )
+		{
+			return;
+		}
+
+		topicid.type = MQTTSN_TOPIC_TYPE_NORMAL;
+		topicid.data.long_.len = topicName.lenstring.len;
+		topicid.data.long_.name = topicName.lenstring.data;
+
+		id = client->getTopics()->add(&topicid)->getTopicId();
+
+		MQTTSNPacket* regAck = new MQTTSNPacket();
+		regAck->setREGACK(id, msgId, MQTTSN_RC_ACCEPTED);
+		Event* ev = new Event();
+		ev->setClientSendEvent(client, regAck);
+		_gateway->getClientSendQue()->post(ev);
+	}
+}
+
+void MQTTSNPublishHandler::handleRegAck( Client* client, MQTTSNPacket* packet)
+{
+    uint16_t id;
+    uint16_t msgId;
+    uint8_t rc;
+    if ( client->isActive() || client->isAwake())
+    {
+        if ( packet->getREGACK(&id, &msgId, &rc) == 0 )
+        {
+            return;
+        }
+
+        MQTTSNPacket* regAck = client->getWaitREGACKPacketList()->getPacket(msgId);
+
+        if ( regAck != nullptr )
+        {
+            client->getWaitREGACKPacketList()->erase(msgId);
+            Event* ev = new Event();
+            ev->setClientSendEvent(client, regAck);
+            _gateway->getClientSendQue()->post(ev);
+        }
+        if (client->isHoldPringReqest() && client->getWaitREGACKPacketList()->getCount() == 0 )
+        {
+            /* send PINGREQ to the broker */
+           client->resetPingRequest();
+           MQTTGWPacket* pingreq = new MQTTGWPacket();
+           pingreq->setHeader(PINGREQ);
+           Event* evt = new Event();
+           evt->setBrokerSendEvent(client, pingreq);
+           _gateway->getBrokerSendQue()->post(evt);
+        }
+    }
+
+}
+
+
+
+
+void MQTTSNPublishHandler::handleAggregatePublish(Client* client, MQTTSNPacket* packet)
+{
+	int msgId = 0;
+	MQTTGWPacket* publish = handlePublish(client, packet);
+	if ( publish != nullptr )
+	{
+		if ( publish->getMsgId() > 0 )
+		{
+			if ( packet->isDuplicate() )
+			{
+				msgId = _gateway->getAdapterManager()->getAggregater()->getMsgId(client, packet->getMsgId());
+			}
+			else
+			{
+				msgId = _gateway->getAdapterManager()->getAggregater()->addMessageIdTable(client, packet->getMsgId());
+			}
+			publish->setMsgId(msgId);
+		}
+		Event* ev1 = new Event();
+		ev1->setBrokerSendEvent(client, publish);
+		_gateway->getBrokerSendQue()->post(ev1);
+	}
+}
+
+void MQTTSNPublishHandler::handleAggregateAck(Client* client, MQTTSNPacket* packet, int type)
+{
+	if ( type == MQTTSN_PUBREC )
+	{
+		uint16_t msgId;
+
+		if ( packet->getACK(&msgId) == 0 )
+		{
+			return;
+		}
+		MQTTSNPacket* ackPacket = new MQTTSNPacket();
+		ackPacket->setPUBREL(msgId);
+		Event* ev = new Event();
+		ev->setClientSendEvent(client, ackPacket);
+		_gateway->getClientSendQue()->post(ev);
+	}
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPublishHandler.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWPublishHandler.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,44 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#ifndef MQTTSNGWPUCLISHHANDLER_H_
+#define MQTTSNGWPUCLISHHANDLER_H_
+
+#include "MQTTGWPacket.h"
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWClient.h"
+
+namespace MQTTSNGW
+{
+class MQTTSNPublishHandler
+{
+public:
+	MQTTSNPublishHandler(Gateway* gateway);
+	~MQTTSNPublishHandler();
+	MQTTGWPacket* handlePublish(Client* client, MQTTSNPacket* packet);
+	void handlePuback(Client* client, MQTTSNPacket* packet);
+	void handleAck(Client* client, MQTTSNPacket* packet, uint8_t packetType);
+	void handleRegister(Client* client, MQTTSNPacket* packet);
+	void handleRegAck( Client* client, MQTTSNPacket* packet);
+
+	void handleAggregatePublish(Client* client, MQTTSNPacket* packet);
+	void handleAggregateAck(Client* client, MQTTSNPacket* packet, int type);
+
+private:
+	Gateway* _gateway;
+};
+
+}
+#endif /* MQTTSNGWPUCLISHHANDLER_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,70 @@
+/**************************************************************************************
+ * Copyright (c) 2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include "MQTTSNGWQoSm1Proxy.h"
+#include "MQTTSNGateway.h"
+#include "SensorNetwork.h"
+#include "MQTTSNGWClientList.h"
+#include <string>
+#include <string.h>
+
+
+using namespace MQTTSNGW;
+
+/*=====================================
+     Class QoSm1Proxy
+ =====================================*/
+QoSm1Proxy:: QoSm1Proxy(Gateway* gw) : Adapter(gw)
+{
+    _gateway = gw;
+}
+
+QoSm1Proxy::~QoSm1Proxy(void)
+{
+
+}
+
+
+void QoSm1Proxy::initialize(void)
+{
+    char param[MQTTSNGW_PARAM_MAX];
+
+    if ( _gateway->hasSecureConnection() )
+    {
+		_isSecure = true;
+    }
+
+    if (_gateway->getParam("QoS-1", param) == 0 )
+    {
+        if (strcasecmp(param, "YES") == 0 )
+        {
+        	/*  Create QoS-1 Clients */
+        	_gateway->getClientList()->setClientList(QOSM1PROXY_TYPE);
+
+            /* initialize Adapter */
+			string name = string(_gateway->getGWParams()->gatewayName) + "QoS-1";
+            setup(name.c_str(), Atype_QoSm1Proxy);
+           _isActive = true;
+        }
+    }
+}
+
+
+bool QoSm1Proxy::isActive(void)
+{
+    return _isActive;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWQoSm1Proxy.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,53 @@
+/**************************************************************************************
+ * Copyright (c) 2018, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef MQTTSNGATEWAY_SRC_MQTTSNGWQOSM1PROXY_H_
+#define MQTTSNGATEWAY_SRC_MQTTSNGWQOSM1PROXY_H_
+
+#include "MQTTSNGWAdapter.h"
+namespace MQTTSNGW
+{
+class Gateway;
+class Adapter;
+class Client;
+class SensorNetAddress;
+class MQTTSNPacket;
+
+/*=====================================
+     Class QoSm1Proxy
+ =====================================*/
+class QoSm1Proxy : public Adapter
+{
+public:
+	QoSm1Proxy(Gateway* gw);
+    ~QoSm1Proxy(void);
+
+    void initialize(void);
+    bool isActive(void);
+
+private:
+    Gateway* _gateway;
+
+    bool _isActive {false};
+    bool _isSecure {false};
+};
+
+
+}
+
+
+
+#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWQOSM1PROXY_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,257 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ *    Tieto Poland Sp. z o.o. - Gateway improvements
+ **************************************************************************************/
+
+#include "MQTTSNGWSubscribeHandler.h"
+#include "MQTTSNGWPacket.h"
+#include "MQTTGWPacket.h"
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWClient.h"
+
+using namespace std;
+using namespace MQTTSNGW;
+
+MQTTSNSubscribeHandler::MQTTSNSubscribeHandler(Gateway* gateway)
+{
+	_gateway = gateway;
+}
+
+MQTTSNSubscribeHandler::~MQTTSNSubscribeHandler()
+{
+
+}
+
+MQTTGWPacket* MQTTSNSubscribeHandler::handleSubscribe(Client* client, MQTTSNPacket* packet)
+{
+	uint8_t dup;
+	int qos;
+	uint16_t msgId;
+	MQTTSN_topicid topicFilter;
+	Topic* topic = nullptr;
+    uint16_t topicId = 0;
+    MQTTGWPacket* subscribe;
+    Event* ev1;
+    Event* evsuback;
+
+	if ( packet->getSUBSCRIBE(&dup, &qos, &msgId, &topicFilter) == 0 )
+	{
+		return nullptr;
+	}
+
+	if ( msgId == 0 )
+	{
+	    return nullptr;
+	}
+
+    if ( topicFilter.type == MQTTSN_TOPIC_TYPE_PREDEFINED )
+    {
+        topic = client->getTopics()->getTopicById(&topicFilter);
+
+
+        if ( topic )
+        {
+            topicId = topic->getTopicId();
+            subscribe = new MQTTGWPacket();
+            subscribe->setSUBSCRIBE((char*)topic->getTopicName()->c_str(), (uint8_t)qos, (uint16_t)msgId);
+        }
+        else
+        {
+        	topic = _gateway->getTopics()->getTopicById(&topicFilter);
+        	if ( !topic )
+        	{
+				topic = client->getTopics()->add(topic->getTopicName()->c_str(), topic->getTopicId());
+			}
+        	else
+        	{
+        		goto RespExit;
+        	}
+        }
+    }
+    else if (topicFilter.type == MQTTSN_TOPIC_TYPE_NORMAL)
+    {
+        topic = client->getTopics()->getTopicByName(&topicFilter);
+        if ( topic  == nullptr )
+        {
+            topic = client->getTopics()->add(&topicFilter);
+            if ( topic == nullptr )
+            {
+                WRITELOG("%s Client(%s) can't add the Topic.%s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER);
+                return nullptr;
+            }
+        }
+        topicId = topic->getTopicId();
+        subscribe = new MQTTGWPacket();
+
+        subscribe->setSUBSCRIBE((char*)topic->getTopicName()->c_str(), (uint8_t)qos, (uint16_t)msgId);
+    }
+    else  //MQTTSN_TOPIC_TYPE_SHORT
+    {
+        char topicstr[3];
+        topicstr[0] = topicFilter.data.short_name[0];
+        topicstr[1] = topicFilter.data.short_name[1];
+        topicstr[2] = 0;
+        topicId = 0;
+        subscribe = new MQTTGWPacket();
+        subscribe->setSUBSCRIBE(topicstr, (uint8_t)qos, (uint16_t)msgId);
+    }
+
+    client->setWaitedSubTopicId(msgId, topicId, topicFilter.type);
+
+    if ( !client->isAggregated() )
+    {
+    	ev1 = new Event();
+		ev1->setBrokerSendEvent(client, subscribe);
+		_gateway->getBrokerSendQue()->post(ev1);
+		return nullptr;
+    }
+    else
+    {
+    	return subscribe;
+    }
+
+
+RespExit:
+     MQTTSNPacket* sSuback = new MQTTSNPacket();
+     sSuback->setSUBACK(qos, topicFilter.data.id, msgId, MQTTSN_RC_NOT_SUPPORTED);
+     evsuback = new Event();
+     evsuback->setClientSendEvent(client, sSuback);
+     _gateway->getClientSendQue()->post(evsuback);
+     return nullptr;
+}
+
+MQTTGWPacket* MQTTSNSubscribeHandler::handleUnsubscribe(Client* client, MQTTSNPacket* packet)
+{
+	uint16_t msgId;
+	MQTTSN_topicid topicFilter;
+    MQTTGWPacket* unsubscribe = nullptr;
+
+	if ( packet->getUNSUBSCRIBE(&msgId, &topicFilter) == 0 )
+	{
+		return nullptr;
+	}
+
+	if ( msgId == 0 )
+    {
+	    return nullptr;
+    }
+
+	Topic* topic = client->getTopics()->getTopicById(&topicFilter);
+
+	if (topicFilter.type == MQTTSN_TOPIC_TYPE_SHORT)
+	{
+	    char shortTopic[3];
+        shortTopic[0] = topicFilter.data.short_name[0];
+        shortTopic[1] = topicFilter.data.short_name[1];
+        shortTopic[2] = 0;
+        unsubscribe = new MQTTGWPacket();
+        unsubscribe->setUNSUBSCRIBE(shortTopic, msgId);
+	}
+	else
+	{
+	    if ( topic == nullptr )
+        {
+            MQTTSNPacket* sUnsuback = new MQTTSNPacket();
+            sUnsuback->setUNSUBACK(msgId);
+            Event* evsuback = new Event();
+            evsuback->setClientSendEvent(client, sUnsuback);
+            _gateway->getClientSendQue()->post(evsuback);
+            return nullptr;
+        }
+        else
+        {
+            unsubscribe = new MQTTGWPacket();
+            unsubscribe->setUNSUBSCRIBE(topic->getTopicName()->c_str(), msgId);
+        }
+	}
+
+    if ( !client->isAggregated() )
+    {
+		Event* ev1 = new Event();
+		ev1->setBrokerSendEvent(client, unsubscribe);
+		_gateway->getBrokerSendQue()->post(ev1);
+		return nullptr;
+    }
+    else
+    {
+    	return unsubscribe;
+    }
+}
+
+void MQTTSNSubscribeHandler::handleAggregateSubscribe(Client* client, MQTTSNPacket* packet)
+{
+	MQTTGWPacket* subscribe = handleSubscribe(client, packet);
+
+	if ( subscribe != nullptr )
+	{
+		UTF8String str = subscribe->getTopic();
+		string* topicName = new string(str.data, str.len);
+		Topic topic = Topic(topicName, MQTTSN_TOPIC_TYPE_NORMAL);
+		 _gateway->getAdapterManager()->addAggregateTopic(&topic, client);
+
+		int msgId = 0;
+		if ( packet->isDuplicate() )
+		{
+			msgId = _gateway->getAdapterManager()->getAggregater()->getMsgId(client, packet->getMsgId());
+		}
+		else
+		{
+			msgId = _gateway->getAdapterManager()->getAggregater()->addMessageIdTable(client, packet->getMsgId());
+		}
+
+		if ( msgId == 0 )
+		{
+			WRITELOG("%s MQTTSNSubscribeHandler can't create MessageIdTableElement  %s%s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER);
+			return;
+		}
+WRITELOG("msgId=%d\n",msgId);
+		subscribe->setMsgId(msgId);
+		Event* ev = new Event();
+		ev->setBrokerSendEvent(client, subscribe);
+		_gateway->getBrokerSendQue()->post(ev);
+	}
+}
+
+void MQTTSNSubscribeHandler::handleAggregateUnsubscribe(Client* client, MQTTSNPacket* packet)
+{
+	MQTTGWPacket* unsubscribe = handleUnsubscribe(client, packet);
+	if ( unsubscribe != nullptr )
+	{
+		UTF8String str = unsubscribe->getTopic();
+		string* topicName = new string(str.data, str.len);
+		Topic topic = Topic(topicName, MQTTSN_TOPIC_TYPE_NORMAL);
+		_gateway->getAdapterManager()->removeAggregateTopic(&topic, client);
+
+		int msgId = 0;
+		if ( packet->isDuplicate() )
+		{
+			msgId = _gateway->getAdapterManager()->getAggregater()->getMsgId(client, packet->getMsgId());
+		}
+		else
+		{
+			msgId = _gateway->getAdapterManager()->getAggregater()->addMessageIdTable(client, packet->getMsgId());
+		}
+
+		if ( msgId == 0 )
+		{
+			WRITELOG("%s MQTTSNUnsubscribeHandler can't create MessageIdTableElement  %s%s\n", ERRMSG_HEADER, client->getClientId(), ERRMSG_FOOTER);
+			return;
+		}
+		unsubscribe->setMsgId(msgId);
+		Event* ev = new Event();
+		ev->setBrokerSendEvent(client, unsubscribe);
+		_gateway->getBrokerSendQue()->post(ev);
+	}
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWSubscribeHandler.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,46 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#ifndef MQTTSNGWSUBSCRIBEHANDLER_H_
+#define MQTTSNGWSUBSCRIBEHANDLER_H_
+
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWPacket.h"
+#include "MQTTSNGWClient.h"
+
+namespace MQTTSNGW
+{
+/*=====================================
+        Class MQTTSNSubscribeHandler
+ =====================================*/
+class MQTTSNSubscribeHandler
+{
+public:
+	MQTTSNSubscribeHandler(Gateway* gateway);
+	~MQTTSNSubscribeHandler();
+	MQTTGWPacket* handleSubscribe(Client* client, MQTTSNPacket* packet);
+	MQTTGWPacket* handleUnsubscribe(Client* client, MQTTSNPacket* packet);
+	void handleAggregateSubscribe(Client* client, MQTTSNPacket* packet);
+	void handleAggregateUnsubscribe(Client* client, MQTTSNPacket* packet);
+
+private:
+	Gateway* _gateway;
+};
+
+}
+
+
+#endif /* MQTTSNGWSUBSCRIBEHANDLER_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWTopic.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWTopic.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,519 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ *    Tieto Poland Sp. z o.o. - Gateway improvements
+ **************************************************************************************/
+#include "MQTTSNGWTopic.h"
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGateway.h"
+#include <string.h>
+
+using namespace MQTTSNGW;
+
+/*=====================================
+ Class Topic
+ ======================================*/
+Topic::Topic()
+{
+    _type = MQTTSN_TOPIC_TYPE_NORMAL;
+	_topicName = nullptr;
+	_topicId = 0;
+	_next = nullptr;
+}
+
+Topic::Topic(string* topic, MQTTSN_topicTypes type)
+{
+    _type = type;
+	_topicName = topic;
+	_topicId = 0;
+	_next = nullptr;
+}
+
+Topic::~Topic()
+{
+	if ( _topicName )
+	{
+		delete _topicName;
+	}
+}
+
+string* Topic::getTopicName(void)
+{
+	return _topicName;
+}
+
+uint16_t Topic::getTopicId(void)
+{
+	return _topicId;
+}
+
+MQTTSN_topicTypes Topic::getType(void)
+{
+    return _type;
+}
+
+bool Topic::isMatch(string* topicName)
+{
+	string::size_type tlen = _topicName->size();
+
+	string::size_type tpos = 0;
+	string::size_type tloc = 0;
+	string::size_type pos = 0;
+	string::size_type loc = 0;
+	string wildcard = "#";
+	string wildcards = "+";
+
+	while(true)
+	{
+		loc = topicName->find('/', pos);
+		tloc = _topicName->find('/', tpos);
+
+		if ( loc != string::npos && tloc != string::npos )
+		{
+			string subtopic = topicName->substr(pos, loc - pos);
+			string subtopict = _topicName->substr(tpos, tloc - tpos);
+			if (subtopict == wildcard)
+			{
+				return true;
+			}
+			else if (subtopict == wildcards)
+			{
+				if ( (tpos = tloc + 1 ) > tlen )
+				{
+					pos = loc + 1;
+					loc = topicName->find('/', pos);
+					if ( loc == string::npos )
+					{
+						return true;
+					}
+					else
+					{
+						return false;
+					}
+				}
+				pos = loc + 1;
+			}
+			else if ( subtopic != subtopict )
+			{
+				return false;
+			}
+			else
+			{
+				if ( (tpos = tloc + 1) > tlen )
+				{
+					return false;
+				}
+
+				pos = loc + 1;
+			}
+		}
+		else if ( loc == string::npos && tloc == string::npos )
+		{
+			string subtopic = topicName->substr(pos);
+			string subtopict = _topicName->substr(tpos);
+			if ( subtopict == wildcard || subtopict == wildcards)
+			{
+				return true;
+			}
+			else if ( subtopic == subtopict )
+			{
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+		else if ( loc == string::npos && tloc != string::npos )
+		{
+			string subtopic = topicName->substr(pos);
+			string subtopict = _topicName->substr(tpos, tloc - tpos);
+			if ( subtopic != subtopict)
+			{
+				return false;
+			}
+
+			tpos = tloc + 1;
+
+			return _topicName->substr(tpos) == wildcard;
+		}
+		else if ( loc != string::npos && tloc == string::npos )
+		{
+			return _topicName->substr(tpos) == wildcard;
+		}
+	}
+}
+
+void Topic::print(void)
+{
+    WRITELOG("TopicName=%s  ID=%d  Type=%d\n", _topicName->c_str(), _topicId, _type);
+}
+
+/*=====================================
+ Class Topics
+ ======================================*/
+Topics::Topics()
+{
+    _first = nullptr;
+    _nextTopicId = 0;
+    _cnt = 0;
+}
+
+Topics::~Topics()
+{
+    Topic* p = _first;
+    while (p)
+    {
+        Topic* q = p->_next;
+        delete p;
+        p = q;
+    }
+}
+
+Topic* Topics::getTopicByName(const MQTTSN_topicid* topicid)
+{
+    Topic* p = _first;
+    char* ch = topicid->data.long_.name;
+
+    string sname = string(ch, ch + topicid->data.long_.len);
+    while (p)
+    {
+         if (  p->_topicName->compare(sname) == 0 )
+         {
+             return p;
+         }
+         p = p->_next;
+    }
+    return 0;
+}
+
+Topic* Topics::getTopicById(const MQTTSN_topicid* topicid)
+{
+    Topic* p = _first;
+
+    while (p)
+    {
+        if ( p->_type == topicid->type && p->_topicId == topicid->data.id )
+        {
+            return p;
+        }
+        p = p->_next;
+    }
+    return 0;
+}
+
+// For MQTTSN_TOPIC_TYPE_NORMAL */
+Topic* Topics::add(const MQTTSN_topicid* topicid)
+{
+    if (topicid->type != MQTTSN_TOPIC_TYPE_NORMAL )
+    {
+        return 0;
+    }
+
+    Topic* topic = getTopicByName(topicid);
+
+    if ( topic )
+    {
+        return topic;
+    }
+    string name(topicid->data.long_.name, topicid->data.long_.len);
+    return add(name.c_str(), 0);
+}
+
+Topic* Topics::add(const char* topicName, uint16_t id)
+{
+    MQTTSN_topicid topicId;
+
+    if (  _cnt >= MAX_TOPIC_PAR_CLIENT )
+    {
+        return 0;
+    }
+
+    topicId.data.long_.name = (char*)const_cast<char*>(topicName);
+    topicId.data.long_.len = strlen(topicName);
+
+
+    Topic* topic = getTopicByName(&topicId);
+
+    if ( topic )
+    {
+        return topic;
+    }
+
+    topic = new Topic();
+
+    if (topic == nullptr)
+    {
+        return nullptr;
+    }
+
+    string* name = new string(topicName);
+    topic->_topicName = name;
+
+    if ( id == 0 )
+    {
+        topic->_type = MQTTSN_TOPIC_TYPE_NORMAL;
+        topic->_topicId = getNextTopicId();
+    }
+    else
+    {
+        topic->_type = MQTTSN_TOPIC_TYPE_PREDEFINED;
+        topic->_topicId  = id;
+    }
+
+    _cnt++;
+
+    if ( _first == nullptr)
+    {
+        _first = topic;
+    }
+    else
+    {
+        Topic* tp = _first;
+        while (tp)
+        {
+            if (tp->_next == nullptr)
+            {
+                tp->_next = topic;
+                break;
+            }
+            else
+            {
+                tp = tp->_next;
+            }
+        }
+    }
+    return topic;
+}
+
+uint16_t Topics::getNextTopicId()
+{
+    return ++_nextTopicId == 0xffff ? _nextTopicId += 2 : _nextTopicId;
+}
+
+Topic* Topics::match(const MQTTSN_topicid* topicid)
+{
+    if (topicid->type != MQTTSN_TOPIC_TYPE_NORMAL)
+    {
+        return 0;
+    }
+    string topicName(topicid->data.long_.name, topicid->data.long_.len);
+
+    Topic* topic = _first;
+    while (topic)
+    {
+        if (topic->isMatch(&topicName))
+        {
+            return topic;
+        }
+        topic = topic->_next;
+    }
+    return 0;
+}
+
+
+void Topics::eraseNormal(void)
+{
+    Topic* topic = _first;
+    Topic* next = nullptr;
+    Topic* prev = nullptr;
+
+    while (topic)
+    {
+        if ( topic->_type == MQTTSN_TOPIC_TYPE_NORMAL )
+        {
+            next = topic->_next;
+            if ( _first == topic )
+            {
+                _first = next;
+            }
+            if ( prev  )
+            {
+                prev->_next = next;
+            }
+            delete topic;
+            _cnt--;
+            topic = next;
+        }
+        else
+        {
+            prev = topic;
+            topic = topic->_next;
+        }
+    }
+}
+
+void Topics::print(void)
+{
+    Topic* topic = _first;
+    if (topic == nullptr )
+    {
+        WRITELOG("No Topic.\n");
+    }
+    else
+    {
+        while (topic)
+        {
+            topic->print();
+            topic = topic->_next;
+        }
+    }
+}
+
+uint8_t Topics::getCount(void)
+{
+    return _cnt;
+}
+
+/*=====================================
+ Class TopicIdMap
+ =====================================*/
+TopicIdMapElement::TopicIdMapElement(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type)
+{
+    _msgId = msgId;
+    _topicId = topicId;
+    _type = type;
+    _next = nullptr;
+    _prev = nullptr;
+}
+
+TopicIdMapElement::~TopicIdMapElement()
+{
+
+}
+
+MQTTSN_topicTypes TopicIdMapElement::getTopicType(void)
+{
+    return _type;
+}
+
+uint16_t TopicIdMapElement::getTopicId(void)
+{
+    return  _topicId;
+}
+
+TopicIdMap::TopicIdMap()
+{
+    _maxInflight = MAX_INFLIGHTMESSAGES;
+    _msgIds = 0;
+    _first = nullptr;
+    _end = nullptr;
+    _cnt = 0;
+}
+
+TopicIdMap::~TopicIdMap()
+{
+    TopicIdMapElement* p = _first;
+    while ( p )
+    {
+        TopicIdMapElement* q = p->_next;
+        delete p;
+        p = q;
+    }
+}
+
+TopicIdMapElement* TopicIdMap::getElement(uint16_t msgId)
+{
+    TopicIdMapElement* p = _first;
+    while ( p )
+    {
+        if ( p->_msgId == msgId )
+        {
+            return p;
+        }
+        p = p->_next;
+    }
+    return 0;
+}
+
+TopicIdMapElement* TopicIdMap::add(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type)
+{
+    if ( _cnt > _maxInflight * 2 || ( topicId == 0 && type != MQTTSN_TOPIC_TYPE_SHORT ) )
+    {
+        return 0;
+    }
+    if ( getElement(msgId) )
+    {
+        erase(msgId);
+    }
+
+    TopicIdMapElement* elm = new TopicIdMapElement(msgId, topicId, type);
+    if ( elm == 0 )
+    {
+        return 0;
+    }
+    if ( _first == nullptr )
+    {
+        _first = elm;
+        _end = elm;
+    }
+    else
+    {
+        elm->_prev = _end;
+        _end->_next = elm;
+        _end = elm;
+    }
+    _cnt++;
+    return elm;
+}
+
+void TopicIdMap::erase(uint16_t msgId)
+{
+    TopicIdMapElement* p = _first;
+    while ( p )
+    {
+        if ( p->_msgId == msgId )
+        {
+            if ( p->_prev == nullptr )
+            {
+                _first = p->_next;
+            }
+            else
+            {
+                p->_prev->_next = p->_next;
+            }
+
+            if ( p->_next == nullptr )
+            {
+                _end = p->_prev;
+            }
+            else
+            {
+                p->_next->_prev = p->_prev;
+            }
+            delete p;
+            break;
+
+        }
+        p = p->_next;
+    }
+    _cnt--;
+}
+
+void TopicIdMap::clear(void)
+{
+    TopicIdMapElement* p = _first;
+    while ( p )
+    {
+        TopicIdMapElement* q = p->_next;
+        delete p;
+        p = q;
+    }
+    _first = nullptr;
+    _end = nullptr;
+    _cnt = 0;
+}
+
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWTopic.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWTopic.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,115 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ *    Tieto Poland Sp. z o.o. - Gateway improvements
+ **************************************************************************************/
+
+#ifndef MQTTSNGATEWAY_SRC_MQTTSNGWTOPIC_H_
+#define MQTTSNGATEWAY_SRC_MQTTSNGWTOPIC_H_
+
+#include "MQTTSNGWPacket.h"
+#include "MQTTSNPacket.h"
+
+namespace MQTTSNGW
+{
+
+
+/*=====================================
+ Class Topic
+ ======================================*/
+class Topic
+{
+    friend class Topics;
+public:
+    Topic();
+    Topic(string* topic, MQTTSN_topicTypes type);
+    ~Topic();
+    string* getTopicName(void);
+    uint16_t getTopicId(void);
+    MQTTSN_topicTypes getType(void);
+    bool isMatch(string* topicName);
+    void print(void);
+private:
+    MQTTSN_topicTypes _type;
+    uint16_t _topicId;
+    string*  _topicName;
+    Topic* _next;
+};
+
+/*=====================================
+ Class Topics
+ ======================================*/
+class Topics
+{
+public:
+    Topics();
+    ~Topics();
+    Topic* add(const MQTTSN_topicid* topicid);
+    Topic* add(const char* topicName, uint16_t id = 0);
+    Topic* getTopicByName(const MQTTSN_topicid* topic);
+    Topic* getTopicById(const MQTTSN_topicid* topicid);
+    Topic* match(const MQTTSN_topicid* topicid);
+    void eraseNormal(void);
+    uint16_t getNextTopicId();
+    void print(void);
+    uint8_t getCount(void);
+private:
+    uint16_t _nextTopicId;
+    Topic* _first;
+    uint8_t  _cnt;
+};
+
+/*=====================================
+ Class TopicIdMapElement
+ =====================================*/
+class TopicIdMapElement
+{
+    friend class TopicIdMap;
+public:
+    TopicIdMapElement(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type);
+    ~TopicIdMapElement();
+    MQTTSN_topicTypes getTopicType(void);
+    uint16_t getTopicId(void);
+
+private:
+    uint16_t _msgId;
+    uint16_t _topicId;
+    MQTTSN_topicTypes _type;
+    TopicIdMapElement* _next;
+    TopicIdMapElement* _prev;
+};
+
+class TopicIdMap
+{
+public:
+    TopicIdMap();
+    ~TopicIdMap();
+    TopicIdMapElement* getElement(uint16_t msgId);
+    TopicIdMapElement* add(uint16_t msgId, uint16_t topicId, MQTTSN_topicTypes type);
+    void erase(uint16_t msgId);
+    void clear(void);
+private:
+    uint16_t* _msgIds;
+    TopicIdMapElement* _first;
+    TopicIdMapElement* _end;
+    int _cnt;
+    int _maxInflight;
+};
+
+
+}
+
+
+
+#endif /* MQTTSNGATEWAY_SRC_MQTTSNGWTOPIC_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWVersion.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWVersion.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,22 @@
+/**************************************************************************************
+ * Copyright (c) 2017, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial version
+ **************************************************************************************/
+
+#ifndef MQTTSNGWVERSION_H_IN_
+#define MQTTSNGWVERSION_H_IN_
+
+#define PAHO_GATEWAY_VERSION "1.3.1"
+
+#endif /* MQTTSNGWVERSION_H_IN_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWVersion.h.in
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGWVersion.h.in	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,22 @@
+/**************************************************************************************
+ * Copyright (c) 2017, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial version
+ **************************************************************************************/
+
+#ifndef MQTTSNGWVERSION_H_IN_
+#define MQTTSNGWVERSION_H_IN_
+
+#define PAHO_GATEWAY_VERSION "@GATEWAY_VERSION@"
+
+#endif /* MQTTSNGWVERSION_H_IN_ */
\ No newline at end of file
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGateway.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGateway.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,526 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGateway.h"
+#include "SensorNetwork.h"
+#include "MQTTSNGWProcess.h"
+#include "MQTTSNGWVersion.h"
+#include "MQTTSNGWQoSm1Proxy.h"
+#include "MQTTSNGWClient.h"
+#include <string.h>
+using namespace MQTTSNGW;
+
+char* currentDateTime(void);
+
+/*=====================================
+ Class Gateway
+ =====================================*/
+MQTTSNGW::Gateway* theGateway = nullptr;
+
+Gateway::Gateway(void)
+{
+    theMultiTaskProcess = this;
+    theProcess = this;
+    _packetEventQue.setMaxSize(MAX_INFLIGHTMESSAGES * MAX_CLIENTS);
+    _clientList = new ClientList();
+    _adapterManager = new AdapterManager(this);
+    _topics = new Topics();
+}
+
+Gateway::~Gateway()
+{
+	if ( _params.loginId )
+	{
+		free(_params.loginId);
+	}
+	if ( _params.password )
+	{
+		free(_params.password);
+	}
+	if ( _params.gatewayName )
+	{
+		free(_params.gatewayName);
+	}
+	if ( _params.brokerName )
+	{
+		free(_params.brokerName);
+	}
+	if ( _params.port )
+	{
+		free(_params.port);
+	}
+	if ( _params.portSecure )
+	{
+		free(_params.portSecure);
+	}
+	if ( _params.certKey )
+	{
+		free(_params.certKey);
+	}
+	if ( _params.privateKey )
+	{
+		free(_params.privateKey);
+	}
+	if ( _params.rootCApath )
+	{
+		free(_params.rootCApath);
+	}
+	if ( _params.rootCAfile )
+	{
+		free(_params.rootCAfile);
+	}
+	if ( _params.clientListName )
+	{
+		free(_params.clientListName);
+	}
+	if ( _params.configName )
+	{
+		free(_params.configName);
+	}
+
+    if ( _params.qosMinusClientListName )
+    {
+        free(_params.qosMinusClientListName);
+    }
+
+    if ( _adapterManager )
+    {
+        delete _adapterManager;
+    }
+    if ( _clientList )
+    {
+        delete _clientList;
+    }
+
+    if ( _topics )
+	{
+		delete _topics;
+	}
+}
+
+int Gateway::getParam(const char* parameter, char* value)
+{
+    return MultiTaskProcess::getParam(parameter, value);
+}
+
+void Gateway::initialize(int argc, char** argv)
+{
+	char param[MQTTSNGW_PARAM_MAX];
+	string fileName;
+    theGateway = this;
+
+	MultiTaskProcess::initialize(argc, argv);
+	resetRingBuffer();
+
+	_params.configDir = *getConfigDirName();
+    fileName = _params.configDir + *getConfigFileName();
+    _params.configName = strdup(fileName.c_str());
+
+	if (getParam("BrokerName", param) == 0)
+	{
+		_params.brokerName = strdup(param);
+	}
+	if (getParam("BrokerPortNo", param) == 0)
+	{
+		_params.port = strdup(param);
+	}
+	if (getParam("BrokerSecurePortNo", param) == 0)
+	{
+		_params.portSecure = strdup(param);
+	}
+
+	if (getParam("CertKey", param) == 0)
+	{
+		_params.certKey = strdup(param);
+	}
+	if (getParam("PrivateKey", param) == 0)
+		{
+			_params.privateKey = strdup(param);
+		}
+	if (getParam("RootCApath", param) == 0)
+	{
+		_params.rootCApath = strdup(param);
+	}
+	if (getParam("RootCAfile", param) == 0)
+	{
+		_params.rootCAfile = strdup(param);
+	}
+
+	if (getParam("GatewayID", param) == 0)
+	{
+		_params.gatewayId = atoi(param);
+	}
+
+	if (_params.gatewayId == 0 || _params.gatewayId > 255)
+	{
+		throw Exception( "Gateway::initialize: invalid Gateway Id");
+	}
+
+	if (getParam("GatewayName", param) == 0)
+	{
+		_params.gatewayName = strdup(param);
+	}
+
+	if (_params.gatewayName == 0 )
+	{
+		throw Exception( "Gateway::initialize: Gateway Name is missing.");
+	}
+
+	_params.mqttVersion = DEFAULT_MQTT_VERSION;
+	if (getParam("MQTTVersion", param) == 0)
+	{
+		_params.mqttVersion = atoi(param);
+	}
+
+	_params.maxInflightMsgs = DEFAULT_MQTT_VERSION;
+	if (getParam("MaxInflightMsgs", param) == 0)
+	{
+		_params.maxInflightMsgs = atoi(param);
+	}
+
+	_params.keepAlive = DEFAULT_KEEP_ALIVE_TIME;
+	if (getParam("KeepAlive", param) == 0)
+	{
+		_params.keepAlive = atoi(param);
+	}
+
+	if (getParam("LoginID", param) == 0)
+	{
+		_params.loginId = strdup(param);
+	}
+
+	if (getParam("Password", param) == 0)
+	{
+		_params.password = strdup(param);
+	}
+
+	if (getParam("ClientAuthentication", param) == 0)
+	{
+		if (!strcasecmp(param, "YES"))
+		{
+			_params.clientAuthentication = true;
+		}
+	}
+
+	/*  ClientList and Adapters  Initialize  */
+	_adapterManager->initialize();
+
+	bool aggregate = _adapterManager->isAggregaterActive();
+	_clientList->initialize(aggregate);
+
+	/*  Setup predefined topics  */
+	_clientList->setPredefinedTopics(aggregate);
+}
+
+void Gateway::run(void)
+{
+    /* write prompts */
+	_lightIndicator.redLight(true);
+	WRITELOG("\n%s", PAHO_COPYRIGHT4);
+	WRITELOG("\n%s\n", PAHO_COPYRIGHT0);
+	WRITELOG("%s\n", PAHO_COPYRIGHT1);
+	WRITELOG("%s\n", PAHO_COPYRIGHT2);
+	WRITELOG(" *\n%s\n", PAHO_COPYRIGHT3);
+	WRITELOG(" * Version: %s\n", PAHO_GATEWAY_VERSION);
+	WRITELOG("%s\n", PAHO_COPYRIGHT4);
+	WRITELOG("\n%s %s has been started.\n\n", currentDateTime(), _params.gatewayName);
+	WRITELOG(" ConfigFile: %s\n", _params.configName);
+
+	if ( _params.clientListName )
+	{
+		WRITELOG(" ClientList: %s\n", _params.clientListName);
+	}
+
+    if (  _params.predefinedTopicFileName )
+    {
+        WRITELOG(" PreDefFile: %s\n", _params.predefinedTopicFileName);
+    }
+
+	WRITELOG(" SensorN/W:  %s\n", _sensorNetwork.getDescription());
+	WRITELOG(" Broker:     %s : %s, %s\n", _params.brokerName, _params.port, _params.portSecure);
+	WRITELOG(" RootCApath: %s\n", _params.rootCApath);
+	WRITELOG(" RootCAfile: %s\n", _params.rootCAfile);
+	WRITELOG(" CertKey:    %s\n", _params.certKey);
+	WRITELOG(" PrivateKey: %s\n\n\n", _params.privateKey);
+
+
+	/* Run Tasks until CTRL+C entred */
+	MultiTaskProcess::run();
+
+	/* stop Tasks */
+	Event* ev = new Event();
+	ev->setStop();
+	_packetEventQue.post(ev);
+	ev = new Event();
+	ev->setStop();
+	_brokerSendQue.post(ev);
+	ev = new Event();
+	ev->setStop();
+	_clientSendQue.post(ev);
+
+	/* wait until all Task stop */
+	MultiTaskProcess::waitStop();
+
+	WRITELOG("\n%s MQTT-SN Gateway  stoped\n\n", currentDateTime());
+	_lightIndicator.allLightOff();
+}
+
+EventQue* Gateway::getPacketEventQue()
+{
+	return &_packetEventQue;
+}
+
+EventQue* Gateway::getClientSendQue()
+{
+	return &_clientSendQue;
+}
+
+EventQue* Gateway::getBrokerSendQue()
+{
+	return &_brokerSendQue;
+}
+
+ClientList* Gateway::getClientList()
+{
+	return _clientList;
+}
+
+SensorNetwork* Gateway::getSensorNetwork()
+{
+	return &_sensorNetwork;
+}
+
+LightIndicator* Gateway::getLightIndicator()
+{
+	return &_lightIndicator;
+}
+
+GatewayParams* Gateway::getGWParams(void)
+{
+	return &_params;
+}
+
+AdapterManager* Gateway::getAdapterManager(void)
+{
+    return _adapterManager;
+}
+
+Topics* Gateway::getTopics(void)
+{
+    return _topics;
+}
+
+bool Gateway::hasSecureConnection(void)
+{
+	return (  _params.certKey
+			&& _params.privateKey
+			&& _params.rootCApath
+			&& _params.rootCAfile );
+}
+/*=====================================
+ Class EventQue
+ =====================================*/
+EventQue::EventQue()
+{
+
+}
+
+EventQue::~EventQue()
+{
+	_mutex.lock();
+	while (_que.size() > 0)
+	{
+		delete _que.front();
+		_que.pop();
+	}
+	_mutex.unlock();
+}
+
+void  EventQue::setMaxSize(uint16_t maxSize)
+{
+	_que.setMaxSize((int)maxSize);
+}
+
+Event* EventQue::wait(void)
+{
+	Event* ev = nullptr;
+
+	while(ev == nullptr)
+	{
+		if ( _que.size() == 0 )
+		{
+			_sem.wait();
+		}
+		_mutex.lock();
+		ev = _que.front();
+		_que.pop();
+		_mutex.unlock();
+	}
+	return ev;
+}
+
+Event* EventQue::timedwait(uint16_t millsec)
+{
+	Event* ev;
+	if ( _que.size() == 0 )
+	{
+		_sem.timedwait(millsec);
+	}
+	_mutex.lock();
+
+	if (_que.size() == 0)
+	{
+		ev = new Event();
+		ev->setTimeout();
+	}
+	else
+	{
+		ev = _que.front();
+		_que.pop();
+	}
+	_mutex.unlock();
+	return ev;
+}
+
+void EventQue::post(Event* ev)
+{
+	if ( ev )
+	{
+		_mutex.lock();
+		if ( _que.post(ev) )
+		{
+			_sem.post();
+		}
+		else
+		{
+			delete ev;
+		}
+		_mutex.unlock();
+	}
+}
+
+int EventQue::size()
+{
+	_mutex.lock();
+	int sz = _que.size();
+	_mutex.unlock();
+	return sz;
+}
+
+
+/*=====================================
+ Class Event
+ =====================================*/
+Event::Event()
+{
+
+}
+
+Event::~Event()
+{
+	if (_sensorNetAddr)
+	{
+		delete _sensorNetAddr;
+	}
+
+	if (_mqttSNPacket)
+	{
+		delete _mqttSNPacket;
+	}
+
+	if (_mqttGWPacket)
+	{
+		delete _mqttGWPacket;
+	}
+}
+
+EventType Event::getEventType()
+{
+	return _eventType;
+}
+
+void Event::setClientSendEvent(Client* client, MQTTSNPacket* packet)
+{
+	_client = client;
+	_eventType = EtClientSend;
+	_mqttSNPacket = packet;
+}
+
+void Event::setBrokerSendEvent(Client* client, MQTTGWPacket* packet)
+{
+	_client = client;
+	_eventType = EtBrokerSend;
+	_mqttGWPacket = packet;
+}
+
+void Event::setClientRecvEvent(Client* client, MQTTSNPacket* packet)
+{
+	_client = client;
+	_eventType = EtClientRecv;
+	_mqttSNPacket = packet;
+}
+
+void Event::setBrokerRecvEvent(Client* client, MQTTGWPacket* packet)
+{
+	_client = client;
+	_eventType = EtBrokerRecv;
+	_mqttGWPacket = packet;
+}
+
+void Event::setTimeout(void)
+{
+	_eventType = EtTimeout;
+}
+
+void Event::setStop(void)
+{
+	_eventType = EtStop;
+}
+
+void Event::setBrodcastEvent(MQTTSNPacket* msg)
+{
+	_mqttSNPacket = msg;
+	_eventType = EtBroadcast;
+}
+
+void Event::setClientSendEvent(SensorNetAddress* addr, MQTTSNPacket* msg)
+{
+	_eventType = EtSensornetSend;
+	_sensorNetAddr = addr;
+	_mqttSNPacket = msg;
+}
+
+Client* Event::getClient(void)
+{
+	return _client;
+}
+
+SensorNetAddress* Event::getSensorNetAddress(void)
+{
+	return _sensorNetAddr;
+}
+
+MQTTSNPacket* Event::getMQTTSNPacket()
+{
+	return _mqttSNPacket;
+}
+
+MQTTGWPacket* Event::getMQTTGWPacket(void)
+{
+	return _mqttGWPacket;
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGateway.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/MQTTSNGateway.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,210 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#ifndef MQTTSNGATEWAY_H_
+#define MQTTSNGATEWAY_H_
+
+#include <MQTTSNGWAdapterManager.h>
+#include "MQTTSNGWProcess.h"
+#include "MQTTSNPacket.h"
+#include "MQTTSNGWClient.h"
+
+namespace MQTTSNGW
+{
+/*=================================
+ *    Starting prompt
+ ==================================*/
+#define PAHO_COPYRIGHT0 " * MQTT-SN Transparent Gateway"
+#define PAHO_COPYRIGHT1 " * Part of Project Paho in Eclipse"
+#define PAHO_COPYRIGHT2 " * (http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt-sn.embedded-c.git/)"
+#define PAHO_COPYRIGHT3 " * Author : Tomoaki YAMAGUCHI"
+#define PAHO_COPYRIGHT4 " ***************************************************************************"
+/*==========================================================
+ *           Log Formats
+ *
+ *           RED    : \033[0m\033[1;31m
+ *           green  : \033[0m\033[0;32m
+ *           yellow : \033[0m\033[0;33m
+ *           blue   : \033[0m\033[0;34m
+ *           white  : \033[0m\033[0;37m
+ ===========================================================*/
+#define CLIENT      "Client"
+#define CLIENTS     "Clients"
+#define UNKNOWNCL   "Unknown Client !"
+
+#define LEFTARROW   "<---"
+#define RIGHTARROW  "--->"
+#define LEFTARROWB   "<==="
+#define RIGHTARROWB  "===>"
+
+#define FORMAT_Y_G_G_NL        "\n%s   \033[0m\033[0;33m%-18s\033[0m\033[0;32m%-6s%-34.32s \033[0m\033[0;34m%s\033[0m\033[0;37m\n"
+#define FORMAT_Y_G_G             "%s   \033[0m\033[0;33m%-18s\033[0m\033[0;32m%-6s%-34.32s \033[0m\033[0;34m%s\033[0m\033[0;37m\n"
+#define FORMAT_Y_Y_G             "%s   \033[0m\033[0;33m%-18s%-6s\033[0m\033[0;32m%-34.32s \033[0m\033[0;34m%s\033[0m\033[0;37m\n"
+#define FORMAT_Y_W_G             "%s   \033[0m\033[0;33m%-18s\033[0m\033[0;37m%-6s\033[0m\033[0;32m%-34.32s \033[0m\033[0;34m%s\033[0m\033[0;37m\n"
+#define FORMAT_Y_Y_W             "%s   \033[0m\033[0;33m%-18s%-6s\033[0m\033[0;37m%-34.32s \033[0m\033[0;34m%s\033[0m\033[0;37m\n"
+
+#define FORMAT_G_MSGID_G_G_NL  "\n%s   \033[0m\033[0;32m%-11s%-5s  %-6s%-34.32s \033[0m\033[0;34m%s\033[0m\033[0;37m\n"
+#define FORMAT_G_MSGID_G_G       "%s   \033[0m\033[0;32m%-11s%-5s  %-6s%-34.32s \033[0m\033[0;34m%s\033[0m\033[0;37m\n"
+#define FORMAT_G_MSGID_W_G       "%s   \033[0m\033[0;32m%-11s%-5s  \033[0m\033[0;37m%-6s\033[0m\033[0;32m%-34.32 s\033[0m\033[0;34m%s\033[0m\033[0;37m\n"
+#define FORMAT_G_MSGID_Y_W       "%s   \033[0m\033[0;32m%-11s%-5s  \033[0m\033[0;33m%-6s\033[0m\033[0;37m%-34.32s \033[0m\033[0;34m%s\033[0m\033[0;37m\n"
+
+#define FORMAT_W_MSGID_Y_W_NL  "\n%s   %-11s%-5s  \033[0m\033[0;33m%-6s\033[0m\033[0;37m%-34.32s \033[0m\033[0;34m%s\033[0m\033[0;37m\n"
+#define FORMAT_W_MSGID_Y_W       "%s   %-11s%-5s  \033[0m\033[0;33m%-6s\033[0m\033[0;37m%-34.32s \033[0m\033[0;34m%s\033[0m\033[0;37m\n"
+#define FORMAT_W_MSGID_W_G       "%s   %-11s%-5s  %-6s\033[0m\033[0;32m%-34.32s \033[0m\033[0;34m%s\033[0m\033[0;37m\n"
+#define FORMAT_W_MSGID_G_G       "%s   %-11s%-5s  \033[0m\033[0;32m%-6s%-34.32s \033[0m\033[0;34m%s\033[0m\033[0;37m\n"
+
+#define FORMAT_BL_NL           "\n%s   \033[0m\033[0;34m%-18s%-6s%-34.32s %s\033[0m\033[0;37m\n"
+#define FORMAT_W_NL            "\n%s   %-18s%-6s%-34.32s %s\n"
+
+#define ERRMSG_HEADER            "\033[0m\033[0;31mError:"
+#define ERRMSG_FOOTER            "\033[0m\033[0;37m"
+
+/*=====================================
+         Class Event
+  ====================================*/
+class Client;
+
+enum EventType{
+	Et_NA = 0,
+	EtStop,
+	EtTimeout,
+	EtBrokerRecv,
+	EtBrokerSend,
+	EtClientRecv,
+	EtClientSend,
+	EtBroadcast,
+	EtSensornetSend
+};
+
+
+class Event{
+public:
+	Event();
+	~Event();
+	EventType getEventType(void);
+	void setClientRecvEvent(Client*, MQTTSNPacket*);
+	void setClientSendEvent(Client*, MQTTSNPacket*);
+	void setBrokerRecvEvent(Client*, MQTTGWPacket*);
+	void setBrokerSendEvent(Client*, MQTTGWPacket*);
+	void setBrodcastEvent(MQTTSNPacket*);  // ADVERTISE and GWINFO
+	void setTimeout(void);                 // Required by EventQue<Event>.timedwait()
+	void setStop(void);
+	void setClientSendEvent(SensorNetAddress*, MQTTSNPacket*);
+	Client* getClient(void);
+	SensorNetAddress* getSensorNetAddress(void);
+	MQTTSNPacket* getMQTTSNPacket(void);
+	MQTTGWPacket* getMQTTGWPacket(void);
+
+private:
+	EventType   _eventType {Et_NA};
+	Client*     _client {nullptr};
+	SensorNetAddress* _sensorNetAddr {nullptr};
+	MQTTSNPacket* _mqttSNPacket {nullptr};
+	MQTTGWPacket* _mqttGWPacket {nullptr};
+};
+
+
+/*=====================================
+ Class EventQue
+ ====================================*/
+class EventQue
+{
+public:
+	EventQue();
+	~EventQue();
+	Event* wait(void);
+	Event* timedwait(uint16_t millsec);
+	void setMaxSize(uint16_t maxSize);
+	void post(Event*);
+	int  size();
+
+private:
+	Que<Event> _que;
+	Mutex      _mutex;
+	Semaphore  _sem;
+};
+
+
+
+/*=====================================
+ Class GatewayParams
+ ====================================*/
+class GatewayParams
+{
+public:
+     string configDir;
+	char* configName {nullptr};
+	char* clientListName {nullptr};
+	char* loginId {nullptr};
+	char* password {nullptr};
+	uint16_t keepAlive {0};
+	uint8_t  gatewayId {0};
+	uint8_t  mqttVersion {0};
+	uint16_t maxInflightMsgs {0};
+	char* gatewayName {nullptr};
+	char* brokerName {nullptr};
+	char* port {nullptr};
+	char* portSecure {nullptr};
+	char* rootCApath {nullptr};
+	char* rootCAfile {nullptr};
+	char* certKey {nullptr};
+	char* privateKey {nullptr};
+	char* predefinedTopicFileName {nullptr};
+	char* qosMinusClientListName {nullptr};
+	bool  clientAuthentication {false};
+};
+
+
+
+/*=====================================
+     Class Gateway
+ =====================================*/
+class AdapterManager;
+class ClientList;
+
+class Gateway: public MultiTaskProcess{
+public:
+    Gateway(void);
+	~Gateway();
+	virtual void initialize(int argc, char** argv);
+	void run(void);
+
+	EventQue* getPacketEventQue(void);
+	EventQue* getClientSendQue(void);
+	EventQue* getBrokerSendQue(void);
+	ClientList* getClientList(void);
+	SensorNetwork* getSensorNetwork(void);
+	LightIndicator* getLightIndicator(void);
+	GatewayParams* getGWParams(void);
+	AdapterManager* getAdapterManager(void);
+	int getParam(const char* parameter, char* value);
+	bool hasSecureConnection(void);
+	Topics* getTopics(void);
+
+private:
+	GatewayParams  _params;
+	ClientList* _clientList {nullptr};
+	EventQue   _packetEventQue;
+	EventQue   _brokerSendQue;
+	EventQue   _clientSendQue;
+	LightIndicator _lightIndicator;
+	SensorNetwork  _sensorNetwork;
+	AdapterManager* _adapterManager {nullptr};
+	Topics* _topics;
+};
+
+}
+
+#endif /* MQTTSNGATEWAY_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Network.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Network.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,639 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include <string.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <regex>
+
+#include "Network.h"
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGWProcess.h"
+
+using namespace std;
+using namespace MQTTSNGW;
+
+#define SOCKET_MAXCONNECTIONS  5
+char* currentDateTime();
+
+/*========================================
+ Class TCPStack
+ =======================================*/
+TCPStack::TCPStack()
+{
+	_addrinfo = 0;
+	_sockfd = 0;
+}
+
+TCPStack::~TCPStack()
+{
+	if (_addrinfo)
+	{
+		freeaddrinfo(_addrinfo);
+	}
+}
+
+bool TCPStack::isValid()
+{
+	return (_sockfd > 0);
+}
+
+void TCPStack::close()
+{
+	_mutex.lock();
+	if (_sockfd > 0)
+	{
+		::close(_sockfd);
+		_sockfd = 0;
+		if (_addrinfo)
+		{
+			freeaddrinfo(_addrinfo);
+			_addrinfo = 0;
+		}
+	}
+	_mutex.unlock();
+
+}
+
+bool TCPStack::bind(const char* service)
+{
+	if (isValid())
+	{
+		return false;
+	}
+	addrinfo hints;
+	memset(&hints, 0, sizeof(addrinfo));
+	hints.ai_family = AF_INET;
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_flags = AI_PASSIVE;
+
+	if (_addrinfo)
+	{
+		freeaddrinfo(_addrinfo);
+	}
+	int err = getaddrinfo(0, service, &hints, &_addrinfo);
+	if (err)
+	{
+		WRITELOG("\n%s   \x1b[0m\x1b[31merror:\x1b[0m\x1b[37mgetaddrinfo(): %s\n", currentDateTime(),
+				gai_strerror(err));
+		return false;
+	}
+
+	_sockfd = socket(_addrinfo->ai_family, _addrinfo->ai_socktype, _addrinfo->ai_protocol);
+	if (_sockfd < 0)
+	{
+		return false;
+	}
+	int on = 1;
+	if (setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*) &on, sizeof(on)) == -1)
+	{
+		return false;
+	}
+
+	if (::bind(_sockfd, _addrinfo->ai_addr, _addrinfo->ai_addrlen) < 0)
+	{
+		return false;
+	}
+	return true;
+}
+
+bool TCPStack::listen()
+{
+	if (!isValid())
+	{
+		return false;
+	}
+	int listen_return = ::listen(_sockfd, SOCKET_MAXCONNECTIONS);
+	if (listen_return == -1)
+	{
+		return false;
+	}
+	return true;
+}
+
+bool TCPStack::accept(TCPStack& new_socket)
+{
+	sockaddr_storage sa;
+	socklen_t len = sizeof(sa);
+	new_socket._sockfd = ::accept(_sockfd, (struct sockaddr*) &sa, &len);
+	if (new_socket._sockfd <= 0)
+	{
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+}
+
+int TCPStack::send(const uint8_t* buf, int length)
+{
+	return ::send(_sockfd, buf, length, MSG_NOSIGNAL);
+}
+
+int TCPStack::recv(uint8_t* buf, int len)
+{
+	return ::recv(_sockfd, buf, len, 0);
+}
+
+bool TCPStack::connect(const char* host, const char* service)
+{
+	if (isValid())
+	{
+		return true;
+	}
+	addrinfo hints;
+	memset(&hints, 0, sizeof(addrinfo));
+	hints.ai_family = AF_INET;
+	hints.ai_socktype = SOCK_STREAM;
+	if (_addrinfo)
+	{
+		freeaddrinfo(_addrinfo);
+	}
+
+	int err = getaddrinfo(host, service, &hints, &_addrinfo);
+	if (err)
+	{
+		WRITELOG("\n%s   \x1b[0m\x1b[31merror:\x1b[0m\x1b[37mgetaddrinfo(): %s\n", currentDateTime(),
+				gai_strerror(err));
+		return false;
+	}
+
+	int sockfd = socket(_addrinfo->ai_family, _addrinfo->ai_socktype, _addrinfo->ai_protocol);
+
+	if (sockfd < 0)
+	{
+		return false;
+	}
+	int on = 1;
+
+	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*) &on, sizeof(on)) == -1)
+	{
+		return false;
+	}
+
+	if (::connect(sockfd, _addrinfo->ai_addr, _addrinfo->ai_addrlen) < 0)
+	{
+		DEBUGLOG("Can not connect the socket. Check the PortNo! \n");
+		::close(sockfd);
+		return false;
+	}
+
+	_sockfd = sockfd;
+	return true;
+}
+
+void TCPStack::setNonBlocking(const bool b)
+{
+	int opts;
+
+	opts = fcntl(_sockfd, F_GETFL);
+
+	if (opts < 0)
+	{
+		return;
+	}
+
+	if (b)
+	{
+		opts = (opts | O_NONBLOCK);
+	}
+	else
+	{
+		opts = (opts & ~O_NONBLOCK);
+	}
+	fcntl(_sockfd, F_SETFL, opts);
+}
+
+int TCPStack::getSock()
+{
+	return _sockfd;
+}
+
+/*========================================
+ Class Network
+ =======================================*/
+int Network::_numOfInstance = 0;
+SSL_CTX* Network::_ctx = 0;
+SSL_SESSION* Network::_session = 0;
+
+Network::Network(bool secure) :
+		TCPStack()
+{
+	_ssl = 0;
+	_secureFlg = secure;
+	_busy = false;
+	_sslValid = false;
+}
+
+Network::~Network()
+{
+	close();
+}
+
+bool Network::connect(const char* host, const char* port)
+{
+	bool rc = false;
+	_mutex.lock();
+	if (_secureFlg)
+	{
+		goto exit;
+	}
+
+	if (getSock() == 0)
+	{
+		if (!TCPStack::connect(host, port))
+		{
+			goto exit;
+		}
+	}
+	rc = true;
+exit:
+	_mutex.unlock();
+	return rc;
+}
+
+bool Network::connect(const char* host, const char* port, const char* caPath, const char* caFile, const char* certkey, const char* prvkey)
+{
+	char errmsg[256];
+	char peer_CN[256];
+	bool rc;
+
+	_mutex.lock();
+	try
+	{
+		if (!_secureFlg)
+		{
+			WRITELOG("TLS is not required.\n");
+			throw false;
+		}
+
+		if (_ctx == 0)
+		{
+			SSL_load_error_strings();
+			SSL_library_init();
+
+#if ( OPENSSL_VERSION_NUMBER >= 0x10100000L )
+			_ctx = SSL_CTX_new(TLS_client_method());
+#elif ( OPENSSL_VERSION_NUMBER >= 0x10001000L )
+			_ctx = SSL_CTX_new(TLSv1_client_method());
+#else
+			_ctx = SSL_CTX_new(SSLv23_client_method());
+#endif
+
+			if (_ctx == 0)
+			{
+				ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
+				WRITELOG("SSL_CTX_new() %s\n", errmsg);
+				throw false;
+			}
+
+
+			if (!SSL_CTX_load_verify_locations(_ctx, caFile, caPath))
+			{
+				ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
+				WRITELOG("SSL_CTX_load_verify_locations() %s\n", errmsg);
+				throw false;
+			}
+
+			if ( certkey )
+			{
+				if ( SSL_CTX_use_certificate_file(_ctx, certkey, SSL_FILETYPE_PEM) != 1 )
+				{
+					ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
+					WRITELOG("SSL_CTX_use_certificate_file() %s %s\n", certkey, errmsg);
+					throw false;
+				}
+			}
+			if ( prvkey )
+			{
+				if ( SSL_CTX_use_PrivateKey_file(_ctx, prvkey, SSL_FILETYPE_PEM) != 1 )
+				{
+					ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
+					WRITELOG("SSL_use_PrivateKey_file() %s %s\n", prvkey, errmsg);
+					throw false;
+				}
+			}
+		}
+
+		if (! TCPStack::isValid())
+		{
+			if ( !TCPStack::connect(host, port) )
+			{
+				throw false;
+			}
+		}
+
+		_ssl = SSL_new(_ctx);
+		if (_ssl == 0)
+		{
+			ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
+			WRITELOG("SSL_new()  %s\n", errmsg);
+			throw false;
+		}
+
+		if (!SSL_set_fd(_ssl, TCPStack::getSock()))
+		{
+			ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
+			WRITELOG("SSL_set_fd()  %s\n", errmsg);
+			SSL_free(_ssl);
+			_ssl = 0;
+			throw false;
+		}
+
+		if (_session)
+		{
+			SSL_set_session(_ssl, _session);
+		}
+
+		if (SSL_connect(_ssl) != 1)
+		{
+			ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
+			WRITELOG("SSL_connect() %s\n", errmsg);
+			SSL_free(_ssl);
+			_ssl = 0;
+			throw false;
+		}
+
+		int result;
+		if ( (result = SSL_get_verify_result(_ssl)) != X509_V_OK)
+		{
+			WRITELOG("SSL_get_verify_result() error: %s.\n", X509_verify_cert_error_string(result));
+			SSL_free(_ssl);
+			_ssl = 0;
+			throw false;
+		}
+
+		X509* peer = SSL_get_peer_certificate(_ssl);
+		X509_NAME_get_text_by_NID(X509_get_subject_name(peer), NID_commonName, peer_CN, 256);
+		char* pos = peer_CN;
+		if ( *pos == '*')
+		{
+			while (*host++ != '.');
+			pos += 2;
+		}
+		if ( strcmp(host, pos))
+		{
+			WRITELOG("SSL_get_peer_certificate() error: Broker %s dosen't match the host name %s\n", peer_CN, host);
+			SSL_free(_ssl);
+			_ssl = 0;
+			throw false;
+		}
+
+		if (_session == 0)
+		{
+			_session = SSL_get1_session(_ssl);
+		}
+		_numOfInstance++;
+		_sslValid = true;
+		rc = true;
+	}
+	catch (bool x)
+	{
+		rc = x;
+	}
+	_mutex.unlock();
+	return rc;
+}
+
+int Network::send(const uint8_t* buf, uint16_t length)
+{
+	char errmsg[256];
+	fd_set rset;
+	fd_set wset;
+	bool writeBlockedOnRead = false;
+	int bpos = 0;
+
+	if (!_secureFlg)
+	{
+		return TCPStack::send(buf, length);
+	}
+	else
+	{
+		_mutex.lock();
+
+		if ( !_ssl )
+		{
+			_mutex.unlock();
+			return -1;
+		}
+		_busy = true;
+
+		while (true)
+		{
+			FD_ZERO(&rset);
+			FD_ZERO(&wset);
+			FD_SET(getSock(), &rset);
+			FD_SET(getSock(), &wset);
+
+			int activity = select(getSock() + 1, &rset, &wset, 0, 0);
+			if (activity > 0)
+			{
+				if (FD_ISSET(getSock(), &wset) || (writeBlockedOnRead  && FD_ISSET(getSock(), &rset)))
+				{
+
+					writeBlockedOnRead = false;
+					int r = SSL_write(_ssl, buf + bpos, length);
+
+					switch (SSL_get_error(_ssl, r))
+					{
+					case SSL_ERROR_NONE:
+						length -= r;
+						bpos += r;
+						if (length == 0)
+						{
+							_busy = false;
+							_mutex.unlock();
+							return bpos;
+						}
+						break;
+					case SSL_ERROR_WANT_WRITE:
+						break;
+					case SSL_ERROR_WANT_READ:
+						writeBlockedOnRead = true;
+						break;
+					default:
+						ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
+						WRITELOG("TLSStack::send() default %s\n", errmsg);
+						_busy = false;
+						_mutex.unlock();
+						return -1;
+					}
+				}
+			}
+		}
+	}
+}
+
+int Network::recv(uint8_t* buf, uint16_t len)
+{
+	char errmsg[256];
+	bool writeBlockedOnRead = false;
+	bool readBlockedOnWrite = false;
+	bool readBlocked = false;
+	int rlen = 0;
+	int bpos = 0;
+	fd_set rset;
+	fd_set wset;
+
+	if (!_secureFlg)
+	{
+		return TCPStack::recv(buf, len);
+	}
+
+	if (_busy)
+	{
+		return 0;
+	}
+	_mutex.lock();
+
+	if ( !_ssl )
+	{
+		_mutex.unlock();
+		return 0;
+	}
+
+	_busy = true;
+loop:
+	do
+	{
+		readBlockedOnWrite = false;
+		readBlocked = false;
+
+		rlen = SSL_read(_ssl, buf + bpos, len - bpos);
+
+		switch (SSL_get_error(_ssl, rlen))
+		{
+		case SSL_ERROR_NONE:
+			_busy = false;
+			_mutex.unlock();
+			return rlen + bpos;
+			break;
+		case SSL_ERROR_ZERO_RETURN:
+			SSL_shutdown(_ssl);
+			_ssl = 0;
+			_numOfInstance--;
+			//TCPStack::close();
+			_busy = false;
+			_mutex.unlock();
+			return -1;
+			break;
+		case SSL_ERROR_WANT_READ:
+			readBlocked = true;
+			break;
+		case SSL_ERROR_WANT_WRITE:
+			readBlockedOnWrite = true;
+			break;
+		default:
+			ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
+			WRITELOG("Network::recv() %s\n", errmsg);
+			_busy = false;
+			_mutex.unlock();
+			return -1;
+		}
+	} while (SSL_pending(_ssl) && !readBlocked);
+
+	bpos += rlen;
+	while (true)
+	{
+		FD_ZERO(&rset);
+		FD_ZERO(&wset);
+		FD_SET(getSock(), &rset);
+		FD_SET(getSock(), &wset);
+
+		int activity = select(getSock() + 1, &rset, &wset, 0, 0);
+		if (activity > 0)
+		{
+			if ((FD_ISSET(getSock(),&rset) && !writeBlockedOnRead)
+					|| (readBlockedOnWrite && FD_ISSET(getSock(), &wset)))
+			{
+				goto loop;
+			}
+		}
+		else
+		{
+			ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
+			WRITELOG("TLSStack::recv() select %s\n", errmsg);
+			_busy = false;
+			_mutex.unlock();
+			return -1;
+		}
+	}
+}
+
+void Network::close(void)
+{
+	_mutex.lock();
+	if (_secureFlg)
+	{
+		if (_ssl)
+		{
+			SSL_shutdown(_ssl);
+			SSL_free(_ssl);
+			_numOfInstance--;
+			_ssl = 0;
+			_sslValid = false;
+			_busy = false;
+		}
+		if (_session && _numOfInstance == 0)
+		{
+			SSL_SESSION_free(_session);
+			_session = 0;
+		}
+		if (_ctx && _numOfInstance == 0)
+		{
+			SSL_CTX_free(_ctx);
+			_ctx = 0;
+			ERR_free_strings();
+		}
+	}
+	TCPStack::close();
+	_mutex.unlock();
+}
+
+bool Network::isValid()
+{
+	if ( TCPStack::isValid() )
+	{
+		if (_secureFlg)
+		{
+			if (_sslValid && !_busy)
+			{
+				return true;
+			}
+		}
+		else
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+int Network::getSock()
+{
+	return TCPStack::getSock();
+}
+
+bool Network::isSecure()
+{
+	return _secureFlg;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Network.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Network.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,95 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef NETWORK_H_
+#define NETWORK_H_
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <netdb.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#include "Threading.h"
+#include "MQTTSNGWDefines.h"
+
+using namespace std;
+using namespace MQTTSNGW;
+
+/*========================================
+ Class TCPStack
+ =======================================*/
+class TCPStack
+{
+public:
+	TCPStack();
+	virtual ~TCPStack();
+
+	// Server initialization
+	bool bind(const char* service);
+	bool listen();
+	bool accept(TCPStack&);
+
+	// Client initialization
+	bool connect(const char* host, const char* service);
+
+	int send(const uint8_t* buf, int length);
+	int recv(uint8_t* buf, int len);
+	void close();
+
+	void setNonBlocking(const bool);
+
+	bool isValid();
+	int getSock();
+
+private:
+	int _sockfd;
+	addrinfo* _addrinfo;
+	Mutex _mutex;
+};
+
+/*========================================
+ Class Network
+ =======================================*/
+class Network: public TCPStack
+{
+public:
+	Network(bool secure);
+	virtual ~Network();
+
+	bool connect(const char* host, const char* port, const char* caPath, const char* caFile, const char* cert, const char* prvkey);
+	bool connect(const char* host, const char* port);
+	void close(void);
+	int  send(const uint8_t* buf, uint16_t length);
+	int  recv(uint8_t* buf, uint16_t len);
+
+	bool isValid(void);
+	bool isSecure(void);
+	int  getSock(void);
+
+private:
+	static SSL_CTX* _ctx;
+	static SSL_SESSION* _session;
+	static int _numOfInstance;
+	SSL* _ssl;
+	bool _secureFlg;
+	Mutex _mutex;
+	bool _busy;
+	bool _sslValid;
+};
+
+#endif /* NETWORK_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Threading.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Threading.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,538 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include "MQTTSNGWProcess.h"
+#include "Threading.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+#include <semaphore.h>
+#include <fcntl.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+
+using namespace std;
+using namespace MQTTSNGW;
+
+#if defined(OSX)
+int sem_timedwait(sem_type sem, const struct timespec *timeout)
+{
+	int rc = -1;
+	int64_t tout = timeout->tv_sec * 1000L + tv_nsec * 1000000L
+	rc = (int)dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, tout));
+	if (rc != 0)
+	{
+		rc = ETIMEDOUT;
+	}
+ 	return rc;
+}
+#endif
+
+/*=====================================
+ Class Mutex
+ =====================================*/
+
+Mutex::Mutex(void)
+{
+	pthread_mutexattr_t attr;
+	pthread_mutexattr_init(&attr);
+	pthread_mutex_init(&_mutex, &attr);
+	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
+	_shmid = 0;
+	_pmutex = 0;
+}
+
+Mutex::Mutex(const char* fileName)
+{
+	pthread_mutexattr_t attr;
+
+	key_t key = ftok(fileName, 1);
+
+	if ((_shmid = shmget(key, sizeof(pthread_mutex_t), IPC_CREAT | 0666)) < 0)
+	{
+		throw Exception( -1, "Mutex can't create a shared memory.");
+	}
+	_pmutex = (pthread_mutex_t*) shmat(_shmid, NULL, 0);
+	if (_pmutex < 0)
+	{
+		throw Exception( -1, "Mutex can't attach shared memory.");
+	}
+
+	pthread_mutexattr_init(&attr);
+
+	if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED) != 0)
+	{
+		throw Exception( -1, "Mutex can't set the process-shared flag");
+	}
+	if (pthread_mutex_init(_pmutex, &attr) != 0)
+	{
+		throw Exception( -1, "Mutex can't initialize.");
+	}
+}
+
+Mutex::~Mutex(void)
+{
+	if (_pmutex)
+	{
+		pthread_mutex_lock(_pmutex);
+		pthread_mutex_unlock(_pmutex);
+		pthread_mutex_destroy(_pmutex);
+	}
+	else
+	{
+		pthread_mutex_lock(&_mutex);
+		pthread_mutex_unlock(&_mutex);
+		pthread_mutex_destroy(&_mutex);
+	}
+	if (_shmid)
+	{
+		shmctl(_shmid, IPC_RMID, NULL);
+	}
+}
+
+void Mutex::lock(void)
+{
+	if (_pmutex)
+	{
+		pthread_mutex_lock(_pmutex);
+	}
+	else
+	{
+		try
+		{
+			if (pthread_mutex_lock(&_mutex))
+			{
+				throw;
+			}
+		} catch (char* errmsg)
+		{
+			throw Exception( -1, "The same thread can't aquire a mutex twice.");
+		}
+	}
+}
+
+void Mutex::unlock(void)
+{
+
+	if (_pmutex)
+	{
+		pthread_mutex_unlock(_pmutex);
+	}
+	else
+	{
+		try
+		{
+			if (pthread_mutex_unlock(&_mutex))
+			{
+				throw;
+			}
+		} catch (char* errmsg)
+		{
+			throw Exception( -1, "Mutex can't unlock.");
+		}
+	}
+}
+
+/*=====================================
+ Class Semaphore
+ =====================================*/
+
+Semaphore::Semaphore()
+{
+	sem_init(&_sem, 0, 0);
+	_name = 0;
+	_psem = 0;
+}
+
+Semaphore::Semaphore(unsigned int val)
+{
+	sem_init(&_sem, 0, val);
+	_name = 0;
+	_psem = 0;
+}
+
+Semaphore::Semaphore(const char* name, unsigned int val)
+{
+	_psem = sem_open(name, O_CREAT, 0666, val);
+	if (_psem == SEM_FAILED)
+	{
+		throw Exception( -1, "Semaphore can't be created.");
+	}
+	_name = strdup(name);
+	if (_name == NULL)
+	{
+		throw Exception( -1, "Semaphore can't allocate memories.");
+	}
+}
+
+Semaphore::~Semaphore()
+{
+	if (_name)
+	{
+		sem_close(_psem);
+		sem_unlink(_name);
+		free(_name);
+	}
+	else
+	{
+		sem_destroy(&_sem);
+	}
+}
+
+void Semaphore::post(void)
+{
+	int val = 0;
+	if (_psem)
+	{
+		sem_getvalue(_psem, &val);
+		if (val <= 0)
+		{
+			sem_post(_psem);
+		}
+	}
+	else
+	{
+		sem_getvalue(&_sem, &val);
+		if (val <= 0)
+		{
+			sem_post(&_sem);
+		}
+	}
+}
+
+void Semaphore::wait(void)
+{
+	if (_psem)
+	{
+		sem_wait(_psem);
+	}
+	else
+	{
+		sem_wait(&_sem);
+	}
+}
+
+void Semaphore::timedwait(uint16_t millsec)
+{
+	struct timespec ts;
+	clock_gettime(CLOCK_REALTIME, &ts);
+	ts.tv_sec += millsec / 1000;
+	ts.tv_nsec = (millsec % 1000) * 1000000;
+	if (_psem)
+	{
+		sem_timedwait(_psem, &ts);
+	}
+	else
+	{
+		sem_timedwait(&_sem, &ts);
+	}
+}
+
+/*=========================================
+ Class RingBuffer
+ =========================================*/
+RingBuffer::RingBuffer()
+{
+	RingBuffer(MQTTSNGW_KEY_DIRECTORY);
+}
+
+RingBuffer::RingBuffer(const char* keyDirectory)
+{
+	int fp = 0;
+	string fileName = keyDirectory + string(MQTTSNGW_RINGBUFFER_KEY);
+	fp = open(fileName.c_str(), O_CREAT, S_IRGRP);
+	if ( fp > 0 )
+	{
+		close(fp);
+	}
+
+	fileName = keyDirectory + string(MQTTSNGW_RB_MUTEX_KEY);
+	fp = open(fileName.c_str(), O_CREAT, S_IRGRP);
+	if ( fp > 0 )
+	{
+		close(fp);
+	}
+
+	key_t key = ftok(MQTTSNGW_RINGBUFFER_KEY, 1);
+
+	if ((_shmid = shmget(key, PROCESS_LOG_BUFFER_SIZE,
+	IPC_CREAT | IPC_EXCL | 0666)) >= 0)
+	{
+		if ((_shmaddr = (uint16_t*) shmat(_shmid, NULL, 0)) > 0)
+		{
+			_length = (uint16_t*) _shmaddr;
+			_start = (uint16_t*) _length + sizeof(uint16_t*);
+			_end = (uint16_t*) _start + sizeof(uint16_t*);
+			_buffer = (char*) _end + sizeof(uint16_t*);
+			_createFlg = true;
+
+			*_length = PROCESS_LOG_BUFFER_SIZE - sizeof(uint16_t*) * 3 - 16;
+			*_start = *_end = 0;
+		}
+		else
+		{
+			throw Exception(-1, "RingBuffer can't attach shared memory.");
+		}
+	}
+	else if ((_shmid = shmget(key, PROCESS_LOG_BUFFER_SIZE, IPC_CREAT | 0666)) >= 0)
+	{
+		if ((_shmaddr = (uint16_t*) shmat(_shmid, NULL, 0)) > 0)
+		{
+			_length = (uint16_t*) _shmaddr;
+			_start = (uint16_t*) _length + sizeof(uint16_t*);
+			_end = (uint16_t*) _start + sizeof(uint16_t*);
+			_buffer = (char*) _end + sizeof(uint16_t*);
+			_createFlg = false;
+		}
+		else
+		{
+			throw Exception(-1, "RingBuffer can't create a shared memory.");
+		}
+	}
+	else
+	{
+		throw Exception(-1, "RingBuffer can't create a shared memory.");
+	}
+
+	_pmx = new Mutex(MQTTSNGW_RB_MUTEX_KEY);
+}
+
+RingBuffer::~RingBuffer()
+{
+	if (_createFlg)
+	{
+		if (_shmid > 0)
+		{
+			shmctl(_shmid, IPC_RMID, NULL);
+		}
+	}
+	else
+	{
+		if (_shmid > 0)
+		{
+			shmdt(_shmaddr);
+		}
+	}
+
+	if (_pmx > 0)
+	{
+		delete _pmx;
+	}
+}
+
+void RingBuffer::put(char* data)
+{
+	_pmx->lock();
+
+	uint16_t dlen = strlen(data);
+	uint16_t blen = *_length - *_end;
+
+	if (*_end > *_start)
+	{
+		if (dlen < blen)
+		{
+			strncpy(_buffer + *_end, data, dlen);
+			if (*_end - *_start == 1)
+			{ // Buffer is empty.
+				*_start = *_end;
+			}
+			*_end += dlen;
+		}
+		else
+		{
+			strncpy(_buffer + *_end, data, blen);
+			strncpy(_buffer, data + blen, dlen - blen);
+			if (*_end - *_start == 1)
+			{ // Buffer is empty.
+				*_start = *_end;
+				*_end = dlen - blen;
+			}
+			else
+			{
+				*_end = dlen - blen;
+				*_start = *_end + 1;
+			}
+		}
+	}
+	else if (*_end == *_start)
+	{
+		if (dlen < blen)
+		{
+			strncpy(_buffer + *_end, data, dlen);
+			*_end += dlen;
+		}
+		else
+		{
+			const char* errmsg = "RingBuffer Error: data is too long";
+			strcpy(_buffer + *_end, errmsg);
+			*_end += strlen(errmsg);
+		}
+	}
+	else
+	{    // *_end < *_start
+		if (dlen < *_start - *_end)
+		{
+			strncpy(_buffer + *_end, data, dlen);
+			*_end += dlen;
+			*_start = *_end + 1;
+		}
+		else
+		{
+			if (dlen < blen)
+			{
+				strncpy(_buffer + *_end, data, dlen);
+				*_end += dlen;
+				*_start = *_end + 1;
+			}
+			else
+			{
+				strncpy(_buffer + *_end, data, blen);
+				strncpy(_buffer, data + blen, dlen - blen);
+				*_start = *_end;
+				*_end = dlen - blen;
+			}
+		}
+	}
+	_pmx->unlock();
+}
+
+int RingBuffer::get(char* buf, int length)
+{
+	int len = 0;
+	_pmx->lock();
+
+	if (*_end > *_start)
+	{
+		if (length > *_end - *_start)
+		{
+			len = *_end - *_start;
+			if (len == 1)
+			{
+				len = 0;
+			}
+			strncpy(buf, _buffer + *_start, len);
+			*_start = *_end - 1;
+		}
+		else
+		{
+			len = length;
+			strncpy(buf, _buffer + *_start, len);
+			*_start = *_start + len;
+		}
+	}
+	else if (*_end < *_start)
+	{
+		int blen = *_length - *_start;
+		if (length > blen)
+		{
+			strncpy(buf, _buffer + *_start, blen);
+			*_start = 0;
+			if (length - (blen + *_end) > 0)
+			{
+				strncpy(buf + blen, _buffer, *_end);
+				len = blen + *_end;
+				if (*_end > 0)
+				{
+					*_start = *_end - 1;
+				}
+			}
+			else
+			{
+				strncpy(buf + blen, _buffer, length - blen);
+				len = length;
+				*_start = length - blen;
+			}
+		}
+		else
+		{
+			strncpy(buf, _buffer + *_start, length);
+			*_start += length;
+			len = length;
+		}
+	}
+	_pmx->unlock();
+	return len;
+}
+
+void RingBuffer::reset()
+{
+	_pmx->lock();
+	if ( _start && _end )
+	{
+		*_start = *_end = 0;
+	}
+	else
+	{
+		throw Exception(-1, "RingBuffer can't reset. need to clear shared memory.");
+	}
+	_pmx->unlock();
+}
+
+/*=====================================
+ Class Thread
+ =====================================*/
+Thread::Thread()
+{
+	_threadID = 0;
+}
+
+Thread::~Thread()
+{
+}
+
+void* Thread::_run(void* runnable)
+{
+	static_cast<Runnable*>(runnable)->EXECRUN();
+	return 0;
+}
+
+void Thread::initialize(int argc, char** argv)
+{
+
+}
+
+pthread_t Thread::getID()
+{
+	return pthread_self();
+}
+
+bool Thread::equals(pthread_t *t1, pthread_t *t2)
+{
+	return (pthread_equal(*t1, *t2) ? false : true);
+}
+
+int Thread::start(void)
+{
+	Runnable* runnable = this;
+	return pthread_create(&_threadID, 0, _run, runnable);
+}
+
+void Thread::stopProcess(void)
+{
+	theMultiTaskProcess->threadStoped();
+}
+
+void Thread::stop(void)
+{
+	if ( _threadID )
+	{
+		pthread_join(_threadID, NULL);
+		_threadID = 0;
+	}
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Threading.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Threading.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,139 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef THREADING_H_
+#define THREADING_H_
+
+#include <pthread.h>
+#include <semaphore.h>
+#include "MQTTSNGWDefines.h"
+
+namespace MQTTSNGW
+{
+#define MQTTSNGW_KEY_DIRECTORY "./"
+#define MQTTSNGW_RINGBUFFER_KEY   "ringbuffer.key"
+#define MQTTSNGW_RB_MUTEX_KEY     "rbmutex.key"
+#define MQTTSNGW_RB_SEMAPHOR_NAME "/rbsemaphor"
+
+/*=====================================
+         Class Mutex
+  ====================================*/
+class Mutex
+{
+public:
+	Mutex();
+	Mutex(const char* name);
+	~Mutex();
+	void lock(void);
+	void unlock(void);
+
+private:
+	pthread_mutex_t _mutex;
+	pthread_mutex_t* _pmutex;
+	int   _shmid;
+};
+
+/*=====================================
+         Class Semaphore
+  ====================================*/
+class Semaphore
+{
+public:
+	Semaphore();
+	Semaphore(unsigned int val);
+	Semaphore(const char* name, unsigned int val);
+	~Semaphore();
+	void post(void);
+	void wait(void);
+	void timedwait(uint16_t millsec);
+
+private:
+	sem_t* _psem;
+	sem_t  _sem;
+	char*  _name;
+};
+
+/*=====================================
+        Class RingBuffer
+ =====================================*/
+class RingBuffer
+{
+public:
+	RingBuffer();
+	RingBuffer(const char* keyDirctory);
+	~RingBuffer();
+	void put(char* buffer);
+	int get(char* buffer, int bufferLength);
+	void reset();
+private:
+	void* _shmaddr;
+	uint16_t* _length;
+	uint16_t* _start;
+	uint16_t* _end;
+	char* _buffer;
+	int _shmid;
+	Mutex* _pmx;
+	bool _createFlg;
+};
+
+
+/*=====================================
+         Class Runnable
+  ====================================*/
+class Runnable
+{
+public:
+	Runnable(){}
+	virtual ~Runnable(){}
+	virtual void EXECRUN(){}
+};
+
+#define MAGIC_WORD_FOR_THREAD \
+public: void EXECRUN() \
+{ \
+	try \
+	{ \
+		run(); \
+		stopProcess(); \
+	} \
+	catch(...) \
+	{ \
+		throw; \
+	} \
+}
+
+/*=====================================
+         Class Thread
+  ====================================*/
+class Thread : virtual public Runnable{
+public:
+	Thread();
+    ~Thread();
+	int start(void);
+	static pthread_t getID();
+	static bool equals(pthread_t*, pthread_t*);
+	virtual void initialize(int argc, char** argv);
+	void stopProcess(void);
+	void waitStop(void);
+	void stop(void);
+private:
+	static void* _run(void*);
+	pthread_t _threadID;
+};
+
+}
+
+#endif /* THREADING_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Timer.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Timer.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,227 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include "Timer.h"
+#include "MQTTSNGWDefines.h"
+
+using namespace std;
+using namespace MQTTSNGW;
+
+/*=====================================
+ Print Current Date & Time
+ =====================================*/
+char theCurrentTime[32];
+
+const char* currentDateTime()
+{
+	struct timeval now;
+	struct tm tstruct;
+	gettimeofday(&now, 0);
+	tstruct = *localtime(&now.tv_sec);
+	strftime(theCurrentTime, sizeof(theCurrentTime), "%Y%m%d %H%M%S", &tstruct);
+	sprintf(theCurrentTime + 15, ".%03d", (int)now.tv_usec / 1000 );
+	return theCurrentTime;
+}
+
+/*============================================
+ Timer
+ ============================================*/
+Timer::Timer(void)
+{
+	stop();
+}
+
+Timer::~Timer(void)
+{
+
+}
+
+void Timer::start(uint32_t msecs)
+{
+	gettimeofday(&_startTime, 0);
+	_millis = msecs;
+}
+
+bool Timer::isTimeup(void)
+{
+	return isTimeup(_millis);
+}
+
+bool Timer::isTimeup(uint32_t msecs)
+{
+	struct timeval curTime;
+	long secs, usecs;
+	if (_startTime.tv_sec == 0)
+	{
+		return false;
+	}
+	else
+	{
+		gettimeofday(&curTime, 0);
+		secs = (curTime.tv_sec - _startTime.tv_sec) * 1000;
+		usecs = (curTime.tv_usec - _startTime.tv_usec) / 1000.0;
+		return ((secs + usecs) > (long) msecs);
+	}
+}
+
+void Timer::stop()
+{
+	_startTime.tv_sec = 0;
+	_millis = 0;
+}
+
+/*=====================================
+Class LightIndicator
+=====================================*/
+
+LightIndicator::LightIndicator()
+{
+	_greenStatus = false;
+	for ( int i = 0; i <= MAX_GPIO; i++)
+	{
+		_gpio[i] = 0;
+	}
+	init();
+}
+
+LightIndicator::~LightIndicator()
+{
+	for ( int i = 0; i <= MAX_GPIO; i++)
+	{
+		if ( _gpio[i] )
+		{
+			close( _gpio[i]);
+		}
+	}
+}
+
+void LightIndicator::greenLight(bool on)
+{
+	if (on)
+	{
+		if (!_greenStatus)
+		{
+			_greenStatus = true;
+			//Turn Green on & turn Red off
+			lit(LIGHT_INDICATOR_GREEN, "1");
+			lit(LIGHT_INDICATOR_RED, "0");
+		}
+	}
+	else
+	{
+		if (_greenStatus)
+		{
+			_greenStatus = false;
+			//Turn Green off & turn Red on
+			lit(LIGHT_INDICATOR_GREEN, "0");
+			lit(LIGHT_INDICATOR_RED, "1");
+		}
+	}
+}
+void LightIndicator::blueLight(bool on)
+{
+	if (on)
+	{
+		lit(LIGHT_INDICATOR_BLUE, "1");
+		if ( !_greenStatus )
+		{
+			greenLight(true);
+		}
+	}
+	else
+	{
+		lit(LIGHT_INDICATOR_BLUE, "0");
+	}
+}
+
+void LightIndicator::redLight(bool on)
+{
+	if (on)
+	{
+		lit(LIGHT_INDICATOR_RED, "1");
+	}
+	else
+	{
+		lit(LIGHT_INDICATOR_RED, "0");
+	}
+}
+
+void LightIndicator::allLightOff(void)
+{
+	lit(LIGHT_INDICATOR_RED, "0");
+	lit(LIGHT_INDICATOR_BLUE, "0");
+	lit(LIGHT_INDICATOR_GREEN, "0");
+	_greenStatus = false;
+}
+
+void LightIndicator::init()
+{
+	pinMode(LIGHT_INDICATOR_GREEN);
+	pinMode(LIGHT_INDICATOR_RED);
+	pinMode(LIGHT_INDICATOR_BLUE);
+}
+
+int LightIndicator::lit(int gpioNo, const char* onoff)
+{
+	int rc = 0;
+	if( _gpio[gpioNo] )
+	{
+		rc = write(_gpio[gpioNo], onoff, 1);
+	}
+	return rc;
+}
+
+void LightIndicator::pinMode(int gpioNo)
+{
+	int rc = 0;
+	int fd = rc; // eliminate unused warnning of compiler
+
+	fd = open("/sys/class/gpio/export", O_WRONLY);
+	if ( fd < 0 )
+	{
+		return;
+	}
+	char no[4];
+
+	sprintf(no,"%d", gpioNo);
+	rc = write(fd, no, strlen(no));
+	close(fd);
+
+	char fileName[64];
+	sprintf( fileName, "/sys/class/gpio/gpio%d/direction", gpioNo);
+
+	fd = open(fileName, O_WRONLY);
+	if ( fd < 0 )
+	{
+		return;
+	}
+	rc = write(fd,"out", 3);
+	close(fd);
+	sprintf( fileName, "/sys/class/gpio/gpio%d/value", gpioNo);
+	fd = open(fileName, O_WRONLY);
+	if ( fd > 0 )
+	{
+		_gpio[gpioNo] = fd;
+	}
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Timer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/Timer.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,74 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+#ifndef MQTTSNGATEWAY_SRC_LINUX_TIMER_H_
+#define MQTTSNGATEWAY_SRC_LINUX_TIMER_H_
+
+#include <stdint.h>
+#include <sys/time.h>
+#include "MQTTSNGWDefines.h"
+
+namespace MQTTSNGW
+{
+/*==========================================================
+ *           Light Indicators
+ ===========================================================*/
+#define MAX_GPIO                27    // GPIO02 - GPIO27
+#define LIGHT_INDICATOR_GREEN   23    // RPi connector 16
+#define LIGHT_INDICATOR_RED     24    // RPi connector 18
+#define LIGHT_INDICATOR_BLUE    25    // RPi connector 22
+
+/*============================================
+ Timer
+ ============================================*/
+class Timer
+{
+public:
+	Timer(void);
+	~Timer(void);
+	void start(uint32_t msecs = 0);
+	bool isTimeup(void);
+	bool isTimeup(uint32_t msecs);
+	void stop();
+
+private:
+	struct timeval _startTime;
+	uint32_t _millis;
+};
+
+/*=====================================
+ Class LightIndicator
+ =====================================*/
+class LightIndicator
+{
+public:
+	LightIndicator();
+	~LightIndicator();
+	void greenLight(bool on);
+	void blueLight(bool on);
+	void redLight(bool on);
+	void allLightOff(void);
+
+private:
+	void init();
+	int  lit(int gpioNo, const char* onoff);
+	void pinMode(int gpioNo);
+	bool _greenStatus;
+	int _gpio[MAX_GPIO + 1];
+};
+
+}
+
+#endif /* MQTTSNGATEWAY_SRC_LINUX_TIMER_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/udp/SensorNetwork.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,428 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <regex>
+#include <string>
+#include <stdlib.h>
+#include "SensorNetwork.h"
+#include "MQTTSNGWProcess.h"
+
+using namespace std;
+using namespace MQTTSNGW;
+
+/*===========================================
+  Class  SensorNetAddreess
+
+  These 4 methods are minimum requirements for the SensorNetAddress class.
+   isMatch(SensorNetAddress* )
+   operator =(SensorNetAddress& )
+   setAddress(string* )
+   sprint(char* )
+
+  UDPPort class requires these 3 methods.
+   getIpAddress(void)
+   getPortNo(void)
+   setAddress(uint32_t IpAddr, uint16_t port)
+
+ ============================================*/
+SensorNetAddress::SensorNetAddress()
+{
+	_portNo = 0;
+	_IpAddr = 0;
+}
+
+SensorNetAddress::~SensorNetAddress()
+{
+
+}
+
+uint32_t SensorNetAddress::getIpAddress(void)
+{
+	return _IpAddr;
+}
+
+uint16_t SensorNetAddress::getPortNo(void)
+{
+	return _portNo;
+}
+
+void SensorNetAddress::setAddress(uint32_t IpAddr, uint16_t port)
+{
+	_IpAddr = IpAddr;
+	_portNo = port;
+}
+
+/**
+ *  Set Address data to SensorNetAddress
+ *
+ *  @param  *ip_port is "IP_Address:PortNo" format string
+ *  @return success = 0,  Invalid format = -1
+ *
+ *  This function is used in ClientList::authorize(const char* fileName)
+ *  e.g.
+ *  Authorized clients are defined by fileName = "clients.conf"
+ *
+ *  Client02,172.16.1.7:12002
+ *  Client03,172.16.1.8:13003
+ *  Client01,172.16.1.6:12001
+ *
+ *  This definition is necessary when using TLS connection.
+ *  Gateway rejects clients not on the list for security reasons.
+ *
+ */
+int SensorNetAddress::setAddress(string* ip_port)
+{
+	size_t pos = ip_port->find_first_of(":");
+
+	if ( pos == string::npos )
+	{
+		_portNo = 0;
+		_IpAddr = INADDR_NONE;
+		return -1;
+	}
+
+	string ip = ip_port->substr(0, pos);
+	string port = ip_port->substr(pos + 1);
+	int portNo = 0;
+
+	if ((portNo = atoi(port.c_str())) == 0 || (_IpAddr = inet_addr(ip.c_str())) == INADDR_NONE)
+	{
+		return -1;
+	}
+	_portNo = htons(portNo);
+	return 0;
+}
+
+bool SensorNetAddress::isMatch(SensorNetAddress* addr)
+{
+	return ((this->_portNo == addr->_portNo) && (this->_IpAddr == addr->_IpAddr));
+}
+
+SensorNetAddress& SensorNetAddress::operator =(SensorNetAddress& addr)
+{
+	this->_portNo = addr._portNo;
+	this->_IpAddr = addr._IpAddr;
+	return *this;
+}
+
+
+char* SensorNetAddress::sprint(char* buf)
+{
+	struct in_addr  inaddr = { _IpAddr };
+	char* ip = inet_ntoa(inaddr);
+	sprintf( buf, "%s:", ip);
+	sprintf( buf + strlen(buf), "%d", ntohs(_portNo));
+	return buf;
+}
+
+
+/*================================================================
+   Class  SensorNetwork
+
+   In Gateway version 1.0
+
+   getDescpription( )  is used by Gateway::initialize( )
+   initialize( )       is used by ClientSendTask::initialize( )
+   getSenderAddress( ) is used by ClientRecvTask::run( )
+   broadcast( )        is used by MQTTSNPacket::broadcast( )
+   unicast( )          is used by MQTTSNPacket::unicast( )
+   read( )             is used by MQTTSNPacket::recv( )
+
+ ================================================================*/
+
+SensorNetwork::SensorNetwork()
+{
+}
+
+SensorNetwork::~SensorNetwork()
+{
+}
+
+int SensorNetwork::unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendToAddr)
+{
+	return UDPPort::unicast(payload, payloadLength, sendToAddr);
+}
+
+int SensorNetwork::broadcast(const uint8_t* payload, uint16_t payloadLength)
+{
+	return UDPPort::broadcast(payload, payloadLength);
+}
+
+int SensorNetwork::read(uint8_t* buf, uint16_t bufLen)
+{
+	return UDPPort::recv(buf, bufLen, &_clientAddr);
+}
+
+/**
+ *  Prepare UDP sockets and description of SensorNetwork like
+ *   "UDP Multicast 225.1.1.1:1883 Gateway Port 10000".
+ *   The description is for a start up prompt.
+ *  @return success = 0, error = -1
+ */
+int SensorNetwork::initialize(void)
+{
+	char param[MQTTSNGW_PARAM_MAX];
+	uint16_t multicastPortNo = 0;
+	uint16_t unicastPortNo = 0;
+	string ip;
+
+	/*
+	 * theProcess->getParam( ) copies
+	 * a text specified by "Key" into param[] from the Gateway.conf
+	 *
+	 *  in Gateway.conf e.g.
+	 *
+	 *  # UDP
+     *  GatewayPortNo=10000
+     *  MulticastIP=225.1.1.1
+     *  MulticastPortNo=1883
+     *
+	 */
+	if (theProcess->getParam("MulticastIP", param) == 0)
+	{
+		ip = param;
+		_description = "UDP Multicast ";
+		_description += param;
+	}
+	if (theProcess->getParam("MulticastPortNo", param) == 0)
+	{
+		multicastPortNo = atoi(param);
+		_description += ":";
+		_description += param;
+	}
+	if (theProcess->getParam("GatewayPortNo", param) == 0)
+	{
+		unicastPortNo = atoi(param);
+		_description += " Gateway Port ";
+		_description += param;
+	}
+
+	/*  Prepare UDP sockets */
+	return UDPPort::open(ip.c_str(), multicastPortNo, unicastPortNo);
+}
+
+const char* SensorNetwork::getDescription(void)
+{
+	return _description.c_str();
+}
+
+SensorNetAddress* SensorNetwork::getSenderAddress(void)
+{
+	return &_clientAddr;
+}
+
+/*=========================================
+ Class udpStack
+ =========================================*/
+
+UDPPort::UDPPort()
+{
+	_disconReq = false;
+	_sockfdUnicast = -1;
+	_sockfdMulticast = -1;
+}
+
+UDPPort::~UDPPort()
+{
+	close();
+}
+
+void UDPPort::close(void)
+{
+	if (_sockfdUnicast > 0)
+	{
+		::close(_sockfdUnicast);
+		_sockfdUnicast = -1;
+	}
+	if (_sockfdMulticast > 0)
+	{
+		::close(_sockfdMulticast);
+		_sockfdMulticast = -1;
+	}
+}
+
+int UDPPort::open(const char* ipAddress, uint16_t multiPortNo, uint16_t uniPortNo)
+{
+	char loopch = 0;
+	const int reuse = 1;
+
+	if (uniPortNo == 0 || multiPortNo == 0)
+	{
+		D_NWSTACK("error portNo undefined in UDPPort::open\n");
+		return -1;
+	}
+
+	uint32_t ip = inet_addr(ipAddress);
+	_grpAddr.setAddress(ip, htons(multiPortNo));
+	_clientAddr.setAddress(ip, htons(uniPortNo));
+
+	/*------ Create unicast socket --------*/
+	_sockfdUnicast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (_sockfdUnicast < 0)
+	{
+		D_NWSTACK("error can't create unicast socket in UDPPort::open\n");
+		return -1;
+	}
+
+	setsockopt(_sockfdUnicast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
+
+	sockaddr_in addru;
+	addru.sin_family = AF_INET;
+	addru.sin_port = htons(uniPortNo);
+	addru.sin_addr.s_addr = INADDR_ANY;
+
+	if (::bind(_sockfdUnicast, (sockaddr*) &addru, sizeof(addru)) < 0)
+	{
+		D_NWSTACK("error can't bind unicast socket in UDPPort::open\n");
+		return -1;
+	}
+	if (setsockopt(_sockfdUnicast, IPPROTO_IP, IP_MULTICAST_LOOP, (char*) &loopch, sizeof(loopch)) < 0)
+	{
+		D_NWSTACK("error IP_MULTICAST_LOOP in UDPPort::open\n");
+		close();
+		return -1;
+	}
+
+	/*------ Create Multicast socket --------*/
+	_sockfdMulticast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (_sockfdMulticast < 0)
+	{
+		D_NWSTACK("error can't create multicast socket in UDPPort::open\n");
+		close();
+		return -1;
+	}
+
+	setsockopt(_sockfdMulticast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
+
+	sockaddr_in addrm;
+	addrm.sin_family = AF_INET;
+	addrm.sin_port = _grpAddr.getPortNo();
+	addrm.sin_addr.s_addr = INADDR_ANY;
+
+	if (::bind(_sockfdMulticast, (sockaddr*) &addrm, sizeof(addrm)) < 0)
+	{
+		D_NWSTACK("error can't bind multicast socket in UDPPort::open\n");
+		return -1;
+	}
+	if (setsockopt(_sockfdMulticast, IPPROTO_IP, IP_MULTICAST_LOOP, (char*) &loopch, sizeof(loopch)) < 0)
+	{
+		D_NWSTACK("error IP_MULTICAST_LOOP in UDPPort::open\n");
+		close();
+		return -1;
+	}
+
+	ip_mreq mreq;
+	mreq.imr_interface.s_addr = INADDR_ANY;
+	mreq.imr_multiaddr.s_addr = _grpAddr.getIpAddress();
+
+	if (setsockopt(_sockfdMulticast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
+	{
+		D_NWSTACK("error Multicast IP_ADD_MEMBERSHIP in UDPPort::open\n");
+		close();
+		return -1;
+	}
+
+	if (setsockopt(_sockfdUnicast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
+	{
+		D_NWSTACK("error Unicast IP_ADD_MEMBERSHIP in UDPPort::open\n");
+		close();
+		return -1;
+	}
+	return 0;
+}
+
+int UDPPort::unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* addr)
+{
+	sockaddr_in dest;
+	dest.sin_family = AF_INET;
+	dest.sin_port = addr->getPortNo();
+	dest.sin_addr.s_addr = addr->getIpAddress();
+
+	int status = ::sendto(_sockfdUnicast, buf, length, 0, (const sockaddr*) &dest, sizeof(dest));
+	if (status < 0)
+	{
+		D_NWSTACK("errno == %d in UDPPort::sendto\n", errno);
+	}
+	D_NWSTACK("sendto %s:%u length = %d\n", inet_ntoa(dest.sin_addr), ntohs(dest.sin_port), status);
+	return status;
+}
+
+int UDPPort::broadcast(const uint8_t* buf, uint32_t length)
+{
+	return unicast(buf, length, &_grpAddr);
+}
+
+int UDPPort::recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr)
+{
+	struct timeval timeout;
+	fd_set recvfds;
+	int maxSock = 0;
+
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 1000000;    // 1 sec
+	FD_ZERO(&recvfds);
+	FD_SET(_sockfdUnicast, &recvfds);
+	FD_SET(_sockfdMulticast, &recvfds);
+
+	if (_sockfdMulticast > _sockfdUnicast)
+	{
+		maxSock = _sockfdMulticast;
+	}
+	else
+	{
+		maxSock = _sockfdUnicast;
+	}
+
+	int rc = 0;
+	if ( select(maxSock + 1, &recvfds, 0, 0, &timeout) > 0 )
+	{
+		if (FD_ISSET(_sockfdUnicast, &recvfds))
+		{
+			rc = recvfrom(_sockfdUnicast, buf, len, 0, addr);
+		}
+		else if (FD_ISSET(_sockfdMulticast, &recvfds))
+		{
+			rc = recvfrom(_sockfdMulticast, buf, len, 0, &_grpAddr);
+		}
+	}
+	return rc;
+}
+
+int UDPPort::recvfrom(int sockfd, uint8_t* buf, uint16_t len, uint8_t flags, SensorNetAddress* addr)
+{
+	sockaddr_in sender;
+	socklen_t addrlen = sizeof(sender);
+	memset(&sender, 0, addrlen);
+
+	int status = ::recvfrom(sockfd, buf, len, flags, (sockaddr*) &sender, &addrlen);
+
+	if (status < 0 && errno != EAGAIN)
+	{
+		D_NWSTACK("errno == %d in UDPPort::recvfrom\n", errno);
+		return -1;
+	}
+	addr->setAddress(sender.sin_addr.s_addr, sender.sin_port);
+	D_NWSTACK("recved from %s:%d length = %d\n", inet_ntoa(sender.sin_addr),ntohs(sender.sin_port), status);
+	return status;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/udp/SensorNetwork.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/udp/SensorNetwork.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,104 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef SENSORNETWORK_H_
+#define SENSORNETWORK_H_
+
+#include "MQTTSNGWDefines.h"
+#include <string>
+
+using namespace std;
+
+namespace MQTTSNGW
+{
+
+#ifdef  DEBUG_NWSTACK
+  #define D_NWSTACK(...) printf(__VA_ARGS__)
+#else
+  #define D_NWSTACK(...)
+#endif
+
+/*===========================================
+ Class  SensorNetAddreess
+ ============================================*/
+class SensorNetAddress
+{
+public:
+	SensorNetAddress();
+	~SensorNetAddress();
+	void setAddress(uint32_t IpAddr, uint16_t port);
+	int  setAddress(string* data);
+	uint16_t getPortNo(void);
+	uint32_t getIpAddress(void);
+	bool isMatch(SensorNetAddress* addr);
+	SensorNetAddress& operator =(SensorNetAddress& addr);
+	char* sprint(char* buf);
+private:
+	uint16_t _portNo;
+	uint32_t _IpAddr;
+};
+
+/*========================================
+ Class UpdPort
+ =======================================*/
+class UDPPort
+{
+public:
+	UDPPort();
+	virtual ~UDPPort();
+
+	int open(const char* ipAddress, uint16_t multiPortNo,	uint16_t uniPortNo);
+	void close(void);
+	int unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* sendToAddr);
+	int broadcast(const uint8_t* buf, uint32_t length);
+	int recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr);
+
+private:
+	void setNonBlocking(const bool);
+	int recvfrom(int sockfd, uint8_t* buf, uint16_t len, uint8_t flags,	SensorNetAddress* addr);
+
+	int _sockfdUnicast;
+	int _sockfdMulticast;
+
+	SensorNetAddress _grpAddr;
+	SensorNetAddress _clientAddr;
+	bool _disconReq;
+
+};
+
+/*===========================================
+ Class  SensorNetwork
+ ============================================*/
+class SensorNetwork: public UDPPort
+{
+public:
+	SensorNetwork();
+	~SensorNetwork();
+
+	int unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendto);
+	int broadcast(const uint8_t* payload, uint16_t payloadLength);
+	int read(uint8_t* buf, uint16_t bufLen);
+	int initialize(void);
+	const char* getDescription(void);
+	SensorNetAddress* getSenderAddress(void);
+
+private:
+	SensorNetAddress _clientAddr;   // Sender's address. not gateway's one.
+	string _description;
+};
+
+}
+#endif /* SENSORNETWORK_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/udp6/SensorNetwork.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,457 @@
+/**************************************************************************************
+ * Copyright (c) 2017, Benjamin Aigner
+ * Copyright (c) 2016, Tomoaki Yamaguchi (original UDPv4 implementation)
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Benjamin Aigner - Adaption of the UDPv4 code to use UDPv6
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ *    Tieto Poland Sp. z o.o. - improve portability
+ **************************************************************************************/
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/ip.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <iostream>
+#include <regex>
+#include <string>
+#include <stdlib.h>
+#include "SensorNetwork.h"
+#include "MQTTSNGWProcess.h"
+
+//using namespace std;
+using namespace MQTTSNGW;
+
+/*===========================================
+ Class  SensorNetAddreess
+ ============================================*/
+SensorNetAddress::SensorNetAddress()
+{
+	_portNo = 0;
+	memset((void *)&_IpAddr,0,sizeof(_IpAddr));
+}
+
+SensorNetAddress::~SensorNetAddress()
+{
+}
+
+struct sockaddr_in6 *SensorNetAddress::getIpAddress(void)
+{
+	return &_IpAddr;
+}
+
+uint16_t SensorNetAddress::getPortNo(void)
+{
+	return _portNo;
+}
+
+void SensorNetAddress::setAddress(struct sockaddr_in6 *IpAddr, uint16_t port)
+{
+	memcpy((void *)&_IpAddr,IpAddr,sizeof(_IpAddr));
+	_portNo = port;
+}
+
+/**
+ *  convert Text data to SensorNetAddress
+ *  @param  buf is pointer of IP_Address:PortNo format text
+ *  @return success = 0,  Invalid format = -1
+ */
+int SensorNetAddress::setAddress(string* data)
+{
+	const char *cstr = data->c_str();
+	inet_pton(AF_INET6, cstr, &(_IpAddr.sin6_addr));
+	return 0;
+}
+/**
+ *  convert Text data to SensorNetAddress
+ *  @param  buf is pointer of IP_Address:PortNo format text
+ *  @return success = 0,  Invalid format = -1
+ */
+int SensorNetAddress::setAddress(const char* data)
+{
+	inet_pton(AF_INET6, data, &(_IpAddr.sin6_addr));
+	return 0;
+}
+
+char* SensorNetAddress::getAddress(void)
+{
+	inet_ntop(AF_INET6, &(_IpAddr.sin6_addr), _addrString, INET6_ADDRSTRLEN);
+	return _addrString;
+}
+
+bool SensorNetAddress::isMatch(SensorNetAddress* addr)
+{
+	return ((this->_portNo == addr->_portNo) && \
+	(this->_IpAddr.sin6_addr.s6_addr32[0] == addr->_IpAddr.sin6_addr.s6_addr32[0]) && \
+	(this->_IpAddr.sin6_addr.s6_addr32[1] == addr->_IpAddr.sin6_addr.s6_addr32[1]) && \
+	(this->_IpAddr.sin6_addr.s6_addr32[2] == addr->_IpAddr.sin6_addr.s6_addr32[2]) && \
+	(this->_IpAddr.sin6_addr.s6_addr32[3] == addr->_IpAddr.sin6_addr.s6_addr32[3]));
+}
+
+SensorNetAddress& SensorNetAddress::operator =(SensorNetAddress& addr)
+{
+	this->_portNo = addr._portNo;
+	memcpy(&this->_IpAddr.sin6_addr, &addr._IpAddr.sin6_addr, sizeof(this->_IpAddr.sin6_addr));
+	return *this;
+}
+
+
+char* SensorNetAddress::sprint(char* buf)
+{
+	char ip[INET6_ADDRSTRLEN];
+	inet_ntop(AF_INET6, &(_IpAddr.sin6_addr), ip, INET6_ADDRSTRLEN);
+	sprintf( buf, "%s:", ip);
+	sprintf( buf + strlen(buf), "%d", ntohs(_portNo));
+	return buf;
+}
+
+/*===========================================
+ Class  SensorNetwork
+ ============================================*/
+SensorNetwork::SensorNetwork()
+{
+}
+
+SensorNetwork::~SensorNetwork()
+{
+}
+
+int SensorNetwork::unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendToAddr)
+{
+	return UDPPort6::unicast(payload, payloadLength, sendToAddr);
+}
+
+int SensorNetwork::broadcast(const uint8_t* payload, uint16_t payloadLength)
+{
+	return UDPPort6::broadcast(payload, payloadLength);
+}
+
+int SensorNetwork::read(uint8_t* buf, uint16_t bufLen)
+{
+	return UDPPort6::recv(buf, bufLen, &_clientAddr);
+}
+
+int SensorNetwork::initialize(void)
+{
+	char param[MQTTSNGW_PARAM_MAX];
+	uint16_t unicastPortNo = 0;
+	string ip;
+	string broadcast;
+	string interface;
+
+	if (theProcess->getParam("GatewayUDP6Bind", param) == 0)
+	{
+		ip = param;
+		_description = "GatewayUDP6Bind: ";
+		_description += param;
+	}
+	if (theProcess->getParam("GatewayUDP6Port", param) == 0)
+	{
+		unicastPortNo = atoi(param);
+		_description += " Gateway Port: ";
+		_description += param;
+	}
+	if (theProcess->getParam("GatewayUDP6Broadcast", param) == 0)
+	{
+		broadcast = param;
+		_description += " Broadcast Address: ";
+		_description += param;
+	}
+	if (theProcess->getParam("GatewayUDP6If", param) == 0)
+	{
+		interface = param;
+		_description += " Interface: ";
+		_description += param;
+	}
+
+	return UDPPort6::open(ip.c_str(), unicastPortNo, broadcast.c_str(), interface.c_str());
+}
+
+const char* SensorNetwork::getDescription(void)
+{
+	return _description.c_str();
+}
+
+SensorNetAddress* SensorNetwork::getSenderAddress(void)
+{
+	return &_clientAddr;
+}
+
+/*=========================================
+ Class udpStack
+ =========================================*/
+
+UDPPort6::UDPPort6()
+{
+	_disconReq = false;
+	_sockfdUnicast = -1;
+	_sockfdMulticast = -1;
+}
+
+UDPPort6::~UDPPort6()
+{
+	close();
+}
+
+void UDPPort6::close(void)
+{
+	if (_sockfdUnicast > 0)
+	{
+		::close(_sockfdUnicast);
+		_sockfdUnicast = -1;
+	}
+	if (_sockfdMulticast > 0)
+	{
+		::close(_sockfdMulticast);
+		_sockfdMulticast = -1;
+	}
+}
+
+int UDPPort6::open(const char* ipAddress, uint16_t uniPortNo, const char* broadcastAddr, const char* interfaceName)
+{
+	struct addrinfo hints, *res;
+	int errnu;
+	const int reuse = 1;
+
+	if (uniPortNo == 0)
+	{
+		WRITELOG("error portNo undefined in UDPPort::open\n");
+		return -1;
+	}
+
+
+	memset(&hints, 0, sizeof hints);
+	hints.ai_family = AF_INET6;  // use IPv6
+	hints.ai_socktype = SOCK_DGRAM;
+	hints.ai_flags = AI_PASSIVE; //use local IF address
+
+	getaddrinfo(NULL, std::to_string(uniPortNo).c_str(), &hints, &res);
+
+	_sockfdMulticast = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+	if(_sockfdMulticast <0)
+	{
+		WRITELOG("UDP6::open - multicast: %s",strerror(_sockfdMulticast));
+		return errno;
+	}
+
+	//select the interface
+	unsigned int ifindex;
+	ifindex = if_nametoindex(interfaceName);
+	errnu = setsockopt(_sockfdMulticast, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex,sizeof(ifindex));
+	if(errnu <0)
+	{
+		WRITELOG("UDP6::open - limit IF: %s",strerror(errnu));
+		return errnu;
+	}
+
+	strcpy(_interfaceName,interfaceName);
+
+	//restrict the socket to IPv6 only
+	int on = 1;
+	errnu = setsockopt(_sockfdMulticast, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on));
+	if(errnu <0)
+	{
+		WRITELOG("UDP6::open - limit IPv6: %s",strerror(errnu));
+		return errnu;
+	}
+
+	_uniPortNo = uniPortNo;
+	freeaddrinfo(res);
+
+	//init the structs for getaddrinfo
+	//according to: https://beej.us/guide/bgnet/output/html/multipage/
+	memset(&hints, 0, sizeof hints);
+	hints.ai_family = AF_INET6;  // use IPv6, whichever
+	hints.ai_socktype = SOCK_DGRAM;
+	hints.ai_flags = AI_PASSIVE;     // fill in my IP for me
+
+	//no specific address, bind to available ones...
+	getaddrinfo(NULL, std::to_string(uniPortNo).c_str(), &hints, &res);
+
+	//create the socket
+	_sockfdUnicast = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+	if (_sockfdUnicast < 0)
+	{
+		WRITELOG("UDP6::open - unicast socket: %s",strerror(_sockfdUnicast));
+		return -1;
+	}
+
+	//if given, set a given device name to bind to
+	if(strlen(interfaceName) > 0)
+	{
+		//socket option: bind to a given interface name
+		setsockopt(_sockfdUnicast, SOL_SOCKET, SO_BINDTODEVICE, interfaceName, strlen(interfaceName));
+	}
+
+	//socket option: reuse address
+	setsockopt(_sockfdUnicast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
+
+	//finally: bind...
+	errnu = ::bind(_sockfdUnicast, res->ai_addr, res->ai_addrlen);
+	if (errnu  < 0)
+	{
+		WRITELOG("error can't bind unicast socket in UDPPort::open: %s\n",strerror(errnu));
+		return -1;
+	}
+
+	//if given, set a broadcast address; otherwise it will be ::
+	if(strlen(broadcastAddr) > 0)
+	{
+		_grpAddr.setAddress(broadcastAddr);
+	} else {
+		_grpAddr.setAddress("::");
+	}
+	//everything went fine...
+	freeaddrinfo(res);
+	return 0;
+}
+
+//TODO: test if unicast is working too....
+int UDPPort6::unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* addr)
+{
+	char destStr[INET6_ADDRSTRLEN+10];
+	struct addrinfo hints, *res;
+	memset(&hints, 0, sizeof hints);
+	hints.ai_family = AF_INET6;  // use IPv6
+	hints.ai_socktype = SOCK_DGRAM;
+
+	int port = 0;
+	string portStr;
+	if(addr->getPortNo() != 0)
+	{
+		port = htons(addr->getPortNo());
+		portStr = to_string(port);
+	} else {
+		port = _uniPortNo;
+		portStr = to_string(port);
+	}
+
+	if(strlen(_interfaceName) != 0)
+	{
+		strcpy(destStr, addr->getAddress());
+		strcat(destStr,"%");
+		strcat(destStr,_interfaceName);
+		if(IN6_IS_ADDR_LINKLOCAL(addr->getAddress()))
+		{
+			getaddrinfo(destStr, portStr.c_str(), &hints, &res);
+		}
+		else
+		{
+			getaddrinfo(addr->getAddress(), portStr.c_str(), &hints, &res);
+		}
+	} else {
+		strcpy(destStr, addr->getAddress());
+		getaddrinfo(addr->getAddress(), portStr.c_str(), &hints, &res);
+	}
+
+	int status = ::sendto(_sockfdUnicast, buf, length, 0, res->ai_addr, res->ai_addrlen);
+
+	if (status < 0)
+	{
+		WRITELOG("errno in UDPPort::unicast(sendto): %d, %s\n",status,strerror(status));
+	}
+
+	WRITELOG("unicast sendto %s, port: %d length = %d\n", destStr,port,status);
+
+	return status;
+}
+
+int UDPPort6::broadcast(const uint8_t* buf, uint32_t length)
+{
+	struct addrinfo hint,*info;
+	int err;
+	memset( &hint, 0, sizeof( hint ) );
+
+	hint.ai_family = AF_INET6;
+	hint.ai_socktype = SOCK_DGRAM;
+	hint.ai_protocol = 0;
+
+
+
+	if(strlen(_interfaceName) != 0)
+	{
+		char destStr[80];
+		strcpy(destStr, _grpAddr.getAddress());
+		strcat(destStr,"%");
+		strcat(destStr,_interfaceName);
+		if(IN6_IS_ADDR_MC_NODELOCAL(_grpAddr.getAddress()) ||
+		   IN6_IS_ADDR_MC_LINKLOCAL(_grpAddr.getAddress()))
+		{
+			err = getaddrinfo(destStr, std::to_string(_uniPortNo).c_str(), &hint, &info );
+		}
+		else
+		{
+			err = getaddrinfo(_grpAddr.getAddress(), std::to_string(_uniPortNo).c_str(), &hint, &info );
+		}
+	} else {
+		err = getaddrinfo(_grpAddr.getAddress(), std::to_string(_uniPortNo).c_str(), &hint, &info );
+	}
+
+	if( err != 0 ) {
+	    WRITELOG("UDP6::broadcast - getaddrinfo: %s",strerror(err));
+	    return err;
+	}
+
+	err = sendto(_sockfdMulticast, buf, length, 0, info->ai_addr, info->ai_addrlen );
+
+	if(err < 0 ) {
+	    WRITELOG("UDP6::broadcast - sendto: %s",strerror(err));
+	    return errno;
+	}
+
+	return 0;
+}
+
+//TODO: test if this is working properly (GW works, but this function is not completely tested)
+int UDPPort6::recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr)
+{
+	struct timeval timeout;
+	fd_set recvfds;
+
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 1000000;    // 1 sec
+	FD_ZERO(&recvfds);
+	FD_SET(_sockfdUnicast, &recvfds);
+
+	int rc = 0;
+	if ( select(_sockfdUnicast + 1, &recvfds, 0, 0, &timeout) > 0 )
+	{
+		if (FD_ISSET(_sockfdUnicast, &recvfds))
+		{
+			rc = recvfrom(_sockfdUnicast, buf, len, 0, addr);
+		}
+	}
+	return rc;
+}
+
+//TODO: test if this is working properly (GW works, but this function is not completely tested)
+int UDPPort6::recvfrom(int sockfd, uint8_t* buf, uint16_t len, uint8_t flags, SensorNetAddress* addr)
+{
+	sockaddr_in6 sender;
+	socklen_t addrlen = sizeof(sender);
+	memset(&sender, 0, addrlen);
+
+	int status = ::recvfrom(sockfd, buf, len, flags, (sockaddr*) &sender, &addrlen);
+
+	if (status < 0 && errno != EAGAIN)
+	{
+		WRITELOG("errno == %d in UDPPort::recvfrom: %s\n",errno,strerror(errno));
+		return -1;
+	}
+	addr->setAddress(&sender, (uint16_t)sender.sin6_port);
+	//D_NWSTACK("recved from %s:%d length = %d\n", inet_ntoa(sender.sin_addr),ntohs(sender.sin_port), status);
+	return status;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/udp6/SensorNetwork.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/udp6/SensorNetwork.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,112 @@
+/**************************************************************************************
+ * Copyright (c) 2017, Benjamin Aigner
+ * based on UDP implementation (Copyright (c) 2016 Tomoaki Yamaguchi)
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * 	  Benjamin Aigner - port to UDPv6, used by RFC7668 (6lowpan over Bluetooth LE)
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#ifndef SENSORNETWORK_H_
+#define SENSORNETWORK_H_
+
+#include "MQTTSNGWDefines.h"
+#include <arpa/inet.h>
+#include <string>
+
+using namespace std;
+
+namespace MQTTSNGW
+{
+
+#ifdef  DEBUG_NWSTACK
+  #define D_NWSTACK(...) printf(__VA_ARGS__)
+#else
+  #define D_NWSTACK(...)
+#endif
+
+/*===========================================
+ Class  SensorNetAddreess
+ ============================================*/
+class SensorNetAddress
+{
+public:
+	SensorNetAddress();
+	~SensorNetAddress();
+	void setAddress(struct sockaddr_in6 *IpAddr, uint16_t port);
+	int  setAddress(string* data);
+	int  setAddress(const char* data);
+	uint16_t getPortNo(void);
+	struct sockaddr_in6 *getIpAddress(void);
+	char* getAddress(void);
+	bool isMatch(SensorNetAddress* addr);
+	SensorNetAddress& operator =(SensorNetAddress& addr);
+	char* sprint(char* buf);
+private:
+	uint16_t _portNo;
+	char _addrString[INET6_ADDRSTRLEN+1];
+	struct sockaddr_in6 _IpAddr;
+};
+
+/*========================================
+ Class UpdPort
+ =======================================*/
+class UDPPort6
+{
+public:
+	UDPPort6();
+	virtual ~UDPPort6();
+
+	int open(const char* ipAddress, uint16_t uniPortNo, const char* broadcastAddr, const char* interfaceName);
+	void close(void);
+	int unicast(const uint8_t* buf, uint32_t length, SensorNetAddress* sendToAddr);
+	int broadcast(const uint8_t* buf, uint32_t length);
+	int recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr);
+
+private:
+	void setNonBlocking(const bool);
+	int recvfrom(int sockfd, uint8_t* buf, uint16_t len, uint8_t flags,	SensorNetAddress* addr);
+
+	int _sockfdUnicast;
+	int _sockfdMulticast;
+	char _interfaceName[10];
+
+	SensorNetAddress _grpAddr;
+	SensorNetAddress _clientAddr;
+	uint16_t _uniPortNo;
+	bool _disconReq;
+
+};
+
+/*===========================================
+ Class  SensorNetwork
+ ============================================*/
+class SensorNetwork: public UDPPort6
+{
+public:
+	SensorNetwork();
+	~SensorNetwork();
+
+	int unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendto);
+	int broadcast(const uint8_t* payload, uint16_t payloadLength);
+	int read(uint8_t* buf, uint16_t bufLen);
+	int initialize(void);
+	const char* getDescription(void);
+	SensorNetAddress* getSenderAddress(void);
+
+private:
+	SensorNetAddress _clientAddr;   // Sender's address. not gateway's one.
+	string _description;
+};
+
+}
+#endif /* SENSORNETWORK6_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/xbee/SensorNetwork.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,482 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include "SensorNetwork.h"
+#include "MQTTSNGWProcess.h"
+
+using namespace std;
+using namespace MQTTSNGW;
+
+/*===========================================
+ Class  SensorNetAddreess
+ ============================================*/
+SensorNetAddress::SensorNetAddress()
+{
+	memset(_address64, 0, 8);
+	memset(_address16, 0, 2);
+}
+
+SensorNetAddress::~SensorNetAddress()
+{
+
+}
+
+void SensorNetAddress::setAddress(uint8_t* address64, uint8_t* address16)
+{
+	memcpy(_address64, address64, 8);
+	memcpy(_address16, address16, 2);
+}
+
+
+int SensorNetAddress::setAddress(string* address64)
+{
+	memcpy(_address64, address64->c_str(), 8);
+	memset(_address16, 0, sizeof(_address16));
+	return 0;
+}
+
+void SensorNetAddress::setBroadcastAddress(void)
+{
+	memset(_address64, 0, 6);
+	_address64[6] = 0xff;
+	_address64[7] = 0xff;
+	_address16[0] = 0xff;
+	_address16[1] = 0xfe;
+}
+
+bool SensorNetAddress::isMatch(SensorNetAddress* addr)
+{
+
+	return (memcmp(this->_address64, addr->_address64, 8 ) == 0 &&  memcmp(this->_address16, addr->_address16, 2) == 0);
+}
+
+SensorNetAddress& SensorNetAddress::operator =(SensorNetAddress& addr)
+{
+	memcpy(_address64, addr._address64, 8);
+	memcpy(_address16, addr._address16, 2);
+	return *this;
+}
+
+char* SensorNetAddress::sprint(char* buf)
+{
+	char* pbuf = buf;
+	for ( int i = 0; i < 8; i++ )
+	{
+		sprintf(pbuf, "%02X", _address64[i]);
+		pbuf += 2;
+	}
+	return buf;
+}
+
+/*===========================================
+ Class  SensorNetwork
+ ============================================*/
+SensorNetwork::SensorNetwork()
+{
+
+}
+
+SensorNetwork::~SensorNetwork()
+{
+
+}
+
+int SensorNetwork::unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendToAddr)
+{
+	return XBee::unicast(payload, payloadLength, sendToAddr);
+}
+
+int SensorNetwork::broadcast(const uint8_t* payload, uint16_t payloadLength)
+{
+	return XBee::broadcast(payload, payloadLength);
+}
+
+int SensorNetwork::read(uint8_t* buf, uint16_t bufLen)
+{
+	return XBee::recv(buf, bufLen, &_clientAddr);
+}
+
+int SensorNetwork::initialize(void)
+{
+	char param[MQTTSNGW_PARAM_MAX];
+	uint32_t baudrate = 9600;
+	uint8_t apimode = 2;
+
+	if (theProcess->getParam("ApiMode", param) == 0)
+	{
+		apimode = (uint8_t)atoi(param);
+	}
+	setApiMode(apimode);
+	_description = "API mode ";
+	sprintf(param, "%d", apimode);
+	_description += param;
+
+	if (theProcess->getParam("Baudrate", param) == 0)
+	{
+		baudrate = (uint32_t)atoi(param);
+	}
+	_description += ", Baudrate ";
+	sprintf(param ,"%d", baudrate);
+	_description += param;
+
+	theProcess->getParam("SerialDevice", param);
+	_description += ", SerialDevice ";
+	_description += param;
+
+	return XBee::open(param, baudrate);
+}
+
+const char* SensorNetwork::getDescription(void)
+{
+	return _description.c_str();
+}
+
+SensorNetAddress* SensorNetwork::getSenderAddress(void)
+{
+	return &_clientAddr;
+}
+
+/*===========================================
+              Class  XBee
+ ============================================*/
+XBee::XBee(){
+    _serialPort = new SerialPort();
+    _respCd = 0;
+    _respId = 0;
+    _dataLen = 0;
+    _frameId = 0;
+    _apiMode = 2;
+}
+
+XBee::~XBee(){
+	if ( _serialPort )
+	{
+		delete _serialPort;
+	}
+}
+
+int XBee::open(char* device, int baudrate)
+{
+	int rate = B9600;
+
+	switch (baudrate)
+	{
+	case 9600:
+		rate = B9600;
+		break;
+	case 19200:
+		rate = B19200;
+		break;
+	case 38400:
+		rate = B38400;
+		break;
+	case 57600:
+		rate = B57600;
+		break;
+	case 115200:
+		rate = B115200;
+		break;
+	default:
+		return -1;
+	}
+
+	return _serialPort->open(device, rate, false, 1, O_RDWR | O_NOCTTY);
+}
+
+int XBee::broadcast(const uint8_t* payload, uint16_t payloadLen){
+	SensorNetAddress addr;
+	addr.setBroadcastAddress();
+	return send(payload, (uint8_t) payloadLen, &addr);
+}
+
+int XBee:: unicast(const uint8_t* payload, uint16_t payloadLen, SensorNetAddress* addr){
+	return send(payload, (uint8_t) payloadLen, addr);
+}
+
+int XBee::recv(uint8_t* buf, uint16_t bufLen, SensorNetAddress* clientAddr)
+{
+	uint8_t data[128];
+	int len;
+
+	while ( true )
+	{
+
+		if ( (len = readApiFrame(data)) > 0 )
+		{
+
+			if ( data[0] == API_RESPONSE )
+			{
+				memcpy(clientAddr->_address64, data + 1, 8);
+				memcpy(clientAddr->_address16, data + 9, 2);
+				len -= 12;
+				memcpy( buf, data + 12, len);
+				return len;
+			}
+			else if ( data[0] == API_XMITSTATUS )
+			{
+				_respCd = data[5];
+				_respId = data[1];
+				_sem.post();
+			}
+		}
+		else
+		{
+		    return 0;
+		}
+	}
+}
+
+int XBee::readApiFrame(uint8_t* recvData){
+	uint8_t buf;
+	uint8_t pos = 0;
+	uint8_t checksum = 0;
+	uint8_t len = 0;
+
+	 while ( _serialPort->recv(&buf) )
+	 {
+		 if ( buf == START_BYTE)
+		 {
+			pos = 1;
+			 D_NWSTACK("\r\n===> Recv:    ");
+			 break;
+		 }
+	 }
+
+	if ( pos == 0 )
+	{
+		goto errexit;
+	}
+
+    if ( recv(&buf) < 0 ) // MSB length
+    {
+    	goto errexit;
+    }
+
+    if ( recv(&buf) < 0 ) // LSB length
+	{
+    	goto errexit;
+	}
+	else
+	{
+		len = buf;
+	}
+
+    pos = 0;
+    while ( len-- )
+    {
+    	if ( recv(&buf) < 0 )
+    	{
+    		goto errexit;
+    	}
+    	recvData[pos++] = buf;
+    	checksum += buf;
+    }
+
+    recv(&buf);        // checksum
+    if ( (0xff - checksum ) == buf ){
+    	D_NWSTACK("    checksum ok\r\n");
+    	return pos;
+    }
+    else
+    {
+    	D_NWSTACK("    checksum error  %02x\r\n", 0xff - checksum);
+    	goto errexit;
+    }
+errexit:
+	_serialPort->flush();
+	return -1;
+}
+
+int XBee::send(const uint8_t* payload, uint8_t pLen, SensorNetAddress* addr){
+	D_NWSTACK("\r\n===> Send:    ");
+    uint8_t checksum = 0;
+    _respCd = -1;
+
+    _serialPort->send(START_BYTE);
+    send(0x00);              // Message Length
+    send(14 + pLen);         // Message Length
+
+    _serialPort->send(API_XMITREQUEST); // Transmit Request API
+    checksum += API_XMITREQUEST;
+
+    if (_frameId++ == 0x00 ) // Frame ID
+	{
+    	_frameId = 1;
+	}
+    send(_frameId);
+    checksum += _frameId;
+
+	for ( int i = 0; i < 8; i++)    // Address64
+	{
+		send(addr->_address64[i]);
+		checksum += addr->_address64[i];
+	}
+	for ( int i = 0; i < 2; i++)    // Address16
+	{
+		send(addr->_address16[i]);
+		checksum += addr->_address16[i];
+	}
+
+    send(0x00);   // Broadcast Radius
+    checksum += 0x00;
+
+    send(0x00);   // Option: Use the extended transmission timeout 0x40
+    checksum += 0x00;
+
+    D_NWSTACK("\r\n     Payload: ");
+
+    for ( uint8_t i = 0; i < pLen; i++ ){
+        send(payload[i]);     // Payload
+        checksum += payload[i];
+    }
+
+    checksum = 0xff - checksum;
+    D_NWSTACK("   checksum  ");
+    send(checksum);
+    D_NWSTACK("\r\n");
+
+    /* wait Txim Status 0x8B */
+    _sem.timedwait(XMIT_STATUS_TIME_OVER);
+
+    if ( _respCd || _frameId != _respId )
+    {
+    	 D_NWSTACK(" frameId = %02x  Not Acknowleged\r\n", _frameId);
+    	return -1;
+    }
+    return (int)pLen;
+}
+
+void XBee::send(uint8_t c)
+{
+  if(_apiMode == 2 && (c == START_BYTE || c == ESCAPE || c == XON || c == XOFF)){
+	  _serialPort->send(ESCAPE);
+	  _serialPort->send(c ^ 0x20);
+  }else{
+	  _serialPort->send(c);
+  }
+}
+
+int XBee::recv(uint8_t* buf)
+{
+	if (_serialPort->recv(buf) )
+	{
+		if ( *buf == ESCAPE && _apiMode == 2 )
+		{
+			_serialPort->recv(buf);
+			*buf = 0x20 ^ *buf;
+		}
+		return 0;
+	}
+	return -1;
+}
+
+void XBee::setApiMode(uint8_t mode)
+{
+	_apiMode = mode;
+}
+
+/*=========================================
+ Class SerialPort
+ =========================================*/
+SerialPort::SerialPort()
+{
+	_tio.c_iflag = IGNBRK | IGNPAR;
+	_tio.c_cflag = CS8 | CLOCAL | CRTSCTS | CREAD;
+	_tio.c_cc[VINTR] = 0;
+	_tio.c_cc[VTIME] = 10;   // 1 sec.
+	_tio.c_cc[VMIN] = 1;
+	_fd = 0;
+}
+
+SerialPort::~SerialPort()
+{
+	if (_fd)
+	{
+		::close(_fd);
+	}
+}
+
+int SerialPort::open(char* devName, unsigned int baudrate, bool parity,
+		unsigned int stopbit, unsigned int flg)
+{
+	_fd = ::open(devName, flg);
+	if (_fd < 0)
+	{
+		return _fd;
+	}
+
+	if (parity)
+	{
+		_tio.c_cflag = _tio.c_cflag | PARENB;
+	}
+	if (stopbit == 2)
+	{
+		_tio.c_cflag = _tio.c_cflag | CSTOPB;
+	}
+
+	if (cfsetspeed(&_tio, baudrate) < 0)
+	{
+		return errno;
+	}
+	return tcsetattr(_fd, TCSANOW, &_tio);
+}
+
+bool SerialPort::send(unsigned char b)
+{
+	if (write(_fd, &b, 1) < 0)
+	{
+		return false;
+	}
+	else
+	{
+		D_NWSTACK( " %02x", b);
+		return true;
+	}
+}
+
+bool SerialPort::recv(unsigned char* buf)
+{
+    struct timeval timeout;
+    fd_set rfds;
+    FD_ZERO(&rfds);
+    FD_SET(_fd, &rfds);
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 500000;    // 500ms
+    if ( select(_fd + 1, &rfds, 0, 0, &timeout) > 0 )
+    {
+        if (read(_fd, buf, 1) > 0)
+        {
+            D_NWSTACK( " %02x",buf[0] );
+            return true;
+        }
+    }
+    return false;
+}
+
+void SerialPort::flush(void)
+{
+	tcsetattr(_fd, TCSAFLUSH, &_tio);
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/xbee/SensorNetwork.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/linux/xbee/SensorNetwork.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,140 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+#ifndef SENSORNETWORKX_H_
+#define SENSORNETWORKX_H_
+
+#include "MQTTSNGWDefines.h"
+#include "MQTTSNGWProcess.h"
+#include <string>
+#include <termios.h>
+
+using namespace std;
+
+namespace MQTTSNGW
+{
+//#define DEBUG_NWSTACK
+
+#ifdef  DEBUG_NWSTACK
+  #define D_NWSTACK(...) printf(__VA_ARGS__)
+#else
+  #define D_NWSTACK(...)
+#endif
+
+#define API_XMITREQUEST          0x10
+#define API_RESPONSE             0x90
+#define API_MODEMSTATUS          0x8A
+#define API_XMITSTATUS           0x8B
+
+#define XMIT_STATUS_TIME_OVER    5000
+
+#define START_BYTE               0x7e
+#define ESCAPE                   0x7d
+#define XON                      0x11
+#define XOFF                     0x13
+
+/*===========================================
+  Class  SerialPort
+ ============================================*/
+class SerialPort{
+public:
+	SerialPort();
+	~SerialPort();
+	int open(char* devName, unsigned int baudrate,  bool parity, unsigned int stopbit, unsigned int flg);
+	bool send(unsigned char b);
+	bool recv(unsigned char* b);
+	void flush();
+
+private:
+	int _fd;  // file descriptor
+	struct termios _tio;
+};
+
+/*===========================================
+ Class  SensorNetAddreess
+ ============================================*/
+class SensorNetAddress
+{
+	friend class XBee;
+public:
+	SensorNetAddress();
+	~SensorNetAddress();
+	void setAddress(uint8_t* address64, uint8_t* address16);
+	int  setAddress(string* data);
+	void setBroadcastAddress(void);
+	bool isMatch(SensorNetAddress* addr);
+	SensorNetAddress& operator =(SensorNetAddress& addr);
+	char* sprint(char*);
+private:
+	uint8_t _address16[2];
+	uint8_t _address64[8];
+};
+
+/*========================================
+ Class XBee
+ =======================================*/
+class XBee
+{
+public:
+	XBee();
+	~XBee();
+
+	int open(char* device, int boudrate);
+	void close(void);
+	int unicast(const uint8_t* buf, uint16_t length, SensorNetAddress* sendToAddr);
+	int broadcast(const uint8_t* buf, uint16_t length);
+	int recv(uint8_t* buf, uint16_t len, SensorNetAddress* addr);
+	void setApiMode(uint8_t mode);
+
+private:
+	int readApiFrame(uint8_t* recvData);
+	int recv(uint8_t* buf);
+	int send(const uint8_t* payload, uint8_t pLen, SensorNetAddress* addr);
+	void send(uint8_t b);
+
+	Semaphore _sem;
+	Mutex _meutex;
+	SerialPort* _serialPort;
+	uint8_t _frameId;
+	uint8_t _respCd;
+	uint8_t _respId;
+	uint8_t _dataLen;
+	uint8_t _apiMode;
+};
+
+/*===========================================
+ Class  SensorNetwork
+ ============================================*/
+class SensorNetwork: public XBee
+{
+public:
+	SensorNetwork();
+	~SensorNetwork();
+
+	int unicast(const uint8_t* payload, uint16_t payloadLength, SensorNetAddress* sendto);
+	int broadcast(const uint8_t* payload, uint16_t payloadLength);
+	int read(uint8_t* buf, uint16_t bufLen);
+	int initialize(void);
+	const char* getDescription(void);
+	SensorNetAddress* getSenderAddress(void);
+
+private:
+	SensorNetAddress _clientAddr;   // Sender's address. not gateway's one.
+	string _description;
+};
+
+}
+
+#endif /* SENSORNETWORKX_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/mainGateway.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/mainGateway.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,40 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+#include "MQTTSNGateway.h"
+#include "MQTTSNGWBrokerRecvTask.h"
+#include "MQTTSNGWBrokerSendTask.h"
+#include "MQTTSNGWClientRecvTask.h"
+#include "MQTTSNGWClientSendTask.h"
+#include "MQTTSNGWPacketHandleTask.h"
+
+using namespace MQTTSNGW;
+
+/*
+ *  Gateway Application
+ */
+Gateway gateway;
+PacketHandleTask  task1(&gateway);
+ClientRecvTask    task2(&gateway);
+ClientSendTask    task3(&gateway);
+BrokerRecvTask    task4(&gateway);
+BrokerSendTask    task5(&gateway);
+
+int main(int argc, char** argv)
+{
+    gateway.initialize(argc, argv);
+    gateway.run();
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/mainLogmonitor.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/mainLogmonitor.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,33 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation and/or initial documentation
+ **************************************************************************************/
+
+#include "MQTTSNGWProcess.h"
+#include "MQTTSNGWLogmonitor.h"
+
+using namespace MQTTSNGW;
+
+
+/*
+ *   Logmonitor process
+ */
+int main(int argc, char** argv)
+{
+	Logmonitor monitor = Logmonitor();
+	monitor.initialize(argc, argv);
+	monitor.run();
+	return 0;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestProcess.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestProcess.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,129 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+
+#include <string.h>
+#include <cassert>
+#include "TestProcess.h"
+#include "TestTopics.h"
+#include "TestQue.h"
+#include "TestTree23.h"
+#include "TestTopicIdMap.h"
+#include "MQTTSNGWProcess.h"
+#include "MQTTSNGWClient.h"
+#include "MQTTSNGWPacket.h"
+#include "Timer.h"
+
+using namespace std;
+using namespace MQTTSNGW;
+
+#define ARGV    "./Build/testPFW"
+#define CONFDIR "./"
+#define CONF    "gateway.conf"
+
+const char* currentDateTime(void);
+
+TestProcess::TestProcess()
+{
+	theMultiTaskProcess = this;
+	theProcess = this;
+}
+
+TestProcess::~TestProcess()
+{
+
+}
+
+void TestProcess::initialize(int argc, char** argv)
+{
+	MultiTaskProcess::initialize(argc, argv);
+	assert(0 == strcmp(CONFDIR, getConfigDirName()->c_str()));
+	assert(0 == strcmp(CONF, getConfigFileName()->c_str()));
+	resetRingBuffer();
+}
+
+void TestProcess::run(void)
+{
+	char value[256];
+	int i = 0;
+	Timer tm;
+
+	/* Test command line parameter */
+
+	assert(1 == getArgc() || 3 == getArgc() );
+	assert(0 == strcmp(ARGV, *getArgv()));
+	getParam("BrokerName", value);
+	assert(0 == strcmp("iot.eclipse.org", value));
+
+	/* Test RingBuffer */
+	for ( i = 0; i < 1000; i++)
+	{
+		putLog("Test RingBuffer %d ", 1234567890);
+	}
+	putLog("\n\nRingBuffer Test complieted.\n\n");
+
+	/* Test Timer */
+	printf("Timer Test start\n");
+	printf("%s Timer start\n",  currentDateTime());
+	tm.start(1000);
+	while (!tm.isTimeup());
+	printf("%s Timer 1sec\n", currentDateTime());
+
+	tm.start();
+	while (!tm.isTimeup(1000));
+	printf("%s Timer 1sec\n", currentDateTime());
+	printf("Timer Test completed\n\n");
+
+	/* Test Que */
+    printf("Test  Que            ");
+	TestQue* tque = new TestQue();
+	tque->test();
+	delete tque;
+
+	/* Test Tree23 */
+    //printf("Test  Tree23         ");
+	//TestTree23* tree23 = new TestTree23();
+	//tree23->test();
+	//delete tree23;
+
+	/* Test TopicTable */
+    printf("Test  Topic          ");
+	TestTopics* testTopic = new TestTopics();
+	testTopic->test();
+	delete testTopic;
+
+	/* Test TopicIdMap */
+    printf("Test  TopicIdMap     ");
+	TestTopicIdMap* testMap = new TestTopicIdMap();
+	testMap->test();
+	delete testMap;
+
+	/* Test EventQue */
+	/*
+	printf("Test  EventQue       ");
+	Client* client = new Client();
+	_evQue.setMaxSize(EVENT_CNT);
+	for ( int i = 0; i < EVENT_CNT + 4; i++ )
+	{
+		Event* ev = new Event();
+		MQTTSNPacket* packet = new MQTTSNPacket();
+		packet->setDISCONNECT(i);
+		ev->setClientSendEvent(client, packet);
+		_evQue.post(ev);
+	}
+	delete client;
+	*/
+	//MultiTaskProcess::run();
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestProcess.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestProcess.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,38 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+#ifndef TESTPROCESS_H_
+#define TESTPROCESS_H_
+
+#include "MQTTSNGWProcess.h"
+#include "MQTTSNGateway.h"
+#define EVENT_CNT 10
+namespace MQTTSNGW
+{
+class TestProcess: public MultiTaskProcess{
+public:
+	TestProcess();
+	~TestProcess();
+	virtual void initialize(int argc, char** argv);
+	void run(void);
+	EventQue* getEventQue(void) { return &_evQue; }
+
+private:
+	EventQue _evQue;
+};
+
+}
+
+#endif /* TESTPROCESS_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestQue.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestQue.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,100 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+#include <string.h>
+#include <tests/TestProcess.h>
+#include <cassert>
+#include "TestQue.h"
+using namespace std;
+using namespace MQTTSNGW;
+
+TestQue::TestQue()
+{
+
+}
+
+TestQue::~TestQue()
+{
+
+}
+
+void TestQue::test(void)
+{
+	int* v = 0;
+	int i = 0;
+
+	for ( i = 0; i < 10; i++ )
+	{
+		v = new int(i);
+		this->post(v);
+	}
+	assert( 10 == this->size());
+
+	for ( i = 0; i < 10; i++ )
+	{
+		assert(i == *this->front());
+		int* p = this->front();
+		if ( p )
+		{
+			assert(i == *p);
+			this->pop();
+			delete p;
+		}
+	}
+	assert(0 == this->front());
+	assert(0 == this->size());
+
+	this->setMaxSize(5);
+	for ( i = 0; i < 10; i++ )
+	{
+		v = new int(i);
+		this->post(v);
+		assert( 5 >= this->size());
+	}
+	for ( i = 0; i < 10; i++ )
+	{
+		int* p = this->front();
+		if ( p )
+		{
+			this->pop();
+			delete p;
+		}
+	}
+	printf("[ OK ]\n");
+}
+
+int* TestQue::front(void)
+{
+	return _que.front();
+}
+void TestQue::pop(void)
+{
+	_que.pop();
+}
+int TestQue::size(void)
+{
+	return _que.size();
+}
+void TestQue::setMaxSize(int maxsize)
+{
+	_que.setMaxSize(maxsize);
+}
+
+void TestQue::post(int* val)
+{
+	_que.post(val);
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestQue.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestQue.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,41 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+#ifndef MQTTSNGATEWAY_SRC_TESTS_TESTQUE_H_
+#define MQTTSNGATEWAY_SRC_TESTS_TESTQUE_H_
+
+#include "MQTTSNGWProcess.h"
+
+namespace MQTTSNGW
+{
+
+class TestQue
+{
+public:
+	TestQue();
+	~TestQue();
+	void post(int*);
+	int* front(void);
+	void pop(void);
+	int size(void);
+	void setMaxSize(int maxsize);
+	void test(void);
+private:
+	Que<int> _que;
+};
+}
+
+
+#endif /* MQTTSNGATEWAY_SRC_TESTS_TESTQUE_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTask.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTask.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,73 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+#include <unistd.h>
+#include <cassert>
+#include "TestTask.h"
+#include "Threading.h"
+#include "TestProcess.h"
+using namespace std;
+using namespace MQTTSNGW;
+
+TestTask::TestTask(TestProcess* proc)
+{
+	proc->attach((Thread*)this);
+	_proc = proc;
+}
+
+TestTask::~TestTask()
+{
+
+}
+
+void TestTask::initialize(int argc, char** argv)
+{
+	printf("Task initialize complite.\n");
+}
+
+void TestTask::run(void)
+{
+	int evcnt = 0;
+	EventQue* evQue = _proc->getEventQue();
+	uint16_t duration = 0;
+
+
+	while (true)
+	{
+		Event* ev = evQue->timedwait(5000);
+		evcnt++;
+		if ( ev->getEventType() == EtTimeout )
+		{
+			assert(EVENT_CNT + 1 == evcnt);
+			delete ev;
+			printf("[ OK ]\n");
+			break;
+		}
+		MQTTSNPacket* packet = ev->getMQTTSNPacket();
+		packet->getDISCONNECT(&duration);
+		delete ev;
+	}
+
+	while(true)
+	{
+		if ( CHK_SIGINT)
+		{
+			printf("\nTest  Task           [ OK ]\n");
+			return;
+		}
+		printf("Enter CTRL+C\n");
+		sleep(1);
+	}
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTask.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTask.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,42 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+#ifndef TESTTASK_H_
+#define TESTTASK_H_
+
+#include "TestProcess.h"
+#include "Threading.h"
+
+namespace MQTTSNGW
+{
+
+class TestTask: public Thread
+{
+MAGIC_WORD_FOR_THREAD;
+	;
+public:
+	TestTask(TestProcess* proc);
+	~TestTask();
+	void initialize(int argc, char** argv);
+	void run(void);
+
+private:
+	TestProcess* _proc;
+};
+
+}
+
+
+#endif /* TESTTASK_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTopicIdMap.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTopicIdMap.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,193 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+#include <stdlib.h>
+#include <string.h>
+#include <cassert>
+#include "TestTopicIdMap.h"
+
+using namespace std;
+using namespace MQTTSNGW;
+
+TestTopicIdMap::TestTopicIdMap()
+{
+	_map = new TopicIdMap();
+}
+
+TestTopicIdMap::~TestTopicIdMap()
+{
+	delete _map;
+}
+
+
+bool TestTopicIdMap::testGetElement(uint16_t msgid, uint16_t id, MQTTSN_topicTypes type)
+{
+    TopicIdMapElement* elm = _map->getElement((uint16_t)msgid );
+    if ( elm )
+    {
+       //printf("msgid=%d id=%d type=%d\n", msgid, elm->getTopicId(), elm->getTopicType());
+       return elm->getTopicId() == id && elm->getTopicType() == type;
+    }
+    //printf("msgid=%d\n", msgid);
+    return false;
+}
+
+#define MAXID 30
+
+void TestTopicIdMap::test(void)
+{
+	uint16_t id[MAXID];
+
+	for ( int i = 0; i < MAXID; i++ )
+	{
+		id[i] = i + 1;
+		_map->add(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL);
+	}
+
+	for ( int i = 0; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ )
+	{
+		assert(testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL));
+	}
+
+	for ( int i = MAX_INFLIGHTMESSAGES * 2 + 1; i < MAXID; i++ )
+    {
+        assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL));
+    }
+
+    for ( int i = 0; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ )
+    {
+        assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED));
+    }
+
+	for ( int i = 0; i < 5; i++ )
+	{
+		_map->erase(id[i]);
+	}
+	for ( int i = 0; i < 5; i++ )
+	{
+	    assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL));
+	}
+
+	for ( int i = 5; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ )
+    {
+        assert(testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL));
+    }
+
+	for ( int i = MAX_INFLIGHTMESSAGES * 2 + 1; i < MAXID; i++ )
+    {
+        assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL));
+    }
+
+	_map->clear();
+
+    for ( int i = 0; i < MAXID; i++ )
+    {
+        assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL));
+    }
+
+    for ( int i = 0; i < MAXID; i++ )
+    {
+        _map->add(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT);
+    }
+
+    for ( int i = 0; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ )
+    {
+        assert(testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT));
+    }
+
+    for ( int i = MAX_INFLIGHTMESSAGES * 2 + 1; i < MAXID; i++ )
+    {
+        assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT));
+    }
+
+    for ( int i = 0; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ )
+    {
+        assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_NORMAL));
+    }
+
+    for ( int i = 0; i < 5; i++ )
+    {
+        _map->erase(id[i]);
+    }
+    for ( int i = 0; i < 5; i++ )
+    {
+        assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT));
+    }
+
+    for ( int i = 5; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ )
+    {
+        assert(testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT));
+    }
+
+    for ( int i = MAX_INFLIGHTMESSAGES * 2 + 1; i < MAXID; i++ )
+    {
+        assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT));
+    }
+
+    _map->clear();
+
+    for ( int i = 0; i < MAXID; i++ )
+    {
+        assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT));
+    }
+
+    for ( int i = 0; i < MAXID; i++ )
+    {
+        _map->add(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED);
+    }
+
+    for ( int i = 0; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ )
+    {
+        assert(testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED));
+    }
+
+    for ( int i = MAX_INFLIGHTMESSAGES * 2 + 1; i < MAXID; i++ )
+    {
+        assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED));
+    }
+
+    for ( int i = 0; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ )
+    {
+        assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_SHORT));
+    }
+
+    for ( int i = 0; i < 5; i++ )
+    {
+        _map->erase(id[i]);
+    }
+    for ( int i = 0; i < 5; i++ )
+    {
+        assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED));
+    }
+
+    for ( int i = 5; i < MAX_INFLIGHTMESSAGES * 2 + 1; i++ )
+    {
+        assert(testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED));
+    }
+
+    for ( int i = MAX_INFLIGHTMESSAGES * 2 + 1; i < MAXID; i++ )
+    {
+        assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED));
+    }
+
+    _map->clear();
+
+    for ( int i = 0; i < MAXID; i++ )
+    {
+        assert(!testGetElement(id[i], id[i], MQTTSN_TOPIC_TYPE_PREDEFINED));
+    }
+	printf("[ OK ]\n");
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTopicIdMap.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTopicIdMap.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,33 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+#ifndef MQTTSNGATEWAY_SRC_TESTS_TESTTOPICIDMAP_H_
+#define MQTTSNGATEWAY_SRC_TESTS_TESTTOPICIDMAP_H_
+
+#include "MQTTSNGWClient.h"
+
+class TestTopicIdMap
+{
+public:
+	TestTopicIdMap();
+	~TestTopicIdMap();
+	void test(void);
+	bool testGetElement(uint16_t msgid, uint16_t id, MQTTSN_topicTypes type);
+
+private:
+	TopicIdMap* _map;
+};
+
+#endif /* MQTTSNGATEWAY_SRC_TESTS_TESTTOPICIDMAP_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTopics.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTopics.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,365 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ *    Tieto Poland Sp. z o.o. - Topic test improvements
+ **************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cassert>
+#include "TestTopics.h"
+
+using namespace std;
+using namespace MQTTSNGW;
+
+TestTopics::TestTopics()
+{
+	_topics = new Topics();
+}
+
+TestTopics::~TestTopics()
+{
+	delete _topics;
+}
+
+bool testIsMatch(const char* topicFilter, const char* topicName)
+{
+	string* filter = new string(topicFilter);
+	string* name = new string(topicName);
+
+	Topic topic(filter, MQTTSN_TOPIC_TYPE_NORMAL);
+	bool isMatch = topic.isMatch(name);
+
+	delete name;
+
+	return isMatch;
+}
+
+bool testGetTopicByName(const char* topicName, const char* searchedTopicName)
+{
+	Topics topics;
+	MQTTSN_topicid topicid, serchId;
+	topicid.type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topicid.data.long_.len = strlen(topicName);
+	topicid.data.long_.name = const_cast<char*>(topicName);
+
+	topics.add(&topicid);
+
+	serchId.type = MQTTSN_TOPIC_TYPE_NORMAL;
+	serchId.data.long_.len = strlen(searchedTopicName);
+	serchId.data.long_.name = const_cast<char*>(searchedTopicName);
+
+	return topics.getTopicByName(&serchId) != 0;
+}
+
+bool testGetTopicById(const char* topicName, const char* searchedTopicName)
+{
+	Topics topics;
+	MQTTSN_topicid topicid, stopicid;
+	topicid.type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topicid.data.long_.len = strlen(topicName);
+	topicid.data.long_.name = const_cast<char*>(topicName);
+	stopicid.type = MQTTSN_TOPIC_TYPE_NORMAL;
+    stopicid.data.long_.len = strlen(searchedTopicName);
+    stopicid.data.long_.name = const_cast<char*>(searchedTopicName);
+
+	Topic* tp = topics.add(&topicid);
+	Topic*stp = topics.add(&stopicid);
+	topicid.data.id  = tp->getTopicId();
+	stopicid.data.id  = stp->getTopicId();
+
+	stp = topics.getTopicById(&stopicid);
+
+	return stp->getTopicId() == tp->getTopicId();
+}
+
+bool testGetPredefinedTopicByName(const char* topicName, const uint16_t id, const char* searchedTopicName)
+{
+    Topics topics;
+    MQTTSN_topicid topicid;
+
+    topics.add(topicName, id);
+
+    topicid.type = MQTTSN_TOPIC_TYPE_PREDEFINED;
+    topicid.data.long_.len = strlen(searchedTopicName);
+    topicid.data.long_.name = const_cast<char*>(searchedTopicName);
+
+    return topics.getTopicByName(&topicid) != 0;
+}
+
+bool testGetPredefinedTopicById(const char* topicName, const uint16_t id, uint16_t sid)
+{
+    Topics topics;
+    MQTTSN_topicid topicid;
+
+    Topic* t = topics.add(topicName, id);
+
+    topicid.type = MQTTSN_TOPIC_TYPE_PREDEFINED;
+    topicid.data.id  = sid;
+
+    Topic* tp = topics.getTopicById(&topicid);
+
+    if ( tp )
+    {
+        return tp->getTopicId() == id && strcmp(t->getTopicName()->c_str(), topicName) == 0;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+void TestTopics::test(void)
+{
+	const int TOPIC_COUNT = 13;
+
+	MQTTSN_topicid topic[TOPIC_COUNT];
+	char tp[TOPIC_COUNT][10];
+
+	/* create Topic */
+	strcpy(tp[0], "Topic/+");
+	tp[0][7] = 0;
+	topic[0].type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topic[0].data.long_.len = strlen(tp[0]);
+	topic[0].data.long_.name = tp[0];
+
+	for ( int i = 1; i < 10 ; i++ )
+	{
+		sprintf(tp[i], "Topic/+/%d", i);
+		topic[i].type = MQTTSN_TOPIC_TYPE_NORMAL;
+		topic[i].data.long_.len = strlen(tp[i]);
+		topic[i].data.long_.name = tp[i];
+	}
+
+	strcpy(tp[10], "TOPIC/#");
+	tp[10][7] = 0;
+	topic[10].type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topic[10].data.long_.len = strlen(tp[10]);
+	topic[10].data.long_.name = tp[10];
+
+	strcpy(tp[11], "+/0/#");
+	tp[11][7] = 0;
+	topic[11].type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topic[11].data.long_.len = strlen(tp[11]);
+	topic[11].data.long_.name = tp[11];
+
+	tp[12][0] = '#';
+	tp[12][1] = 0;
+	topic[12].type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topic[12].data.long_.len = strlen(tp[12]);
+	topic[12].data.long_.name = tp[12];
+
+
+	/* Test EraseNorma() */
+	for ( int i = 0; i < TOPIC_COUNT; i++ )
+    {
+        MQTTSN_topicid pos = topic[i];
+        Topic* t = _topics->add(&pos);
+        //printf("Topic=%s ID=%d\n", t->getTopicName()->c_str(), t->getTopicId());
+        assert(t !=0);
+    }
+	_topics->eraseNormal();
+	assert(_topics->getCount() == 0);
+
+	/* Add Topic to Topics */
+	for ( int i = 0; i < TOPIC_COUNT; i++ )
+	{
+		MQTTSN_topicid pos = topic[i];
+		Topic* t = _topics->add(&pos);
+		//printf("Topic=%s ID=%d\n", t->getTopicName()->c_str(), t->getTopicId());
+		assert(t !=0);
+	}
+
+	for ( int i = 0; i < 5; i++ )
+	{
+		string str = "Test/";
+		str += 0x30 + i;
+		Topic* t = _topics->add(str.c_str());
+		//printf("Topic=%s ID=%d\n", t->getTopicName()->c_str(), t->getTopicId());
+		assert(t !=0);
+	}
+
+	/* Get Topic by MQTTSN_topicid  by Name*/
+	for ( int i = 0; i < TOPIC_COUNT; i++ )
+	{
+		Topic* t = _topics->getTopicByName(&topic[i]);
+		//printf("Topic=%s ID=%d\n", t->getTopicName()->c_str(), t->getTopicId());
+		assert(strcmp(t->getTopicName()->c_str(), topic[i].data.long_.name) == 0 );
+	}
+
+    /* Get Topic by MQTTSN_topicid  by ID*/
+    for ( int i = 0; i < TOPIC_COUNT; i++ )
+    {
+        Topic* t = _topics->getTopicByName(&topic[i]);
+        MQTTSN_topicid stpid;
+        stpid.type = MQTTSN_TOPIC_TYPE_NORMAL;
+        stpid.data.id =t->getTopicId();
+        Topic* st = _topics->getTopicById(&stpid);
+        //printf("Topic=%s ID=%d ID=%d\n", t->getTopicName()->c_str(), t->getTopicId(), st->getTopicId());
+        assert(t->getTopicId() == st->getTopicId() );
+    }
+
+	/* Test Wildcard */
+	for ( int i = 0; i < 10 ; i++ )
+	{
+		MQTTSN_topicid tp1;
+		char tp0[10];
+		sprintf(tp0, "Topic/%d/%d", i, i);
+		tp1.type = MQTTSN_TOPIC_TYPE_NORMAL;
+		tp1.data.long_.len = strlen(tp0);
+		tp1.data.long_.name = tp0;
+
+		Topic* t = _topics->match(&tp1);
+/*
+		if (t)
+		{
+			printf("Topic=%s  match to %s\n", tp0, t->getTopicName()->c_str());
+		}
+		else
+		{
+			printf("Topic=%s unmatch\n", tp0);
+		}
+*/
+		assert(t != 0);
+	}
+
+	for ( int i = 0; i < 10 ; i++ )
+	{
+		MQTTSN_topicid tp1;
+		char tp0[10];
+		sprintf(tp0, "Topic/%d", i);
+		tp1.type = MQTTSN_TOPIC_TYPE_NORMAL;
+		tp1.data.long_.len = strlen(tp0);
+		tp1.data.long_.name = tp0;
+
+		Topic* t = _topics->match(&tp1);
+/*
+		if (t)
+		{
+			printf("Topic=%s  match to %s\n", tp0, t->getTopicName()->c_str());
+		}
+		else
+		{
+			printf("Topic=%s unmatch\n", tp0);
+		}
+*/
+		assert(t != 0);
+		assert(t->getTopicName()->compare(tp[0]) == 0);
+	}
+
+	for ( int i = 0; i < 10 ; i++ )
+	{
+		MQTTSN_topicid tpid1;
+		char tp0[10];
+		sprintf(tp0, "TOPIC/%d/%d", i, i);
+		tpid1.type = MQTTSN_TOPIC_TYPE_NORMAL;
+		tpid1.data.long_.len = strlen(tp0);
+		tpid1.data.long_.name = tp0;
+
+		Topic* t = _topics->match(&tpid1);
+/*
+		if (t)
+		{
+			printf("Topic=%s  match to %s\n", tp0, t->getTopicName()->c_str());
+		}
+		else
+		{
+			printf("Topic=%s unmatch\n", tp0);
+		}
+*/
+		assert( t != 0);
+		assert(t->getTopicName()->compare(tp[10]) == 0);
+	}
+
+	{
+		MQTTSN_topicid tp1;
+		char tp0[10];
+		strcpy(tp0, "Topic");
+		tp1.type = MQTTSN_TOPIC_TYPE_NORMAL;
+		tp1.data.long_.len = strlen(tp0);
+		tp1.data.long_.name = tp0;
+
+		Topic* t = _topics->match(&tp1);
+
+		assert(t != 0);
+		assert(t->getTopicName()->compare(tp[12]) == 0);
+	}
+
+	{
+		MQTTSN_topicid tp1;
+		char tp0[20];
+		strcpy(tp0, "Topic/multi/level");
+		tp1.type = MQTTSN_TOPIC_TYPE_NORMAL;
+		tp1.data.long_.len = strlen(tp0);
+		tp1.data.long_.name = tp0;
+
+		Topic* t = _topics->match(&tp1);
+
+		assert(t != 0);
+		assert(t->getTopicName()->compare(tp[12]) == 0);
+	}
+
+
+	assert(testIsMatch("#", "one"));
+	assert(testIsMatch("#", "one/"));
+	assert(testIsMatch("#", "one/two"));
+	assert(testIsMatch("#", "one/two/"));
+	assert(testIsMatch("#", "one/two/three"));
+	assert(testIsMatch("#", "one/two/three/"));
+
+	assert(!testIsMatch("one/+", "one"));
+	assert(testIsMatch("one/+", "one/"));
+	assert(testIsMatch("one/+", "one/two"));
+	assert(!testIsMatch("one/+", "one/two/"));
+	assert(!testIsMatch("one/+", "one/two/three"));
+
+	assert(!testIsMatch("one/+/three/+", "one/two/three"));
+	assert(testIsMatch("one/+/three/+", "one/two/three/"));
+	assert(testIsMatch("one/+/three/+", "one/two/three/four"));
+	assert(!testIsMatch("one/+/three/+", "one/two/three/four/"));
+
+	assert(testIsMatch("one/+/three/#", "one/two/three"));
+	assert(testIsMatch("one/+/three/#", "one/two/three/"));
+	assert(testIsMatch("one/+/three/#", "one/two/three/four"));
+	assert(testIsMatch("one/+/three/#", "one/two/three/four/"));
+	assert(testIsMatch("one/+/three/#", "one/two/three/four/five"));
+
+	// examples from MQTT specification
+	assert(testIsMatch("sport/tennis/player1/#", "sport/tennis/player1"));
+	assert(testIsMatch("sport/tennis/player1/#", "sport/tennis/player1/ranking"));
+	assert(testIsMatch("sport/tennis/player1/#", "sport/tennis/player1/score/wimbledon"));
+	assert(testIsMatch("sport/tennis/+", "sport/tennis/player1"));
+	assert(testIsMatch("sport/tennis/+", "sport/tennis/player2"));
+	assert(!testIsMatch("sport/tennis/+", "sport/tennis/player1/ranking"));
+	assert(testIsMatch("+/+", "/finance"));
+	assert(testIsMatch("/+", "/finance"));
+	assert(!testIsMatch("+", "/finance"));
+
+	assert(testGetTopicById("mytopic", "mytopic"));
+	assert(!testGetTopicById("mytopic", "mytop"));
+	assert(!testGetTopicById("mytopic", "mytopiclong"));
+
+	assert(testGetTopicByName("mytopic", "mytopic"));
+	assert(!testGetTopicByName("mytopic", "mytop"));
+	assert(!testGetTopicByName("mytopic", "mytopiclong"));
+
+    assert(testGetPredefinedTopicByName("mypretopic", 1, "mypretopic"));
+    assert(!testGetPredefinedTopicByName("mypretopic", 1, "mypretop"));
+    assert(!testGetPredefinedTopicByName("mypretopic", 1, "mypretopiclong"));
+
+    assert(testGetPredefinedTopicById("mypretopic2", 2, 2));
+    assert(!testGetPredefinedTopicById("mypretopic2", 2, 1));
+
+	printf("[ OK ]\n");
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTopics.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTopics.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,32 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+#ifndef MQTTSNGATEWAY_SRC_TESTS_TESTTOPICS_H_
+#define MQTTSNGATEWAY_SRC_TESTS_TESTTOPICS_H_
+
+#include "MQTTSNGWClient.h"
+
+class TestTopics
+{
+public:
+	TestTopics();
+	~TestTopics();
+	void test(void);
+
+private:
+	Topics* _topics;
+};
+
+#endif /* MQTTSNGATEWAY_SRC_TESTS_TESTTOPICS_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTree23.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTree23.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,91 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+#include "TestTree23.h"
+#include <stdio.h>
+#include <string>
+#include <cassert>
+
+using namespace std;
+using namespace MQTTSNGW;
+
+TestTree23::TestTree23()
+{
+
+}
+
+TestTree23::~TestTree23()
+{
+
+}
+
+void TestTree23::test(void)
+{
+	int N = 100;
+
+	Key* r1[100];
+	Integer* r2[100];
+
+	for ( int i = 0; i < N; i++)
+	{
+		char buff[5];
+		sprintf(buff,"%d", i);
+		r1[i] = new Key(string(buff));
+		r2[i] = new Integer(i);
+		this->add(r1[i], r2[i]);
+	}
+
+	for ( int i = 0; i < N; i++)
+	{
+		Integer* rc = this->getVal(r1[i]);
+		//printf("key=%d  val=%d\n", i, rc->_val);
+		assert(i == rc->_val);
+	}
+
+	for ( int i = 20; i < 50; i++)
+	{
+		this->remove(r1[i]);
+		//printf("key=%d  str=%s\n", i, r1[i]->_key.c_str());
+	}
+
+	for ( int i = 0; i < 20; i++)
+	{
+		bool rc = this->find(r1[i]);
+		assert(rc == true);
+		//printf("key=%d  find=%d\n", i, rc);
+		Integer* val = this->getVal(r1[i]);
+		//printf("key=%d  val=%d\n", i, val->_val);
+		assert(val->_val == i);
+	}
+	for (  int i = 20; i < 50; i++ )
+	{
+		bool rc = this->find(r1[i]);
+		assert(rc == false);
+		//printf("key=%d  find=%d\n", i, rc);
+		Integer* val = this->getVal(r1[i]);
+		assert(val == 0);
+	}
+	for ( int i = 50; i < N; i++)
+	{
+		bool rc = this->find(r1[i]);
+		assert(rc == true);
+		//printf("key=%d  find=%d\n", i, rc);
+		Integer* val = this->getVal(r1[i]);
+		//printf("key=%d  val=%d\n", i, val->_val);
+		assert(val->_val == i);
+	}
+	printf("[ OK ]\n");
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTree23.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/TestTree23.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,74 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+#ifndef MQTTSNGATEWAY_SRC_TESTS_TESTTREE23_H_
+#define MQTTSNGATEWAY_SRC_TESTS_TESTTREE23_H_
+
+#include "MQTTSNGWProcess.h"
+
+namespace MQTTSNGW
+{
+
+class Integer
+{
+public:
+	int _val;
+	Integer(){_val = 0;}
+	Integer(int val){_val = val;}
+};
+
+class Key
+{
+public:
+	string _key;
+	Key(){};
+	Key(string key){_key = key;}
+	int compare(Key* obj){
+		if ( _key == obj->_key )
+		{
+			return 0;
+		}
+		else if ( _key < obj->_key )
+		{
+			return -1;
+		}
+		else
+		{
+			return 1;
+		}
+	}
+};
+
+
+
+class TestTree23
+{
+public:
+	TestTree23();
+	~TestTree23();
+	void add(Key* key, Integer* val){_tree23.add(key, val);}
+	Tree23Node<Key, Integer>* add(Tree23Node<Key, Integer>* n, Tree23Elm<Key, Integer>* elm){return _tree23.add(n, elm);}
+	void remove(Key* k){_tree23.remove(k);}
+	Tree23Node<Key, Integer>* remove(Tree23Node<Key, Integer>* node, Key* k){return _tree23.remove(node, k);}
+	bool find(Key* key){return _tree23.find(key);}
+	Integer* getVal(Key* key){return _tree23.getVal(key);}
+	void test(void);
+private:
+	Tree23<Key, Integer> _tree23;
+};
+
+}
+
+#endif /* MQTTSNGATEWAY_SRC_TESTS_TESTTREE23_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/mainTestProcess.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNGateway/src/tests/mainTestProcess.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,32 @@
+/**************************************************************************************
+ * Copyright (c) 2016, Tomoaki Yamaguchi
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Tomoaki Yamaguchi - initial API and implementation 
+ **************************************************************************************/
+#include "TestProcess.h"
+#include "TestTask.h"
+
+using namespace MQTTSNGW;
+
+TestProcess* test = new TestProcess();
+//TestTask* task = new TestTask(test);
+
+int main(int argc, char** argv)
+{
+	test->initialize(argc, argv);
+	test->run();
+	delete test;
+	printf("\nPass all tests. \n");
+	return 0;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,21 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+PROJECT("paho-mqttsnpacket" C)
+
+ADD_SUBDIRECTORY(src)
+ADD_SUBDIRECTORY(samples)
+ADD_SUBDIRECTORY(test)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,61 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+PROJECT(mqtt-sn-samples)
+
+INCLUDE_DIRECTORIES(../src)
+
+ADD_EXECUTABLE(
+  qos0pub
+  qos0pub.c transport.c
+)
+
+TARGET_LINK_LIBRARIES(qos0pub MQTTSNPacketClient)
+
+ADD_EXECUTABLE(
+  qos0pub_register
+  qos0pub_register.c transport.c
+)
+
+TARGET_LINK_LIBRARIES(qos0pub_register MQTTSNPacketClient)
+
+ADD_EXECUTABLE(
+  qos-1pub
+  qos-1pub.c transport.c
+)
+
+TARGET_LINK_LIBRARIES(qos-1pub MQTTSNPacketClient)
+
+ADD_EXECUTABLE(
+  qos-1pub_extended
+  qos-1pub_extended.c transport.c
+)
+
+TARGET_LINK_LIBRARIES(qos-1pub_extended MQTTSNPacketClient)
+
+ADD_EXECUTABLE(
+  qos1pub
+  qos1pub.c transport.c
+)
+
+TARGET_LINK_LIBRARIES(qos1pub MQTTSNPacketClient)
+
+ADD_EXECUTABLE(
+  pub0sub1
+  pub0sub1.c transport.c
+)
+
+TARGET_LINK_LIBRARIES(pub0sub1 MQTTSNPacketClient)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/IBMIoTUDPExample.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/IBMIoTUDPExample.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - refactoring to remove STL and other changes
+ *******************************************************************************/
+
+#define WARN printf
+
+#include "MQTTClient.h"
+
+#define DEFAULT_STACK_SIZE -1
+
+#include "linux.cpp"
+
+#include <stdlib.h>
+
+// Configuration values needed to connect to IBM IoT Cloud
+#define ORG "quickstart"             // For a registered connection, replace with your org
+#define ID "8002f7f1ad23"                        // For a registered connection, replace with your id
+#define AUTH_TOKEN ""                // For a registered connection, replace with your auth-token
+#define TYPE "mytype"       // For a registered connection, replace with your type
+
+#define MQTT_PORT 1883
+#define MQTT_TLS_PORT 8883
+#define IBM_IOT_PORT MQTT_PORT
+
+#define MQTT_MAX_PACKET_SIZE 250
+
+bool quickstartMode = true;
+char org[11] = ORG;  
+char type[30] = TYPE;
+char id[30] = ID;                 // mac without colons
+char auth_token[30] = AUTH_TOKEN; // Auth_token is only used in non-quickstart mode
+
+bool connected = false;
+const char* joystickPos = "CENTRE";
+int blink_interval = 0;
+
+
+
+int connect(MQTT::Client<IPStack, Countdown, MQTT_MAX_PACKET_SIZE>* client, IPStack* ipstack)
+{   
+    const char* iot_ibm = ".messaging.internetofthings.ibmcloud.com";
+    
+    char hostname[strlen(org) + strlen(iot_ibm) + 1];
+    sprintf(hostname, "%s%s", org, iot_ibm);
+	DEBUG("connecting to %s\n", hostname);
+    int rc = ipstack->connect(hostname, IBM_IOT_PORT);
+    if (rc != 0)
+        return rc;
+     
+    // Construct clientId - d:org:type:id
+    char clientId[strlen(org) + strlen(type) + strlen(id) + 5];
+    sprintf(clientId, "d:%s:%s:%s", org, type, id);
+    DEBUG("clientid is %s\n", clientId);
+    
+    // MQTT Connect
+    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+    data.MQTTVersion = 4;
+    data.clientID.cstring = clientId;
+    
+    if (!quickstartMode) 
+    {        
+        data.username.cstring = "use-token-auth";
+        data.password.cstring = auth_token;
+    }
+    
+    if ((rc = client->connect(data)) == 0) 
+        connected = true;
+    return rc;
+}
+
+
+int getConnTimeout(int attemptNumber)
+{  // First 10 attempts try within 3 seconds, next 10 attempts retry after every 1 minute
+   // after 20 attempts, retry every 10 minutes
+    return (attemptNumber < 10) ? 3 : (attemptNumber < 20) ? 60 : 600;
+}
+
+
+void attemptConnect(MQTT::Client<IPStack, Countdown, MQTT_MAX_PACKET_SIZE>* client, IPStack* ipstack)
+{
+    int retryAttempt = 0;
+    connected = false;
+        
+    while (connect(client, ipstack) != 0) 
+    {    
+        int timeout = getConnTimeout(++retryAttempt);
+        WARN("Retry attempt number %d waiting %d\n", retryAttempt, timeout);
+        
+        // if ipstack and client were on the heap we could deconstruct and goto a label where they are constructed
+        //  or maybe just add the proper members to do this disconnect and call attemptConnect(...)
+        
+        sleep(timeout);
+    }
+}
+
+
+int publish(MQTT::Client<IPStack, Countdown, MQTT_MAX_PACKET_SIZE>* client, IPStack* ipstack)
+{
+    MQTT::Message message;
+    char* pubTopic = "iot-2/evt/status/fmt/json";
+	static const char* joypos[] = {"LEFT", "RIGHT", "CENTRE", "UP", "DOWN"};
+            
+    char buf[250];
+    sprintf(buf,
+     "{\"d\":{\"myName\":\"IoT mbed\",\"accelX\":%0.4f,\"accelY\":%0.4f,\"accelZ\":%0.4f,\"temp\":%0.4f,\"joystick\":\"%s\",\"potentiometer1\":%0.4f,\"potentiometer2\":%0.4f}}",
+			(rand() % 10) * 2.0, (rand() % 10) * 2.0, (rand() % 10) * 2.0, (rand() % 10) + 18.0, joypos[rand() % 5], (rand() % 10) * 30.0, (rand() % 10) * 30.0); 
+            //MMA.x(), MMA.y(), MMA.z(), sensor.temp(), joystickPos, ain1.read(), ain2.read());
+    message.qos = MQTT::QOS0;
+    message.retained = false;
+    message.dup = false;
+    message.payload = (void*)buf;
+    message.payloadlen = strlen(buf);
+    
+    LOG("Publishing %s\n", buf);
+    return client->publish(pubTopic, message);
+}
+
+
+void messageArrived(MQTT::MessageData& md)
+{
+    MQTT::Message &message = md.message;
+    char topic[md.topicName.lenstring.len + 1];
+    
+    sprintf(topic, "%.*s", md.topicName.lenstring.len, md.topicName.lenstring.data);
+    
+    LOG("Message arrived on topic %s: %.*s\n",  topic, message.payloadlen, message.payload);
+          
+    // Command topic: iot-2/cmd/blink/fmt/json - cmd is the string between cmd/ and /fmt/
+    char* start = strstr(topic, "/cmd/") + 5;
+    int len = strstr(topic, "/fmt/") - start;
+    
+    if (memcmp(start, "blink", len) == 0)
+    {
+        char payload[message.payloadlen + 1];
+        sprintf(payload, "%.*s", message.payloadlen, (char*)message.payload);
+    
+        char* pos = strchr(payload, '}');
+        if (pos != NULL)
+        {
+            *pos = '\0';
+            if ((pos = strchr(payload, ':')) != NULL)
+            {
+                int blink_rate = atoi(pos + 1);       
+                blink_interval = (blink_rate <= 0) ? 0 : (blink_rate > 50 ? 1 : 50/blink_rate);
+            }
+        }
+    }
+    else
+        WARN("Unsupported command: %.*s\n", len, start);
+}
+
+
+int main()
+{    
+    quickstartMode = (strcmp(org, "quickstart") == 0);
+    
+    IPStack ipstack = IPStack();
+    MQTT::Client<IPStack, Countdown, MQTT_MAX_PACKET_SIZE> client(ipstack);
+    
+    attemptConnect(&client, &ipstack);
+    
+    if (!quickstartMode) 
+    {
+        int rc = 0;
+        if ((rc = client.subscribe("iot-2/cmd/+/fmt/json", MQTT::QOS1, messageArrived)) != 0)
+            WARN("rc from MQTT subscribe is %d\n", rc); 
+    }
+   
+    int count = 0;
+    while (true)
+    {
+        if (++count == 100)
+        {               // Publish a message every second
+            if (publish(&client, &ipstack) != 0) 
+                attemptConnect(&client, &ipstack);   // if we have lost the connection
+            count = 0;
+        }
+        client.yield(10);  // allow the MQTT client to receive messages
+    }
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/lowlevel.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/lowlevel.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - "commonalization" from prior samples and/or documentation extension
+ *******************************************************************************/
+
+#include <sys/types.h>
+
+#if !defined(SOCKET_ERROR)
+	/** error in socket operation */
+	#define SOCKET_ERROR -1
+#endif
+
+#if defined(WIN32)
+/* default on Windows is 64 - increase to make Linux and Windows the same */
+#define FD_SETSIZE 1024
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define MAXHOSTNAMELEN 256
+#define EAGAIN WSAEWOULDBLOCK
+#define EINTR WSAEINTR
+#define EINVAL WSAEINVAL
+#define EINPROGRESS WSAEINPROGRESS
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define ENOTCONN WSAENOTCONN
+#define ECONNRESET WSAECONNRESET
+#define ioctl ioctlsocket
+#define socklen_t int
+#else
+#define INVALID_SOCKET SOCKET_ERROR
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#endif
+
+#if defined(WIN32)
+#include <Iphlpapi.h>
+#else
+#include <sys/ioctl.h>
+#include <net/if.h>
+#endif
+
+/**
+This simple low-level implementation assumes a single connection for a single thread. Thus, a static
+variable is used for that connection.
+On other scenarios, the user must solve this by taking into account that the current implementation of
+MQTTSNPacket_read() has a function pointer for a function call to get the data to a buffer, but no provisions
+to know the caller or other indicator (the socket id): int (*getfn)(unsigned char*, int)
+*/
+static int mysock = INVALID_SOCKET;
+
+int Socket_error(char* aString, int sock)
+{
+#if defined(WIN32)
+	int errno;
+#endif
+
+#if defined(WIN32)
+	errno = WSAGetLastError();
+#endif
+	if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS && errno != EWOULDBLOCK)
+	{
+		if (strcmp(aString, "shutdown") != 0 || (errno != ENOTCONN && errno != ECONNRESET))
+		{
+			int orig_errno = errno;
+			char* errmsg = strerror(errno);
+
+			printf("Socket error %d (%s) in %s for socket %d\n", orig_errno, errmsg, aString, sock);
+		}
+	}
+	return errno;
+}
+
+
+int lowlevel_sendPacketBuffer(char* host, int port, unsigned char* buf, int buflen)
+{
+	struct sockaddr_in cliaddr;
+	int rc = 0;
+
+	memset(&cliaddr, 0, sizeof(cliaddr));
+	cliaddr.sin_family = AF_INET;
+	cliaddr.sin_addr.s_addr = inet_addr(host);
+	cliaddr.sin_port = htons(port);
+
+	if ((rc = sendto(mysock, buf, buflen, 0, (const struct sockaddr*)&cliaddr, sizeof(cliaddr))) == SOCKET_ERROR)
+		Socket_error("sendto", mysock);
+	else
+		rc = 0;
+	return rc;
+}
+
+
+int lowlevel_getdata(unsigned char* buf, int count)
+{
+	int rc = recvfrom(mysock, buf, count, 0, NULL, NULL);
+	//printf("received %d bytes count %d\n", rc, (int)count);
+	return rc;
+}
+
+/**
+return >=0 for a socket descriptor, <0 for an error code
+*/
+int lowlevel_open()
+{
+	mysock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (mysock == INVALID_SOCKET)
+		return Socket_error("socket", mysock);
+
+	return mysock;
+}
+
+int lowlevel_close()
+{
+int rc;
+
+	rc = shutdown(mysock, SHUT_WR);
+	rc = close(mysock);
+
+	return rc;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/lowlevel.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/lowlevel.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - "commonalization" from prior samples and/or documentation extension
+ *******************************************************************************/
+
+int lowlevel_sendPacketBuffer(char* host, int port, unsigned char* buf, int buflen);
+int lowlevel_getdata(unsigned char* buf, int count);
+int lowlevel_open(void);
+int lowlevel_close(void);
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/pub0sub1.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/pub0sub1.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - clarifications and/or documentation extension
+ *
+ * Description:
+ * Normal topic name is automatically registered at subscription, then
+ * a message is published and the node receives it itself
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTSNPacket.h"
+#include "lowlevel.h"
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+	int mysock;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	MQTTSN_topicid topic;
+	unsigned char* payload = (unsigned char*)"mypayload";
+	int payloadlen = strlen((char*)payload);
+	int len = 0;
+	unsigned char dup = 0;
+	int qos = 1;
+	unsigned char retained = 0;
+	short packetid = 1;
+	char *topicname = "a long topic name";
+	char *host = "127.0.0.1";
+	int port = 1883;
+	MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer;
+	unsigned short topicid;
+
+	mysock = lowlevel_open();
+	if(mysock < 0)
+		return mysock;
+
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	options.clientID.cstring = "pub0sub1 MQTT-SN";
+	len = MQTTSNSerialize_connect(buf, buflen, &options);
+	rc = lowlevel_sendPacketBuffer(host, port, buf, len);
+
+	/* wait for connack */
+	if (MQTTSNPacket_read(buf, buflen, lowlevel_getdata) == MQTTSN_CONNACK)
+	{
+		int connack_rc = -1;
+
+		if (MQTTSNDeserialize_connack(&connack_rc, buf, buflen) != 1 || connack_rc != 0)
+		{
+			printf("Unable to connect, return code %d\n", connack_rc);
+			goto exit;
+		}
+		else 
+			printf("connected rc %d\n", connack_rc);
+	}
+	else
+		goto exit;
+
+
+	/* subscribe */
+	printf("Subscribing\n");
+	topic.type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topic.data.long_.name = topicname;
+	topic.data.long_.len = strlen(topic.data.long_.name);
+	len = MQTTSNSerialize_subscribe(buf, buflen, 0, 2, packetid, &topic);
+	rc = lowlevel_sendPacketBuffer(host, port, buf, len);
+
+	if (MQTTSNPacket_read(buf, buflen, lowlevel_getdata) == MQTTSN_SUBACK) 	/* wait for suback */
+	{
+		unsigned short submsgid;
+		int granted_qos;
+		unsigned char returncode;
+
+		rc = MQTTSNDeserialize_suback(&granted_qos, &topicid, &submsgid, &returncode, buf, buflen);
+		if (granted_qos != 2 || returncode != 0)
+		{
+			printf("granted qos != 2, %d return code %d\n", granted_qos, returncode);
+			goto exit;
+		}
+		else
+			printf("suback topic id %d\n", topicid);
+	}
+	else
+		goto exit;
+
+	printf("Publishing\n");
+	/* publish with short name */
+	topic.type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topic.data.id = topicid;
+	++packetid;
+	len = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, packetid,
+			topic, payload, payloadlen);
+	rc = lowlevel_sendPacketBuffer(host, port, buf, len);
+
+	/* wait for puback */
+	if (MQTTSNPacket_read(buf, buflen, lowlevel_getdata) == MQTTSN_PUBACK)
+	{
+		unsigned short packet_id, topic_id;
+		unsigned char returncode;
+
+		if (MQTTSNDeserialize_puback(&topic_id, &packet_id, &returncode, buf, buflen) != 1 || returncode != MQTTSN_RC_ACCEPTED)
+			printf("Unable to publish, return code %d\n", returncode);
+		else 
+			printf("puback received, msgid %d topic id %d\n", packet_id, topic_id);
+	}
+	else
+		goto exit;
+
+	printf("Receive publish\n");
+	if (MQTTSNPacket_read(buf, buflen, lowlevel_getdata) == MQTTSN_PUBLISH)
+	{
+		unsigned short packet_id;
+		int qos, payloadlen;
+		unsigned char* payload;
+		unsigned char dup, retained;
+		MQTTSN_topicid pubtopic;
+
+		if (MQTTSNDeserialize_publish(&dup, &qos, &retained, &packet_id, &pubtopic,
+				&payload, &payloadlen, buf, buflen) != 1)
+			printf("Error deserializing publish\n");
+		else 
+			printf("publish received, id %d qos %d\n", packet_id, qos);
+
+		if (qos == 1)
+		{
+			len = MQTTSNSerialize_puback(buf, buflen, pubtopic.data.id, packet_id, MQTTSN_RC_ACCEPTED);
+			rc = lowlevel_sendPacketBuffer(host, port, buf, len);
+			if (rc == 0)
+				printf("puback sent\n");
+		}
+	}
+	else
+		goto exit;
+
+	len = MQTTSNSerialize_disconnect(buf, buflen, 0);
+	rc = lowlevel_sendPacketBuffer(host, port, buf, len);
+
+exit:
+	lowlevel_close();
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/qos-1pub.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/qos-1pub.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - clarifications and/or documentation extension
+ *
+ * Description:
+ * A qos -1 message can be sent without connecting
+ * Short topic name used to avoid registration process
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTSNPacket.h"
+#include "lowlevel.h"
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+	int mysock;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	MQTTSN_topicid topic;
+	unsigned char* payload = (unsigned char*)"mypayload";
+	int payloadlen = strlen((char*)payload);
+	int len = 0;
+	int dup = 0;
+	int qos = 3;
+	int retained = 0;
+	short packetid = 0;
+	char *host = "127.0.0.1";
+	int port = 1883;
+
+	mysock = lowlevel_open();
+	if(mysock < 0)
+		return mysock;
+
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	/* publish with short name */
+	topic.type = MQTTSN_TOPIC_TYPE_SHORT;
+	memcpy(topic.data.short_name, "tt", 2);
+	len = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, packetid,
+			topic, payload, payloadlen);
+
+	rc = lowlevel_sendPacketBuffer(host, port, buf, len);
+
+	lowlevel_close();
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/qos-1pub_extended.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/qos-1pub_extended.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - clarifications and/or documentation extension
+ *
+ * Description:
+ * Extension to the specs in which a node can send a normal (long) topic name inside the
+ * payload area to avoid the registration process and the usage of short/predefined types
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTSNPacket.h"
+#include "lowlevel.h"
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+	int mysock;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	MQTTSN_topicid topic;
+	unsigned char* payload = (unsigned char*)"mypayload";
+	int payloadlen = strlen((char*)payload);
+	int len = 0;
+	int dup = 0;
+	int qos = 3;
+	int retained = 0;
+	short packetid = 0;
+	char *topicname = "a long topic name";
+	char *host = "127.0.0.1";
+	int port = 1883;
+
+	mysock = lowlevel_open();
+	if(mysock < 0)
+		return mysock;
+
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	topic.type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topic.data.long_.name = topicname;
+	topic.data.long_.len = strlen(topicname);
+
+	len = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, packetid,
+			topic, payload, payloadlen);
+
+	rc = lowlevel_sendPacketBuffer(host, port, buf, len);
+
+	lowlevel_close();
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/qos0pub.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/qos0pub.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - clarifications and/or documentation extension
+ *
+ * Description:
+ * Short topic name used to avoid registration process
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTSNPacket.h"
+#include "lowlevel.h"
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+	int mysock;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	MQTTSN_topicid topic;
+	unsigned char* payload = (unsigned char*)"mypayload";
+	int payloadlen = strlen((char*)payload);
+	int len = 0;
+	int dup = 0;
+	int qos = 0;
+	int retained = 0;
+	short packetid = 0;
+//	char *topicname = "a long topic name";
+	char *host = "127.0.0.1";
+	int port = 1883;
+	MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer;
+
+	mysock = lowlevel_open();
+	if(mysock < 0)
+		return mysock;
+
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	options.clientID.cstring = "myclientid";
+	len = MQTTSNSerialize_connect(buf, buflen, &options);
+	rc = lowlevel_sendPacketBuffer(host, port, buf, len);
+
+	/* wait for connack */
+	if (MQTTSNPacket_read(buf, buflen, lowlevel_getdata) == MQTTSN_CONNACK)
+	{
+		int connack_rc = -1;
+
+		if (MQTTSNDeserialize_connack(&connack_rc, buf, buflen) != 1 || connack_rc != 0)
+		{
+			printf("Unable to connect, return code %d\n", connack_rc);
+			goto exit;
+		}
+		else 
+			printf("connected rc %d\n", connack_rc);
+	}
+	else
+		goto exit;
+
+	 
+	/* publish with short name */
+	topic.type = MQTTSN_TOPIC_TYPE_SHORT;
+	memcpy(topic.data.short_name, "tt", 2);
+	len = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, packetid,
+			topic, payload, payloadlen);
+	rc = lowlevel_sendPacketBuffer(host, port, buf, len);
+
+	printf("rc %d from send packet for publish length %d\n", rc, len);
+
+exit:
+	lowlevel_close();
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/qos0pub_register.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/qos0pub_register.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - clarifications and/or documentation extension
+ *
+ * Description:
+ * Normal topic name used to show registration process
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTSNPacket.h"
+#include "lowlevel.h"
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+	int mysock;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	MQTTSN_topicid topic;
+	MQTTSNString topicstr;
+	unsigned char* payload = (unsigned char*)"mypayload";
+	int payloadlen = strlen((char*)payload);
+	int len = 0;
+	int dup = 0;
+	int qos = 0;
+	int retained = 0;
+	short packetid = 0;
+	char *topicname = "a long topic name";
+	char *host = "127.0.0.1";
+	int port = 1883;
+	MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer;
+	unsigned short topicid;
+
+	mysock = lowlevel_open();
+	if(mysock < 0)
+		return mysock;
+
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	options.clientID.cstring = "myclientid";
+	len = MQTTSNSerialize_connect(buf, buflen, &options);
+	rc = lowlevel_sendPacketBuffer(host, port, buf, len);
+
+	/* wait for connack */
+	if (MQTTSNPacket_read(buf, buflen, lowlevel_getdata) == MQTTSN_CONNACK)
+	{
+		int connack_rc = -1;
+
+		if (MQTTSNDeserialize_connack(&connack_rc, buf, buflen) != 1 || connack_rc != 0)
+		{
+			printf("Unable to connect, return code %d\n", connack_rc);
+			goto exit;
+		}
+		else 
+			printf("connected rc %d\n", connack_rc);
+	}
+	else
+		goto exit;
+
+	/* register topic name */
+	printf("Registering\n");
+	topicstr.cstring = topicname;
+	topicstr.lenstring.len = strlen(topicname);
+	len = MQTTSNSerialize_register(buf, buflen, 0, packetid, &topicstr);
+	rc = lowlevel_sendPacketBuffer(host, port, buf, len);
+
+	if (MQTTSNPacket_read(buf, buflen, lowlevel_getdata) == MQTTSN_REGACK) 	/* wait for regack */
+	{
+		unsigned short submsgid;
+		unsigned char returncode;
+
+		rc = MQTTSNDeserialize_regack(&topicid, &submsgid, &returncode, buf, buflen);
+		if (returncode != 0)
+		{
+			printf("return code %d\n", returncode);
+			goto exit;
+		}
+		else
+			printf("regack topic id %d\n", topicid);
+	}
+	else
+		goto exit;
+
+	/* publish with obtained id */
+	printf("Publishing\n");
+	topic.type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topic.data.id = topicid;
+	++packetid;
+	len = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, packetid,
+			topic, payload, payloadlen);
+	rc = lowlevel_sendPacketBuffer(host, port, buf, len);
+
+	printf("rc %d from send packet for publish length %d\n", rc, len);
+
+exit:
+	lowlevel_close();
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/qos1pub.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/linux/udp/qos1pub.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - clarifications and/or documentation extension
+ *
+ * Description:
+ * Short topic name used to avoid registration process
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTSNPacket.h"
+#include "lowlevel.h"
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+	int mysock;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	MQTTSN_topicid topic;
+	unsigned char* payload = (unsigned char*)"mypayload";
+	int payloadlen = strlen((char*)payload);
+	int len = 0;
+	int dup = 0;
+	int qos = 1;
+	int retained = 0;
+	short packetid = 1;
+	char *host = "127.0.0.1";
+	int port = 1883;
+	MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer;
+
+	mysock = lowlevel_open();
+	if(mysock < 0)
+		return mysock;
+
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	options.clientID.cstring = "myclientid";
+	len = MQTTSNSerialize_connect(buf, buflen, &options);
+	rc = lowlevel_sendPacketBuffer(host, port, buf, len);
+
+	/* wait for connack */
+	if (MQTTSNPacket_read(buf, buflen, lowlevel_getdata) == MQTTSN_CONNACK)
+	{
+		int connack_rc = -1;
+
+		if (MQTTSNDeserialize_connack(&connack_rc, buf, buflen) != 1 || connack_rc != 0)
+		{
+			printf("Unable to connect, return code %d\n", connack_rc);
+			goto exit;
+		}
+		else 
+			printf("connected rc %d\n", connack_rc);
+	}
+	else
+		goto exit;
+
+	/* publish with short name */
+	topic.type = MQTTSN_TOPIC_TYPE_SHORT;
+	memcpy(topic.data.short_name, "tt", 2);
+	len = MQTTSNSerialize_publish(buf, buflen - len, dup, qos, retained, packetid,
+			topic, payload, payloadlen);
+	rc = lowlevel_sendPacketBuffer(host, port, buf, len);
+
+	/* wait for puback */
+	if (MQTTSNPacket_read(buf, buflen, lowlevel_getdata) == MQTTSN_PUBACK)
+	{
+		unsigned short packet_id, topic_id;
+		unsigned char returncode;
+
+		if (MQTTSNDeserialize_puback(&topic_id, &packet_id, &returncode, buf, buflen) != 1 || returncode != MQTTSN_RC_ACCEPTED)
+			printf("Unable to publish, return code %d\n", returncode);
+		else 
+			printf("puback received, id %d\n", packet_id);
+	}
+	else
+		goto exit;
+
+	len = MQTTSNSerialize_disconnect(buf, buflen, 0);
+	rc = lowlevel_sendPacketBuffer(host, port, buf, len);
+
+exit:
+	lowlevel_close();
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/pub0sub1.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/pub0sub1.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - clarifications and/or documentation extension
+ *
+ * Description:
+ * Normal topic name is automatically registered at subscription, then
+ * a message is published and the node receives it itself
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTSNPacket.h"
+#include "transport.h"
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+	int mysock;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	MQTTSN_topicid topic;
+	unsigned char* payload = (unsigned char*)"mypayload";
+	int payloadlen = strlen((char*)payload);
+	int len = 0;
+	unsigned char dup = 0;
+	int qos = 1;
+	unsigned char retained = 0;
+	short packetid = 1;
+	char *topicname = "a long topic name";
+	char *host = "127.0.0.1";
+	int port = 1883;
+	MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer;
+	unsigned short topicid;
+
+	mysock = transport_open();
+	if(mysock < 0)
+		return mysock;
+
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	options.clientID.cstring = "pub0sub1 MQTT-SN";
+	len = MQTTSNSerialize_connect(buf, buflen, &options);
+	rc = transport_sendPacketBuffer(host, port, buf, len);
+
+	/* wait for connack */
+	if (MQTTSNPacket_read(buf, buflen, transport_getdata) == MQTTSN_CONNACK)
+	{
+		int connack_rc = -1;
+
+		if (MQTTSNDeserialize_connack(&connack_rc, buf, buflen) != 1 || connack_rc != 0)
+		{
+			printf("Unable to connect, return code %d\n", connack_rc);
+			goto exit;
+		}
+		else 
+			printf("connected rc %d\n", connack_rc);
+	}
+	else
+		goto exit;
+
+
+	/* subscribe */
+	printf("Subscribing\n");
+	topic.type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topic.data.long_.name = topicname;
+	topic.data.long_.len = strlen(topic.data.long_.name);
+	len = MQTTSNSerialize_subscribe(buf, buflen, 0, 2, packetid, &topic);
+	rc = transport_sendPacketBuffer(host, port, buf, len);
+
+	if (MQTTSNPacket_read(buf, buflen, transport_getdata) == MQTTSN_SUBACK) 	/* wait for suback */
+	{
+		unsigned short submsgid;
+		int granted_qos;
+		unsigned char returncode;
+
+		rc = MQTTSNDeserialize_suback(&granted_qos, &topicid, &submsgid, &returncode, buf, buflen);
+		if (granted_qos != 2 || returncode != 0)
+		{
+			printf("granted qos != 2, %d return code %d\n", granted_qos, returncode);
+			goto exit;
+		}
+		else
+			printf("suback topic id %d\n", topicid);
+	}
+	else
+		goto exit;
+
+	printf("Publishing\n");
+	/* publish with short name */
+	topic.type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topic.data.id = topicid;
+	++packetid;
+	len = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, packetid,
+			topic, payload, payloadlen);
+	rc = transport_sendPacketBuffer(host, port, buf, len);
+
+	/* wait for puback */
+	if (MQTTSNPacket_read(buf, buflen, transport_getdata) == MQTTSN_PUBACK)
+	{
+		unsigned short packet_id, topic_id;
+		unsigned char returncode;
+
+		if (MQTTSNDeserialize_puback(&topic_id, &packet_id, &returncode, buf, buflen) != 1 || returncode != MQTTSN_RC_ACCEPTED)
+			printf("Unable to publish, return code %d\n", returncode);
+		else 
+			printf("puback received, msgid %d topic id %d\n", packet_id, topic_id);
+	}
+	else
+		goto exit;
+
+	printf("Receive publish\n");
+	if (MQTTSNPacket_read(buf, buflen, transport_getdata) == MQTTSN_PUBLISH)
+	{
+		unsigned short packet_id;
+		int qos, payloadlen;
+		unsigned char* payload;
+		unsigned char dup, retained;
+		MQTTSN_topicid pubtopic;
+
+		if (MQTTSNDeserialize_publish(&dup, &qos, &retained, &packet_id, &pubtopic,
+				&payload, &payloadlen, buf, buflen) != 1)
+			printf("Error deserializing publish\n");
+		else 
+			printf("publish received, id %d qos %d\n", packet_id, qos);
+
+		if (qos == 1)
+		{
+			len = MQTTSNSerialize_puback(buf, buflen, pubtopic.data.id, packet_id, MQTTSN_RC_ACCEPTED);
+			rc = transport_sendPacketBuffer(host, port, buf, len);
+			if (rc == 0)
+				printf("puback sent\n");
+		}
+	}
+	else
+		goto exit;
+
+	len = MQTTSNSerialize_disconnect(buf, buflen, 0);
+	rc = transport_sendPacketBuffer(host, port, buf, len);
+
+exit:
+	transport_close();
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/qos-1pub.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/qos-1pub.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - clarifications and/or documentation extension
+ *
+ * Description:
+ * A qos -1 message can be sent without connecting
+ * Short topic name used to avoid registration process
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTSNPacket.h"
+#include "transport.h"
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+	int mysock;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	MQTTSN_topicid topic;
+	unsigned char* payload = (unsigned char*)"mypayload";
+	int payloadlen = strlen((char*)payload);
+	int len = 0;
+	int dup = 0;
+	int qos = 3;
+	int retained = 0;
+	short packetid = 0;
+	char *host = "127.0.0.1";
+	int port = 1883;
+
+	mysock = transport_open();
+	if(mysock < 0)
+		return mysock;
+
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	/* publish with short name */
+	topic.type = MQTTSN_TOPIC_TYPE_SHORT;
+	memcpy(topic.data.short_name, "tt", 2);
+	len = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, packetid,
+			topic, payload, payloadlen);
+
+	rc = transport_sendPacketBuffer(host, port, buf, len);
+
+	transport_close();
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/qos-1pub_extended.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/qos-1pub_extended.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - clarifications and/or documentation extension
+ *
+ * Description:
+ * Extension to the specs in which a node can send a normal (long) topic name inside the
+ * payload area to avoid the registration process and the usage of short/predefined types
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTSNPacket.h"
+#include "transport.h"
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+	int mysock;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	MQTTSN_topicid topic;
+	unsigned char* payload = (unsigned char*)"mypayload";
+	int payloadlen = strlen((char*)payload);
+	int len = 0;
+	int dup = 0;
+	int qos = 3;
+	int retained = 0;
+	short packetid = 0;
+	char *topicname = "a long topic name";
+	char *host = "127.0.0.1";
+	int port = 1883;
+
+	mysock = transport_open();
+	if(mysock < 0)
+		return mysock;
+
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	topic.type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topic.data.long_.name = topicname;
+	topic.data.long_.len = strlen(topicname);
+
+	len = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, packetid,
+			topic, payload, payloadlen);
+
+	rc = transport_sendPacketBuffer(host, port, buf, len);
+
+	transport_close();
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/qos0pub.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/qos0pub.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - clarifications and/or documentation extension
+ *
+ * Description:
+ * Short topic name used to avoid registration process
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTSNPacket.h"
+#include "transport.h"
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+	int mysock;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	MQTTSN_topicid topic;
+	unsigned char* payload = (unsigned char*)"mypayload";
+	int payloadlen = strlen((char*)payload);
+	int len = 0;
+	int dup = 0;
+	int qos = 0;
+	int retained = 0;
+	short packetid = 0;
+//	char *topicname = "a long topic name";
+	char *host = "127.0.0.1";
+	int port = 1883;
+	MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer;
+
+	mysock = transport_open();
+	if(mysock < 0)
+		return mysock;
+
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	options.clientID.cstring = "myclientid";
+	len = MQTTSNSerialize_connect(buf, buflen, &options);
+	rc = transport_sendPacketBuffer(host, port, buf, len);
+
+	/* wait for connack */
+	if (MQTTSNPacket_read(buf, buflen, transport_getdata) == MQTTSN_CONNACK)
+	{
+		int connack_rc = -1;
+
+		if (MQTTSNDeserialize_connack(&connack_rc, buf, buflen) != 1 || connack_rc != 0)
+		{
+			printf("Unable to connect, return code %d\n", connack_rc);
+			goto exit;
+		}
+		else 
+			printf("connected rc %d\n", connack_rc);
+	}
+	else
+		goto exit;
+
+	 
+	/* publish with short name */
+	topic.type = MQTTSN_TOPIC_TYPE_SHORT;
+	memcpy(topic.data.short_name, "tt", 2);
+	len = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, packetid,
+			topic, payload, payloadlen);
+	rc = transport_sendPacketBuffer(host, port, buf, len);
+
+	printf("rc %d from send packet for publish length %d\n", rc, len);
+
+exit:
+	transport_close();
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/qos0pub_register.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/qos0pub_register.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - clarifications and/or documentation extension
+ *
+ * Description:
+ * Normal topic name used to show registration process
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "MQTTSNPacket.h"
+#include "transport.h"
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+	int mysock;
+	unsigned char buf[500];
+	int buflen = sizeof(buf);
+	MQTTSN_topicid topic;
+	MQTTSNString topicstr;
+	int len = 0;
+	int retained = 0;
+	char *topicname = "iot-2/evt/status/fmt/json";
+	char *host = "127.0.0.1";
+	int port = 20000;
+	MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer;
+	unsigned short topicid;
+
+	mysock = transport_open();
+	if(mysock < 0)
+		return mysock;
+
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	options.clientID.cstring = "d:quickstart:udptest:9002f7f1ad23";
+	len = MQTTSNSerialize_connect(buf, buflen, &options);
+	rc = transport_sendPacketBuffer(host, port, buf, len);
+
+	/* wait for connack */
+	if (MQTTSNPacket_read(buf, buflen, transport_getdata) == MQTTSN_CONNACK)
+	{
+		int connack_rc = -1;
+
+		if (MQTTSNDeserialize_connack(&connack_rc, buf, buflen) != 1 || connack_rc != 0)
+		{
+			printf("Unable to connect, return code %d\n", connack_rc);
+			goto exit;
+		}
+		else 
+			printf("connected rc %d\n", connack_rc);
+	}
+	else
+	{
+		printf("could not connect to gateway\n");
+		goto exit;
+	}
+
+	/* register topic name */
+	printf("Registering\n");
+	int packetid = 1;
+	topicstr.cstring = topicname;
+	topicstr.lenstring.len = strlen(topicname);
+	len = MQTTSNSerialize_register(buf, buflen, 0, packetid, &topicstr);
+	rc = transport_sendPacketBuffer(host, port, buf, len);
+
+	if (MQTTSNPacket_read(buf, buflen, transport_getdata) == MQTTSN_REGACK) 	/* wait for regack */
+	{
+		unsigned short submsgid;
+		unsigned char returncode;
+
+		rc = MQTTSNDeserialize_regack(&topicid, &submsgid, &returncode, buf, buflen);
+		if (returncode != 0)
+		{
+			printf("return code %d\n", returncode);
+			goto exit;
+		}
+		else
+			printf("regack topic id %d\n", topicid);
+	}
+	else
+		goto exit;
+
+    while (1)
+    {
+        if (1)
+        {               
+			/* publish with obtained id */
+			printf("Publishing\n");
+			topic.type = MQTTSN_TOPIC_TYPE_NORMAL;
+			topic.data.id = topicid;
+			static const char* joypos[] = {"SN-LEFT", "SN-RIGHT", "SN-CENTRE", "SN-UP", "SN-DOWN"};
+
+		   	unsigned char payload[250];
+    		int payloadlen = sprintf((char*)payload,
+     "{\"d\":{\"myName\":\"IoT mbed\",\"accelX\":%0.4f,\"accelY\":%0.4f,\"accelZ\":%0.4f,\"temp\":%0.4f,\"joystick\":\"%s\",\"potentiometer1\":%0.4f,\"potentiometer2\":%0.4f}}",
+			(rand() % 10) * 2.0, (rand() % 10) * 2.0, (rand() % 10) * 2.0, (rand() % 10) + 18.0, joypos[rand() % 5], (rand() % 10) * 30.0, (rand() % 10) * 30.0); 
+			len = MQTTSNSerialize_publish(buf, buflen, 0, 0, retained, 0, topic, payload, payloadlen);
+			rc = transport_sendPacketBuffer(host, port, buf, len);
+
+			printf("rc %d from send packet for publish length %d\n", rc, len);
+        }
+        sleep(1);  // Publish a message every second
+	}
+exit:
+	transport_close();
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/qos1pub.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/qos1pub.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - clarifications and/or documentation extension
+ *
+ * Description:
+ * Short topic name used to avoid registration process
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTSNPacket.h"
+#include "transport.h"
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+	int mysock;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	MQTTSN_topicid topic;
+	unsigned char* payload = (unsigned char*)"mypayload";
+	int payloadlen = strlen((char*)payload);
+	int len = 0;
+	int dup = 0;
+	int qos = 1;
+	int retained = 0;
+	short packetid = 1;
+	char *host = "127.0.0.1";
+	int port = 1883;
+	MQTTSNPacket_connectData options = MQTTSNPacket_connectData_initializer;
+
+	mysock = transport_open();
+	if(mysock < 0)
+		return mysock;
+
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	options.clientID.cstring = "myclientid";
+	len = MQTTSNSerialize_connect(buf, buflen, &options);
+	rc = transport_sendPacketBuffer(host, port, buf, len);
+
+	/* wait for connack */
+	if (MQTTSNPacket_read(buf, buflen, transport_getdata) == MQTTSN_CONNACK)
+	{
+		int connack_rc = -1;
+
+		if (MQTTSNDeserialize_connack(&connack_rc, buf, buflen) != 1 || connack_rc != 0)
+		{
+			printf("Unable to connect, return code %d\n", connack_rc);
+			goto exit;
+		}
+		else 
+			printf("connected rc %d\n", connack_rc);
+	}
+	else
+		goto exit;
+
+	/* publish with short name */
+	topic.type = MQTTSN_TOPIC_TYPE_SHORT;
+	memcpy(topic.data.short_name, "tt", 2);
+	len = MQTTSNSerialize_publish(buf, buflen - len, dup, qos, retained, packetid,
+			topic, payload, payloadlen);
+	rc = transport_sendPacketBuffer(host, port, buf, len);
+
+	/* wait for puback */
+	if (MQTTSNPacket_read(buf, buflen, transport_getdata) == MQTTSN_PUBACK)
+	{
+		unsigned short packet_id, topic_id;
+		unsigned char returncode;
+
+		if (MQTTSNDeserialize_puback(&topic_id, &packet_id, &returncode, buf, buflen) != 1 || returncode != MQTTSN_RC_ACCEPTED)
+			printf("Unable to publish, return code %d\n", returncode);
+		else 
+			printf("puback received, id %d\n", packet_id);
+	}
+	else
+		goto exit;
+
+	len = MQTTSNSerialize_disconnect(buf, buflen, 0);
+	rc = transport_sendPacketBuffer(host, port, buf, len);
+
+exit:
+	transport_close();
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/transport.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/transport.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - "commonalization" from prior samples and/or documentation extension
+ *******************************************************************************/
+
+#include <sys/types.h>
+
+#if !defined(SOCKET_ERROR)
+	/** error in socket operation */
+	#define SOCKET_ERROR -1
+#endif
+
+#if defined(WIN32)
+/* default on Windows is 64 - increase to make Linux and Windows the same */
+#define FD_SETSIZE 1024
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define MAXHOSTNAMELEN 256
+#define EAGAIN WSAEWOULDBLOCK
+#define EINTR WSAEINTR
+#define EINVAL WSAEINVAL
+#define EINPROGRESS WSAEINPROGRESS
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define ENOTCONN WSAENOTCONN
+#define ECONNRESET WSAECONNRESET
+#define ioctl ioctlsocket
+#define socklen_t int
+#else
+#define INVALID_SOCKET SOCKET_ERROR
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#endif
+
+#if defined(WIN32)
+#include <Iphlpapi.h>
+#else
+#include <sys/ioctl.h>
+#include <net/if.h>
+#endif
+
+/**
+This simple low-level implementation assumes a single connection for a single thread. Thus, a static
+variable is used for that connection.
+On other scenarios, the user must solve this by taking into account that the current implementation of
+MQTTSNPacket_read() has a function pointer for a function call to get the data to a buffer, but no provisions
+to know the caller or other indicator (the socket id): int (*getfn)(unsigned char*, int)
+*/
+static int mysock = INVALID_SOCKET;
+
+int Socket_error(char* aString, int sock)
+{
+#if defined(WIN32)
+	int errno;
+#endif
+
+#if defined(WIN32)
+	errno = WSAGetLastError();
+#endif
+	if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS && errno != EWOULDBLOCK)
+	{
+		if (strcmp(aString, "shutdown") != 0 || (errno != ENOTCONN && errno != ECONNRESET))
+		{
+			int orig_errno = errno;
+			char* errmsg = strerror(errno);
+
+			printf("Socket error %d (%s) in %s for socket %d\n", orig_errno, errmsg, aString, sock);
+		}
+	}
+	return errno;
+}
+
+
+int transport_sendPacketBuffer(char* host, int port, unsigned char* buf, int buflen)
+{
+	struct sockaddr_in cliaddr;
+	int rc = 0;
+
+	memset(&cliaddr, 0, sizeof(cliaddr));
+	cliaddr.sin_family = AF_INET;
+	cliaddr.sin_addr.s_addr = inet_addr(host);
+	cliaddr.sin_port = htons(port);
+
+	if ((rc = sendto(mysock, buf, buflen, 0, (const struct sockaddr*)&cliaddr, sizeof(cliaddr))) == SOCKET_ERROR)
+		Socket_error("sendto", mysock);
+	else
+		rc = 0;
+	return rc;
+}
+
+
+int transport_getdata(unsigned char* buf, int count)
+{
+	int rc = recvfrom(mysock, buf, count, 0, NULL, NULL);
+	//printf("received %d bytes count %d\n", rc, (int)count);
+	return rc;
+}
+
+/**
+return >=0 for a socket descriptor, <0 for an error code
+*/
+int transport_open()
+{
+	mysock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (mysock == INVALID_SOCKET)
+		return Socket_error("socket", mysock);
+
+	return mysock;
+}
+
+int transport_close()
+{
+int rc;
+
+	rc = shutdown(mysock, SHUT_WR);
+	rc = close(mysock);
+
+	return rc;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/transport.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/samples/transport.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - "commonalization" from prior samples and/or documentation extension
+ *******************************************************************************/
+
+int transport_sendPacketBuffer(char* host, int port, unsigned char* buf, int buflen);
+int transport_getdata(unsigned char* buf, int count);
+int transport_open(void);
+int transport_close(void);
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,24 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+
+PROJECT(mqtt-sn-packet C)
+
+ADD_LIBRARY(MQTTSNPacketClient SHARED MQTTSNConnectClient.c MQTTSNPacket.c MQTTSNSearchClient.c MQTTSNSubscribeClient.c
+            MQTTSNUnsubscribeClient.c MQTTSNSerializePublish.c MQTTSNDeserializePublish.c)
+
+ADD_LIBRARY(MQTTSNPacketServer SHARED MQTTSNConnectServer.c MQTTSNPacket.c MQTTSNSearchServer.c MQTTSNSubscribeServer.c
+            MQTTSNUnsubscribeServer.c MQTTSNSerializePublish.c MQTTSNDeserializePublish.c)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNConnect.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNConnect.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#ifndef MQTTSNCONNECT_H_
+#define MQTTSNCONNECT_H_
+
+typedef struct
+{
+	/** The eyecatcher for this structure.  must be MQSC. */
+	char struct_id[4];
+	/** The version number of this structure.  Must be 0.
+	  */
+	int struct_version;
+	MQTTSNString clientID;
+	unsigned short duration;
+	unsigned char cleansession;
+	unsigned char willFlag;
+} MQTTSNPacket_connectData;
+
+#define MQTTSNPacket_connectData_initializer { {'M', 'Q', 'S', 'C'}, 0, {NULL, {0, NULL}}, 10, 1, 0 }
+
+int MQTTSNSerialize_connect(unsigned char* buf, int buflen, MQTTSNPacket_connectData* options);
+int MQTTSNDeserialize_connect(MQTTSNPacket_connectData* data, unsigned char* buf, int len);
+
+int MQTTSNSerialize_connack(unsigned char* buf, int buflen, int connack_rc);
+int MQTTSNDeserialize_connack(int* connack_rc, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_disconnect(unsigned char* buf, int buflen, int duration);
+int MQTTSNDeserialize_disconnect(int* duration, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_pingreq(unsigned char* buf, int buflen, MQTTSNString clientid);
+int MQTTSNDeserialize_pingreq(MQTTSNString* clientID, unsigned char* buf, int len);
+
+int MQTTSNSerialize_pingresp(unsigned char* buf, int buflen);
+int MQTTSNDeserialize_pingresp(unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willmsg(unsigned char* buf, int buflen, MQTTSNString willMsg);
+int MQTTSNDeserialize_willmsg(MQTTSNString* willMsg, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willmsgreq(unsigned char* buf, int buflen);
+int MQTTSNDeserialize_willmsgreq(unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willmsgupd(unsigned char* buf, int buflen, MQTTSNString willMsg);
+int MQTTSNDeserialize_willmsgupd(MQTTSNString* willMsg, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willmsgresp(unsigned char* buf, int buflen, int resp_rc);
+int MQTTSNDeserialize_willmsgresp(int* resp_rc, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willtopic(unsigned char* buf, int buflen, int willQoS, unsigned char willRetain, MQTTSNString willTopic);
+int MQTTSNDeserialize_willtopic(int* willQoS, unsigned char* willRetain, MQTTSNString* willTopic, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willtopicreq(unsigned char* buf, int buflen);
+int MQTTSNDeserialize_willtopicreq(unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willtopicupd(unsigned char* buf, int buflen, int willQoS, unsigned char willRetain, MQTTSNString willTopic);
+int MQTTSNDeserialize_willtopicupd(int *willQoS, unsigned char *willRetain, MQTTSNString* willTopic, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_willtopicresp(unsigned char* buf, int buflen, int resp_rc);
+int MQTTSNDeserialize_willtopicresp(int* resp_rc, unsigned char* buf, int buflen);
+
+#endif /* MQTTSNCONNECT_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNConnectClient.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNConnectClient.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,477 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2015 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Nicholas Humfrey - Reformatting to make more consistent; bug 453862
+ *******************************************************************************/
+
+#include "MQTTSNPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+
+/**
+  * Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
+  * @param options the options to be used to build the connect packet
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int MQTTSNSerialize_connectLength(MQTTSNPacket_connectData* options)
+{
+	int len = 0;
+
+	FUNC_ENTRY;
+	len = 5 + MQTTSNstrlen(options->clientID);
+	FUNC_EXIT_RC(len);
+	return len;
+}
+
+
+/**
+  * Serializes the connect options into the buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param len the length in bytes of the supplied buffer
+  * @param options the options to be used to build the connect packet
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_connect(unsigned char* buf, int buflen, MQTTSNPacket_connectData* options)
+{
+	unsigned char *ptr = buf;
+	MQTTSNFlags flags;
+	int len = 0;
+	int rc = -1;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(MQTTSNSerialize_connectLength(options))) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, MQTTSN_CONNECT);      /* write message type */
+
+	flags.all = 0;
+	flags.bits.cleanSession = options->cleansession;
+	flags.bits.will = options->willFlag;
+	writeChar(&ptr, flags.all);
+	writeChar(&ptr, 0x01);                 /* protocol ID */
+	writeInt(&ptr, options->duration);
+	writeMQTTSNString(&ptr, options->clientID);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into connack data - return code
+  * @param connack_rc returned integer value of the connack return code
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_connack(int* connack_rc, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen;
+
+	FUNC_ENTRY;
+	curdata += (rc = MQTTSNPacket_decode(curdata, buflen, &mylen)); /* read length */
+	enddata = buf + mylen;
+	if (enddata - buf < 3)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_CONNACK)
+		goto exit;
+
+	*connack_rc = readChar(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Determines the length of the MQTT disconnect packet (without length field)
+  * @param duration the parameter used for the disconnect
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int MQTTSNSerialize_disconnectLength(int duration)
+{
+	int len = 0;
+
+	FUNC_ENTRY;
+	len = (duration > 0) ? 3 : 1;
+	FUNC_EXIT_RC(len);
+	return len;
+}
+
+
+/**
+  * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer, to avoid overruns
+  * @param duration optional duration, not added to packet if < 0
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_disconnect(unsigned char* buf, int buflen, int duration)
+{
+	int rc = -1;
+	unsigned char *ptr = buf;
+	int len = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(MQTTSNSerialize_disconnectLength(duration))) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, MQTTSN_DISCONNECT);      /* write message type */
+
+	if (duration > 0)
+		writeInt(&ptr, duration);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer, to avoid overruns
+  * @param clientid optional string, not added to packet string == NULL
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_pingreq(unsigned char* buf, int buflen, MQTTSNString clientid)
+{
+	int rc = -1;
+	unsigned char *ptr = buf;
+	int len = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(MQTTSNstrlen(clientid) + 1)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, MQTTSN_PINGREQ);      /* write message type */
+
+	writeMQTTSNString(&ptr, clientid);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_pingresp(unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata < 1)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_PINGRESP)
+		goto exit;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a willtopic or willtopicupd packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param len the length in bytes of the supplied buffer
+  * @param willQoS the qos of the will message
+  * @param willRetain the retained flag of the will message
+  * @param willTopic the topic of the will message
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willtopic1(unsigned char* buf, int buflen, int willQoS, unsigned char willRetain, MQTTSNString willTopic,
+		enum MQTTSN_msgTypes packet_type)
+{
+	unsigned char *ptr = buf;
+	MQTTSNFlags flags;
+	int len = 0;
+	int rc = -1;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(MQTTSNstrlen(willTopic) + 2)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, packet_type);      /* write message type */
+
+	flags.all = 0;
+	flags.bits.QoS = willQoS;
+	flags.bits.retain = willRetain;
+	writeChar(&ptr, flags.all);
+
+	writeMQTTSNString(&ptr, willTopic);
+
+	rc = ptr - buf;
+
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a willtopicupd packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param len the length in bytes of the supplied buffer
+  * @param willQoS the qos of the will message
+  * @param willRetain the retained flag of the will message
+  * @param willTopic the topic of the will message
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willtopicupd(unsigned char* buf, int buflen, int willQoS, unsigned char willRetain, MQTTSNString willTopic)
+{
+	return MQTTSNSerialize_willtopic1(buf, buflen, willQoS, willRetain, willTopic, MQTTSN_WILLTOPICUPD);
+}
+
+
+/**
+  * Serializes a willtopic packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param len the length in bytes of the supplied buffer
+  * @param willQoS the qos of the will message
+  * @param willRetain the retained flag of the will message
+  * @param willTopic the topic of the will message
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willtopic(unsigned char* buf, int buflen, int willQoS, unsigned char willRetain, MQTTSNString willTopic)
+{
+	return MQTTSNSerialize_willtopic1(buf, buflen, willQoS, willRetain, willTopic, MQTTSN_WILLTOPIC);
+}
+
+
+/**
+  * Serializes a willmsg or willmsgupd packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param willMsg the will message
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willmsg1(unsigned char* buf, int buflen, MQTTSNString willMsg, enum MQTTSN_msgTypes packet_type)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = -1;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(MQTTSNstrlen(willMsg) + 1)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, packet_type);      /* write message type */
+
+	writeMQTTSNString(&ptr, willMsg);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a willmsg packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param len the length in bytes of the supplied buffersage
+  * @param willMsg the will message
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willmsg(unsigned char* buf, int buflen, MQTTSNString willMsg)
+{
+	return MQTTSNSerialize_willmsg1(buf, buflen, willMsg, MQTTSN_WILLMSG);
+}
+
+
+/**
+  * Serializes a willmsgupd packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param len the length in bytes of the supplied buffersage
+  * @param willMsg the will message
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willmsgupd(unsigned char* buf, int buflen, MQTTSNString willMsg)
+{
+	return MQTTSNSerialize_willmsg1(buf, buflen, willMsg, MQTTSN_WILLMSGUPD);
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_willtopicreq(unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = -1;
+	int mylen;
+
+	FUNC_ENTRY;
+	if (MQTTSNPacket_decode(curdata++, buflen, &mylen) != 1) /* read length */
+		goto exit;
+	if (mylen > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	enddata = buf + mylen;
+	if (enddata - curdata < 1)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_WILLTOPICREQ)
+		goto exit;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_willmsgreq(unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = -1;
+	int mylen;
+
+	FUNC_ENTRY;
+	if (MQTTSNPacket_decode(curdata++, buflen, &mylen) != 1) /* read length */
+		goto exit;
+	if (mylen > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	enddata = buf + mylen;
+	if (enddata - curdata < 1)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_WILLMSGREQ)
+		goto exit;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into willtopicresp data - return code
+  * @param connack_rc returned integer value of the return code
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_willtopicresp(int* resp_rc, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - buf < 3)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_WILLTOPICRESP)
+		goto exit;
+
+	*resp_rc = readChar(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into willmsgresp data - return code
+  * @param connack_rc returned integer value of the return code
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_willmsgresp(int* resp_rc, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - buf < 3)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_WILLMSGRESP)
+		goto exit;
+
+	*resp_rc = readChar(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNConnectServer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNConnectServer.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,430 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTSNPacket.h"
+#include <string.h>
+
+#define min(a, b) ((a < b) ? 1 : 0)
+
+
+/**
+  * Deserializes the supplied (wire) buffer into connect data structure
+  * @param data the connect data structure to be filled out
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_connect(MQTTSNPacket_connectData* data, unsigned char* buf, int len)
+{
+	MQTTSNFlags flags;
+	unsigned char* curdata = buf;
+	unsigned char* enddata = &buf[len];
+	int rc = 0;
+	int version;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, len, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata < 2)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_CONNECT)
+		goto exit;
+
+	flags.all = readChar(&curdata);
+	data->cleansession = flags.bits.cleanSession;
+	data->willFlag = flags.bits.will;
+
+	if ((version = (int)readChar(&curdata)) != MQTTSN_PROTOCOL_VERSION)
+		goto exit;
+
+	data->duration = readInt(&curdata);
+
+	if (!readMQTTSNString(&data->clientID, &curdata, enddata))
+		goto exit;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes the connack packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param connack_rc the integer connack return code to be used 
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_connack(unsigned char* buf, int buflen, int connack_rc)
+{
+	int rc = 0;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 3)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	ptr += MQTTSNPacket_encode(ptr, 3); /* write length */
+	writeChar(&ptr, MQTTSN_CONNACK);
+	writeChar(&ptr, connack_rc);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into disconnect data - optional duration
+  * @param duration returned integer value of the duration field, -1 if no duration was specified
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_disconnect(int* duration, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = -1;
+	int mylen;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata < 1)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_DISCONNECT)
+		goto exit;
+
+	if (enddata - curdata == 2)
+		*duration = readInt(&curdata);
+	else if (enddata != curdata)
+		goto exit;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a willtopicreq packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willtopicreq(unsigned char* buf, int buflen)
+{
+	int rc = 0;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 2)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	ptr += MQTTSNPacket_encode(ptr, 2); /* write length */
+	writeChar(&ptr, MQTTSN_WILLTOPICREQ);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a willmsgreq packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willmsgreq(unsigned char* buf, int buflen)
+{
+	int rc = 0;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 2)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	ptr += MQTTSNPacket_encode(ptr, 2); /* write length */
+	writeChar(&ptr, MQTTSN_WILLMSGREQ);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+
+/**
+  * Deserializes the supplied (wire) buffer into pingreq data
+  * @param clientID the connect data structure to be filled out
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_pingreq(MQTTSNString* clientID, unsigned char* buf, int len)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = &buf[len];
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, len, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata < 1)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_PINGREQ)
+		goto exit;
+
+	if (!readMQTTSNString(clientID, &curdata, enddata))
+		goto exit;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a pingresp packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_pingresp(unsigned char* buf, int buflen)
+{
+	int rc = 0;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 2)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	ptr += MQTTSNPacket_encode(ptr, 2); /* write length */
+	writeChar(&ptr, MQTTSN_PINGRESP);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into willtopic or willtopicupd data structure
+  * @param data the connect data structure to be filled out
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_willtopic1(int *willQoS, unsigned char *willRetain, MQTTSNString* willTopic, unsigned char* buf, int len,
+		enum MQTTSN_msgTypes packet_type)
+{
+	MQTTSNFlags flags;
+	unsigned char* curdata = buf;
+	unsigned char* enddata = &buf[len];
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, len, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata > buf + len)
+		goto exit;
+
+	if (readChar(&curdata) != packet_type)
+		goto exit;
+
+	flags.all = readChar(&curdata);
+	*willQoS = flags.bits.QoS;
+	*willRetain = flags.bits.retain;
+
+	if (!readMQTTSNString(willTopic, &curdata, enddata))
+		goto exit;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into willtopic data structure
+  * @param data the connect data structure to be filled out
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_willtopic(int *willQoS, unsigned char *willRetain, MQTTSNString* willTopic, unsigned char* buf, int len)
+{
+	return MQTTSNDeserialize_willtopic1(willQoS, willRetain, willTopic, buf, len, MQTTSN_WILLTOPIC);
+}
+
+/**
+  * Deserializes the supplied (wire) buffer into willtopic data structure
+  * @param data the connect data structure to be filled out
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_willtopicupd(int *willQoS, unsigned char *willRetain, MQTTSNString* willTopic, unsigned char* buf, int len)
+{
+	return MQTTSNDeserialize_willtopic1(willQoS, willRetain, willTopic, buf, len, MQTTSN_WILLTOPICUPD);
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into willmsg or willmsgupd data
+  * @param willMsg the will message to be retrieved
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_willmsg1(MQTTSNString* willMsg, unsigned char* buf, int len, enum MQTTSN_msgTypes packet_type)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = &buf[len];
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, len, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata > buf + len)
+		goto exit;
+
+	if (readChar(&curdata) != packet_type)
+		goto exit;
+
+	if (!readMQTTSNString(willMsg, &curdata, enddata))
+		goto exit;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into willmsg data
+  * @param willMsg the will message to be retrieved
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_willmsg(MQTTSNString* willMsg, unsigned char* buf, int len)
+{
+	return MQTTSNDeserialize_willmsg1(willMsg, buf, len, MQTTSN_WILLMSG);
+}
+
+/**
+  * Deserializes the supplied (wire) buffer into willmsgupd data
+  * @param willMsg the will message to be retrieved
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_willmsgupd(MQTTSNString* willMsg, unsigned char* buf, int len)
+{
+	return MQTTSNDeserialize_willmsg1(willMsg, buf, len, MQTTSN_WILLMSGUPD);
+}
+
+
+/**
+  * Serializes the willtopicresp packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param rc the integer return code to be used
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willtopicresp(unsigned char* buf, int buflen, int resp_rc)
+{
+	int rc = 0;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 3)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	ptr += MQTTSNPacket_encode(ptr, 3); /* write length */
+	writeChar(&ptr, MQTTSN_WILLTOPICRESP);
+	writeChar(&ptr, resp_rc);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes the willmsgresp packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param rc the integer return code to be used
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_willmsgresp(unsigned char* buf, int buflen, int resp_rc)
+{
+	int rc = 0;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 3)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	ptr += MQTTSNPacket_encode(ptr, 3); /* write length */
+	writeChar(&ptr, MQTTSN_WILLMSGRESP);
+	writeChar(&ptr, resp_rc);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNDeserializePublish.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNDeserializePublish.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,225 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTSNPacket.h"
+#include <string.h>
+
+#define min(a, b) ((a < b) ? 1 : 0)
+
+/**
+  * Deserializes the supplied (wire) buffer into publish data
+  * @param dup returned integer - the MQTT dup flag
+  * @param qos returned integer - the MQTT QoS value
+  * @param retained returned integer - the MQTT retained flag
+  * @param packetid returned integer - the MQTT packet identifier
+  * @param topicName returned MQTTSNString - the MQTT topic in the publish
+  * @param payload returned byte buffer - the MQTT publish payload
+  * @param payloadlen returned integer - the length of the MQTT payload
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success
+  */
+int MQTTSNDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTSN_topicid* topic,
+		unsigned char** payload, int* payloadlen, unsigned char* buf, int buflen)
+{
+	MQTTSNFlags flags;
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_PUBLISH)
+		goto exit;
+
+	flags.all = readChar(&curdata);
+	*dup = flags.bits.dup;
+	*qos = flags.bits.QoS;
+	*retained = flags.bits.retain;
+
+	topic->type = (MQTTSN_topicTypes)flags.bits.topicIdType;
+	if (topic->type == MQTTSN_TOPIC_TYPE_NORMAL && *qos == 3)
+	{
+		/* special arrangement for long topic names in QoS -1 publishes.  The length of the topic is in the topicid field */
+		topic->data.long_.len = readInt(&curdata);
+	}
+	else if (topic->type == MQTTSN_TOPIC_TYPE_NORMAL || topic->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		topic->data.id = readInt(&curdata);
+	else
+	{
+		topic->data.short_name[0] = readChar(&curdata);
+		topic->data.short_name[1] = readChar(&curdata);
+	}
+	*packetid = readInt(&curdata);
+
+	if (topic->type == MQTTSN_TOPIC_TYPE_NORMAL && *qos == 3)
+	{
+		topic->data.long_.name = (char*)curdata;
+		curdata += topic->data.long_.len;
+	}
+
+	*payloadlen = enddata - curdata;
+	*payload = curdata;
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+int MQTTSNDeserialize_puback(unsigned short* topicid, unsigned short* packetid,
+		unsigned char* returncode, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_PUBACK)
+		goto exit;
+
+	*topicid = readInt(&curdata);
+	*packetid = readInt(&curdata);
+	*returncode = readChar(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into an ack
+  * @param packettype returned integer - the MQTT packet type
+  * @param packetid returned integer - the MQTT packet identifier
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTSNDeserialize_ack(unsigned char* type, unsigned short* packetid, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	*type = readChar(&curdata);
+	if (*type != MQTTSN_PUBREL && *type != MQTTSN_PUBREC && *type != MQTTSN_PUBCOMP)
+		goto exit;
+
+	*packetid = readInt(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into register data
+  * @param topicid returned topic id
+  * @param packetid returned integer - the MQTT packet identifier
+  * @param topicName returned MQTTSNString - the MQTT topic in the register
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success
+  */
+int MQTTSNDeserialize_register(unsigned short* topicid, unsigned short* packetid, MQTTSNString* topicname,
+		unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_REGISTER)
+		goto exit;
+
+	*topicid = readInt(&curdata);
+	*packetid = readInt(&curdata);
+
+	topicname->lenstring.data = (char*)curdata;
+	topicname->lenstring.len = enddata - curdata;
+	topicname->cstring = NULL;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into register data
+  * @param topicid returned topic id
+  * @param packetid returned integer - the MQTT packet identifier
+  * @param return_code returned integer return code
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success
+  */
+int MQTTSNDeserialize_regack(unsigned short* topicid, unsigned short* packetid, unsigned char* return_code,
+		unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_REGACK)
+		goto exit;
+
+	*topicid = readInt(&curdata);
+	*packetid = readInt(&curdata);
+	*return_code = readChar(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNPacket.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNPacket.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,311 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTSNPacket.h"
+
+#include <string.h>
+
+static const char* packet_names[] =
+{
+		"ADVERTISE", "SEARCHGW", "GWINFO", "RESERVED", "CONNECT", "CONNACK",
+		"WILLTOPICREQ", "WILLTOPIC", "WILLMSGREQ", "WILLMSG", "REGISTER", "REGACK",
+		"PUBLISH", "PUBACK", "PUBCOMP", "PUBREC", "PUBREL", "RESERVED",
+		"SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", "PINGREQ", "PINGRESP",
+		"DISCONNECT", "RESERVED", "WILLTOPICUPD", "WILLTOPICRESP", "WILLMSGUPD",
+		"WILLMSGRESP"
+};
+
+static const char* encapsulation_packet_name = "ENCAPSULATED";
+
+/**
+ * Returns a character string representing the packet name given a MsgType code
+ * @param code MsgType code
+ * @return the corresponding packet name
+ */
+const char* MQTTSNPacket_name(int code)
+{
+    if ( code == MQTTSN_ENCAPSULATED )
+    {
+        return encapsulation_packet_name;
+    }
+	return (code >= 0 && code <= MQTTSN_WILLMSGRESP) ? packet_names[code] : "UNKNOWN";
+}
+
+
+/**
+ * Calculates the full packet length including length field
+ * @param length the length of the MQTT-SN packet without the length field
+ * @return the total length of the MQTT-SN packet including the length field
+ */
+int MQTTSNPacket_len(int length)
+{
+	return (length > 255) ? length + 3 : length + 1;
+}
+
+/**
+ * Encodes the MQTT-SN message length
+ * @param buf the buffer into which the encoded data is written
+ * @param length the length to be encoded
+ * @return the number of bytes written to the buffer
+ */
+int MQTTSNPacket_encode(unsigned char* buf, int length)
+{
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if (length > 255)
+	{
+		writeChar(&buf, 0x01);
+		writeInt(&buf, length);
+		rc += 3;
+	}
+	else
+		buf[rc++] = length;
+
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+ * Obtains the MQTT-SN packet length from received data
+ * @param getcharfn pointer to function to read the next character from the data source
+ * @param value the decoded length returned
+ * @return the number of bytes read from the socket
+ */
+int MQTTSNPacket_decode(unsigned char* buf, int buflen, int* value)
+{
+	int len = MQTTSNPACKET_READ_ERROR;
+#define MAX_NO_OF_LENGTH_BYTES 3
+
+	FUNC_ENTRY;
+	if (buflen <= 0)
+		goto exit;
+
+	if (buf[0] == 1)
+	{
+		unsigned char* bufptr = &buf[1];
+		if (buflen < MAX_NO_OF_LENGTH_BYTES)
+			goto exit;
+		*value = readInt(&bufptr);
+		len = 3;
+	}
+	else
+	{
+		*value = buf[0];
+		len = 1;
+	}
+exit:
+	FUNC_EXIT_RC(len);
+	return len;
+}
+
+/**
+ * Check if two MQTT-SN topics are equal. Long names are not checked.
+ * @param a pointer to first topic
+ * @param b pointer to second topic
+ * @return boolean true if topics are equal and flase otherwise
+ */
+int MQTTSNTopic_equals(const MQTTSN_topicid* const a, const MQTTSN_topicid* const b)
+{
+    if ((a->type == b->type)
+            && (a->data.id == b->data.id)
+            && (a->data.short_name[0] == b->data.short_name[0])
+            && (a->data.short_name[1] == b->data.short_name[1])) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+#if 0 // Those are already defined in MQTTPacket.c
+/**
+ * Calculates an integer from two bytes read from the input buffer
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the integer value calculated
+ */
+int readInt(unsigned char** pptr)
+{
+	unsigned char* ptr = *pptr;
+	int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
+	*pptr += 2;
+	return len;
+}
+
+
+/**
+ * Reads one character from the input buffer.
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the character read
+ */
+char readChar(unsigned char** pptr)
+{
+	char c = **pptr;
+	(*pptr)++;
+	return c;
+}
+
+
+/**
+ * Writes one character to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param c the character to write
+ */
+void writeChar(unsigned char** pptr, char c)
+{
+	**pptr = (unsigned char)c;
+	(*pptr)++;
+}
+
+
+/**
+ * Writes an integer as 2 bytes to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param anInt the integer to write: 0 to 65535
+ */
+void writeInt(unsigned char** pptr, int anInt)
+{
+	**pptr = (unsigned char)(anInt / 256);
+	(*pptr)++;
+	**pptr = (unsigned char)(anInt % 256);
+	(*pptr)++;
+}
+
+
+/**
+ * Writes a "UTF" string to an output buffer.  Converts C string to length-delimited.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param string the C string to write
+ */
+void writeCString(unsigned char** pptr, char* string)
+{
+	int len = strlen(string);
+	memcpy(*pptr, string, len);
+	*pptr += len;
+}
+
+
+int getLenStringLen(char* ptr)
+{
+	int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
+	return len;
+}
+#endif
+
+void writeMQTTSNString(unsigned char** pptr, MQTTSNString MQTTSNString)
+{
+	if (MQTTSNString.lenstring.len > 0)
+	{
+		memcpy(*pptr, (const unsigned char*)MQTTSNString.lenstring.data, MQTTSNString.lenstring.len);
+		*pptr += MQTTSNString.lenstring.len;
+	}
+	else if (MQTTSNString.cstring)
+		writeCString(pptr, MQTTSNString.cstring);
+}
+
+
+/**
+ * @param MQTTSNString the MQTTSNString structure into which the data is to be read
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param enddata pointer to the end of the data: do not read beyond
+ * @return 1 if successful, 0 if not
+ */
+int readMQTTSNString(MQTTSNString* MQTTSNString, unsigned char** pptr, unsigned char* enddata)
+{
+	int rc = 0;
+
+	FUNC_ENTRY;
+	MQTTSNString->lenstring.len = enddata - *pptr;
+	if (MQTTSNString->lenstring.len > 0)
+	{
+		MQTTSNString->lenstring.data = (char*)*pptr;
+		*pptr += MQTTSNString->lenstring.len;
+	}
+	else
+	{
+		MQTTSNString->lenstring.data = NULL;
+		MQTTSNString->cstring = NULL;
+	}
+	rc = 1;
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+ * Return the length of the MQTTSNString - C string if there is one, otherwise the length delimited string
+ * @param MQTTSNString the string to return the length of
+ * @return the length of the string
+ */
+int MQTTSNstrlen(MQTTSNString MQTTSNString)
+{
+	int rc = 0;
+
+	if (MQTTSNString.cstring)
+		rc = strlen(MQTTSNString.cstring);
+	else
+		rc = MQTTSNString.lenstring.len;
+	return rc;
+}
+
+
+/**
+ * Helper function to read packet data from some source into a buffer
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param getfn pointer to a function which will read any number of bytes from the needed source
+ * @return integer MQTT packet type, or MQTTSNPACKET_READ_ERROR on error
+ */
+int MQTTSNPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int))
+{
+	int rc = MQTTSNPACKET_READ_ERROR;
+	const int MQTTSN_MIN_PACKET_LENGTH = 2;
+	int len = 0;  /* the length of the whole packet including length field */
+	int lenlen = 0;
+	int datalen = 0;
+
+	/* 1. read a packet - UDP style */
+	if ((len = (*getfn)(buf, buflen)) < MQTTSN_MIN_PACKET_LENGTH)
+		goto exit;
+
+	/* 2. read the length.  This is variable in itself */
+	lenlen = MQTTSNPacket_decode(buf, len, &datalen);
+	if (datalen != len)
+		goto exit; /* there was an error */
+
+	rc = buf[lenlen]; /* return the packet type */
+exit:
+	return rc;
+}
+
+int MQTTSNPacket_read_nb(unsigned char* buf, int buflen)
+{
+	int rc = MQTTSNPACKET_READ_ERROR;
+	int len = buflen;  /* the length of the whole packet including length field */
+	int lenlen = 0;
+	int datalen = 0;
+
+	/* 2. read the length.  This is variable in itself */
+	lenlen = MQTTSNPacket_decode(buf, len, &datalen);
+	if (datalen != len)
+		goto exit; /* there was an error */
+
+	rc = buf[lenlen]; /* return the packet type */
+exit:
+	return rc;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNPacket.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNPacket.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    TomoakiiYamaguchi - modify for C++
+ *******************************************************************************/
+
+#ifndef MQTTSNPACKET_H_
+#define MQTTSNPACKET_H_
+
+#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
+extern "C" {
+#endif
+
+enum errors
+{
+	MQTTSNPACKET_BUFFER_TOO_SHORT = -2,
+	MQTTSNPACKET_READ_ERROR = -1,
+	MQTTSNPACKET_READ_COMPLETE
+};
+
+#define MQTTSN_PROTOCOL_VERSION 0x01
+
+enum MQTTSN_connackCodes
+{
+	MQTTSN_RC_ACCEPTED,
+	MQTTSN_RC_REJECTED_CONGESTED,
+	MQTTSN_RC_REJECTED_INVALID_TOPIC_ID,
+	MQTTSN_RC_NOT_SUPPORTED
+};
+
+typedef enum
+{
+	MQTTSN_TOPIC_TYPE_NORMAL, /* topic id in publish, topic name in subscribe */
+	MQTTSN_TOPIC_TYPE_PREDEFINED,
+	MQTTSN_TOPIC_TYPE_SHORT
+}MQTTSN_topicTypes;
+
+enum MQTTSN_msgTypes
+{
+	MQTTSN_ADVERTISE, MQTTSN_SEARCHGW, MQTTSN_GWINFO, MQTTSN_RESERVED1,
+	MQTTSN_CONNECT, MQTTSN_CONNACK,
+	MQTTSN_WILLTOPICREQ, MQTTSN_WILLTOPIC, MQTTSN_WILLMSGREQ, MQTTSN_WILLMSG, 
+	MQTTSN_REGISTER, MQTTSN_REGACK,
+	MQTTSN_PUBLISH, MQTTSN_PUBACK, MQTTSN_PUBCOMP, MQTTSN_PUBREC, MQTTSN_PUBREL, MQTTSN_RESERVED2,
+	MQTTSN_SUBSCRIBE, MQTTSN_SUBACK, MQTTSN_UNSUBSCRIBE, MQTTSN_UNSUBACK, 
+	MQTTSN_PINGREQ, MQTTSN_PINGRESP,
+	MQTTSN_DISCONNECT, MQTTSN_RESERVED3, 
+	MQTTSN_WILLTOPICUPD, MQTTSN_WILLTOPICRESP, MQTTSN_WILLMSGUPD, MQTTSN_WILLMSGRESP,
+	MQTTSN_ENCAPSULATED = 0xfe
+};
+
+
+typedef struct
+{
+	MQTTSN_topicTypes type;
+	union
+	{
+		unsigned short id;
+		char short_name[2];
+		struct
+		{
+			char* name;
+			int len;
+		} long_;
+	} data;
+} MQTTSN_topicid;
+
+/**
+ * Bitfields for the MQTT-SN flags byte.
+ */
+typedef union
+{
+	unsigned char all;
+#if defined(REVERSED)
+	struct
+	{
+		int dup: 1;
+		unsigned int QoS : 2;
+		unsigned int retain : 1;
+		unsigned int will : 1;
+		unsigned int cleanSession : 1;
+		unsigned int topicIdType : 2;
+	} bits;
+#else
+	struct
+	{
+		unsigned int topicIdType : 2;
+		unsigned int cleanSession : 1;
+		unsigned int will : 1;
+		unsigned int retain : 1;
+		unsigned int QoS : 2;
+		int dup: 1;
+	} bits;
+#endif
+} MQTTSNFlags;
+
+
+typedef struct
+{
+	int len;
+	char* data;
+} MQTTSNLenString;
+
+typedef struct
+{
+	char* cstring;
+	MQTTSNLenString lenstring;
+} MQTTSNString;
+
+#define MQTTSNString_initializer {NULL, {0, NULL}}
+
+int MQTTSNstrlen(MQTTSNString mqttsnstring);
+
+#include "MQTTSNConnect.h"
+#include "MQTTSNPublish.h"
+#include "MQTTSNSubscribe.h"
+#include "MQTTSNUnsubscribe.h"
+#include "MQTTSNSearch.h"
+
+const char* MQTTSNPacket_name(int ptype);
+int MQTTSNPacket_len(int length);
+
+int MQTTSNPacket_encode(unsigned char* buf, int length);
+int MQTTSNPacket_decode(unsigned char* buf, int buflen, int* value);
+int MQTTSNTopic_equals(const MQTTSN_topicid* const a, const MQTTSN_topicid* const b);
+
+int readInt(unsigned char** pptr);
+char readChar(unsigned char** pptr);
+void writeChar(unsigned char** pptr, char c);
+void writeInt(unsigned char** pptr, int anInt);
+int readMQTTSNString(MQTTSNString* mqttstring, unsigned char** pptr, unsigned char* enddata);
+void writeCString(unsigned char** pptr, const char* string);
+void writeMQTTSNString(unsigned char** pptr, MQTTSNString mqttstring);
+
+int MQTTSNPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int));
+int MQTTSNPacket_read_nb(unsigned char* buf, int buflen);
+
+
+#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
+}
+#endif
+
+
+#endif /* MQTTSNPACKET_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNPublish.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNPublish.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#if !defined(MQTTSNPUBLISH_H_)
+#define MQTTSNPUBLISH_H_
+
+int MQTTSNSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
+		MQTTSN_topicid topic, unsigned char* payload, int payloadlen);
+int MQTTSNDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid,
+		MQTTSN_topicid* topic, unsigned char** payload, int* payloadlen, unsigned char* buf, int len);
+
+int MQTTSNSerialize_puback(unsigned char* buf, int buflen, unsigned short topicid, unsigned short packetid,
+		unsigned char returncode);
+int MQTTSNDeserialize_puback(unsigned short* topicid, unsigned short* packetid,
+		unsigned char* returncode, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_pubrec(unsigned char* buf, int buflen, unsigned short packetid);
+int MQTTSNSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid);
+
+int MQTTSNDeserialize_ack(unsigned char* packettype, unsigned short* packetid, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_register(unsigned char* buf, int buflen, unsigned short topicid, unsigned short packetid,
+		MQTTSNString* topicname);
+int MQTTSNDeserialize_register(unsigned short* topicid, unsigned short* packetid, MQTTSNString* topicname,
+		unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_regack(unsigned char* buf, int buflen, unsigned short topicid, unsigned short packetid,
+		unsigned char return_code);
+int MQTTSNDeserialize_regack(unsigned short* topicid, unsigned short* packetid, unsigned char* return_code,
+		unsigned char* buf, int buflen);
+int MQTTSNSerialize_pubrel(unsigned char* buf, int buflen, unsigned short packetid);
+
+#endif /* MQTTSNPUBLISH_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSearch.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSearch.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#if !defined(MQTTSNSEARCH_H_)
+#define MQTTSNSEARCH_H_
+
+int MQTTSNSerialize_advertise(unsigned char* buf, int buflen, unsigned char gatewayid, unsigned short duration);
+int MQTTSNDeserialize_advertise(unsigned char* gatewayid, unsigned short* duration, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_searchgw(unsigned char* buf, int buflen, unsigned char radius);
+int MQTTSNDeserialize_searchgw(unsigned char* radius, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_gwinfo(unsigned char* buf, int buflen, unsigned char gatewayid, unsigned short gatewayaddress_len,
+		unsigned char* gatewayaddress);
+int MQTTSNDeserialize_gwinfo(unsigned char* gatewayid, unsigned short* gatewayaddress_len, unsigned char** gatewayaddress,
+		unsigned char* buf, int buflen);
+
+#endif /* MQTTSNSEARCH_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSearchClient.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSearchClient.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTSNPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+
+/**
+  * Deserializes the supplied (wire) buffer into advertise data
+  * @param gatewayid the returned gateway id
+  * @param duration the returned duration - the time interval until the next advertise will be sent
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success
+  */
+int MQTTSNDeserialize_advertise(unsigned char* gatewayid, unsigned short* duration,	unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_ADVERTISE)
+		goto exit;
+
+	*gatewayid = readChar(&curdata);
+	*duration = readInt(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+
+/**
+  * Serializes the supplied searchgw data into the supplied buffer, ready for sending
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param radius the broadcast radius of this message
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSNSerialize_searchgw(unsigned char* buf, int buflen, unsigned char radius)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(2)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len);   /* write length */
+	writeChar(&ptr, MQTTSN_SEARCHGW);      /* write message type */
+
+	writeChar(&ptr, radius);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into gwinfo data
+  * @param gatewayid the returned gateway id
+  * @param gatewayaddress_len the optional returned length of the gateway address (0 if none)
+  * @param gatewayaddress the optional returned gateway address (set to NULL if none)
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success
+  */
+int MQTTSNDeserialize_gwinfo(unsigned char* gatewayid, unsigned short* gatewayaddress_len,
+		unsigned char** gatewayaddress, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_GWINFO)
+		goto exit;
+
+	*gatewayid = readChar(&curdata);
+
+	*gatewayaddress_len = enddata - curdata;
+	*gatewayaddress = (gatewayaddress_len > 0) ? curdata : NULL;
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSearchServer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSearchServer.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTSNPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+
+/**
+  * Serializes the supplied advertise data into the supplied buffer, ready for sending
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param radius the broadcast radius of this message
+  * @param duration - the time interval until the next advertise will be sent
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSNSerialize_advertise(unsigned char* buf, int buflen, unsigned char gatewayid, unsigned short duration)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(4)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len);   /* write length */
+	writeChar(&ptr, MQTTSN_ADVERTISE);      /* write message type */
+
+	writeChar(&ptr, gatewayid);
+	writeInt(&ptr, duration);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into searchgw data
+  * @param radius the returned broadcast radius of this message
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success
+  */
+int MQTTSNDeserialize_searchgw(unsigned char* radius, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_SEARCHGW)
+		goto exit;
+
+	*radius = readChar(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes the supplied gwinfo data into the supplied buffer, ready for sending
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param gatewayid the gateway id
+  * @param gatewayaddress_len the optional length of the gateway address (0 if none)
+  * @param gatewayaddress the optional gateway address (NULL if none)
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSNSerialize_gwinfo(unsigned char* buf, int buflen, unsigned char gatewayid, unsigned short gatewayaddress_len,
+		unsigned char* gatewayaddress)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(2 + gatewayaddress_len)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len);   /* write length */
+	writeChar(&ptr, MQTTSN_GWINFO);      /* write message type */
+
+	writeChar(&ptr, gatewayid);
+	if (gatewayaddress_len > 0 && gatewayaddress != NULL)
+	{
+		memcpy(ptr, gatewayaddress, gatewayaddress_len);
+		ptr += gatewayaddress_len;
+	}
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+
+}
+
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSerializePublish.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSerializePublish.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,290 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTSNPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+
+/**
+  * Determines the length of the MQTT publish packet that would be produced using the supplied parameters
+  * @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0)
+  * @param topicName the topic name to be used in the publish  
+  * @param payloadlen the length of the payload to be sent
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int MQTTSNSerialize_publishLength(int payloadlen, MQTTSN_topicid topic, int qos)
+{
+	int len = 6;
+
+	if (topic.type == MQTTSN_TOPIC_TYPE_NORMAL && qos == 3)
+		len += topic.data.long_.len;
+
+	return payloadlen + len;
+}
+
+
+/**
+  * Serializes the supplied publish data into the supplied buffer, ready for sending
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param dup integer - the MQTT dup flag
+  * @param qos integer - the MQTT QoS value
+  * @param retained integer - the MQTT retained flag
+  * @param packetid integer - the MQTT packet identifier
+  * @param topic MQTTSN_topicid - the MQTT topic in the publish
+  * @param payload byte buffer - the MQTT publish payload
+  * @param payloadlen integer - the length of the MQTT payload
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSNSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
+		MQTTSN_topicid topic, unsigned char* payload, int payloadlen)
+{
+	unsigned char *ptr = buf;
+	MQTTSNFlags flags;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(MQTTSNSerialize_publishLength(payloadlen, topic, qos))) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, MQTTSN_PUBLISH);      /* write message type */
+
+	flags.all = 0;
+	flags.bits.dup = dup;
+	flags.bits.QoS = qos;
+	flags.bits.retain = retained;
+	flags.bits.topicIdType = topic.type;
+	writeChar(&ptr, flags.all);
+
+	if (topic.type == MQTTSN_TOPIC_TYPE_NORMAL && qos == 3)
+	{
+		/* special arrangement for long topic names in QoS -1 publishes.  The length of the topic is in the topicid field */
+		writeInt(&ptr, topic.data.long_.len); /* topic length */
+	}
+	else if (topic.type == MQTTSN_TOPIC_TYPE_NORMAL || topic.type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		writeInt(&ptr, topic.data.id);
+	else
+	{
+		writeChar(&ptr, topic.data.short_name[0]);
+		writeChar(&ptr, topic.data.short_name[1]);
+	}
+	writeInt(&ptr, packetid);
+	if (topic.type == MQTTSN_TOPIC_TYPE_NORMAL && qos == 3)
+	{
+		memcpy(ptr, topic.data.long_.name, topic.data.long_.len);
+		ptr += topic.data.long_.len;
+	}
+	memcpy(ptr, payload, payloadlen);
+	ptr += payloadlen;
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+int MQTTSNSerialize_puback(unsigned char* buf, int buflen, unsigned short topicid, unsigned short packetid,
+		unsigned char returncode)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(6)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, MQTTSN_PUBACK);      /* write message type */
+
+	writeInt(&ptr, topicid);
+	writeInt(&ptr, packetid);
+	writeChar(&ptr, returncode);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+
+}
+
+
+
+/**
+  * Serializes the ack packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param type the MQTT-SN packet type
+  * @param packetid the MQTT-SN packet identifier
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_ack(unsigned char* buf, int buflen, unsigned short packet_type, unsigned short packetid)
+{
+	int rc = 0;
+	unsigned char *ptr = buf;
+	int len = 4; /* ack packet length */
+
+	FUNC_ENTRY;
+	if (len > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, packet_type);      /* write packet type */
+
+	writeInt(&ptr, packetid);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a puback packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param packetid integer - the MQTT packet identifier
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_pubrec(unsigned char* buf, int buflen, unsigned short packetid)
+{
+	return MQTTSNSerialize_ack(buf, buflen, MQTTSN_PUBREC, packetid);
+}
+
+
+/**
+  * Serializes a pubrel packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param dup integer - the MQTT dup flag
+  * @param packetid integer - the MQTT packet identifier
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_pubrel(unsigned char* buf, int buflen, unsigned short packetid)
+{
+	return MQTTSNSerialize_ack(buf, buflen, MQTTSN_PUBREL, packetid);
+}
+
+
+/**
+  * Serializes a pubrel packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param packetid integer - the MQTT packet identifier
+  * @return serialized length, or error if 0
+  */
+int MQTTSNSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid)
+{
+	return MQTTSNSerialize_ack(buf, buflen, MQTTSN_PUBCOMP, packetid);
+}
+
+
+/**
+  * Determines the length of the MQTT register packet that would be produced using the supplied parameters
+  * @param topicnamelen the length of the topic name to be used in the register
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int MQTTSNSerialize_registerLength(int topicnamelen)
+{
+	return topicnamelen + 5;
+}
+
+/**
+  * Serializes the supplied register data into the supplied buffer, ready for sending
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param topicid if sent by a gateway, contains the id for the topicname, otherwise 0
+  * @param packetid integer - the MQTT packet identifier
+  * @param topicname null-terminated topic name string
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSNSerialize_register(unsigned char* buf, int buflen, unsigned short topicid, unsigned short packetid,
+		MQTTSNString* topicname)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+	int topicnamelen = 0;
+
+	FUNC_ENTRY;
+	topicnamelen = (topicname->cstring) ? strlen(topicname->cstring) : topicname->lenstring.len;
+	if ((len = MQTTSNPacket_len(MQTTSNSerialize_registerLength(topicnamelen))) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len);  /* write length */
+	writeChar(&ptr, MQTTSN_REGISTER);      /* write message type */
+
+	writeInt(&ptr, topicid);
+	writeInt(&ptr, packetid);
+
+	memcpy(ptr, (topicname->cstring) ? topicname->cstring : topicname->lenstring.data, topicnamelen);
+	ptr += topicnamelen;
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes the supplied register data into the supplied buffer, ready for sending
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param topicid if sent by a gateway, contains the id for the topicname, otherwise 0
+  * @param packetid integer - the MQTT packet identifier
+  * @param return_code integer return code
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSNSerialize_regack(unsigned char* buf, int buflen, unsigned short topicid, unsigned short packetid,
+		unsigned char return_code)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(6)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len);  /* write length */
+	writeChar(&ptr, MQTTSN_REGACK);      /* write message type */
+
+	writeInt(&ptr, topicid);
+	writeInt(&ptr, packetid);
+	writeChar(&ptr, return_code);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSubscribe.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSubscribe.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#if !defined(MQTTSNSUBSCRIBE_H_)
+#define MQTTSNSUBSCRIBE_H_
+
+int MQTTSNSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned short packetid,
+        MQTTSN_topicid* topicFilter);
+int MQTTSNDeserialize_subscribe(unsigned char* dup, int* qos, unsigned short* packetid,
+        MQTTSN_topicid* topicFilter, unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_suback(unsigned char* buf, int buflen, int qos, unsigned short topicid, unsigned short packetid,
+		unsigned char returncode);
+int MQTTSNDeserialize_suback(int* qos, unsigned short* topicid, unsigned short* packetid,
+		unsigned char* returncode, unsigned char* buf, int buflen);
+
+#endif /* MQTTSNSUBSCRIBE_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSubscribeClient.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSubscribeClient.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTSNPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+  * Determines the length of the MQTTSN subscribe packet that would be produced using the supplied parameters, 
+  * excluding length
+  * @param topicName the topic name to be used in the publish  
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int MQTTSNSerialize_subscribeLength(MQTTSN_topicid* topicFilter)
+{
+	int len = 4;
+
+	if (topicFilter->type == MQTTSN_TOPIC_TYPE_NORMAL)
+		len += topicFilter->data.long_.len;
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_SHORT || topicFilter->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		len += 2;
+
+	return len;
+}
+
+
+/**
+  * Serializes the supplied subscribe data into the supplied buffer, ready for sending
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param dup integer - the MQTT-SN dup flag
+  * @param qos integer - the MQTT-SN QoS value
+  * @param packetid integer - the MQTT-SN packet identifier
+  * @param topic MQTTSN_topicid - the MQTT-SN topic in the subscribe
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSNSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned short packetid,
+		MQTTSN_topicid* topicFilter)
+{
+	unsigned char *ptr = buf;
+	MQTTSNFlags flags;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(MQTTSNSerialize_subscribeLength(topicFilter))) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len);   /* write length */
+	writeChar(&ptr, MQTTSN_SUBSCRIBE);      /* write message type */
+
+	flags.all = 0;
+	flags.bits.dup = dup;
+	flags.bits.QoS = qos;
+	flags.bits.topicIdType = topicFilter->type;
+	writeChar(&ptr, flags.all);
+
+	writeInt(&ptr, packetid);
+
+	/* now the topic id or name */
+	if (topicFilter->type == MQTTSN_TOPIC_TYPE_NORMAL) /* means long topic name */
+	{
+		memcpy(ptr, topicFilter->data.long_.name, topicFilter->data.long_.len);
+		ptr += topicFilter->data.long_.len;
+	}
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		writeInt(&ptr, topicFilter->data.id);
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_SHORT)
+	{
+		writeChar(&ptr, topicFilter->data.short_name[0]);
+		writeChar(&ptr, topicFilter->data.short_name[1]);
+	}
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into suback data
+  * @param qos the returned qos
+  * @param topicid returned if "accepted" the value which will be used by the gateway in subsequent PUBLISH packets
+  * @param packetid returned - the same value as the one contained in the corresponding SUBSCRIBE
+  * @param returncode returned - "accepted" or rejection reason
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success
+  */
+int MQTTSNDeserialize_suback(int* qos, unsigned short* topicid, unsigned short* packetid,
+		unsigned char* returncode, unsigned char* buf, int buflen)
+{
+	MQTTSNFlags flags;
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_SUBACK)
+		goto exit;
+
+	flags.all = readChar(&curdata);
+	*qos = flags.bits.QoS;
+
+	*topicid = readInt(&curdata);
+	*packetid = readInt(&curdata);
+	*returncode = readChar(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSubscribeServer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNSubscribeServer.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTSNPacket.h"
+#include <string.h>
+
+
+/**
+  * Deserializes the supplied (wire) buffer into subscribe data
+  * @param dup the returned MQTT-SN dup flag
+  * @param qos the returned qos
+  * @param packetid returned - the same value as the one contained in the corresponding SUBSCRIBE
+  * @param topicFilter returned - the topic filter - normal, predefined or short
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success
+  */
+int MQTTSNDeserialize_subscribe(unsigned char* dup, int* qos, unsigned short* packetid,
+        MQTTSN_topicid* topicFilter, unsigned char* buf, int buflen)
+{
+	MQTTSNFlags flags;
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_SUBSCRIBE)
+		goto exit;
+
+	flags.all = readChar(&curdata);
+	*dup = flags.bits.dup;
+	*qos = flags.bits.QoS;
+
+	*packetid = readInt(&curdata);
+
+	topicFilter->type = (MQTTSN_topicTypes)flags.bits.topicIdType;
+
+	if (topicFilter->type == MQTTSN_TOPIC_TYPE_NORMAL)
+	{
+		topicFilter->data.long_.len = enddata - curdata;
+		topicFilter->data.long_.name = (char*)curdata;
+	}
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		topicFilter->data.id = readInt(&curdata);
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_SHORT)
+	{
+		topicFilter->data.short_name[0] = readChar(&curdata);
+		topicFilter->data.short_name[1] = readChar(&curdata);
+	}
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes the supplied suback data into the supplied buffer, ready for sending
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param qos integer - the MQTT-SN QoS value
+  * @param topicid if "accepted" the value which will be used by the gateway in subsequent PUBLISH packets
+  * @param packetid integer - the MQTT-SN packet identifier
+  * @param returncode returned - "accepted" or rejection reason
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSNSerialize_suback(unsigned char* buf, int buflen, int qos, unsigned short topicid, unsigned short packetid,
+		unsigned char returncode)
+{
+	MQTTSNFlags flags;
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(7)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, MQTTSN_SUBACK);      /* write message type */
+
+	flags.all = 0;
+	flags.bits.QoS = qos;
+	writeChar(&ptr, flags.all);
+
+	writeInt(&ptr, topicid);
+	writeInt(&ptr, packetid);
+	writeChar(&ptr, returncode);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNUnsubscribe.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNUnsubscribe.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#if !defined(MQTTSNUNSUBSCRIBE_H_)
+#define MQTTSNUNSUBSCRIBE_H_
+
+int MQTTSNSerialize_unsubscribe(unsigned char* buf, int buflen,
+		unsigned short packetid, MQTTSN_topicid* topicFilter);
+int MQTTSNDeserialize_unsubscribe(unsigned short* packetid, MQTTSN_topicid* topicFilter,
+		unsigned char* buf, int buflen);
+
+int MQTTSNSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid);
+int MQTTSNDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int buflen);
+
+#endif /* MQTTSNUNSUBSCRIBE_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNUnsubscribeClient.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNUnsubscribeClient.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTSNPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+  * Determines the length of the MQTTSN subscribe packet that would be produced using the supplied parameters, 
+  * excluding length
+  * @param topicName the topic name to be used in the publish  
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int MQTTSNSerialize_unsubscribeLength(MQTTSN_topicid* topicFilter)
+{
+	int len = 4;
+
+	if (topicFilter->type == MQTTSN_TOPIC_TYPE_NORMAL)
+		len += topicFilter->data.long_.len;
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_SHORT || topicFilter->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		len += 2;
+
+	return len;
+}
+
+
+int MQTTSNSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned short packetid, MQTTSN_topicid* topicFilter)
+{
+	unsigned char *ptr = buf;
+	MQTTSNFlags flags;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(MQTTSNSerialize_unsubscribeLength(topicFilter))) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len);   /* write length */
+	writeChar(&ptr, MQTTSN_UNSUBSCRIBE);      /* write message type */
+
+	flags.all = 0;
+	flags.bits.topicIdType = topicFilter->type;
+	writeChar(&ptr, flags.all);
+
+	writeInt(&ptr, packetid);
+
+	/* now the topic id or name */
+	if (topicFilter->type == MQTTSN_TOPIC_TYPE_NORMAL) /* means long topic name */
+	{
+		memcpy(ptr, topicFilter->data.long_.name, topicFilter->data.long_.len);
+		ptr += topicFilter->data.long_.len;
+	}
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		writeInt(&ptr, topicFilter->data.id);
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_SHORT)
+	{
+		writeChar(&ptr, topicFilter->data.short_name[0]);
+		writeChar(&ptr, topicFilter->data.short_name[1]);
+	}
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into unsuback data
+  * @param packetid returned - the same value as the one contained in the corresponding SUBSCRIBE
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success
+  */
+int MQTTSNDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int buflen)
+{
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_UNSUBACK)
+		goto exit;
+
+	*packetid = readInt(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNUnsubscribeServer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/MQTTSNUnsubscribeServer.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTSNPacket.h"
+
+int MQTTSNDeserialize_unsubscribe(unsigned short* packetid, MQTTSN_topicid* topicFilter,
+		unsigned char* buf, int buflen)
+{
+	MQTTSNFlags flags;
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	curdata += MQTTSNPacket_decode(curdata, buflen, &mylen); /* read length */
+	enddata = buf + mylen;
+	if (enddata - curdata > buflen)
+		goto exit;
+
+	if (readChar(&curdata) != MQTTSN_UNSUBSCRIBE)
+		goto exit;
+
+	flags.all = readChar(&curdata);
+	*packetid = readInt(&curdata);
+
+	topicFilter->type = (MQTTSN_topicTypes)flags.bits.topicIdType;
+	if (topicFilter->type == MQTTSN_TOPIC_TYPE_NORMAL)
+	{
+		topicFilter->data.long_.len = enddata - curdata;
+		topicFilter->data.long_.name = (char*)curdata;
+	}
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_PREDEFINED)
+		topicFilter->data.id = readInt(&curdata);
+	else if (topicFilter->type == MQTTSN_TOPIC_TYPE_SHORT)
+	{
+		topicFilter->data.short_name[0] = readChar(&curdata);
+		topicFilter->data.short_name[1] = readChar(&curdata);
+	}
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+int MQTTSNSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid)
+{
+	unsigned char *ptr = buf;
+	int len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if ((len = MQTTSNPacket_len(3)) > buflen)
+	{
+		rc = MQTTSNPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	ptr += MQTTSNPacket_encode(ptr, len); /* write length */
+	writeChar(&ptr, MQTTSN_UNSUBACK);      /* write message type */
+
+	writeInt(&ptr, packetid);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/StackTrace.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/src/StackTrace.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#ifndef STACKTRACE_H_
+#define STACKTRACE_H_
+
+#include <stdio.h>
+#define NOSTACKTRACE 1
+
+#if defined(NOSTACKTRACE)
+#define FUNC_ENTRY
+#define FUNC_ENTRY_NOLOG
+#define FUNC_ENTRY_MED
+#define FUNC_ENTRY_MAX
+#define FUNC_EXIT
+#define FUNC_EXIT_NOLOG
+#define FUNC_EXIT_MED
+#define FUNC_EXIT_MAX
+#define FUNC_EXIT_RC(x)
+#define FUNC_EXIT_MED_RC(x)
+#define FUNC_EXIT_MAX_RC(x)
+#else
+#if defined(WIN32)
+#define inline __inline
+#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM)
+#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1)
+#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM)
+#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM)
+#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM)
+#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1)
+#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM)
+#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM)
+#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM)
+#else
+#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM)
+#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1)
+#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM)
+#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM)
+#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM)
+#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1)
+#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM)
+#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM)
+#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM)
+#endif
+#endif
+
+void StackTrace_entry(const char* name, int line, int trace);
+void StackTrace_exit(const char* name, int line, void* return_value, int trace);
+
+void StackTrace_printStack(FILE* dest);
+char* StackTrace_get(unsigned long);
+
+
+#endif /* STACKTRACE_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/test/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/test/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,35 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+PROJECT(mqtt-sn-tests)
+
+INCLUDE_DIRECTORIES(../src)
+
+ADD_EXECUTABLE(
+  test1
+  test1.c
+)
+
+TARGET_LINK_LIBRARIES(test1 MQTTSNPacketClient MQTTSNPacketServer)
+
+ADD_TEST(NAME test1 COMMAND test1)
+
+ADD_EXECUTABLE(
+  test2
+  test2.c
+)
+
+TARGET_LINK_LIBRARIES(test2 MQTTSNPacketClient MQTTSNPacketServer)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/test/build_test
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/test/build_test	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,3 @@
+gcc -Wall test1.c -o test1 -I../src ../src/MQTTSNConnectClient.c ../src/MQTTSNConnectServer.c ../src/MQTTSNPacket.c ../src/MQTTSNSerializePublish.c ../src/MQTTSNDeserializePublish.c ../src/MQTTSNSubscribeClient.c ../src/MQTTSNSubscribeServer.c ../src/MQTTSNUnsubscribeClient.c ../src/MQTTSNUnsubscribeServer.c ../src/MQTTSNSearchClient.c ../src/MQTTSNSearchServer.c
+
+gcc -Wall test2.c -o test2 -I../src ../src/MQTTSNConnectClient.c ../src/MQTTSNConnectServer.c ../src/MQTTSNPacket.c ../src/MQTTSNSerializePublish.c ../src/MQTTSNDeserializePublish.c ../src/MQTTSNSubscribeClient.c 
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/test/test1.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/test/test1.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,956 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+
+#include "MQTTSNPacket.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#if !defined(_WINDOWS)
+	#include <sys/time.h>
+  	#include <sys/socket.h>
+	#include <unistd.h>
+  	#include <errno.h>
+#else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define MAXHOSTNAMELEN 256
+#define EAGAIN WSAEWOULDBLOCK
+#define EINTR WSAEINTR
+#define EINPROGRESS WSAEINPROGRESS
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define ENOTCONN WSAENOTCONN
+#define ECONNRESET WSAECONNRESET
+#endif
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+struct Options
+{
+	char* connection;         /**< connection to system under test. */
+	char** haconnections;
+	int hacount;
+	int verbose;
+	int test_no;
+} options =
+{
+	"tcp://m2m.eclipse.org:1883",
+	NULL,
+	0,
+	0,
+	0,
+};
+
+void usage()
+{
+
+}
+
+void getopts(int argc, char** argv)
+{
+	int count = 1;
+
+	while (count < argc)
+	{
+		if (strcmp(argv[count], "--test_no") == 0)
+		{
+			if (++count < argc)
+				options.test_no = atoi(argv[count]);
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--connection") == 0)
+		{
+			if (++count < argc)
+			{
+				options.connection = argv[count];
+				printf("\nSetting connection to %s\n", options.connection);
+			}
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--haconnections") == 0)
+		{
+			if (++count < argc)
+			{
+				char* tok = strtok(argv[count], " ");
+				options.hacount = 0;
+				options.haconnections = malloc(sizeof(char*) * 5);
+				while (tok)
+				{
+					options.haconnections[options.hacount] = malloc(strlen(tok) + 1);
+					strcpy(options.haconnections[options.hacount], tok);
+					options.hacount++;
+					tok = strtok(NULL, " ");
+				}
+			}
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--verbose") == 0)
+		{
+			options.verbose = 1;
+			printf("\nSetting verbose on\n");
+		}
+		count++;
+	}
+}
+
+
+#define LOGA_DEBUG 0
+#define LOGA_INFO 1
+#include <stdarg.h>
+#include <time.h>
+#include <sys/timeb.h>
+void MyLog(int LOGA_level, char* format, ...)
+{
+	static char msg_buf[256];
+	va_list args;
+	struct timeb ts;
+
+	struct tm *timeinfo;
+
+	if (LOGA_level == LOGA_DEBUG && options.verbose == 0)
+	  return;
+
+	ftime(&ts);
+	timeinfo = localtime(&ts.time);
+	strftime(msg_buf, 80, "%Y%m%d %H%M%S", timeinfo);
+
+	sprintf(&msg_buf[strlen(msg_buf)], ".%.3hu ", ts.millitm);
+
+	va_start(args, format);
+	vsnprintf(&msg_buf[strlen(msg_buf)], sizeof(msg_buf) - strlen(msg_buf), format, args);
+	va_end(args);
+
+	printf("%s\n", msg_buf);
+	fflush(stdout);
+}
+
+
+#if defined(WIN32) || defined(_WINDOWS)
+#define mqsleep(A) Sleep(1000*A)
+#define START_TIME_TYPE DWORD
+static DWORD start_time = 0;
+START_TIME_TYPE start_clock(void)
+{
+	return GetTickCount();
+}
+#elif defined(AIX)
+#define mqsleep sleep
+#define START_TIME_TYPE struct timespec
+START_TIME_TYPE start_clock(void)
+{
+	static struct timespec start;
+	clock_gettime(CLOCK_REALTIME, &start);
+	return start;
+}
+#else
+#define mqsleep sleep
+#define START_TIME_TYPE struct timeval
+/* TODO - unused - remove? static struct timeval start_time; */
+START_TIME_TYPE start_clock(void)
+{
+	struct timeval start_time;
+	gettimeofday(&start_time, NULL);
+	return start_time;
+}
+#endif
+
+
+#if defined(WIN32)
+long elapsed(START_TIME_TYPE start_time)
+{
+	return GetTickCount() - start_time;
+}
+#elif defined(AIX)
+#define assert(a)
+long elapsed(struct timespec start)
+{
+	struct timespec now, res;
+
+	clock_gettime(CLOCK_REALTIME, &now);
+	ntimersub(now, start, res);
+	return (res.tv_sec)*1000L + (res.tv_nsec)/1000000L;
+}
+#else
+long elapsed(START_TIME_TYPE start_time)
+{
+	struct timeval now, res;
+
+	gettimeofday(&now, NULL);
+	timersub(&now, &start_time, &res);
+	return (res.tv_sec)*1000 + (res.tv_usec)/1000;
+}
+#endif
+
+
+#define assert(a, b, c, d) myassert(__FILE__, __LINE__, a, b, c, d)
+#define assert1(a, b, c, d, e) myassert(__FILE__, __LINE__, a, b, c, d, e)
+
+int tests = 0;
+int failures = 0;
+FILE* xml;
+START_TIME_TYPE global_start_time;
+char output[3000];
+char* cur_output = output;
+
+
+void write_test_result()
+{
+	long duration = elapsed(global_start_time);
+
+	fprintf(xml, " time=\"%ld.%.3ld\" >\n", duration / 1000, duration % 1000);
+	if (cur_output != output)
+	{
+		fprintf(xml, "%s", output);
+		cur_output = output;
+	}
+	fprintf(xml, "</testcase>\n");
+}
+
+
+void myassert(char* filename, int lineno, char* description, int value, char* format, ...)
+{
+	++tests;
+	if (!value)
+	{
+		va_list args;
+
+		++failures;
+		printf("Assertion failed, file %s, line %d, description: %s\n", filename, lineno, description);
+
+		va_start(args, format);
+		vprintf(format, args);
+		va_end(args);
+
+		cur_output += sprintf(cur_output, "<failure type=\"%s\">file %s, line %d </failure>\n",
+                        description, filename, lineno);
+	}
+    else
+    	MyLog(LOGA_DEBUG, "Assertion succeeded, file %s, line %d, description: %s", filename, lineno, description);
+}
+
+#define min(a, b) ((a < b) ? a : b)
+
+int checkMQTTSNStrings(MQTTSNString a, MQTTSNString b)
+{
+	if (!a.lenstring.data)
+	{
+		a.lenstring.data = a.cstring;
+		if (a.cstring)
+			a.lenstring.len = strlen(a.cstring);
+	}
+	if (!b.lenstring.data)
+	{
+		b.lenstring.data = b.cstring;
+		if (b.cstring)
+			b.lenstring.len = strlen(b.cstring);
+	}
+	return memcmp(a.lenstring.data, b.lenstring.data, min(a.lenstring.len, b.lenstring.len)) == 0;
+}
+
+int checkMQTTSNTopics(MQTTSN_topicid a, MQTTSN_topicid b)
+{
+	int rc = 0;
+
+	if (a.type != b.type)
+		goto exit;
+
+	if (a.data.long_.name)
+		rc = memcmp(a.data.long_.name, b.data.long_.name, a.data.long_.len) == 0;
+	else if (a.type == MQTTSN_TOPIC_TYPE_SHORT)
+		rc = (memcpy(a.data.short_name, b.data.short_name, 2) == 0);
+	else
+		rc = (a.data.id == b.data.id);
+
+exit:
+	return rc;
+}
+
+
+int checkConnectPackets(MQTTSNPacket_connectData* before, MQTTSNPacket_connectData* after)
+{
+	int rc = 0;
+	int start_failures = failures;
+
+	assert("struct_ids should be the same",
+			memcmp(before->struct_id, after->struct_id, 4) == 0, "struct_ids were different %.4s\n", after->struct_id);
+
+	assert("struct_versions should be the same",
+			before->struct_version == after->struct_version, "struct_versions were different\n", rc);
+
+	assert("ClientIDs should be the same",
+			checkMQTTSNStrings(before->clientID, after->clientID), "ClientIDs were different\n", rc);
+
+	assert("durations should be the same",
+			before->duration == after->duration, "durations were different\n", rc);
+
+	assert("cleansessions should be the same",
+			before->cleansession == after->cleansession, "cleansessions were different\n", rc);
+
+	assert("willFlags should be the same",
+				before->willFlag == after->willFlag, "willFlags were different\n", rc);
+
+	return failures == start_failures;
+}
+
+int test1(struct Options options)
+{
+	MQTTSNPacket_connectData data = MQTTSNPacket_connectData_initializer;
+	MQTTSNPacket_connectData data_after = MQTTSNPacket_connectData_initializer;
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+	MQTTSNString clientid = MQTTSNString_initializer, clientid_after = MQTTSNString_initializer;
+	int duration_after = -1;
+
+	fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 1 - serialization of connect and back");
+
+	data.clientID.cstring = "me too";
+
+	data.duration = 20;
+	data.cleansession = 1;
+
+	data.willFlag = 1;
+
+	rc = MQTTSNSerialize_connect(buf, buflen, &data);
+	assert("good rc from serialize connect", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_connect(&data_after, buf, buflen);
+	assert("good rc from deserialize connect", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	rc = checkConnectPackets(&data, &data_after);
+	assert("packets should be the same",  rc == 1, "packets were different\n", rc);
+
+	/* Pingreq without clientid */
+	rc = MQTTSNSerialize_pingreq(buf, buflen, clientid);
+	assert("good rc from serialize pingreq", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_pingreq(&clientid_after, buf, buflen);
+	assert("good rc from deserialize pingreq", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("ClientIDs should be the same",
+			checkMQTTSNStrings(clientid, clientid_after), "ClientIDs were different\n", rc);
+
+	/* Pingreq with clientid */
+	clientid.cstring = "this is me";
+	rc = MQTTSNSerialize_pingreq(buf, buflen, clientid);
+	assert("good rc from serialize pingreq", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_pingreq(&clientid_after, buf, buflen);
+	assert("good rc from deserialize pingreq", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("ClientIDs should be the same",
+			checkMQTTSNStrings(clientid, clientid_after), "ClientIDs were different\n", rc);
+
+	rc = MQTTSNSerialize_pingresp(buf, buflen);
+	assert("good rc from serialize pingresp", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_pingresp(buf, buflen);
+	assert("good rc from deserialize pingresp", rc == 1, "rc was %d\n", rc);
+
+	/* Disconnect without duration */
+	rc = MQTTSNSerialize_disconnect(buf, buflen, 0);
+	assert("good rc from serialize disconnect", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_disconnect(&duration_after, buf, buflen);
+	assert("good rc from deserialize disconnect", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("durations should be the same", -1 == duration_after, "durations were different\n", rc);
+
+	/* Disconnect with duration */
+	rc = MQTTSNSerialize_disconnect(buf, buflen, 33);
+	assert("good rc from serialize disconnect", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_disconnect(&duration_after, buf, buflen);
+	assert("good rc from deserialize disconnect", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("durations should be the same", 33 == duration_after, "durations were different\n", rc);
+
+	/* Pingreq with clientid */
+	clientid.cstring = "this is me";
+	rc = MQTTSNSerialize_pingreq(buf, buflen, clientid);
+	assert("good rc from serialize pingreq", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_pingreq(&clientid_after, buf, buflen);
+	assert("good rc from deserialize pingreq", rc == 1, "rc was %d\n", rc);
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST1: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test2(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+
+	unsigned char dup = 0;
+	int qos = 2;
+	unsigned char retained = 0;
+	unsigned short msgid = 23;
+	MQTTSN_topicid topic;
+	unsigned char *payload = (unsigned char*)"kkhkhkjkj jkjjk jk jk ";
+	int payloadlen = strlen((char*)payload);
+
+	unsigned char dup2 = 1;
+	int qos2 = 1;
+	unsigned char retained2 = 1;
+	unsigned short msgid2 = 3243;
+	MQTTSN_topicid topic2;
+	unsigned char *payload2 = NULL;
+	int payloadlen2 = 0;
+	unsigned char acktype;
+
+	unsigned char returncode = 3, returncode2 = -99;
+
+	fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 2 - serialization of publish and back");
+
+	memset(&topic, 0, sizeof(topic));
+	memset(&topic2, 0, sizeof(topic2));
+	topic.type = MQTTSN_TOPIC_TYPE_SHORT;
+	memcpy(topic.data.short_name, "my", 2);
+	rc = MQTTSNSerialize_publish(buf, buflen, dup, qos, retained, msgid, topic,
+			payload, payloadlen);
+	assert("good rc from serialize publish", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_publish(&dup2, &qos2, &retained2, &msgid2, &topic2,
+			&payload2, &payloadlen2, buf, buflen);
+	assert("good rc from deserialize publish", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2);
+	assert("qoss should be the same", qos == qos2, "qoss were different %d\n", qos2);
+	assert("retaineds should be the same", retained == retained2, "retaineds were different %d\n", retained2);
+	assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
+
+	assert("topics should be the same",
+			checkMQTTSNTopics(topic, topic2), "topics were different %s\n", "");
+
+	assert("payload lengths should be the same",
+				payloadlen == payloadlen2, "payload lengths were different %d\n", payloadlen2);
+
+	assert("payloads should be the same",
+						memcmp(payload, payload2, payloadlen) == 0, "payloads were different %s\n", "");
+
+	rc = MQTTSNSerialize_puback(buf, buflen, topic.data.id, msgid, returncode);
+	assert("good rc from serialize puback", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_puback(&topic2.data.id, &msgid2, &returncode2, buf, buflen);
+	assert("good rc from deserialize puback", rc > 0, "rc was %d\n", rc);
+	assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
+	assert("return codes should be the same", returncode == returncode2, "return codes were different %d\n", returncode2);
+
+	rc = MQTTSNSerialize_pubrec(buf, buflen, msgid);
+	assert("good rc from serialize pubrec", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_ack(&acktype, &msgid2, buf, buflen);
+	assert("good rc from deserialize pubrec", rc == 1, "rc was %d\n", rc);
+	assert("Acktype should be MQTTSN_PUBREC", acktype == MQTTSN_PUBREC, "acktype was %d\n", acktype);
+	assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
+
+/*exit:*/
+	MyLog(LOGA_INFO, "TEST2: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test3(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+
+	fprintf(xml, "<testcase classname=\"test3\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 3 - will messages");
+
+	rc = MQTTSNSerialize_willtopicreq(buf, buflen);
+	assert("good rc from serialize willtopicreq", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_willtopicreq(buf, buflen);
+	assert("good rc from deserialize willtopicreq", rc == 1, "rc was %d\n", rc);
+
+	rc = MQTTSNSerialize_willmsgreq(buf, buflen);
+	assert("good rc from serialize willmsgreq", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_willmsgreq(buf, rc);
+	assert("good rc from deserialize willmsgreq", rc == 1, "rc was %d\n", rc);
+
+	memset(buf, '\0', sizeof(buf));
+	int willQoS = 1, willQoS1 = 0;
+	unsigned char willRetain = 1, willRetain1 = 0;
+	MQTTSNString willTopic = MQTTSNString_initializer, willTopic1 = MQTTSNString_initializer;
+	willTopic.cstring = "a will topic";
+	rc = MQTTSNSerialize_willtopic(buf, buflen, willQoS, willRetain, willTopic);
+	assert("good rc from serialize willtopic", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_willtopic(&willQoS1, &willRetain1, &willTopic1, buf, rc);
+	assert("good rc from deserialize willtopic", rc == 1, "rc was %d\n", rc);
+	assert("willQoSs are the same", willQoS == willQoS1, "willQoS1 was %d\n", willQoS1);
+	assert("willRetains are the same", willRetain == willRetain1, "willRetain1 was %d\n", willRetain1);
+	assert("willTopics are the same", checkMQTTSNStrings(willTopic, willTopic1), "willTopic1 was %.s\n", willTopic1.lenstring.data);
+
+	memset(buf, '\0', sizeof(buf));
+	willQoS = 2; willRetain = 1; willQoS1 = 0; willRetain1 = 0;
+	MQTTSNString initTopic = MQTTSNString_initializer;
+	memcpy(&willTopic, &initTopic, sizeof(initTopic));
+	memcpy(&willTopic1, &initTopic, sizeof(initTopic));
+	willTopic.cstring = "a will topic update";
+	rc = MQTTSNSerialize_willtopicupd(buf, buflen, willQoS, willRetain, willTopic);
+	assert("good rc from serialize willtopicupd", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_willtopicupd(&willQoS1, &willRetain1, &willTopic1, buf, rc);
+	assert("good rc from deserialize willtopicupd", rc == 1, "rc was %d\n", rc);
+	assert("willQoSs are the same", willQoS == willQoS1, "willQoS1 was %d\n", willQoS1);
+	assert("willRetains are the same", willRetain == willRetain1, "willRetain1 was %d\n", willRetain1);
+	assert("willTopics are the same", checkMQTTSNStrings(willTopic, willTopic1), "willTopic1 was %.s\n", willTopic1.lenstring.data);
+
+	memset(buf, '\0', sizeof(buf));
+	MQTTSNString willMsg = MQTTSNString_initializer, willMsg1 = MQTTSNString_initializer;
+	willMsg.cstring = "a will message";
+	rc = MQTTSNSerialize_willmsg(buf, buflen, willMsg);
+	assert("good rc from serialize willmsg", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_willmsg(&willMsg1, buf, rc);
+	assert("good rc from deserialize willmsg", rc == 1, "rc was %d\n", rc);
+	assert("willMsgs are the same", checkMQTTSNStrings(willMsg, willMsg1), "willMsg1 was %.s\n", willMsg1.lenstring.data);
+
+	memset(buf, '\0', sizeof(buf));
+	memcpy(&willMsg, &initTopic, sizeof(initTopic));
+	memcpy(&willMsg1, &initTopic, sizeof(initTopic));
+	willMsg.cstring = "a will message";
+	rc = MQTTSNSerialize_willmsgupd(buf, buflen, willMsg);
+	assert("good rc from serialize willmsgupd", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_willmsgupd(&willMsg1, buf, rc);
+	assert("good rc from deserialize willmsgupd", rc == 1, "rc was %d\n", rc);
+	assert("willMsgs are the same", checkMQTTSNStrings(willMsg, willMsg1), "willMsg1 was %.s\n", willMsg1.lenstring.data);
+
+	int resp_rc = 33, resp_rc2 = 0;
+	rc = MQTTSNSerialize_willmsgresp(buf, buflen, resp_rc);
+	assert("good rc from serialize willmsgresp", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_willmsgresp(&resp_rc2, buf, buflen);
+	assert("good rc from deserialize willmsgresp", rc == 1, "rc was %d\n", rc);
+	assert("resp rcs should be the same", resp_rc == resp_rc2, "resp rcs were different %d\n", resp_rc2);
+
+	resp_rc = 67, resp_rc2 = 0;
+	rc = MQTTSNSerialize_willtopicresp(buf, buflen, resp_rc);
+	assert("good rc from serialize willmsgresp", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_willtopicresp(&resp_rc2, buf, buflen);
+	assert("good rc from deserialize willmsgresp", rc == 1, "rc was %d\n", rc);
+	assert("resp rcs should be the same", resp_rc == resp_rc2, "resp rcs were different %d\n", resp_rc2);
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST3: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+
+
+int test4(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	size_t buflen = sizeof(buf);
+
+	unsigned char dup = 0;
+	unsigned short packetid = 23;
+	MQTTSN_topicid topicFilter;
+	int req_qos = 2;
+
+	unsigned char dup2 = 1;
+	unsigned short packetid2 = 2223;
+	MQTTSN_topicid topicFilter2;
+	int req_qos2 = 0;
+
+	fprintf(xml, "<testcase classname=\"test4\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 4 - serialization of subscribe and back");
+
+	memset(&topicFilter, '\0', sizeof(topicFilter));
+	memset(&topicFilter2, '\0', sizeof(topicFilter2));
+	topicFilter.type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topicFilter.data.long_.name = "mytopic";
+	topicFilter.data.long_.len = strlen(topicFilter.data.long_.name);
+	rc = MQTTSNSerialize_subscribe(buf, buflen, dup, req_qos, packetid, &topicFilter);
+	assert("good rc from serialize subscribe", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_subscribe(&dup2, &req_qos2, &packetid2, &topicFilter2, buf, buflen);
+	assert("good rc from deserialize subscribe", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2);
+	assert("msgids should be the same", packetid == packetid2, "packetids were different %d\n", packetid2);
+
+	assert("topics should be the same",
+					checkMQTTSNTopics(topicFilter, topicFilter2), "topics were different %s\n", "");
+	assert("qoss should be the same", req_qos == req_qos2, "qoss were different %d\n", req_qos2);
+
+/*exit:*/
+	MyLog(LOGA_INFO, "TEST4: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test5(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	size_t buflen = sizeof(buf);
+
+	unsigned short packetid = 23;
+	MQTTSN_topicid topicFilter;
+
+	unsigned short packetid2 = 2223;
+	MQTTSN_topicid topicFilter2;
+
+	fprintf(xml, "<testcase classname=\"test5\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 5 - serialization of unsubscribe and back");
+
+	memset(&topicFilter, '\0', sizeof(topicFilter));
+	memset(&topicFilter2, '\0', sizeof(topicFilter2));
+	topicFilter.type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topicFilter.data.long_.name = "mytopic";
+	topicFilter.data.long_.len = strlen(topicFilter.data.long_.name);
+	rc = MQTTSNSerialize_unsubscribe(buf, buflen, packetid, &topicFilter);
+	assert("good rc from serialize unsubscribe", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_unsubscribe(&packetid2, &topicFilter2, buf, buflen);
+	assert("good rc from deserialize unsubscribe", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("msgids should be the same", packetid == packetid2, "packetids were different %d\n", packetid2);
+
+	assert("topics should be the same",
+					checkMQTTSNTopics(topicFilter, topicFilter2), "topics were different %s\n", "");
+
+/*exit:*/
+	MyLog(LOGA_INFO, "TEST5: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test6(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+
+	int connack_rc = 77;
+
+	int connack_rc2 = 0;
+
+	fprintf(xml, "<testcase classname=\"test6\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 6 - serialization of connack and back");
+
+	rc = MQTTSNSerialize_connack(buf, buflen, connack_rc);
+	assert("good rc from serialize connack", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_connack(&connack_rc2, buf, buflen);
+	assert("good rc from deserialize connack", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("connack rcs should be the same", connack_rc == connack_rc2, "connack rcs were different %d\n", connack_rc2);
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST6: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test7(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+	unsigned short packetid = 255, packetid2 = 0;
+	int qos = 2, qos2 = 0;
+	unsigned short topicid = 233, topicid2 = 0;
+	unsigned char return_code = 32, return_code2 = 0;
+
+	fprintf(xml, "<testcase classname=\"test7\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 7 - serialization of suback and back");
+
+	rc = MQTTSNSerialize_suback(buf, buflen, qos, topicid, packetid, return_code);
+	assert("good rc from serialize suback", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_suback(&qos2, &topicid2, &packetid2, &return_code2, buf, buflen);
+	assert("good rc from deserialize suback", rc == 1, "rc was %d\n", rc);
+
+	assert("packetids should be the same", packetid == packetid2, "packetids were different %d\n", packetid2);
+	assert("qoss should be the same", qos == qos2, "qoss were different %d\n", qos2);
+	assert("topicids should be the same", topicid == topicid2, "topicids were different %d\n", topicid2);
+	assert("return codes should be the same", return_code == return_code2, "return codes were different %d\n", return_code2);
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST7: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test8(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+	unsigned short packetid = 255, packetid2 = 0;
+
+	fprintf(xml, "<testcase classname=\"test8\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 8 - serialization of unsuback and back");
+
+	rc = MQTTSNSerialize_unsuback(buf, buflen, packetid);
+	assert("good rc from serialize unsuback", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_unsuback(&packetid2, buf, buflen);
+	assert("good rc from deserialize unsuback", rc == 1, "rc was %d\n", rc);
+
+	assert("packetids should be the same", packetid == packetid2, "packetids were different %d\n", packetid2);
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST8: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test9(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+	unsigned short packetid = 255, packetid2 = 0;
+	unsigned short topicid = 233, topicid2 = 0;
+	MQTTSNString topicname = MQTTSNString_initializer, topicname2 = MQTTSNString_initializer;
+
+	fprintf(xml, "<testcase classname=\"test9\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 9 - serialization of register and back");
+
+	rc = MQTTSNSerialize_register(buf, buflen, topicid, packetid, &topicname);
+	assert("good rc from serialize register", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_register(&topicid2, &packetid2, &topicname2, buf, buflen);
+	assert("good rc from deserialize register", rc == 1, "rc was %d\n", rc);
+
+	assert("packetids should be the same", packetid == packetid2, "packetids were different %d\n", packetid2);
+	assert("topicids should be the same", topicid == topicid2, "topicids were different %d\n", topicid2);
+	assert("topicnames should be the same",
+			checkMQTTSNStrings(topicname, topicname2), "topicnames were different\n", rc);
+
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST9: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test10(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+	unsigned short packetid = 255, packetid2 = 0;
+	unsigned short topicid = 233, topicid2 = 0;
+	unsigned char return_code = 127, return_code2 = 0;
+
+	fprintf(xml, "<testcase classname=\"test10\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 10 - serialization of regack and back");
+
+	rc = MQTTSNSerialize_regack(buf, buflen, topicid, packetid, return_code);
+	assert("good rc from serialize regack", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_regack(&topicid2, &packetid2, &return_code2, buf, buflen);
+	assert("good rc from deserialize regack", rc == 1, "rc was %d\n", rc);
+
+	assert("packetids should be the same", packetid == packetid2, "packetids were different %d\n", packetid2);
+	assert("topicids should be the same", topicid == topicid2, "topicids were different %d\n", topicid2);
+	assert("return codes should be the same", return_code == return_code2, "return_codes were different %d\n", return_code2);
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST10: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test11(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+	unsigned char gatewayid = 255, gatewayid2 = 0;
+	unsigned short duration = 3233, duration2 = 0;
+
+	fprintf(xml, "<testcase classname=\"test11\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 11 - serialization of advertise and back");
+
+	rc = MQTTSNSerialize_advertise(buf, buflen, gatewayid, duration);
+	assert("good rc from serialize advertise", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_advertise(&gatewayid2, &duration2, buf, buflen);
+	assert("good rc from deserialize advertise", rc == 1, "rc was %d\n", rc);
+
+	assert("gatewayids should be the same", gatewayid == gatewayid2, "gatewayids were different %d\n", gatewayid2);
+	assert("return codes should be the same", duration == duration2, "return_codes were different %d\n", duration2);
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST11: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test12(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+	unsigned char radius = 255, radius2 = 0;
+
+	fprintf(xml, "<testcase classname=\"test12\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 12 - serialization of searchgw and back");
+
+	rc = MQTTSNSerialize_searchgw(buf, buflen, radius);
+	assert("good rc from serialize searchgw", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_searchgw(&radius2, buf, buflen);
+	assert("good rc from deserialize searchgw", rc == 1, "rc was %d\n", rc);
+
+	assert("radiuss should be the same", radius == radius2, "radiuss were different %d\n", radius2);
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST12: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test13(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+	unsigned char gatewayid = 255, gatewayid2 = 0;
+	unsigned short gatewayaddress_len = 16, gatewayaddress_len2 = 0;
+	unsigned char gatewayaddress[40] = "a gateway address", *gatewayaddress2 = NULL;
+
+	fprintf(xml, "<testcase classname=\"test11\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 13 - serialization of gwinfo and back");
+
+	rc = MQTTSNSerialize_gwinfo(buf, buflen, gatewayid, gatewayaddress_len, gatewayaddress);
+	assert("good rc from serialize gwinfo", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_gwinfo(&gatewayid2, &gatewayaddress_len2, &gatewayaddress2, buf, buflen);
+	assert("good rc from deserialize gwinfo", rc == 1, "rc was %d\n", rc);
+
+	assert("gatewayids should be the same", gatewayid == gatewayid2, "gatewayids were different %d\n", gatewayid2);
+	assert("gateway lengths should be the same", gatewayaddress_len == gatewayaddress_len2, "gateway lengths were different %d\n", gatewayaddress_len2);
+	assert("gateway addresses should be the same", memcmp(gatewayaddress, gatewayaddress2, gatewayaddress_len) == 0,
+			"gateway addresses were different %.10s\n", gatewayaddress2);
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST13: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+ 	int (*tests[])() = {NULL, test1, test2, test3, test4, test5, test6, test7, test8, test9, test10, test11, test12, test13};
+
+	xml = fopen("TEST-test1.xml", "w");
+	fprintf(xml, "<testsuite name=\"test1\" tests=\"%d\">\n", (int)(ARRAY_SIZE(tests) - 1));
+
+	getopts(argc, argv);
+
+ 	if (options.test_no == 0)
+	{ /* run all the tests */
+ 	   	for (options.test_no = 1; options.test_no < ARRAY_SIZE(tests); ++options.test_no)
+			rc += tests[options.test_no](options); /* return number of failures.  0 = test succeeded */
+	}
+	else
+ 	   	rc = tests[options.test_no](options); /* run just the selected test */
+
+ 	if (rc == 0)
+		MyLog(LOGA_INFO, "verdict pass");
+	else
+		MyLog(LOGA_INFO, "verdict fail");
+
+	fprintf(xml, "</testsuite>\n");
+	fclose(xml);
+	return rc;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/test/test2.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/MQTTSNPacket/test/test2.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,703 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+
+#include "MQTTSNPacket.h"
+
+#include <sys/types.h>
+
+#if !defined(SOCKET_ERROR)
+	/** error in socket operation */
+	#define SOCKET_ERROR -1
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#if !defined(_WINDOWS)
+#define INVALID_SOCKET SOCKET_ERROR
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define MAXHOSTNAMELEN 256
+#define EAGAIN WSAEWOULDBLOCK
+#define EINTR WSAEINTR
+#define EINPROGRESS WSAEINPROGRESS
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define ENOTCONN WSAENOTCONN
+#define ECONNRESET WSAECONNRESET
+#endif
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+struct Options
+{
+	char* host;  
+	int port;
+	int verbose;
+	int test_no;
+} options =
+{
+	"127.0.0.1",
+	1884,
+	0,
+	0,
+};
+
+void usage()
+{
+
+}
+
+void getopts(int argc, char** argv)
+{
+	int count = 1;
+
+	while (count < argc)
+	{
+		if (strcmp(argv[count], "--test_no") == 0)
+		{
+			if (++count < argc)
+				options.test_no = atoi(argv[count]);
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--host") == 0)
+		{
+			if (++count < argc)
+			{
+				options.host = argv[count];
+				printf("\nSetting host to %s\n", options.host);
+			}
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--port") == 0)
+		{
+			if (++count < argc)
+				options.port = atoi(argv[count]);
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--verbose") == 0)
+		{
+			options.verbose = 1;
+			printf("\nSetting verbose on\n");
+		}
+		count++;
+	}
+}
+
+
+#define LOGA_DEBUG 0
+#define LOGA_INFO 1
+#include <stdarg.h>
+#include <time.h>
+#include <sys/timeb.h>
+void MyLog(int LOGA_level, char* format, ...)
+{
+	static char msg_buf[256];
+	va_list args;
+	struct timeb ts;
+
+	struct tm *timeinfo;
+
+	if (LOGA_level == LOGA_DEBUG && options.verbose == 0)
+	  return;
+
+	ftime(&ts);
+	timeinfo = localtime(&ts.time);
+	strftime(msg_buf, 80, "%Y%m%d %H%M%S", timeinfo);
+
+	sprintf(&msg_buf[strlen(msg_buf)], ".%.3hu ", ts.millitm);
+
+	va_start(args, format);
+	vsnprintf(&msg_buf[strlen(msg_buf)], sizeof(msg_buf) - strlen(msg_buf), format, args);
+	va_end(args);
+
+	printf("%s\n", msg_buf);
+	fflush(stdout);
+}
+
+
+#if defined(WIN32) || defined(_WINDOWS)
+#define mqsleep(A) Sleep(1000*A)
+#define START_TIME_TYPE DWORD
+static DWORD start_time = 0;
+START_TIME_TYPE start_clock(void)
+{
+	return GetTickCount();
+}
+#elif defined(AIX)
+#define mqsleep sleep
+#define START_TIME_TYPE struct timespec
+START_TIME_TYPE start_clock(void)
+{
+	static struct timespec start;
+	clock_gettime(CLOCK_REALTIME, &start);
+	return start;
+}
+#else
+#define mqsleep sleep
+#define START_TIME_TYPE struct timeval
+/* TODO - unused - remove? static struct timeval start_time; */
+START_TIME_TYPE start_clock(void)
+{
+	struct timeval start_time;
+	gettimeofday(&start_time, NULL);
+	return start_time;
+}
+#endif
+
+
+#if defined(WIN32)
+long elapsed(START_TIME_TYPE start_time)
+{
+	return GetTickCount() - start_time;
+}
+#elif defined(AIX)
+#define assert(a)
+long elapsed(struct timespec start)
+{
+	struct timespec now, res;
+
+	clock_gettime(CLOCK_REALTIME, &now);
+	ntimersub(now, start, res);
+	return (res.tv_sec)*1000L + (res.tv_nsec)/1000000L;
+}
+#else
+long elapsed(START_TIME_TYPE start_time)
+{
+	struct timeval now, res;
+
+	gettimeofday(&now, NULL);
+	timersub(&now, &start_time, &res);
+	return (res.tv_sec)*1000 + (res.tv_usec)/1000;
+}
+#endif
+
+
+#define assert(a, b, c, d) myassert(__FILE__, __LINE__, a, b, c, d)
+#define assert1(a, b, c, d, e) myassert(__FILE__, __LINE__, a, b, c, d, e)
+
+int tests = 0;
+int failures = 0;
+FILE* xml;
+START_TIME_TYPE global_start_time;
+char output[3000];
+char* cur_output = output;
+
+
+void write_test_result()
+{
+	long duration = elapsed(global_start_time);
+
+	fprintf(xml, " time=\"%ld.%.3ld\" >\n", duration / 1000, duration % 1000);
+	if (cur_output != output)
+	{
+		fprintf(xml, "%s", output);
+		cur_output = output;
+	}
+	fprintf(xml, "</testcase>\n");
+}
+
+
+void myassert(char* filename, int lineno, char* description, int value, char* format, ...)
+{
+	++tests;
+	if (!value)
+	{
+		va_list args;
+
+		++failures;
+		printf("Assertion failed, file %s, line %d, description: %s\n", filename, lineno, description);
+
+		va_start(args, format);
+		vprintf(format, args);
+		va_end(args);
+
+		cur_output += sprintf(cur_output, "<failure type=\"%s\">file %s, line %d </failure>\n",
+                        description, filename, lineno);
+	}
+    else
+    	MyLog(LOGA_DEBUG, "Assertion succeeded, file %s, line %d, description: %s", filename, lineno, description);
+}
+
+#define min(a, b) ((a < b) ? a : b)
+
+int Socket_error(char* aString, int sock)
+{
+#if defined(WIN32)
+	int errno;
+#endif
+
+#if defined(WIN32)
+	errno = WSAGetLastError();
+#endif
+	if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS && errno != EWOULDBLOCK)
+	{
+		if (strcmp(aString, "shutdown") != 0 || (errno != ENOTCONN && errno != ECONNRESET))
+		{
+			int orig_errno = errno;
+			char* errmsg = strerror(errno);
+
+			printf("Socket error %d (%s) in %s for socket %d\n", orig_errno, errmsg, aString, sock);
+		}
+	}
+	return errno;
+}
+
+
+int sendPacketBuffer(int asocket, char* host, int port, unsigned char* buf, int buflen)
+{
+	struct sockaddr_in cliaddr;
+	int rc = 0;
+
+	memset(&cliaddr, 0, sizeof(cliaddr));
+	cliaddr.sin_family = AF_INET;
+	cliaddr.sin_addr.s_addr = inet_addr(host);
+	cliaddr.sin_port = htons(port);
+
+	if ((rc = sendto(asocket, buf, buflen, 0, (const struct sockaddr*)&cliaddr, sizeof(cliaddr))) == SOCKET_ERROR)
+		Socket_error("sendto", asocket);
+	else
+		rc = 0;
+	return rc;
+}
+
+
+int mysock = 0;
+
+int getdata(unsigned char* buf, int count)
+{
+	int rc = recvfrom(mysock, buf, count, 0, NULL, NULL);
+	//printf("received %d bytes count %d\n", rc, (int)count);
+	return rc;
+}
+
+
+int connectDisconnect(struct Options options)
+{
+	MQTTSNPacket_connectData data = MQTTSNPacket_connectData_initializer;
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+	int len = 0;
+
+	mysock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (mysock == INVALID_SOCKET)
+		rc = Socket_error("socket", mysock);
+
+	data.clientID.cstring = "test2/test1";
+
+	data.cleansession = 0;
+
+	rc = MQTTSNSerialize_connect(buf, buflen, &data);
+	assert("good rc from serialize connect", rc > 0, "rc was %d\n", rc);
+
+	rc = sendPacketBuffer(mysock, options.host, options.port, buf, rc);
+	assert("good rc from sendPacketBuffer", rc == 0, "rc was %d\n", rc);
+
+	/* wait for connack */
+	if (MQTTSNPacket_read(buf, buflen, getdata) == MQTTSN_CONNACK)
+	{
+		int connack_rc = -1;
+
+		if (MQTTSNDeserialize_connack(&connack_rc, buf, buflen) != 1 || connack_rc != 0)
+		{
+			printf("Unable to connect, return code %d\n", connack_rc);
+			goto exit;
+		}
+		else 
+			printf("connected rc %d\n", connack_rc);
+	}
+	else
+		goto exit;
+
+	len = MQTTSNSerialize_disconnect(buf, buflen, 0);
+	rc = sendPacketBuffer(mysock, options.host, options.port, buf, len);
+
+	rc = shutdown(mysock, SHUT_WR);
+	rc = close(mysock);
+
+exit:
+	return rc;
+}
+
+int test1(struct Options options)
+{
+
+	fprintf(xml, "<testcase classname=\"test1\" name=\"reconnect\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 1 - reconnection");
+
+	connectDisconnect(options);
+	connectDisconnect(options);
+
+	MyLog(LOGA_INFO, "TEST1: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int connectSubscribeDisconnect(struct Options options)
+{
+	MQTTSNPacket_connectData data = MQTTSNPacket_connectData_initializer;
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+	int len = 0;
+	MQTTSN_topicid topic;
+
+	mysock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (mysock == INVALID_SOCKET)
+		rc = Socket_error("socket", mysock);
+
+	data.clientID.cstring = "test2/test1";
+
+	data.cleansession = 0;
+
+	rc = MQTTSNSerialize_connect(buf, buflen, &data);
+	assert("good rc from serialize connect", rc > 0, "rc was %d\n", rc);
+
+	rc = sendPacketBuffer(mysock, options.host, options.port, buf, rc);
+	assert("good rc from sendPacketBuffer", rc == 0, "rc was %d\n", rc);
+
+	/* wait for connack */
+	if (MQTTSNPacket_read(buf, buflen, getdata) == MQTTSN_CONNACK)
+	{
+		int connack_rc = -1;
+
+		rc = MQTTSNDeserialize_connack(&connack_rc, buf, buflen);
+		assert("Good rc from deserialize connack", rc == 1, "rc was %d\n", rc);
+		assert("Good rc from connect", connack_rc == 0, "connack_rc was %d\n", rc);
+		if (connack_rc != 0)
+			goto exit;
+	}
+	else
+		goto exit;
+
+	/* subscribe */
+	printf("Subscribing\n");
+	topic.type = MQTTSN_TOPIC_TYPE_NORMAL;
+	topic.data.long_.name = "substopic";
+	topic.data.long_.len = strlen(topic.data.long_.name);
+	len = MQTTSNSerialize_subscribe(buf, buflen, 0, 2, /*msgid*/ 1, &topic);
+	rc = sendPacketBuffer(mysock, options.host, options.port, buf, len);
+
+	if (MQTTSNPacket_read(buf, buflen, getdata) == MQTTSN_SUBACK) 	/* wait for suback */
+	{
+		unsigned short submsgid;
+		int granted_qos;
+		unsigned char returncode;
+		unsigned short topicid;
+
+		rc = MQTTSNDeserialize_suback(&granted_qos, &topicid, &submsgid, &returncode, buf, buflen);
+		if (granted_qos != 2 || returncode != 0)
+		{
+			printf("granted qos != 2, %d return code %d\n", granted_qos, returncode);
+			goto exit;
+		}
+		else
+			printf("suback topic id %d\n", topicid);
+	}
+	else
+		goto exit;
+
+	len = MQTTSNSerialize_disconnect(buf, buflen, 0);
+	rc = sendPacketBuffer(mysock, options.host, options.port, buf, len);
+
+	rc = shutdown(mysock, SHUT_WR);
+	rc = close(mysock);
+
+exit:
+	return rc;
+}
+
+
+/*
+ * Connect non-cleansession, subscribe, disconnect.
+ * Then reconnect non-cleansession.
+ */
+int test2(struct Options options)
+{
+
+	fprintf(xml, "<testcase classname=\"test2\" name=\"clientid free\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 2 - clientid free");
+
+	connectSubscribeDisconnect(options);
+	connectDisconnect(options);
+
+	MyLog(LOGA_INFO, "TEST2: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+#if 0
+int test3(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+
+	fprintf(xml, "<testcase classname=\"test3\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 3 - will messages");
+
+	rc = MQTTSNSerialize_willtopicreq(buf, buflen);
+	assert("good rc from serialize willtopicreq", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_willtopicreq(buf, buflen);
+	assert("good rc from deserialize willtopicreq", rc == 1, "rc was %d\n", rc);
+
+	rc = MQTTSNSerialize_willmsgreq(buf, buflen);
+	assert("good rc from serialize willmsgreq", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_willmsgreq(buf, rc);
+	assert("good rc from deserialize willmsgreq", rc == 1, "rc was %d\n", rc);
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST1: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+#if 0
+int test3(struct Options options)
+{
+	int i = 0;
+	int rc = 0;
+	char buf[100];
+	int buflen = sizeof(buf);
+#define TOPIC_COUNT 2
+
+	int dup = 0;
+	int msgid = 23;
+	int count = TOPIC_COUNT;
+	MQTTString topicStrings[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
+	int req_qoss[TOPIC_COUNT] = {2, 1};
+
+	int dup2 = 1;
+	int msgid2 = 2223;
+	int count2 = 0;
+	MQTTString topicStrings2[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
+	int req_qoss2[TOPIC_COUNT] = {0, 0};
+
+	fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 2 - serialization of subscribe and back");
+
+	topicStrings[0].cstring = "mytopic";
+	topicStrings[1].cstring = "mytopic2";
+	rc = MQTTSerialize_subscribe(buf, buflen, dup, msgid, count, topicStrings, req_qoss);
+	assert("good rc from serialize subscribe", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTDeserialize_subscribe(&dup2, &msgid2, 2, &count2, topicStrings2, req_qoss2, buf, buflen);
+	assert("good rc from deserialize subscribe", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2);
+	assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
+
+	assert("count should be the same", count == count2, "counts were different %d\n", count2);
+
+	for (i = 0; i < count2; ++i)
+	{
+		assert("topics should be the same",
+					checkMQTTStrings(topicStrings[i], topicStrings2[i]), "topics were different %s\n", "");
+
+		assert("qoss should be the same", req_qoss[i] == req_qoss2[i], "qoss were different %d\n", req_qoss2[i]);
+	}
+
+/*exit:*/
+	MyLog(LOGA_INFO, "TEST3: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test4(struct Options options)
+{
+	int i = 0;
+	int rc = 0;
+	char buf[100];
+	int buflen = sizeof(buf);
+#define TOPIC_COUNT 2
+
+	int msgid = 23;
+	int count = TOPIC_COUNT;
+	int granted_qoss[TOPIC_COUNT] = {2, 1};
+;
+	int msgid2 = 2223;
+	int count2 = 0;
+	int granted_qoss2[TOPIC_COUNT] = {0, 0};
+
+	fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 4 - serialization of suback and back");
+
+	rc = MQTTSerialize_suback(buf, buflen, msgid, count, granted_qoss);
+	assert("good rc from serialize suback", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTDeserialize_suback(&msgid2, 2, &count2, granted_qoss2, buf, buflen);
+	assert("good rc from deserialize suback", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
+
+	assert("count should be the same", count == count2, "counts were different %d\n", count2);
+
+	for (i = 0; i < count2; ++i)
+		assert("qoss should be the same", granted_qoss[i] == granted_qoss2[i], "qoss were different %d\n", granted_qoss2[i]);
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST4: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test5(struct Options options)
+{
+	int i = 0;
+	int rc = 0;
+	char buf[100];
+	int buflen = sizeof(buf);
+#define TOPIC_COUNT 2
+
+	int dup = 0;
+	int msgid = 23;
+	int count = TOPIC_COUNT;
+	MQTTString topicStrings[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
+
+	int dup2 = 1;
+	int msgid2 = 2223;
+	int count2 = 0;
+	MQTTString topicStrings2[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
+
+	fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 2 - serialization of unsubscribe and back");
+
+	topicStrings[0].cstring = "mytopic";
+	topicStrings[1].cstring = "mytopic2";
+	rc = MQTTSerialize_unsubscribe(buf, buflen, dup, msgid, count, topicStrings);
+	assert("good rc from serialize unsubscribe", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTDeserialize_unsubscribe(&dup2, &msgid2, 2, &count2, topicStrings2, buf, buflen);
+	assert("good rc from deserialize unsubscribe", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2);
+	assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
+
+	assert("count should be the same", count == count2, "counts were different %d\n", count2);
+
+	for (i = 0; i < count2; ++i)
+		assert("topics should be the same",
+					checkMQTTStrings(topicStrings[i], topicStrings2[i]), "topics were different %s\n", "");
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST5: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+#endif
+
+
+int test6(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+
+	int connack_rc = 77;
+
+	int connack_rc2 = 0;
+
+	fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 2 - serialization of connack and back");
+
+	rc = MQTTSNSerialize_connack(buf, buflen, connack_rc);
+	assert("good rc from serialize connack", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTSNDeserialize_connack(&connack_rc2, buf, buflen);
+	assert("good rc from deserialize connack", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("dups should be the same", connack_rc == connack_rc2, "dups were different %d\n", connack_rc2);
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST6: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+#endif
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+ 	int (*tests[])() = {NULL, test1, test2};
+
+	xml = fopen("TEST-test1.xml", "w");
+	fprintf(xml, "<testsuite name=\"test2\" tests=\"%d\">\n", (int)(ARRAY_SIZE(tests) - 1));
+
+	getopts(argc, argv);
+
+ 	if (options.test_no == 0)
+	{ /* run all the tests */
+ 	   	for (options.test_no = 1; options.test_no < ARRAY_SIZE(tests); ++options.test_no)
+			rc += tests[options.test_no](options); /* return number of failures.  0 = test succeeded */
+	}
+	else
+ 	   	rc = tests[options.test_no](options); /* run just the selected test */
+
+ 	if (rc == 0)
+		MyLog(LOGA_INFO, "verdict pass");
+	else
+		MyLog(LOGA_INFO, "verdict fail");
+
+	fprintf(xml, "</testsuite>\n");
+	fclose(xml);
+	return rc;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/README.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/README.md	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,48 @@
+# Eclipse Paho MQTT-SN C/C++ client for Embedded platforms
+
+This repository contains the source code for the [Eclipse Paho](http://eclipse.org/paho) MQTT-SN C/C++ client library for Embedded platorms.
+
+It is dual licensed under the EPL and EDL (see about.html and notice.html for more details).  You can choose which of these licenses you want to use the code under.  The EDL allows you to embed the code into your application, and distribute your application in binary or source form without contributing any of your code, or any changes you make back to Paho.  See the EDL for the exact conditions.
+
+There are three sub-projects:
+
+1. MQTTSNPacket - simple de/serialization of MQTT-SN packets, plus helper functions
+2. MQTTGateway - MQTT-SN transparent/aggregating gateway - connects MQTT-SN clients with an MQTT server.  See the README within the project for more information.
+3. MQTTSNClient - high(er) level C++ client (not yet complete)
+
+The *MQTTSNPacket* directory contains the lowest level C library with the smallest requirements.  This supplies simple serialization
+and deserialization routines.  They serve as a base for the higher level libraries, but can also be used on their own.
+It is mainly up to you to write and read to and from the network.
+
+The *MQTTSNGateway* directory contains an MQTT-SN to MQTT transparent/aggregating gateway (see the MQTT-SN specification for a description of that.)  It can
+be used to connect the MQTT-SN client to an MQTT server.
+
+The *MQTTSNClient* directory contains the next level C++ library.  This is intended to mirror the way the MQTTClient works in the Paho embedded
+MQTT project, but it's not yet complete.
+
+## Build requirements / compilation
+
+CMake builds for MQTTSNPacket with a Makefile for MQTTSNGateway have been introduced, along with Travis-CI configuration for automated build & testing.
+
+The travis-build.sh file has the full build and test sequence for Linux.
+
+
+## Usage and API
+
+See the samples directories for examples of intended use.  Doxygen config files are available in the doc directory.
+
+## Runtime tracing
+
+
+## Reporting bugs
+
+This project uses GitHub Issues here: [github.com/eclipse/paho.mqtt-sn.embedded-c/issues](https://github.com/eclipse/paho.mqtt-sn.embedded-c/issues) to track ongoing development and issues.
+
+## More information
+
+Discussion of the Paho clients takes place on the [Eclipse Mattermost Paho channel](https://mattermost.eclipse.org/eclipse/channels/paho) and the [Eclipse paho-dev mailing list](https://dev.eclipse.org/mailman/listinfo/paho-dev).
+
+General questions about the MQTT protocol are discussed in the [MQTT Google Group](https://groups.google.com/forum/?hl=en-US&fromgroups#!forum/mqtt).
+
+More information is available via the [MQTT community](http://mqtt.org).
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/about.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/about.html	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+ 
+<p><em>March 19, 2014</em></p>	
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content").  Unless otherwise 
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL") and Eclipse Distribution License Version 1.0 ("EDL").
+A copy of the EPL is available at 
+<a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> 
+and a copy of the EDL is available at 
+<a href="http://www.eclipse.org/org/documents/edl-v10.php">http://www.eclipse.org/org/documents/edl-v10.php</a>. 
+For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is 
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content.  Check the Redistributor's license that was 
+provided with the Content.  If no such license exists, contact the Redistributor.  Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body></html>
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/doc/DoxyfileMQTTSNPacket.in
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/doc/DoxyfileMQTTSNPacket.in	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,2430 @@
+# Doxyfile 1.8.13
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "Eclipse Paho Embedded MQTTSNPacket C Client Library"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           = "doc/pahologo.png"
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = "doc/MQTTSNPacket/"
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        = MQTTSNPacket/src
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 0
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = YES
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = MQTTSNPacket/src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NONE
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             = __attribute__(x)=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           =
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/doc/pahologo.png
Binary file mbed-mqtt-master/paho_mqtt-sn_embedded_c/doc/pahologo.png has changed
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/edl-v10
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/edl-v10	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,15 @@
+
+Eclipse Distribution License - v 1.0
+
+Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    Neither the name of the Eclipse Foundation, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/epl-v10
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/epl-v10	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,70 @@
+Eclipse Public License - v 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
+b) in the case of each subsequent Contributor:
+i) changes to the Program, and
+ii) additions to the Program;
+where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
+b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
+c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
+d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
+
+a) it complies with the terms and conditions of this Agreement; and
+b) its license agreement:
+i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
+ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
+iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
+iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
+When the Program is made available in source code form:
+
+a) it must be made available under this Agreement; and
+b) a copy of this Agreement must be included with each copy of the Program.
+Contributors may not remove or alter any copyright notices contained within the Program.
+
+Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/notice.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/notice.html	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Eclipse Foundation Software User Agreement</title>
+</head>
+
+<body lang="EN-US">
+<h2>Eclipse Foundation Software User Agreement</h2>
+<p>February 1, 2011</p>
+
+<h3>Usage Of Content</h3>
+
+<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+   (COLLECTIVELY &quot;CONTENT&quot;).  USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+   CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU AGREE THAT YOUR USE
+   OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
+   NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
+   CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+
+<h3>Applicable Licenses</h3>
+
+<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
+   (&quot;EPL&quot;).  A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+   For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
+   repository (&quot;Repository&quot;) in software modules (&quot;Modules&quot;) and made available as downloadable archives (&quot;Downloads&quot;).</p>
+
+<ul>
+       <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content.  Typical modules may include plug-ins (&quot;Plug-ins&quot;), plug-in fragments (&quot;Fragments&quot;), and features (&quot;Features&quot;).</li>
+       <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java&trade; ARchive) in a directory named &quot;plugins&quot;.</li>
+       <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.  Each Feature may be packaged as a sub-directory in a directory named &quot;features&quot;.  Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of the Plug-ins
+      and/or Fragments associated with that Feature.</li>
+       <li>Features may also include other Features (&quot;Included Features&quot;). Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of Included Features.</li>
+</ul>
+
+<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named &quot;about.html&quot; (&quot;Abouts&quot;). The terms and conditions governing Features and
+Included Features should be contained in files named &quot;license.html&quot; (&quot;Feature Licenses&quot;).  Abouts and Feature Licenses may be located in any directory of a Download or Module
+including, but not limited to the following locations:</p>
+
+<ul>
+       <li>The top-level (root) directory</li>
+       <li>Plug-in and Fragment directories</li>
+       <li>Inside Plug-ins and Fragments packaged as JARs</li>
+       <li>Sub-directories of the directory named &quot;src&quot; of certain Plug-ins</li>
+       <li>Feature directories</li>
+</ul>
+
+<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license (&quot;Feature Update License&quot;) during the
+installation process.  If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
+inform you where you can locate them.  Feature Update Licenses may be found in the &quot;license&quot; property of files named &quot;feature.properties&quot; found within a Feature.
+Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
+that directory.</p>
+
+<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.  SOME OF THESE
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+
+<ul>
+       <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
+       <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
+       <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
+       <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
+       <li>Metro Link Public License 1.00 (available at <a href="http://www.opengroup.org/openmotif/supporters/metrolink/license.html">http://www.opengroup.org/openmotif/supporters/metrolink/license.html</a>)</li>
+       <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
+</ul>
+
+<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT.  If no About, Feature License, or Feature Update License is provided, please
+contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
+
+
+<h3>Use of Provisioning Technology</h3>
+
+<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
+   Update Manager (&quot;Provisioning Technology&quot;) for the purpose of allowing users to install software, documentation, information and/or
+   other materials (collectively &quot;Installable Software&quot;). This capability is provided with the intent of allowing such users to
+   install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a
+       href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+   (&quot;Specification&quot;).</p>
+
+<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
+   applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
+   in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
+   Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
+
+<ol>
+       <li>A series of actions may occur (&quot;Provisioning Process&quot;) in which a user may execute the Provisioning Technology
+       on a machine (&quot;Target Machine&quot;) with the intent of installing, extending or updating the functionality of an Eclipse-based
+       product.</li>
+       <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
+       accessed and copied to the Target Machine.</li>
+       <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
+       Software (&quot;Installable Software Agreement&quot;) and such Installable Software Agreement shall be accessed from the Target
+       Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
+       the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
+       indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
+</ol>
+
+<h3>Cryptography</h3>
+
+<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
+   another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
+   possession, or use, and re-export of encryption software, to see if this is permitted.</p>
+
+<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
+</body>
+</html>
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt-sn_embedded_c/travis-build.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt-sn_embedded_c/travis-build.sh	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -e
+
+rm -rf build.paho
+mkdir build.paho
+cd build.paho
+echo "travis build dir $TRAVIS_BUILD_DIR pwd $PWD"
+cmake ..
+make
+ctest -VV --timeout 600
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/.gitignore
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/.gitignore	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,8 @@
+/dep/
+/build/
+/build.paho/
+*.swp
+*.pyc
+/doc/MQTTClient/
+/doc/MQTTPacket/
+/doc/MQTTClient-C/
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/.travis.yml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/.travis.yml	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,29 @@
+sudo: true
+language: c
+
+compiler:
+  - gcc
+
+os:
+  - linux
+
+sudo: required
+
+before_install:
+  - ./travis-install.sh
+
+script:
+  - if [[ "$COVERITY_SCAN_BRANCH" != 1 ]]; then ./travis-build.sh; fi
+
+addons:
+  apt:
+    sources:
+      - george-edison55-precise-backports # cmake 3.2.3 / doxygen 1.8.3
+      - sourceline: 'ppa:mosquitto-dev/mosquitto-ppa'
+    packages:
+      - cmake
+      - cmake-data
+      - mosquitto
+      - doxygen
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,46 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+cmake_minimum_required(VERSION 2.8)
+project (embedded-mqtt)
+set(CMAKE_BUILD_TYPE Debug)
+
+message(STATUS "CMake version: " ${CMAKE_VERSION})
+message(STATUS "CMake system name: " ${CMAKE_SYSTEM_NAME})
+
+set(CMAKE_SCRIPTS "${CMAKE_SOURCE_DIR}/cmake")
+set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")
+
+## build settings
+set(PAHO_VERSION_MAJOR 1)
+set(PAHO_VERSION_MINOR 0)
+set(PAHO_VERSION_PATCH 0)
+set(CLIENT_VERSION ${PAHO_VERSION_MAJOR}.${PAHO_VERSION_MINOR}.${PAHO_VERSION_PATCH})
+
+string(TIMESTAMP BUILD_TIMESTAMP UTC)
+message(STATUS "Timestamp is ${BUILD_TIMESTAMP}")
+
+set(CPACK_PACKAGE_VERSION_MAJOR ${PAHO_VERSION_MAJOR})
+set(CPACK_PACKAGE_VERSION_MINOR ${PAHO_VERSION_MINOR})
+set(CPACK_PACKAGE_VERSION_PATCH ${PAHO_VERSION_PATCH})
+include(CPack)
+
+include_directories(MQTTPacket/src)
+
+enable_testing()
+ADD_SUBDIRECTORY(MQTTPacket)
+ADD_SUBDIRECTORY(MQTTClient)
+ADD_SUBDIRECTORY(MQTTClient-C)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/CONTRIBUTING.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/CONTRIBUTING.md	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,66 @@
+# Contributing to Paho
+
+Thanks for your interest in this project!
+
+You can contribute bugfixes and new features by sending pull requests through GitHub.
+
+## Legal
+
+In order for your contribution to be accepted, it must comply with the Eclipse Foundation IP policy.
+
+Please read the [Eclipse Foundation policy on accepting contributions via Git](http://wiki.eclipse.org/Development_Resources/Contributing_via_Git).
+
+1. Sign the [Eclipse ECA](http://www.eclipse.org/legal/ECA.php)
+  1. Register for an Eclipse Foundation User ID. You can register [here](https://dev.eclipse.org/site_login/createaccount.php).
+  2. Log into the [Eclipse projects forge](https://www.eclipse.org/contribute/cla), and click on 'Eclipse Contributor Agreement'.
+2. Go to your [account settings](https://dev.eclipse.org/site_login/myaccount.php#open_tab_accountsettings) and add your GitHub username to your account.
+3. Make sure that you _sign-off_ your Git commits in the following format:
+  ``` Signed-off-by: Alex Smith <alexsmith@nowhere.com> ``` This is usually at the bottom of the commit message. You can automate this by adding the '-s' flag when you make the commits. e.g.   ```git commit -s -m "Adding a cool feature"```
+4. Ensure that the email address that you make your commits with is the same one you used to sign up to the Eclipse Foundation website with.
+
+## Contributing a change
+
+1. [Fork the repository on GitHub](https://github.com/eclipse/paho.mqtt.embedded-c/fork)
+2. Clone the forked repository onto your computer: ``` git clone https://github.com/<your username>/paho.mqtt.embedded-c.git ```
+3. Create a new branch from the latest ```develop``` branch with ```git checkout -b YOUR_BRANCH_NAME origin/develop```
+4. Make your changes
+5. If developing a new feature, make sure to include JUnit tests.
+6. Ensure that all new and existing tests pass.
+7. Commit the changes into the branch: ``` git commit -s ``` Make sure that your commit message is meaningful and describes your changes correctly.
+8. If you have a lot of commits for the change, squash them into a single / few commits.
+9. Push the changes in your branch to your forked repository.
+10. Finally, go to [https://github.com/eclipse/paho.mqtt.embedded-c](https://github.com/eclipse/paho.mqtt.embedded-c) and create a pull request from your "YOUR_BRANCH_NAME" branch to the ```develop``` one to request review and merge of the commits in your pushed branch.
+
+
+What happens next depends on the content of the patch. If it is 100% authored
+by the contributor and is less than 1000 lines (and meets the needs of the
+project), then it can be pulled into the main repository. If not, more steps
+are required. These are detailed in the
+[legal process poster](http://www.eclipse.org/legal/EclipseLegalProcessPoster.pdf).
+
+
+
+## Developer resources:
+
+
+Information regarding source code management, builds, coding standards, and more.
+
+- [https://projects.eclipse.org/projects/iot.paho/developer](https://projects.eclipse.org/projects/iot.paho/developer)
+
+Contact:
+--------
+
+Contact the project developers via the project's development
+[mailing list](https://dev.eclipse.org/mailman/listinfo/paho-dev).
+
+Search for bugs:
+----------------
+
+This project uses GitHub Issues here: [github.com/eclipse/paho.mqtt.embedded-c/issues](https://github.com/eclipse/paho.mqtt.embedded-c/issues) to track ongoing development and issues.
+
+Create a new bug:
+-----------------
+
+Be sure to search for existing bugs before you create another one. Remember that contributions are always welcome!
+
+- [Create new Paho bug](https://github.com/eclipse/paho.mqtt.embedded-c/issues)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,21 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+project("paho-mqttclient" C)
+
+ADD_SUBDIRECTORY(src)
+ADD_SUBDIRECTORY(samples)
+ADD_SUBDIRECTORY(test)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/samples/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/samples/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,17 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+add_subdirectory(linux)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/samples/FreeRTOS/MQTTEcho.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/samples/FreeRTOS/MQTTEcho.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,95 @@
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+
+#define MQTT_TASK 1
+#include "MQTTClient.h"
+
+
+void messageArrived(MessageData* data)
+{
+	printf("Message arrived on topic %.*s: %.*s\n", data->topicName->lenstring.len, data->topicName->lenstring.data,
+		data->message->payloadlen, data->message->payload);
+}
+
+static void prvMQTTEchoTask(void *pvParameters)
+{
+	/* connect to m2m.eclipse.org, subscribe to a topic, send and receive messages regularly every 1 sec */
+	MQTTClient client;
+	Network network;
+	unsigned char sendbuf[80], readbuf[80];
+	int rc = 0, 
+		count = 0;
+	MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer;
+
+	pvParameters = 0;
+	NetworkInit(&network);
+	MQTTClientInit(&client, &network, 30000, sendbuf, sizeof(sendbuf), readbuf, sizeof(readbuf));
+
+	char* address = "iot.eclipse.org";
+	if ((rc = NetworkConnect(&network, address, 1883)) != 0)
+		printf("Return code from network connect is %d\n", rc);
+
+#if defined(MQTT_TASK)
+	if ((rc = MQTTStartTask(&client)) != pdPASS)
+		printf("Return code from start tasks is %d\n", rc);
+#endif
+
+	connectData.MQTTVersion = 3;
+	connectData.clientID.cstring = "FreeRTOS_sample";
+
+	if ((rc = MQTTConnect(&client, &connectData)) != 0)
+		printf("Return code from MQTT connect is %d\n", rc);
+	else
+		printf("MQTT Connected\n");
+
+	if ((rc = MQTTSubscribe(&client, "FreeRTOS/sample/#", 2, messageArrived)) != 0)
+		printf("Return code from MQTT subscribe is %d\n", rc);
+
+	while (++count)
+	{
+		MQTTMessage message;
+		char payload[30];
+
+		message.qos = 1;
+		message.retained = 0;
+		message.payload = payload;
+		sprintf(payload, "message number %d", count);
+		message.payloadlen = strlen(payload);
+
+		if ((rc = MQTTPublish(&client, "FreeRTOS/sample/a", &message)) != 0)
+			printf("Return code from MQTT publish is %d\n", rc);
+#if !defined(MQTT_TASK)
+		if ((rc = MQTTYield(&client, 1000)) != 0)
+			printf("Return code from yield is %d\n", rc);
+#endif
+	}
+
+	/* do not return */
+}
+
+
+void vStartMQTTTasks(uint16_t usTaskStackSize, UBaseType_t uxTaskPriority)
+{
+	BaseType_t x = 0L;
+
+	xTaskCreate(prvMQTTEchoTask,	/* The function that implements the task. */
+			"MQTTEcho0",			/* Just a text name for the task to aid debugging. */
+			usTaskStackSize,	/* The stack size is defined in FreeRTOSIPConfig.h. */
+			(void *)x,		/* The task parameter, not used in this case. */
+			uxTaskPriority,		/* The priority assigned to the task is defined in FreeRTOSConfig.h. */
+			NULL);				/* The task handle is not used. */
+}
+/*-----------------------------------------------------------*/
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/samples/linux/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/samples/linux/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,24 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+
+add_executable(
+  stdoutsubc
+  stdoutsub.c
+)
+target_link_libraries(stdoutsubc paho-embed-mqtt3cc paho-embed-mqtt3c)
+target_include_directories(stdoutsubc PRIVATE "../../src" "../../src/linux")
+target_compile_definitions(stdoutsubc PRIVATE MQTTCLIENT_PLATFORM_HEADER=MQTTLinux.h)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/samples/linux/build.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/samples/linux/build.sh	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,3 @@
+cp ../../src/MQTTClient.c .
+sed -e 's/""/"MQTTLinux.h"/g' ../../src/MQTTClient.h > MQTTClient.h
+gcc stdoutsub.c -I ../../src -I ../../src/linux -I ../../../MQTTPacket/src MQTTClient.c ../../src/linux/MQTTLinux.c ../../../MQTTPacket/src/MQTTFormat.c  ../../../MQTTPacket/src/MQTTPacket.c ../../../MQTTPacket/src/MQTTDeserializePublish.c ../../../MQTTPacket/src/MQTTConnectClient.c ../../../MQTTPacket/src/MQTTSubscribeClient.c ../../../MQTTPacket/src/MQTTSerializePublish.c -o stdoutsub ../../../MQTTPacket/src/MQTTConnectServer.c ../../../MQTTPacket/src/MQTTSubscribeServer.c ../../../MQTTPacket/src/MQTTUnsubscribeServer.c ../../../MQTTPacket/src/MQTTUnsubscribeClient.c -DMQTTCLIENT_PLATFORM_HEADER=MQTTLinux.h
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/samples/linux/stdoutsub.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/samples/linux/stdoutsub.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,254 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2016 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution. 
+ *
+ * The Eclipse Public License is available at 
+ *   http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at 
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial contribution
+ *    Ian Craggs - change delimiter option from char to string
+ *    Al Stockdill-Mander - Version using the embedded C client
+ *    Ian Craggs - update MQTTClient function names
+ *******************************************************************************/
+
+/*
+ 
+ stdout subscriber
+ 
+ compulsory parameters:
+ 
+  topic to subscribe to
+ 
+ defaulted parameters:
+ 
+	--host localhost
+	--port 1883
+	--qos 2
+	--delimiter \n
+	--clientid stdout_subscriber
+	
+	--userid none
+	--password none
+
+ for example:
+
+    stdoutsub topic/of/interest --host iot.eclipse.org
+
+*/
+#include <stdio.h>
+#include <memory.h>
+#include "MQTTClient.h"
+
+#include <stdio.h>
+#include <signal.h>
+
+#include <sys/time.h>
+
+
+volatile int toStop = 0;
+
+
+void usage()
+{
+	printf("MQTT stdout subscriber\n");
+	printf("Usage: stdoutsub topicname <options>, where options are:\n");
+	printf("  --host <hostname> (default is localhost)\n");
+	printf("  --port <port> (default is 1883)\n");
+	printf("  --qos <qos> (default is 2)\n");
+	printf("  --delimiter <delim> (default is \\n)\n");
+	printf("  --clientid <clientid> (default is hostname+timestamp)\n");
+	printf("  --username none\n");
+	printf("  --password none\n");
+	printf("  --showtopics <on or off> (default is on if the topic has a wildcard, else off)\n");
+	exit(-1);
+}
+
+
+void cfinish(int sig)
+{
+	signal(SIGINT, NULL);
+	toStop = 1;
+}
+
+
+struct opts_struct
+{
+	char* clientid;
+	int nodelimiter;
+	char* delimiter;
+	enum QoS qos;
+	char* username;
+	char* password;
+	char* host;
+	int port;
+	int showtopics;
+} opts =
+{
+	(char*)"stdout-subscriber", 0, (char*)"\n", QOS2, NULL, NULL, (char*)"localhost", 1883, 0
+};
+
+
+void getopts(int argc, char** argv)
+{
+	int count = 2;
+	
+	while (count < argc)
+	{
+		if (strcmp(argv[count], "--qos") == 0)
+		{
+			if (++count < argc)
+			{
+				if (strcmp(argv[count], "0") == 0)
+					opts.qos = QOS0;
+				else if (strcmp(argv[count], "1") == 0)
+					opts.qos = QOS1;
+				else if (strcmp(argv[count], "2") == 0)
+					opts.qos = QOS2;
+				else
+					usage();
+			}
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--host") == 0)
+		{
+			if (++count < argc)
+				opts.host = argv[count];
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--port") == 0)
+		{
+			if (++count < argc)
+				opts.port = atoi(argv[count]);
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--clientid") == 0)
+		{
+			if (++count < argc)
+				opts.clientid = argv[count];
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--username") == 0)
+		{
+			if (++count < argc)
+				opts.username = argv[count];
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--password") == 0)
+		{
+			if (++count < argc)
+				opts.password = argv[count];
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--delimiter") == 0)
+		{
+			if (++count < argc)
+				opts.delimiter = argv[count];
+			else
+				opts.nodelimiter = 1;
+		}
+		else if (strcmp(argv[count], "--showtopics") == 0)
+		{
+			if (++count < argc)
+			{
+				if (strcmp(argv[count], "on") == 0)
+					opts.showtopics = 1;
+				else if (strcmp(argv[count], "off") == 0)
+					opts.showtopics = 0;
+				else
+					usage();
+			}
+			else
+				usage();
+		}
+		count++;
+	}
+	
+}
+
+
+void messageArrived(MessageData* md)
+{
+	MQTTMessage* message = md->message;
+
+	if (opts.showtopics)
+		printf("%.*s\t", md->topicName->lenstring.len, md->topicName->lenstring.data);
+	if (opts.nodelimiter)
+		printf("%.*s", (int)message->payloadlen, (char*)message->payload);
+	else
+		printf("%.*s%s", (int)message->payloadlen, (char*)message->payload, opts.delimiter);
+	//fflush(stdout);
+}
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	unsigned char readbuf[100];
+	
+	if (argc < 2)
+		usage();
+	
+	char* topic = argv[1];
+
+	if (strchr(topic, '#') || strchr(topic, '+'))
+		opts.showtopics = 1;
+	if (opts.showtopics)
+		printf("topic is %s\n", topic);
+
+	getopts(argc, argv);	
+
+	Network n;
+	MQTTClient c;
+
+	signal(SIGINT, cfinish);
+	signal(SIGTERM, cfinish);
+
+	NetworkInit(&n);
+	NetworkConnect(&n, opts.host, opts.port);
+	MQTTClientInit(&c, &n, 1000, buf, 100, readbuf, 100);
+ 
+	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;       
+	data.willFlag = 0;
+	data.MQTTVersion = 3;
+	data.clientID.cstring = opts.clientid;
+	data.username.cstring = opts.username;
+	data.password.cstring = opts.password;
+
+	data.keepAliveInterval = 10;
+	data.cleansession = 1;
+	printf("Connecting to %s %d\n", opts.host, opts.port);
+	
+	rc = MQTTConnect(&c, &data);
+	printf("Connected %d\n", rc);
+    
+    printf("Subscribing to %s\n", topic);
+	rc = MQTTSubscribe(&c, topic, opts.qos, messageArrived);
+	printf("Subscribed %d\n", rc);
+
+	while (!toStop)
+	{
+		MQTTYield(&c, 1000);	
+	}
+	
+	printf("Stopping\n");
+
+	MQTTDisconnect(&c);
+	NetworkDisconnect(&n);
+
+	return 0;
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,30 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+# MQTTClient Library - C
+
+
+file(GLOB SOURCES "*.c" "linux/*.c")
+
+add_library(
+  paho-embed-mqtt3cc SHARED
+  ${SOURCES}
+)
+install(TARGETS paho-embed-mqtt3cc DESTINATION /usr/lib)
+target_include_directories(paho-embed-mqtt3cc PRIVATE "linux")
+target_link_libraries(paho-embed-mqtt3cc paho-embed-mqtt3c)
+target_compile_definitions(paho-embed-mqtt3cc PRIVATE
+             MQTTCLIENT_PLATFORM_HEADER=MQTTLinux.h MQTTCLIENT_QOS2=1)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/FreeRTOS/MQTTFreeRTOS.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/FreeRTOS/MQTTFreeRTOS.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,240 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2015 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Allan Stockdill-Mander - initial API and implementation and/or initial documentation
+ *    Ian Craggs - convert to FreeRTOS
+ *******************************************************************************/
+
+#include "MQTTFreeRTOS.h"
+
+
+int ThreadStart(Thread* thread, void (*fn)(void*), void* arg)
+{
+	int rc = 0;
+	uint16_t usTaskStackSize = (configMINIMAL_STACK_SIZE * 5);
+	UBaseType_t uxTaskPriority = uxTaskPriorityGet(NULL); /* set the priority as the same as the calling task*/
+
+	rc = xTaskCreate(fn,	/* The function that implements the task. */
+		"MQTTTask",			/* Just a text name for the task to aid debugging. */
+		usTaskStackSize,	/* The stack size is defined in FreeRTOSIPConfig.h. */
+		arg,				/* The task parameter, not used in this case. */
+		uxTaskPriority,		/* The priority assigned to the task is defined in FreeRTOSConfig.h. */
+		&thread->task);		/* The task handle is not used. */
+
+	return rc;
+}
+
+
+void MutexInit(Mutex* mutex)
+{
+	mutex->sem = xSemaphoreCreateMutex();
+}
+
+int MutexLock(Mutex* mutex)
+{
+	return xSemaphoreTake(mutex->sem, portMAX_DELAY);
+}
+
+int MutexUnlock(Mutex* mutex)
+{
+	return xSemaphoreGive(mutex->sem);
+}
+
+
+void TimerCountdownMS(Timer* timer, unsigned int timeout_ms)
+{
+	timer->xTicksToWait = timeout_ms / portTICK_PERIOD_MS; /* convert milliseconds to ticks */
+	vTaskSetTimeOutState(&timer->xTimeOut); /* Record the time at which this function was entered. */
+}
+
+
+void TimerCountdown(Timer* timer, unsigned int timeout) 
+{
+	TimerCountdownMS(timer, timeout * 1000);
+}
+
+
+int TimerLeftMS(Timer* timer) 
+{
+	xTaskCheckForTimeOut(&timer->xTimeOut, &timer->xTicksToWait); /* updates xTicksToWait to the number left */
+	return (timer->xTicksToWait < 0) ? 0 : (timer->xTicksToWait * portTICK_PERIOD_MS);
+}
+
+
+char TimerIsExpired(Timer* timer)
+{
+	return xTaskCheckForTimeOut(&timer->xTimeOut, &timer->xTicksToWait) == pdTRUE;
+}
+
+
+void TimerInit(Timer* timer)
+{
+	timer->xTicksToWait = 0;
+	memset(&timer->xTimeOut, '\0', sizeof(timer->xTimeOut));
+}
+
+
+int FreeRTOS_read(Network* n, unsigned char* buffer, int len, int timeout_ms)
+{
+	TickType_t xTicksToWait = timeout_ms / portTICK_PERIOD_MS; /* convert milliseconds to ticks */
+	TimeOut_t xTimeOut;
+	int recvLen = 0;
+
+	vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */
+	do
+	{
+		int rc = 0;
+
+		FreeRTOS_setsockopt(n->my_socket, 0, FREERTOS_SO_RCVTIMEO, &xTicksToWait, sizeof(xTicksToWait));
+		rc = FreeRTOS_recv(n->my_socket, buffer + recvLen, len - recvLen, 0);
+		if (rc > 0)
+			recvLen += rc;
+		else if (rc < 0)
+		{
+			recvLen = rc;
+			break;
+		}
+	} while (recvLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE);
+
+	return recvLen;
+}
+
+
+int FreeRTOS_write(Network* n, unsigned char* buffer, int len, int timeout_ms)
+{
+	TickType_t xTicksToWait = timeout_ms / portTICK_PERIOD_MS; /* convert milliseconds to ticks */
+	TimeOut_t xTimeOut;
+	int sentLen = 0;
+
+	vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */
+	do
+	{
+		int rc = 0;
+
+		FreeRTOS_setsockopt(n->my_socket, 0, FREERTOS_SO_RCVTIMEO, &xTicksToWait, sizeof(xTicksToWait));
+		rc = FreeRTOS_send(n->my_socket, buffer + sentLen, len - sentLen, 0);
+		if (rc > 0)
+			sentLen += rc;
+		else if (rc < 0)
+		{
+			sentLen = rc;
+			break;
+		}
+	} while (sentLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE);
+
+	return sentLen;
+}
+
+
+void FreeRTOS_disconnect(Network* n)
+{
+	FreeRTOS_closesocket(n->my_socket);
+}
+
+
+void NetworkInit(Network* n)
+{
+	n->my_socket = 0;
+	n->mqttread = FreeRTOS_read;
+	n->mqttwrite = FreeRTOS_write;
+	n->disconnect = FreeRTOS_disconnect;
+}
+
+
+int NetworkConnect(Network* n, char* addr, int port)
+{
+	struct freertos_sockaddr sAddr;
+	int retVal = -1;
+	uint32_t ipAddress;
+
+	if ((ipAddress = FreeRTOS_gethostbyname(addr)) == 0)
+		goto exit;
+
+	sAddr.sin_port = FreeRTOS_htons(port);
+	sAddr.sin_addr = ipAddress;
+
+	if ((n->my_socket = FreeRTOS_socket(FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP)) < 0)
+		goto exit;
+
+	if ((retVal = FreeRTOS_connect(n->my_socket, &sAddr, sizeof(sAddr))) < 0)
+	{
+		FreeRTOS_closesocket(n->my_socket);
+	    goto exit;
+	}
+
+exit:
+	return retVal;
+}
+
+
+#if 0
+int NetworkConnectTLS(Network *n, char* addr, int port, SlSockSecureFiles_t* certificates, unsigned char sec_method, unsigned int cipher, char server_verify)
+{
+	SlSockAddrIn_t sAddr;
+	int addrSize;
+	int retVal;
+	unsigned long ipAddress;
+
+	retVal = sl_NetAppDnsGetHostByName(addr, strlen(addr), &ipAddress, AF_INET);
+	if (retVal < 0) {
+		return -1;
+	}
+
+	sAddr.sin_family = AF_INET;
+	sAddr.sin_port = sl_Htons((unsigned short)port);
+	sAddr.sin_addr.s_addr = sl_Htonl(ipAddress);
+
+	addrSize = sizeof(SlSockAddrIn_t);
+
+	n->my_socket = sl_Socket(SL_AF_INET, SL_SOCK_STREAM, SL_SEC_SOCKET);
+	if (n->my_socket < 0) {
+		return -1;
+	}
+
+	SlSockSecureMethod method;
+	method.secureMethod = sec_method;
+	retVal = sl_SetSockOpt(n->my_socket, SL_SOL_SOCKET, SL_SO_SECMETHOD, &method, sizeof(method));
+	if (retVal < 0) {
+		return retVal;
+	}
+
+	SlSockSecureMask mask;
+	mask.secureMask = cipher;
+	retVal = sl_SetSockOpt(n->my_socket, SL_SOL_SOCKET, SL_SO_SECURE_MASK, &mask, sizeof(mask));
+	if (retVal < 0) {
+		return retVal;
+	}
+
+	if (certificates != NULL) {
+		retVal = sl_SetSockOpt(n->my_socket, SL_SOL_SOCKET, SL_SO_SECURE_FILES, certificates->secureFiles, sizeof(SlSockSecureFiles_t));
+		if (retVal < 0)
+		{
+			return retVal;
+		}
+	}
+
+	retVal = sl_Connect(n->my_socket, (SlSockAddr_t *)&sAddr, addrSize);
+	if (retVal < 0) {
+		if (server_verify || retVal != -453) {
+			sl_Close(n->my_socket);
+			return retVal;
+		}
+	}
+
+	SysTickIntRegister(SysTickIntHandler);
+	SysTickPeriodSet(80000);
+	SysTickEnable();
+
+	return retVal;
+}
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/FreeRTOS/MQTTFreeRTOS.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/FreeRTOS/MQTTFreeRTOS.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2015 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Allan Stockdill-Mander - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#if !defined(MQTTFreeRTOS_H)
+#define MQTTFreeRTOS_H
+
+#include "FreeRTOS.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_IP.h"
+#include "semphr.h"
+#include "task.h"
+
+typedef struct Timer 
+{
+	TickType_t xTicksToWait;
+	TimeOut_t xTimeOut;
+} Timer;
+
+typedef struct Network Network;
+
+struct Network
+{
+	xSocket_t my_socket;
+	int (*mqttread) (Network*, unsigned char*, int, int);
+	int (*mqttwrite) (Network*, unsigned char*, int, int);
+	void (*disconnect) (Network*);
+};
+
+void TimerInit(Timer*);
+char TimerIsExpired(Timer*);
+void TimerCountdownMS(Timer*, unsigned int);
+void TimerCountdown(Timer*, unsigned int);
+int TimerLeftMS(Timer*);
+
+typedef struct Mutex
+{
+	SemaphoreHandle_t sem;
+} Mutex;
+
+void MutexInit(Mutex*);
+int MutexLock(Mutex*);
+int MutexUnlock(Mutex*);
+
+typedef struct Thread
+{
+	TaskHandle_t task;
+} Thread;
+
+int ThreadStart(Thread*, void (*fn)(void*), void* arg);
+
+int FreeRTOS_read(Network*, unsigned char*, int, int);
+int FreeRTOS_write(Network*, unsigned char*, int, int);
+void FreeRTOS_disconnect(Network*);
+
+void NetworkInit(Network*);
+int NetworkConnect(Network*, char*, int);
+/*int NetworkConnectTLS(Network*, char*, int, SlSockSecureFiles_t*, unsigned char, unsigned int, char);*/
+
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/MQTTClient.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/MQTTClient.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,700 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2017 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *   Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
+ *   Ian Craggs - fix for #96 - check rem_len in readPacket
+ *   Ian Craggs - add ability to set message handler separately #6
+ *******************************************************************************/
+#include "MQTTClient.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static void NewMessageData(MessageData* md, MQTTString* aTopicName, MQTTMessage* aMessage) {
+    md->topicName = aTopicName;
+    md->message = aMessage;
+}
+
+
+static int getNextPacketId(MQTTClient *c) {
+    return c->next_packetid = (c->next_packetid == MAX_PACKET_ID) ? 1 : c->next_packetid + 1;
+}
+
+
+static int sendPacket(MQTTClient* c, int length, Timer* timer)
+{
+    int rc = FAILURE,
+        sent = 0;
+
+    while (sent < length && !TimerIsExpired(timer))
+    {
+        rc = c->ipstack->mqttwrite(c->ipstack, &c->buf[sent], length, TimerLeftMS(timer));
+        if (rc < 0)  // there was an error writing the data
+            break;
+        sent += rc;
+    }
+    if (sent == length)
+    {
+        TimerCountdown(&c->last_sent, c->keepAliveInterval); // record the fact that we have successfully sent the packet
+        rc = SUCCESS;
+    }
+    else
+        rc = FAILURE;
+    return rc;
+}
+
+
+void MQTTClientInit(MQTTClient* c, Network* network, unsigned int command_timeout_ms,
+		unsigned char* sendbuf, size_t sendbuf_size, unsigned char* readbuf, size_t readbuf_size)
+{
+    int i;
+    c->ipstack = network;
+
+    for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+        c->messageHandlers[i].topicFilter = 0;
+    c->command_timeout_ms = command_timeout_ms;
+    c->buf = sendbuf;
+    c->buf_size = sendbuf_size;
+    c->readbuf = readbuf;
+    c->readbuf_size = readbuf_size;
+    c->isconnected = 0;
+    c->cleansession = 0;
+    c->ping_outstanding = 0;
+    c->defaultMessageHandler = NULL;
+	  c->next_packetid = 1;
+    TimerInit(&c->last_sent);
+    TimerInit(&c->last_received);
+#if defined(MQTT_TASK)
+	  MutexInit(&c->mutex);
+#endif
+}
+
+
+static int decodePacket(MQTTClient* c, int* value, int timeout)
+{
+    unsigned char i;
+    int multiplier = 1;
+    int len = 0;
+    const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4;
+
+    *value = 0;
+    do
+    {
+        int rc = MQTTPACKET_READ_ERROR;
+
+        if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
+        {
+            rc = MQTTPACKET_READ_ERROR; /* bad data */
+            goto exit;
+        }
+        rc = c->ipstack->mqttread(c->ipstack, &i, 1, timeout);
+        if (rc != 1)
+            goto exit;
+        *value += (i & 127) * multiplier;
+        multiplier *= 128;
+    } while ((i & 128) != 0);
+exit:
+    return len;
+}
+
+
+static int readPacket(MQTTClient* c, Timer* timer)
+{
+    MQTTHeader header = {0};
+    int len = 0;
+    int rem_len = 0;
+
+    /* 1. read the header byte.  This has the packet type in it */
+    int rc = c->ipstack->mqttread(c->ipstack, c->readbuf, 1, TimerLeftMS(timer));
+    if (rc != 1)
+        goto exit;
+
+    len = 1;
+    /* 2. read the remaining length.  This is variable in itself */
+    decodePacket(c, &rem_len, TimerLeftMS(timer));
+    len += MQTTPacket_encode(c->readbuf + 1, rem_len); /* put the original remaining length back into the buffer */
+
+    if (rem_len > (c->readbuf_size - len))
+    {
+        rc = BUFFER_OVERFLOW;
+        goto exit;
+    }
+
+    /* 3. read the rest of the buffer using a callback to supply the rest of the data */
+    if (rem_len > 0 && (rc = c->ipstack->mqttread(c->ipstack, c->readbuf + len, rem_len, TimerLeftMS(timer)) != rem_len)) {
+        rc = 0;
+        goto exit;
+    }
+
+    header.byte = c->readbuf[0];
+    rc = header.bits.type;
+    if (c->keepAliveInterval > 0)
+        TimerCountdown(&c->last_received, c->keepAliveInterval); // record the fact that we have successfully received a packet
+exit:
+    return rc;
+}
+
+
+// assume topic filter and name is in correct format
+// # can only be at end
+// + and # can only be next to separator
+static char isTopicMatched(char* topicFilter, MQTTString* topicName)
+{
+    char* curf = topicFilter;
+    char* curn = topicName->lenstring.data;
+    char* curn_end = curn + topicName->lenstring.len;
+
+    while (*curf && curn < curn_end)
+    {
+        if (*curn == '/' && *curf != '/')
+            break;
+        if (*curf != '+' && *curf != '#' && *curf != *curn)
+            break;
+        if (*curf == '+')
+        {   // skip until we meet the next separator, or end of string
+            char* nextpos = curn + 1;
+            while (nextpos < curn_end && *nextpos != '/')
+                nextpos = ++curn + 1;
+        }
+        else if (*curf == '#')
+            curn = curn_end - 1;    // skip until end of string
+        curf++;
+        curn++;
+    };
+
+    return (curn == curn_end) && (*curf == '\0');
+}
+
+
+int deliverMessage(MQTTClient* c, MQTTString* topicName, MQTTMessage* message)
+{
+    int i;
+    int rc = FAILURE;
+
+    // we have to find the right message handler - indexed by topic
+    for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+    {
+        if (c->messageHandlers[i].topicFilter != 0 && (MQTTPacket_equals(topicName, (char*)c->messageHandlers[i].topicFilter) ||
+                isTopicMatched((char*)c->messageHandlers[i].topicFilter, topicName)))
+        {
+            if (c->messageHandlers[i].fp != NULL)
+            {
+                MessageData md;
+                NewMessageData(&md, topicName, message);
+                c->messageHandlers[i].fp(&md);
+                rc = SUCCESS;
+            }
+        }
+    }
+
+    if (rc == FAILURE && c->defaultMessageHandler != NULL)
+    {
+        MessageData md;
+        NewMessageData(&md, topicName, message);
+        c->defaultMessageHandler(&md);
+        rc = SUCCESS;
+    }
+
+    return rc;
+}
+
+
+int keepalive(MQTTClient* c)
+{
+    int rc = SUCCESS;
+
+    if (c->keepAliveInterval == 0)
+        goto exit;
+
+    if (TimerIsExpired(&c->last_sent) || TimerIsExpired(&c->last_received))
+    {
+        if (c->ping_outstanding)
+            rc = FAILURE; /* PINGRESP not received in keepalive interval */
+        else
+        {
+            Timer timer;
+            TimerInit(&timer);
+            TimerCountdownMS(&timer, 1000);
+            int len = MQTTSerialize_pingreq(c->buf, c->buf_size);
+            if (len > 0 && (rc = sendPacket(c, len, &timer)) == SUCCESS) // send the ping packet
+                c->ping_outstanding = 1;
+        }
+    }
+
+exit:
+    return rc;
+}
+
+
+void MQTTCleanSession(MQTTClient* c)
+{
+    int i = 0;
+
+    for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+        c->messageHandlers[i].topicFilter = NULL;
+}
+
+
+void MQTTCloseSession(MQTTClient* c)
+{
+    c->ping_outstanding = 0;
+    c->isconnected = 0;
+    if (c->cleansession)
+        MQTTCleanSession(c);
+}
+
+
+int cycle(MQTTClient* c, Timer* timer)
+{
+    int len = 0,
+        rc = SUCCESS;
+
+    int packet_type = readPacket(c, timer);     /* read the socket, see what work is due */
+
+    switch (packet_type)
+    {
+        default:
+            /* no more data to read, unrecoverable. Or read packet fails due to unexpected network error */
+            rc = packet_type;
+            goto exit;
+        case 0: /* timed out reading packet */
+            break;
+        case CONNACK:
+        case PUBACK:
+        case SUBACK:
+        case UNSUBACK:
+            break;
+        case PUBLISH:
+        {
+            MQTTString topicName;
+            MQTTMessage msg;
+            int intQoS;
+            msg.payloadlen = 0; /* this is a size_t, but deserialize publish sets this as int */
+            if (MQTTDeserialize_publish(&msg.dup, &intQoS, &msg.retained, &msg.id, &topicName,
+               (unsigned char**)&msg.payload, (int*)&msg.payloadlen, c->readbuf, c->readbuf_size) != 1)
+                goto exit;
+            msg.qos = (enum QoS)intQoS;
+            deliverMessage(c, &topicName, &msg);
+            if (msg.qos != QOS0)
+            {
+                if (msg.qos == QOS1)
+                    len = MQTTSerialize_ack(c->buf, c->buf_size, PUBACK, 0, msg.id);
+                else if (msg.qos == QOS2)
+                    len = MQTTSerialize_ack(c->buf, c->buf_size, PUBREC, 0, msg.id);
+                if (len <= 0)
+                    rc = FAILURE;
+                else
+                    rc = sendPacket(c, len, timer);
+                if (rc == FAILURE)
+                    goto exit; // there was a problem
+            }
+            break;
+        }
+        case PUBREC:
+        case PUBREL:
+        {
+            unsigned short mypacketid;
+            unsigned char dup, type;
+            if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
+                rc = FAILURE;
+            else if ((len = MQTTSerialize_ack(c->buf, c->buf_size,
+                (packet_type == PUBREC) ? PUBREL : PUBCOMP, 0, mypacketid)) <= 0)
+                rc = FAILURE;
+            else if ((rc = sendPacket(c, len, timer)) != SUCCESS) // send the PUBREL packet
+                rc = FAILURE; // there was a problem
+            if (rc == FAILURE)
+                goto exit; // there was a problem
+            break;
+        }
+
+        case PUBCOMP:
+            break;
+        case PINGRESP:
+            c->ping_outstanding = 0;
+            break;
+    }
+
+    if (keepalive(c) != SUCCESS) {
+        //check only keepalive FAILURE status so that previous FAILURE status can be considered as FAULT
+        rc = FAILURE;
+    }
+
+exit:
+    if (rc == SUCCESS)
+        rc = packet_type;
+    else if (c->isconnected)
+        MQTTCloseSession(c);
+    return rc;
+}
+
+
+int MQTTYield(MQTTClient* c, int timeout_ms)
+{
+    int rc = SUCCESS;
+    Timer timer;
+
+    TimerInit(&timer);
+    TimerCountdownMS(&timer, timeout_ms);
+
+	  do
+    {
+        if (cycle(c, &timer) < 0)
+        {
+            rc = FAILURE;
+            break;
+        }
+  	} while (!TimerIsExpired(&timer));
+
+    return rc;
+}
+
+int MQTTIsConnected(MQTTClient* client)
+{
+  return client->isconnected;
+}
+
+void MQTTRun(void* parm)
+{
+	Timer timer;
+	MQTTClient* c = (MQTTClient*)parm;
+
+	TimerInit(&timer);
+
+	while (1)
+	{
+#if defined(MQTT_TASK)
+		MutexLock(&c->mutex);
+#endif
+		TimerCountdownMS(&timer, 500); /* Don't wait too long if no traffic is incoming */
+		cycle(c, &timer);
+#if defined(MQTT_TASK)
+		MutexUnlock(&c->mutex);
+#endif
+	}
+}
+
+
+#if defined(MQTT_TASK)
+int MQTTStartTask(MQTTClient* client)
+{
+	return ThreadStart(&client->thread, &MQTTRun, client);
+}
+#endif
+
+
+int waitfor(MQTTClient* c, int packet_type, Timer* timer)
+{
+    int rc = FAILURE;
+
+    do
+    {
+        if (TimerIsExpired(timer))
+            break; // we timed out
+        rc = cycle(c, timer);
+    }
+    while (rc != packet_type && rc >= 0);
+
+    return rc;
+}
+
+
+
+
+int MQTTConnectWithResults(MQTTClient* c, MQTTPacket_connectData* options, MQTTConnackData* data)
+{
+    Timer connect_timer;
+    int rc = FAILURE;
+    MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer;
+    int len = 0;
+
+#if defined(MQTT_TASK)
+	  MutexLock(&c->mutex);
+#endif
+	  if (c->isconnected) /* don't send connect packet again if we are already connected */
+		  goto exit;
+
+    TimerInit(&connect_timer);
+    TimerCountdownMS(&connect_timer, c->command_timeout_ms);
+
+    if (options == 0)
+        options = &default_options; /* set default options if none were supplied */
+
+    c->keepAliveInterval = options->keepAliveInterval;
+    c->cleansession = options->cleansession;
+    TimerCountdown(&c->last_received, c->keepAliveInterval);
+    if ((len = MQTTSerialize_connect(c->buf, c->buf_size, options)) <= 0)
+        goto exit;
+    if ((rc = sendPacket(c, len, &connect_timer)) != SUCCESS)  // send the connect packet
+        goto exit; // there was a problem
+
+    // this will be a blocking call, wait for the connack
+    if (waitfor(c, CONNACK, &connect_timer) == CONNACK)
+    {
+        data->rc = 0;
+        data->sessionPresent = 0;
+        if (MQTTDeserialize_connack(&data->sessionPresent, &data->rc, c->readbuf, c->readbuf_size) == 1)
+            rc = data->rc;
+        else
+            rc = FAILURE;
+    }
+    else
+        rc = FAILURE;
+
+exit:
+    if (rc == SUCCESS)
+    {
+        c->isconnected = 1;
+        c->ping_outstanding = 0;
+    }
+
+#if defined(MQTT_TASK)
+	  MutexUnlock(&c->mutex);
+#endif
+
+    return rc;
+}
+
+
+int MQTTConnect(MQTTClient* c, MQTTPacket_connectData* options)
+{
+    MQTTConnackData data;
+    return MQTTConnectWithResults(c, options, &data);
+}
+
+
+int MQTTSetMessageHandler(MQTTClient* c, const char* topicFilter, messageHandler messageHandler)
+{
+    int rc = FAILURE;
+    int i = -1;
+
+    /* first check for an existing matching slot */
+    for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+    {
+        if (c->messageHandlers[i].topicFilter != NULL && strcmp(c->messageHandlers[i].topicFilter, topicFilter) == 0)
+        {
+            if (messageHandler == NULL) /* remove existing */
+            {
+                c->messageHandlers[i].topicFilter = NULL;
+                c->messageHandlers[i].fp = NULL;
+            }
+            rc = SUCCESS; /* return i when adding new subscription */
+            break;
+        }
+    }
+    /* if no existing, look for empty slot (unless we are removing) */
+    if (messageHandler != NULL) {
+        if (rc == FAILURE)
+        {
+            for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+            {
+                if (c->messageHandlers[i].topicFilter == NULL)
+                {
+                    rc = SUCCESS;
+                    break;
+                }
+            }
+        }
+        if (i < MAX_MESSAGE_HANDLERS)
+        {
+            c->messageHandlers[i].topicFilter = topicFilter;
+            c->messageHandlers[i].fp = messageHandler;
+        }
+    }
+    return rc;
+}
+
+
+int MQTTSubscribeWithResults(MQTTClient* c, const char* topicFilter, enum QoS qos,
+       messageHandler messageHandler, MQTTSubackData* data)
+{
+    int rc = FAILURE;
+    Timer timer;
+    int len = 0;
+    MQTTString topic = MQTTString_initializer;
+    topic.cstring = (char *)topicFilter;
+
+#if defined(MQTT_TASK)
+	  MutexLock(&c->mutex);
+#endif
+	  if (!c->isconnected)
+		    goto exit;
+
+    TimerInit(&timer);
+    TimerCountdownMS(&timer, c->command_timeout_ms);
+
+    len = MQTTSerialize_subscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic, (int*)&qos);
+    if (len <= 0)
+        goto exit;
+    if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
+        goto exit;             // there was a problem
+
+    if (waitfor(c, SUBACK, &timer) == SUBACK)      // wait for suback
+    {
+        int count = 0;
+        unsigned short mypacketid;
+        data->grantedQoS = QOS0;
+        if (MQTTDeserialize_suback(&mypacketid, 1, &count, (int*)&data->grantedQoS, c->readbuf, c->readbuf_size) == 1)
+        {
+            if (data->grantedQoS != 0x80)
+                rc = MQTTSetMessageHandler(c, topicFilter, messageHandler);
+        }
+    }
+    else
+        rc = FAILURE;
+
+exit:
+    if (rc == FAILURE)
+        MQTTCloseSession(c);
+#if defined(MQTT_TASK)
+	  MutexUnlock(&c->mutex);
+#endif
+    return rc;
+}
+
+
+int MQTTSubscribe(MQTTClient* c, const char* topicFilter, enum QoS qos,
+       messageHandler messageHandler)
+{
+    MQTTSubackData data;
+    return MQTTSubscribeWithResults(c, topicFilter, qos, messageHandler, &data);
+}
+
+
+int MQTTUnsubscribe(MQTTClient* c, const char* topicFilter)
+{
+    int rc = FAILURE;
+    Timer timer;
+    MQTTString topic = MQTTString_initializer;
+    topic.cstring = (char *)topicFilter;
+    int len = 0;
+
+#if defined(MQTT_TASK)
+	  MutexLock(&c->mutex);
+#endif
+	  if (!c->isconnected)
+		  goto exit;
+
+    TimerInit(&timer);
+    TimerCountdownMS(&timer, c->command_timeout_ms);
+
+    if ((len = MQTTSerialize_unsubscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic)) <= 0)
+        goto exit;
+    if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
+        goto exit; // there was a problem
+
+    if (waitfor(c, UNSUBACK, &timer) == UNSUBACK)
+    {
+        unsigned short mypacketid;  // should be the same as the packetid above
+        if (MQTTDeserialize_unsuback(&mypacketid, c->readbuf, c->readbuf_size) == 1)
+        {
+            /* remove the subscription message handler associated with this topic, if there is one */
+            MQTTSetMessageHandler(c, topicFilter, NULL);
+        }
+    }
+    else
+        rc = FAILURE;
+
+exit:
+    if (rc == FAILURE)
+        MQTTCloseSession(c);
+#if defined(MQTT_TASK)
+	  MutexUnlock(&c->mutex);
+#endif
+    return rc;
+}
+
+
+int MQTTPublish(MQTTClient* c, const char* topicName, MQTTMessage* message)
+{
+    int rc = FAILURE;
+    Timer timer;
+    MQTTString topic = MQTTString_initializer;
+    topic.cstring = (char *)topicName;
+    int len = 0;
+
+#if defined(MQTT_TASK)
+	  MutexLock(&c->mutex);
+#endif
+	  if (!c->isconnected)
+		    goto exit;
+
+    TimerInit(&timer);
+    TimerCountdownMS(&timer, c->command_timeout_ms);
+
+    if (message->qos == QOS1 || message->qos == QOS2)
+        message->id = getNextPacketId(c);
+
+    len = MQTTSerialize_publish(c->buf, c->buf_size, 0, message->qos, message->retained, message->id,
+              topic, (unsigned char*)message->payload, message->payloadlen);
+    if (len <= 0)
+        goto exit;
+    if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
+        goto exit; // there was a problem
+
+    if (message->qos == QOS1)
+    {
+        if (waitfor(c, PUBACK, &timer) == PUBACK)
+        {
+            unsigned short mypacketid;
+            unsigned char dup, type;
+            if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
+                rc = FAILURE;
+        }
+        else
+            rc = FAILURE;
+    }
+    else if (message->qos == QOS2)
+    {
+        if (waitfor(c, PUBCOMP, &timer) == PUBCOMP)
+        {
+            unsigned short mypacketid;
+            unsigned char dup, type;
+            if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
+                rc = FAILURE;
+        }
+        else
+            rc = FAILURE;
+    }
+
+exit:
+    if (rc == FAILURE)
+        MQTTCloseSession(c);
+#if defined(MQTT_TASK)
+	  MutexUnlock(&c->mutex);
+#endif
+    return rc;
+}
+
+
+int MQTTDisconnect(MQTTClient* c)
+{
+    int rc = FAILURE;
+    Timer timer;     // we might wait for incomplete incoming publishes to complete
+    int len = 0;
+
+#if defined(MQTT_TASK)
+	MutexLock(&c->mutex);
+#endif
+    TimerInit(&timer);
+    TimerCountdownMS(&timer, c->command_timeout_ms);
+
+	  len = MQTTSerialize_disconnect(c->buf, c->buf_size);
+    if (len > 0)
+        rc = sendPacket(c, len, &timer);            // send the disconnect packet
+    MQTTCloseSession(c);
+
+#if defined(MQTT_TASK)
+	  MutexUnlock(&c->mutex);
+#endif
+    return rc;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/MQTTClient.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/MQTTClient.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,233 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2017 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
+ *    Ian Craggs - documentation and platform specific header
+ *    Ian Craggs - add setMessageHandler function
+ *******************************************************************************/
+
+#if !defined(MQTT_CLIENT_H)
+#define MQTT_CLIENT_H
+
+#if defined(__cplusplus)
+ extern "C" {
+#endif
+
+#if defined(WIN32_DLL) || defined(WIN64_DLL)
+  #define DLLImport __declspec(dllimport)
+  #define DLLExport __declspec(dllexport)
+#elif defined(LINUX_SO)
+  #define DLLImport extern
+  #define DLLExport  __attribute__ ((visibility ("default")))
+#else
+  #define DLLImport
+  #define DLLExport
+#endif
+
+#include "MQTTPacket.h"
+
+#if defined(MQTTCLIENT_PLATFORM_HEADER)
+/* The following sequence of macros converts the MQTTCLIENT_PLATFORM_HEADER value
+ * into a string constant suitable for use with include.
+ */
+#define xstr(s) str(s)
+#define str(s) #s
+#include xstr(MQTTCLIENT_PLATFORM_HEADER)
+#endif
+
+#define MAX_PACKET_ID 65535 /* according to the MQTT specification - do not change! */
+
+#if !defined(MAX_MESSAGE_HANDLERS)
+#define MAX_MESSAGE_HANDLERS 5 /* redefinable - how many subscriptions do you want? */
+#endif
+
+enum QoS { QOS0, QOS1, QOS2, SUBFAIL=0x80 };
+
+/* all failure return codes must be negative */
+enum returnCode { BUFFER_OVERFLOW = -2, FAILURE = -1, SUCCESS = 0 };
+
+/* The Platform specific header must define the Network and Timer structures and functions
+ * which operate on them.
+ *
+typedef struct Network
+{
+	int (*mqttread)(Network*, unsigned char* read_buffer, int, int);
+	int (*mqttwrite)(Network*, unsigned char* send_buffer, int, int);
+} Network;*/
+
+/* The Timer structure must be defined in the platform specific header,
+ * and have the following functions to operate on it.  */
+extern void TimerInit(Timer*);
+extern char TimerIsExpired(Timer*);
+extern void TimerCountdownMS(Timer*, unsigned int);
+extern void TimerCountdown(Timer*, unsigned int);
+extern int TimerLeftMS(Timer*);
+
+typedef struct MQTTMessage
+{
+    enum QoS qos;
+    unsigned char retained;
+    unsigned char dup;
+    unsigned short id;
+    void *payload;
+    size_t payloadlen;
+} MQTTMessage;
+
+typedef struct MessageData
+{
+    MQTTMessage* message;
+    MQTTString* topicName;
+} MessageData;
+
+typedef struct MQTTConnackData
+{
+    unsigned char rc;
+    unsigned char sessionPresent;
+} MQTTConnackData;
+
+typedef struct MQTTSubackData
+{
+    enum QoS grantedQoS;
+} MQTTSubackData;
+
+typedef void (*messageHandler)(MessageData*);
+
+typedef struct MQTTClient
+{
+    unsigned int next_packetid,
+      command_timeout_ms;
+    size_t buf_size,
+      readbuf_size;
+    unsigned char *buf,
+      *readbuf;
+    unsigned int keepAliveInterval;
+    char ping_outstanding;
+    int isconnected;
+    int cleansession;
+
+    struct MessageHandlers
+    {
+        const char* topicFilter;
+        void (*fp) (MessageData*);
+    } messageHandlers[MAX_MESSAGE_HANDLERS];      /* Message handlers are indexed by subscription topic */
+
+    void (*defaultMessageHandler) (MessageData*);
+
+    Network* ipstack;
+    Timer last_sent, last_received;
+#if defined(MQTT_TASK)
+    Mutex mutex;
+    Thread thread;
+#endif
+} MQTTClient;
+
+#define DefaultClient {0, 0, 0, 0, NULL, NULL, 0, 0, 0}
+
+
+/**
+ * Create an MQTT client object
+ * @param client
+ * @param network
+ * @param command_timeout_ms
+ * @param
+ */
+DLLExport void MQTTClientInit(MQTTClient* client, Network* network, unsigned int command_timeout_ms,
+		unsigned char* sendbuf, size_t sendbuf_size, unsigned char* readbuf, size_t readbuf_size);
+
+/** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack
+ *  The nework object must be connected to the network endpoint before calling this
+ *  @param options - connect options
+ *  @return success code
+ */
+DLLExport int MQTTConnectWithResults(MQTTClient* client, MQTTPacket_connectData* options,
+    MQTTConnackData* data);
+
+/** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack
+ *  The nework object must be connected to the network endpoint before calling this
+ *  @param options - connect options
+ *  @return success code
+ */
+DLLExport int MQTTConnect(MQTTClient* client, MQTTPacket_connectData* options);
+
+/** MQTT Publish - send an MQTT publish packet and wait for all acks to complete for all QoSs
+ *  @param client - the client object to use
+ *  @param topic - the topic to publish to
+ *  @param message - the message to send
+ *  @return success code
+ */
+DLLExport int MQTTPublish(MQTTClient* client, const char*, MQTTMessage*);
+
+/** MQTT SetMessageHandler - set or remove a per topic message handler
+ *  @param client - the client object to use
+ *  @param topicFilter - the topic filter set the message handler for
+ *  @param messageHandler - pointer to the message handler function or NULL to remove
+ *  @return success code
+ */
+DLLExport int MQTTSetMessageHandler(MQTTClient* c, const char* topicFilter, messageHandler messageHandler);
+
+/** MQTT Subscribe - send an MQTT subscribe packet and wait for suback before returning.
+ *  @param client - the client object to use
+ *  @param topicFilter - the topic filter to subscribe to
+ *  @param message - the message to send
+ *  @return success code
+ */
+DLLExport int MQTTSubscribe(MQTTClient* client, const char* topicFilter, enum QoS, messageHandler);
+
+/** MQTT Subscribe - send an MQTT subscribe packet and wait for suback before returning.
+ *  @param client - the client object to use
+ *  @param topicFilter - the topic filter to subscribe to
+ *  @param message - the message to send
+ *  @param data - suback granted QoS returned
+ *  @return success code
+ */
+DLLExport int MQTTSubscribeWithResults(MQTTClient* client, const char* topicFilter, enum QoS, messageHandler, MQTTSubackData* data);
+
+/** MQTT Subscribe - send an MQTT unsubscribe packet and wait for unsuback before returning.
+ *  @param client - the client object to use
+ *  @param topicFilter - the topic filter to unsubscribe from
+ *  @return success code
+ */
+DLLExport int MQTTUnsubscribe(MQTTClient* client, const char* topicFilter);
+
+/** MQTT Disconnect - send an MQTT disconnect packet and close the connection
+ *  @param client - the client object to use
+ *  @return success code
+ */
+DLLExport int MQTTDisconnect(MQTTClient* client);
+
+/** MQTT Yield - MQTT background
+ *  @param client - the client object to use
+ *  @param time - the time, in milliseconds, to yield for
+ *  @return success code
+ */
+DLLExport int MQTTYield(MQTTClient* client, int time);
+
+/** MQTT isConnected
+ *  @param client - the client object to use
+ *  @return truth value indicating whether the client is connected to the server
+ */
+DLLExport int MQTTIsConnected(MQTTClient* client);
+
+#if defined(MQTT_TASK)
+/** MQTT start background thread for a client.  After this, MQTTYield should not be called.
+*  @param client - the client object to use
+*  @return success code
+*/
+DLLExport int MQTTStartTask(MQTTClient* client);
+#endif
+
+#if defined(__cplusplus)
+     }
+#endif
+
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/cc3200/MQTTCC3200.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/cc3200/MQTTCC3200.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,196 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Allan Stockdill-Mander - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTCC3200.h"
+
+unsigned long MilliTimer;
+
+void SysTickIntHandler(void) {
+	MilliTimer++;
+}
+
+char expired(Timer* timer) {
+	long left = timer->end_time - MilliTimer;
+	return (left < 0);
+}
+
+
+void countdown_ms(Timer* timer, unsigned int timeout) {
+	timer->end_time = MilliTimer + timeout;
+}
+
+
+void countdown(Timer* timer, unsigned int timeout) {
+	timer->end_time = MilliTimer + (timeout * 1000);
+}
+
+
+int left_ms(Timer* timer) {
+	long left = timer->end_time - MilliTimer;
+	return (left < 0) ? 0 : left;
+}
+
+
+void InitTimer(Timer* timer) {
+	timer->end_time = 0;
+}
+
+
+int cc3200_read(Network* n, unsigned char* buffer, int len, int timeout_ms) {
+	SlTimeval_t timeVal;
+	SlFdSet_t fdset;
+	int rc = 0;
+	int recvLen = 0;
+
+	SL_FD_ZERO(&fdset);
+	SL_FD_SET(n->my_socket, &fdset);
+
+	timeVal.tv_sec = 0;
+	timeVal.tv_usec = timeout_ms * 1000;
+	if (sl_Select(n->my_socket + 1, &fdset, NULL, NULL, &timeVal) == 1) {
+		do {
+			rc = sl_Recv(n->my_socket, buffer + recvLen, len - recvLen, 0);
+			recvLen += rc;
+		} while(recvLen < len);
+	}
+	return recvLen;
+}
+
+
+int cc3200_write(Network* n, unsigned char* buffer, int len, int timeout_ms) {
+	SlTimeval_t timeVal;
+	SlFdSet_t fdset;
+	int rc = 0;
+	int readySock;
+
+	SL_FD_ZERO(&fdset);
+	SL_FD_SET(n->my_socket, &fdset);
+
+	timeVal.tv_sec = 0;
+	timeVal.tv_usec = timeout_ms * 1000;
+	do {
+		readySock = sl_Select(n->my_socket + 1, NULL, &fdset, NULL, &timeVal);
+	} while(readySock != 1);
+	rc = sl_Send(n->my_socket, buffer, len, 0);
+	return rc;
+}
+
+
+void cc3200_disconnect(Network* n) {
+	sl_Close(n->my_socket);
+}
+
+
+void NewNetwork(Network* n) {
+	n->my_socket = 0;
+	n->mqttread = cc3200_read;
+	n->mqttwrite = cc3200_write;
+	n->disconnect = cc3200_disconnect;
+}
+
+int TLSConnectNetwork(Network *n, char* addr, int port, SlSockSecureFiles_t* certificates, unsigned char sec_method, unsigned int cipher, char server_verify) {
+	SlSockAddrIn_t sAddr;
+	int addrSize;
+	int retVal;
+	unsigned long ipAddress;
+
+	retVal = sl_NetAppDnsGetHostByName(addr, strlen(addr), &ipAddress, AF_INET);
+	if (retVal < 0) {
+		return -1;
+	}
+
+	sAddr.sin_family = AF_INET;
+	sAddr.sin_port = sl_Htons((unsigned short)port);
+	sAddr.sin_addr.s_addr = sl_Htonl(ipAddress);
+
+	addrSize = sizeof(SlSockAddrIn_t);
+
+	n->my_socket = sl_Socket(SL_AF_INET,SL_SOCK_STREAM, SL_SEC_SOCKET);
+	if (n->my_socket < 0) {
+		return -1;
+	}
+
+	SlSockSecureMethod method;
+	method.secureMethod = sec_method;
+	retVal = sl_SetSockOpt(n->my_socket, SL_SOL_SOCKET, SL_SO_SECMETHOD, &method, sizeof(method));
+	if (retVal < 0) {
+		return retVal;
+	}
+
+	SlSockSecureMask mask;
+	mask.secureMask = cipher;
+	retVal = sl_SetSockOpt(n->my_socket, SL_SOL_SOCKET, SL_SO_SECURE_MASK, &mask, sizeof(mask));
+	if (retVal < 0) {
+		return retVal;
+	}
+
+	if (certificates != NULL) {
+		retVal = sl_SetSockOpt(n->my_socket, SL_SOL_SOCKET, SL_SO_SECURE_FILES, certificates->secureFiles, sizeof(SlSockSecureFiles_t));
+		if(retVal < 0)
+		{
+			return retVal;
+		}
+	}
+
+	retVal = sl_Connect(n->my_socket, ( SlSockAddr_t *)&sAddr, addrSize);
+	if( retVal < 0 ) {
+		if (server_verify || retVal != -453) {
+			sl_Close(n->my_socket);
+			return retVal;
+		}
+	}
+
+	SysTickIntRegister(SysTickIntHandler);
+	SysTickPeriodSet(80000);
+	SysTickEnable();
+
+	return retVal;
+}
+
+int ConnectNetwork(Network* n, char* addr, int port)
+{
+	SlSockAddrIn_t sAddr;
+	int addrSize;
+	int retVal;
+	unsigned long ipAddress;
+
+	sl_NetAppDnsGetHostByName(addr, strlen(addr), &ipAddress, AF_INET);
+
+	sAddr.sin_family = AF_INET;
+	sAddr.sin_port = sl_Htons((unsigned short)port);
+	sAddr.sin_addr.s_addr = sl_Htonl(ipAddress);
+
+	addrSize = sizeof(SlSockAddrIn_t);
+
+	n->my_socket = sl_Socket(SL_AF_INET,SL_SOCK_STREAM, 0);
+	if( n->my_socket < 0 ) {
+		// error
+		return -1;
+	}
+
+	retVal = sl_Connect(n->my_socket, ( SlSockAddr_t *)&sAddr, addrSize);
+	if( retVal < 0 ) {
+		// error
+		sl_Close(n->my_socket);
+	    return retVal;
+	}
+
+	SysTickIntRegister(SysTickIntHandler);
+	SysTickPeriodSet(80000);
+	SysTickEnable();
+
+	return retVal;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/cc3200/MQTTCC3200.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/cc3200/MQTTCC3200.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Allan Stockdill-Mander - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#ifndef __MQTT_CC3200_
+#define __MQTT_CC3200_
+
+#include "simplelink.h"
+#include "netapp.h"
+#include "socket.h"
+#include "hw_types.h"
+#include "systick.h"
+
+typedef struct Timer Timer;
+
+struct Timer {
+	unsigned long systick_period;
+	unsigned long end_time;
+};
+
+typedef struct Network Network;
+
+struct Network
+{
+	int my_socket;
+	int (*mqttread) (Network*, unsigned char*, int, int);
+	int (*mqttwrite) (Network*, unsigned char*, int, int);
+	void (*disconnect) (Network*);
+};
+
+char expired(Timer*);
+void countdown_ms(Timer*, unsigned int);
+void countdown(Timer*, unsigned int);
+int left_ms(Timer*);
+
+void InitTimer(Timer*);
+
+int cc3200_read(Network*, unsigned char*, int, int);
+int cc3200_write(Network*, unsigned char*, int, int);
+void cc3200_disconnect(Network*);
+void NewNetwork(Network*);
+
+int ConnectNetwork(Network*, char*, int);
+int TLSConnectNetwork(Network*, char*, int, SlSockSecureFiles_t*, unsigned char, unsigned int, char);
+
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/linux/MQTTLinux.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/linux/MQTTLinux.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2017 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Allan Stockdill-Mander - initial API and implementation and/or initial documentation
+ *    Ian Craggs - return codes from linux_read
+ *******************************************************************************/
+
+#include "MQTTLinux.h"
+
+void TimerInit(Timer* timer)
+{
+	timer->end_time = (struct timeval){0, 0};
+}
+
+char TimerIsExpired(Timer* timer)
+{
+	struct timeval now, res;
+	gettimeofday(&now, NULL);
+	timersub(&timer->end_time, &now, &res);
+	return res.tv_sec < 0 || (res.tv_sec == 0 && res.tv_usec <= 0);
+}
+
+
+void TimerCountdownMS(Timer* timer, unsigned int timeout)
+{
+	struct timeval now;
+	gettimeofday(&now, NULL);
+	struct timeval interval = {timeout / 1000, (timeout % 1000) * 1000};
+	timeradd(&now, &interval, &timer->end_time);
+}
+
+
+void TimerCountdown(Timer* timer, unsigned int timeout)
+{
+	struct timeval now;
+	gettimeofday(&now, NULL);
+	struct timeval interval = {timeout, 0};
+	timeradd(&now, &interval, &timer->end_time);
+}
+
+
+int TimerLeftMS(Timer* timer)
+{
+	struct timeval now, res;
+	gettimeofday(&now, NULL);
+	timersub(&timer->end_time, &now, &res);
+	//printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000);
+	return (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000;
+}
+
+
+int linux_read(Network* n, unsigned char* buffer, int len, int timeout_ms)
+{
+	struct timeval interval = {timeout_ms / 1000, (timeout_ms % 1000) * 1000};
+	if (interval.tv_sec < 0 || (interval.tv_sec == 0 && interval.tv_usec <= 0))
+	{
+		interval.tv_sec = 0;
+		interval.tv_usec = 100;
+	}
+
+	setsockopt(n->my_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval, sizeof(struct timeval));
+
+	int bytes = 0;
+	while (bytes < len)
+	{
+		int rc = recv(n->my_socket, &buffer[bytes], (size_t)(len - bytes), 0);
+		if (rc == -1)
+		{
+			if (errno != EAGAIN && errno != EWOULDBLOCK)
+			  bytes = -1;
+			break;
+		}
+		else if (rc == 0)
+		{
+			bytes = 0;
+			break;
+		}
+		else
+			bytes += rc;
+	}
+	return bytes;
+}
+
+
+int linux_write(Network* n, unsigned char* buffer, int len, int timeout_ms)
+{
+	struct timeval tv;
+
+	tv.tv_sec = 0;  /* 30 Secs Timeout */
+	tv.tv_usec = timeout_ms * 1000;  // Not init'ing this can cause strange errors
+
+	setsockopt(n->my_socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv,sizeof(struct timeval));
+	int	rc = write(n->my_socket, buffer, len);
+	return rc;
+}
+
+
+void NetworkInit(Network* n)
+{
+	n->my_socket = 0;
+	n->mqttread = linux_read;
+	n->mqttwrite = linux_write;
+}
+
+
+int NetworkConnect(Network* n, char* addr, int port)
+{
+	int type = SOCK_STREAM;
+	struct sockaddr_in address;
+	int rc = -1;
+	sa_family_t family = AF_INET;
+	struct addrinfo *result = NULL;
+	struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL};
+
+	if ((rc = getaddrinfo(addr, NULL, &hints, &result)) == 0)
+	{
+		struct addrinfo* res = result;
+
+		/* prefer ip4 addresses */
+		while (res)
+		{
+			if (res->ai_family == AF_INET)
+			{
+				result = res;
+				break;
+			}
+			res = res->ai_next;
+		}
+
+		if (result->ai_family == AF_INET)
+		{
+			address.sin_port = htons(port);
+			address.sin_family = family = AF_INET;
+			address.sin_addr = ((struct sockaddr_in*)(result->ai_addr))->sin_addr;
+		}
+		else
+			rc = -1;
+
+		freeaddrinfo(result);
+	}
+
+	if (rc == 0)
+	{
+		n->my_socket = socket(family, type, 0);
+		if (n->my_socket != -1)
+			rc = connect(n->my_socket, (struct sockaddr*)&address, sizeof(address));
+		else
+			rc = -1;
+	}
+
+	return rc;
+}
+
+
+void NetworkDisconnect(Network* n)
+{
+	close(n->my_socket);
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/linux/MQTTLinux.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/src/linux/MQTTLinux.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Allan Stockdill-Mander - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#if !defined(__MQTT_LINUX_)
+#define __MQTT_LINUX_
+
+#if defined(WIN32_DLL) || defined(WIN64_DLL)
+  #define DLLImport __declspec(dllimport)
+  #define DLLExport __declspec(dllexport)
+#elif defined(LINUX_SO)
+  #define DLLImport extern
+  #define DLLExport  __attribute__ ((visibility ("default")))
+#else
+  #define DLLImport
+  #define DLLExport
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+typedef struct Timer
+{
+	struct timeval end_time;
+} Timer;
+
+void TimerInit(Timer*);
+char TimerIsExpired(Timer*);
+void TimerCountdownMS(Timer*, unsigned int);
+void TimerCountdown(Timer*, unsigned int);
+int TimerLeftMS(Timer*);
+
+typedef struct Network
+{
+	int my_socket;
+	int (*mqttread) (struct Network*, unsigned char*, int, int);
+	int (*mqttwrite) (struct Network*, unsigned char*, int, int);
+} Network;
+
+int linux_read(Network*, unsigned char*, int, int);
+int linux_write(Network*, unsigned char*, int, int);
+
+DLLExport void NetworkInit(Network*);
+DLLExport int NetworkConnect(Network*, char*, int);
+DLLExport void NetworkDisconnect(Network*);
+
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/test/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/test/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,20 @@
+PROJECT(mqtt-tests)
+
+SET(MQTT_TEST_BROKER_HOST "localhost" CACHE STRING "Hostname of a test MQTT broker to use")
+SET(MQTT_TEST_PROXY_PORT "1884" CACHE STRING "Port of the test proxy to use")
+SET(MQTT_SSL_HOSTNAME "localhost" CACHE STRING "Hostname of a test SSL MQTT broker to use")
+SET(CERTDIR $ENV{TRAVIS_BUILD_DIR}/test/ssl)
+
+ADD_EXECUTABLE(
+	testc1
+	test1.c
+)
+
+target_link_libraries(testc1 paho-embed-mqtt3cc paho-embed-mqtt3c)
+target_include_directories(testc1 PRIVATE "../src" "../src/linux")
+target_compile_definitions(testc1 PRIVATE MQTTCLIENT_PLATFORM_HEADER=MQTTLinux.h)
+
+ADD_TEST(
+	NAME testc1
+	COMMAND "testc1" "--host" ${MQTT_TEST_BROKER_HOST}
+)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/test/test1.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient-C/test/test1.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,1050 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2017 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial implementation for embedded C client
+ *******************************************************************************/
+
+
+/**
+ * @file
+ * Tests for the Paho embedded C "high" level client
+ */
+
+
+#include "MQTTClient.h"
+#include <string.h>
+#include <stdlib.h>
+
+#if !defined(_WINDOWS)
+  #include <sys/time.h>
+  #include <sys/socket.h>
+  #include <unistd.h>
+  #include <errno.h>
+#else
+  #include <windows.h>
+  #define setenv(a, b, c) _putenv_s(a, b)
+#endif
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+void usage(void)
+{
+	printf("help!!\n");
+	exit(EXIT_FAILURE);
+}
+
+struct Options
+{
+	char* host;         /**< connection to system under test. */
+  int port;
+	char* proxy_host;
+  int proxy_port;
+	int verbose;
+	int test_no;
+	int MQTTVersion;
+	int iterations;
+} options =
+{
+	"localhost",
+  1883,
+	"localhost",
+	1885,
+	0, //verbose
+	0, //test_no
+	4,
+	1,
+};
+
+void getopts(int argc, char** argv)
+{
+	int count = 1;
+
+	while (count < argc)
+	{
+		if (strcmp(argv[count], "--test_no") == 0)
+		{
+			if (++count < argc)
+				options.test_no = atoi(argv[count]);
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--host") == 0)
+		{
+			if (++count < argc)
+			{
+				options.host = argv[count];
+				printf("\nSetting host to %s\n", options.host);
+			}
+			else
+				usage();
+		}
+    else if (strcmp(argv[count], "--port") == 0)
+    {
+      if (++count < argc)
+      {
+        options.port = atoi(argv[count]);
+        printf("\nSetting port to %d\n", options.port);
+      }
+      else
+        usage();
+    }
+		else if (strcmp(argv[count], "--proxy_host") == 0)
+		{
+			if (++count < argc)
+      {
+				options.proxy_host = argv[count];
+        printf("\nSetting proxy_host to %s\n", options.proxy_host);
+      }
+			else
+				usage();
+		}
+    else if (strcmp(argv[count], "--proxy_port") == 0)
+    {
+      if (++count < argc)
+      {
+        options.proxy_port = atoi(argv[count]);
+        printf("\nSetting proxy_port to %d\n", options.proxy_port);
+      }
+      else
+        usage();
+    }
+		else if (strcmp(argv[count], "--MQTTversion") == 0)
+		{
+			if (++count < argc)
+			{
+				options.MQTTVersion = atoi(argv[count]);
+				printf("setting MQTT version to %d\n", options.MQTTVersion);
+			}
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--iterations") == 0)
+		{
+			if (++count < argc)
+				options.iterations = atoi(argv[count]);
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--verbose") == 0)
+		{
+			options.verbose = 1;
+			printf("\nSetting verbose on\n");
+		}
+		count++;
+	}
+}
+
+
+#define LOGA_DEBUG 0
+#define LOGA_INFO 1
+#include <stdarg.h>
+#include <time.h>
+#include <sys/timeb.h>
+void MyLog(int LOGA_level, char* format, ...)
+{
+	static char msg_buf[256];
+	va_list args;
+	struct timeb ts;
+
+	struct tm *timeinfo;
+
+	if (LOGA_level == LOGA_DEBUG && options.verbose == 0)
+	  return;
+
+	ftime(&ts);
+	timeinfo = localtime(&ts.time);
+	strftime(msg_buf, 80, "%Y%m%d %H%M%S", timeinfo);
+
+	sprintf(&msg_buf[strlen(msg_buf)], ".%.3hu ", ts.millitm);
+
+	va_start(args, format);
+	vsnprintf(&msg_buf[strlen(msg_buf)], sizeof(msg_buf) - strlen(msg_buf), format, args);
+	va_end(args);
+
+	printf("%s\n", msg_buf);
+	fflush(stdout);
+}
+
+
+#if defined(WIN32) || defined(_WINDOWS)
+#define mqsleep(A) Sleep(1000*A)
+#define START_TIME_TYPE DWORD
+static DWORD start_time = 0;
+START_TIME_TYPE start_clock(void)
+{
+	return GetTickCount();
+}
+#elif defined(AIX)
+#define mqsleep sleep
+#define START_TIME_TYPE struct timespec
+START_TIME_TYPE start_clock(void)
+{
+	static struct timespec start;
+	clock_gettime(CLOCK_REALTIME, &start);
+	return start;
+}
+#else
+#define mqsleep sleep
+#define START_TIME_TYPE struct timeval
+/* TODO - unused - remove? static struct timeval start_time; */
+START_TIME_TYPE start_clock(void)
+{
+	struct timeval start_time;
+	gettimeofday(&start_time, NULL);
+	return start_time;
+}
+#endif
+
+
+#if defined(WIN32)
+long elapsed(START_TIME_TYPE start_time)
+{
+	return GetTickCount() - start_time;
+}
+#elif defined(AIX)
+#define assert(a)
+long elapsed(struct timespec start)
+{
+	struct timespec now, res;
+
+	clock_gettime(CLOCK_REALTIME, &now);
+	ntimersub(now, start, res);
+	return (res.tv_sec)*1000L + (res.tv_nsec)/1000000L;
+}
+#else
+long elapsed(START_TIME_TYPE start_time)
+{
+	struct timeval now, res;
+
+	gettimeofday(&now, NULL);
+	timersub(&now, &start_time, &res);
+	return (res.tv_sec)*1000 + (res.tv_usec)/1000;
+}
+#endif
+
+
+#define assert(a, b, c, d) myassert(__FILE__, __LINE__, a, b, c, d)
+#define assert1(a, b, c, d, e) myassert(__FILE__, __LINE__, a, b, c, d, e)
+
+int tests = 0;
+int failures = 0;
+FILE* xml;
+START_TIME_TYPE global_start_time;
+char output[3000];
+char* cur_output = output;
+
+
+void write_test_result(void)
+{
+	long duration = elapsed(global_start_time);
+
+	fprintf(xml, " time=\"%ld.%.3ld\" >\n", duration / 1000, duration % 1000);
+	if (cur_output != output)
+	{
+		fprintf(xml, "%s", output);
+		cur_output = output;
+	}
+	fprintf(xml, "</testcase>\n");
+}
+
+
+void myassert(char* filename, int lineno, char* description, int value, char* format, ...)
+{
+	++tests;
+	if (!value)
+	{
+		va_list args;
+
+		++failures;
+		MyLog(LOGA_INFO, "Assertion failed, file %s, line %d, description: %s\n", filename, lineno, description);
+
+		va_start(args, format);
+		vprintf(format, args);
+		va_end(args);
+
+		cur_output += sprintf(cur_output, "<failure type=\"%s\">file %s, line %d </failure>\n",
+                        description, filename, lineno);
+	}
+	else
+		MyLog(LOGA_DEBUG, "Assertion succeeded, file %s, line %d, description: %s", filename, lineno, description);
+}
+
+
+static volatile MessageData* test1_message_data = NULL;
+static MQTTMessage pubmsg;
+
+void messageArrived(MessageData* md)
+{
+  test1_message_data = md;
+  MQTTMessage* m = md->message;
+
+	assert("Good message lengths", pubmsg.payloadlen == m->payloadlen,
+         "payloadlen was %d", m->payloadlen);
+
+  if (pubmsg.payloadlen == m->payloadlen)
+      assert("Good message contents", memcmp(m->payload, pubmsg.payload, m->payloadlen) == 0,
+          "payload was %s", m->payload);
+}
+
+
+/*********************************************************************
+
+Test1: single-threaded client
+
+*********************************************************************/
+void test1_sendAndReceive(MQTTClient* c, int qos, char* test_topic)
+{
+	char* topicName = NULL;
+	int topicLen;
+	int i = 0;
+	int iterations = 50;
+	int rc;
+  int wait_seconds;
+
+	MyLog(LOGA_DEBUG, "%d messages at QoS %d", iterations, qos);
+  memset(&pubmsg, '\0', sizeof(pubmsg));
+	pubmsg.payload = "a much longer message that we can shorten to the extent that we need to payload up to 11";
+	pubmsg.payloadlen = 11;
+	pubmsg.qos = qos;
+	pubmsg.retained = 0;
+  pubmsg.dup = 0;
+
+	for (i = 0; i < iterations; ++i)
+	{
+    test1_message_data = NULL;
+		rc = MQTTPublish(c, test_topic, &pubmsg);
+		assert("Good rc from publish", rc == SUCCESS, "rc was %d", rc);
+
+    /* wait for the message to be received */
+    wait_seconds = 10;
+		while ((test1_message_data == NULL) && (wait_seconds-- > 0))
+		{
+      MQTTYield(c, 100);
+		}
+		assert("Message Arrived", wait_seconds > 0, "Time out waiting for message %d\n", i);
+
+		if (!test1_message_data)
+			printf("No message received within timeout period\n");
+	}
+
+	/* wait to receive any outstanding messages */
+  wait_seconds = 2;
+  while (wait_seconds-- > 0)
+  {
+      MQTTYield(c, 1000);
+  }
+}
+
+
+int test1(struct Options options)
+{
+	int subsqos = 2;
+  Network n;
+	MQTTClient c;
+	int rc = 0;
+	char* test_topic = "C client test1";
+  MQTTPacket_willOptions wopts;
+  unsigned char buf[100];
+  unsigned char readbuf[100];
+
+  printf("test1\n");
+	fprintf(xml, "<testcase classname=\"test1\" name=\"single threaded client using receive\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 1 - single threaded client using receive");
+
+  NetworkInit(&n);
+  NetworkConnect(&n, options.host, options.port);
+  MQTTClientInit(&c, &n, 1000, buf, 100, readbuf, 100);
+
+  MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+  data.willFlag = 1;
+  data.MQTTVersion = options.MQTTVersion;
+  data.clientID.cstring = "single-threaded-test";
+  data.username.cstring = "testuser";
+  data.password.cstring = "testpassword";
+
+  data.keepAliveInterval = 20;
+  data.cleansession = 1;
+
+	data.will.message.cstring = "will message";
+	data.will.qos = 1;
+	data.will.retained = 0;
+	data.will.topicName.cstring = "will topic";
+
+	MyLog(LOGA_DEBUG, "Connecting");
+  rc = MQTTConnect(&c, &data);
+	assert("Good rc from connect", rc == SUCCESS, "rc was %d", rc);
+	if (rc != SUCCESS)
+		goto exit;
+
+	rc = MQTTSubscribe(&c, test_topic, subsqos, messageArrived);
+	assert("Good rc from subscribe", rc == SUCCESS, "rc was %d", rc);
+
+	test1_sendAndReceive(&c, 0, test_topic);
+	test1_sendAndReceive(&c, 1, test_topic);
+	test1_sendAndReceive(&c, 2, test_topic);
+
+	MyLog(LOGA_DEBUG, "Stopping\n");
+
+	rc = MQTTUnsubscribe(&c, test_topic);
+	assert("Unsubscribe successful", rc == SUCCESS, "rc was %d", rc);
+	rc = MQTTDisconnect(&c);
+	assert("Disconnect successful", rc == SUCCESS, "rc was %d", rc);
+
+	/* Just to make sure we can connect again */
+  NetworkConnect(&n, options.host, options.port);
+  rc = MQTTConnect(&c, &data);
+	assert("Connect successful",  rc == SUCCESS, "rc was %d", rc);
+	rc = MQTTDisconnect(&c);
+	assert("Disconnect successful", rc == SUCCESS, "rc was %d", rc);
+
+exit:
+	MyLog(LOGA_INFO, "TEST1: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+/*********************************************************************
+
+Test 2: connack return data
+
+sessionPresent
+
+*********************************************************************/
+int test2(struct Options options)
+{
+	int subsqos = 2;
+  Network n;
+	MQTTClient c;
+	int rc = 0;
+	char* test_topic = "C client test2";
+  MQTTPacket_willOptions wopts;
+  unsigned char buf[100];
+  unsigned char readbuf[100];
+  MQTTConnackData connack;
+  MQTTSubackData suback;
+
+	fprintf(xml, "<testcase classname=\"test2\" name=\"connack return data\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 2 - connack return data");
+
+  NetworkInit(&n);
+  NetworkConnect(&n, options.host, options.port);
+  MQTTClientInit(&c, &n, 1000, buf, 100, readbuf, 100);
+
+  MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+  data.willFlag = 1;
+  data.MQTTVersion = options.MQTTVersion;
+  data.clientID.cstring = "connack-return-data";
+  data.username.cstring = "testuser";
+  data.password.cstring = "testpassword";
+
+  data.keepAliveInterval = 20;
+  data.cleansession = 1;
+
+	data.will.message.cstring = "will message";
+	data.will.qos = 1;
+	data.will.retained = 0;
+	data.will.topicName.cstring = "will topic";
+
+	MyLog(LOGA_DEBUG, "Connecting");
+  rc = MQTTConnect(&c, &data);
+	assert("Good rc from connect", rc == SUCCESS, "rc was %d", rc);
+	if (rc != SUCCESS)
+		goto exit;
+
+	rc = MQTTDisconnect(&c);
+	assert("Disconnect successful", rc == SUCCESS, "rc was %d", rc);
+  NetworkDisconnect(&n);
+
+  /* now connect cleansession false */
+  NetworkConnect(&n, options.host, options.port);
+  data.cleansession = 0;
+  rc = MQTTConnectWithResults(&c, &data, &connack);
+  assert("Good rc from connect", rc == SUCCESS, "rc was %d", rc);
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 0", connack.sessionPresent == 0,
+         "sessionPresent was %d", connack.sessionPresent);
+
+  /* set up some state */
+  rc = MQTTSubscribeWithResults(&c, test_topic, subsqos, messageArrived, &suback);
+  assert("Good rc from subscribe", rc == SUCCESS, "rc was %d", rc);
+  assert("Good granted QoS", suback.grantedQoS == subsqos,
+         "granted QoS was %d", suback.grantedQoS);
+
+  rc = MQTTDisconnect(&c);
+  assert("Disconnect successful", rc == SUCCESS, "rc was %d", rc);
+  NetworkDisconnect(&n);
+
+	/* Connect and check sessionPresent */
+  NetworkConnect(&n, options.host, options.port);
+  rc = MQTTConnectWithResults(&c, &data, &connack);
+	assert("Connect successful",  rc == SUCCESS, "rc was %d", rc);
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 1", connack.sessionPresent == 1,
+           "sessionPresent was %d", connack.sessionPresent);
+
+	rc = MQTTDisconnect(&c);
+	assert("Disconnect successful", rc == SUCCESS, "rc was %d", rc);
+  NetworkDisconnect(&n);
+
+  /* Connect and check sessionPresent is cleared */
+  data.cleansession = 1;
+  NetworkConnect(&n, options.host, options.port);
+  rc = MQTTConnectWithResults(&c, &data, &connack);
+  assert("Connect successful",  rc == SUCCESS, "rc was %d", rc);
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 0", connack.sessionPresent == 0,
+           "sessionPresent was %d", connack.sessionPresent);
+
+  rc = MQTTDisconnect(&c);
+  assert("Disconnect successful", rc == SUCCESS, "rc was %d", rc);
+  NetworkDisconnect(&n);
+
+exit:
+	MyLog(LOGA_INFO, "TEST1: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+/*********************************************************************
+
+Test 3: client session state
+
+*********************************************************************/
+static volatile MessageData* test2_message_data = NULL;
+
+void messageArrived2(MessageData* md)
+{
+    test2_message_data = md;
+	  MQTTMessage *m = md->message;
+
+    assert("Good message lengths", pubmsg.payloadlen == m->payloadlen,
+         "payloadlen was %d", m->payloadlen);
+
+    if (pubmsg.payloadlen == m->payloadlen)
+        assert("Good message contents", memcmp(m->payload, pubmsg.payload, m->payloadlen) == 0,
+          "payload was %s", m->payload);
+}
+
+
+int check_subs_exist(MQTTClient* c, const char* test_topic, int which)
+{
+    int rc = FAILURE;
+    int wait_seconds = 0;
+
+    memset(&pubmsg, '\0', sizeof(pubmsg));
+    pubmsg.payload = (void*)"a much longer message that we can shorten to the extent that we need to payload up to 11";
+    pubmsg.payloadlen = 11;
+    pubmsg.qos = QOS2;
+    pubmsg.retained = 0;
+    pubmsg.dup = 0;
+
+    test1_message_data = test2_message_data = NULL;
+    rc = MQTTPublish(c, test_topic, &pubmsg);
+    assert("Good rc from publish", rc == SUCCESS, "rc was %d", rc);
+
+    /* wait for the message to be received */
+    wait_seconds = 10;
+    while (wait_seconds-- > 0)
+    {
+        MQTTYield(c, 100);
+    }
+
+    rc = (((which == 1 || which == 3) && test1_message_data) ||
+         (which == 2 && test1_message_data == NULL)) ? SUCCESS : FAILURE;
+    assert("test1 subscription", rc == SUCCESS, "test1_message_data %p\n",
+            test1_message_data);
+    rc = (((which == 2 || which == 3) && test2_message_data) ||
+         (which == 1 && test2_message_data == NULL)) ? SUCCESS : FAILURE;
+    assert("test2 subscription", rc == SUCCESS, "test2_message_data %p\n",
+             test2_message_data);
+    return rc;
+}
+
+
+int test3(struct Options options)
+{
+  enum QoS subsqos = QOS2;
+  Network n;
+  MQTTClient c;
+	int rc;
+  const char* test_topic = "C client test3";
+  int wait_seconds = 0;
+  unsigned char buf[100];
+  unsigned char readbuf[100];
+  MQTTConnackData connack;
+  MQTTSubackData suback;
+
+  fprintf(xml, "<testcase classname=\"test3\" name=\"session state\"");
+  global_start_time = start_clock();
+  failures = 0;
+  MyLog(LOGA_INFO, "Starting test 3 - session state");
+
+  NetworkInit(&n);
+  MQTTClientInit(&c, &n, 1000, buf, 100, readbuf, 100);
+
+  MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+  data.willFlag = 1;
+  data.MQTTVersion = options.MQTTVersion;
+  data.clientID.cstring = (char*)"connack-session-state";
+  data.username.cstring = (char*)"testuser";
+  data.password.cstring = (char*)"testpassword";
+
+  data.keepAliveInterval = 10;
+  data.cleansession = 1;
+
+  data.will.message.cstring = (char*)"will message";
+  data.will.qos = 1;
+  data.will.retained = 0;
+  data.will.topicName.cstring = (char*)"will topic";
+
+  assert("Not connected", MQTTIsConnected(&c) == 0,
+         "isconnected was %d", MQTTIsConnected(&c));
+
+  MyLog(LOGA_DEBUG, "Connecting");
+  rc = NetworkConnect(&n, options.host, options.port);
+  assert("Good rc from TCP connect", rc == SUCCESS, "rc was %d", rc);
+  if (rc != SUCCESS)
+    goto exit;
+
+  rc = MQTTConnectWithResults(&c, &data, &connack);
+  assert("Good rc from connect", rc == SUCCESS, "rc was %d", rc);
+  if (rc != SUCCESS)
+    goto exit;
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 0", connack.sessionPresent == 0,
+         "sessionPresent was %d", connack.sessionPresent);
+
+  assert("Good rc in connack", MQTTIsConnected(&c) == 1,
+                "isconnected was %d", MQTTIsConnected(&c));
+
+  rc = MQTTDisconnect(&c);
+  assert("Disconnect successful", rc == SUCCESS, "rc was %d", rc);
+  NetworkDisconnect(&n);
+
+  /* reconnect with cleansession false */
+  data.cleansession = 0;
+  rc = NetworkConnect(&n, options.proxy_host, options.proxy_port);
+  assert("TCP connect successful",  rc == SUCCESS, "rc was %d", rc);
+  rc = MQTTConnectWithResults(&c, &data, &connack);
+  assert("Connect successful",  rc == SUCCESS, "rc was %d", rc);
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 0", connack.sessionPresent == 0,
+           "sessionPresent was %d", connack.sessionPresent);
+
+  rc = MQTTSubscribeWithResults(&c, test_topic, subsqos, messageArrived, &suback);
+  assert("Good rc from subscribe", rc == SUCCESS, "rc was %d", rc);
+  assert("Granted QoS rc from subscribe", suback.grantedQoS == QOS2,
+         "rc was %d", suback.grantedQoS);
+
+  check_subs_exist(&c, test_topic, 1);
+
+  rc = MQTTSubscribeWithResults(&c, test_topic, subsqos, messageArrived2, &suback);
+  assert("Good rc from subscribe", rc == SUCCESS, "rc was %d", rc);
+  assert("Granted QoS rc from subscribe", suback.grantedQoS == QOS2,
+                  "rc was %d", suback.grantedQoS);
+
+  check_subs_exist(&c, test_topic, 2);
+
+  rc = MQTTDisconnect(&c);
+  assert("Disconnect successful", rc == SUCCESS, "rc was %d", rc);
+  NetworkDisconnect(&n);
+
+  /* reconnect with cleansession false */
+  data.cleansession = 0;
+  rc = NetworkConnect(&n, options.proxy_host, options.proxy_port);
+  assert("TCP connect successful",  rc == SUCCESS, "rc was %d", rc);
+  rc = MQTTConnectWithResults(&c, &data, &connack);
+  assert("Connect successful",  rc == SUCCESS, "rc was %d", rc);
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 1", connack.sessionPresent == 1,
+           "sessionPresent was %d", connack.sessionPresent);
+
+  check_subs_exist(&c, test_topic, 2);
+
+  rc = MQTTSubscribeWithResults(&c, test_topic, subsqos, messageArrived, &suback);
+  assert("Good rc from subscribe", rc == SUCCESS, "rc was %d", rc);
+  assert("Granted QoS rc from subscribe", suback.grantedQoS == QOS2,
+            "rc was %d", suback.grantedQoS);
+
+  check_subs_exist(&c, test_topic, 1);
+
+  // cause a connection FAILURE
+  memset(&pubmsg, '\0', sizeof(pubmsg));
+  pubmsg.payload = (void*)"TERMINATE";
+  pubmsg.payloadlen = strlen((char*)pubmsg.payload);
+  pubmsg.qos = QOS0;
+  pubmsg.retained = 0;
+  pubmsg.dup = 0;
+  rc = MQTTPublish(&c, "MQTTSAS topic", &pubmsg);
+  assert("Good rc from publish", rc == SUCCESS, "rc was %d", rc);
+
+  // wait for failure to be noticed by keepalive
+  wait_seconds = 20;
+  while (MQTTIsConnected(&c) && (wait_seconds-- > 0))
+  {
+      MQTTYield(&c, 1000);
+  }
+  assert("Disconnected", !MQTTIsConnected(&c), "isConnected was %d",
+         MQTTIsConnected(&c));
+  NetworkDisconnect(&n);
+
+  /* reconnect with cleansession false */
+  data.cleansession = 0;
+  rc = NetworkConnect(&n, options.host, options.port);
+  assert("TCP connect successful",  rc == SUCCESS, "rc was %d", rc);
+  rc = MQTTConnectWithResults(&c, &data, &connack);
+  assert("Connect successful",  rc == SUCCESS, "rc was %d", rc);
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 1", connack.sessionPresent == 1,
+           "sessionPresent was %d", connack.sessionPresent);
+
+  check_subs_exist(&c, test_topic, 1);
+
+  rc = MQTTSubscribeWithResults(&c, test_topic, subsqos, messageArrived2, &suback);
+  assert("Good rc from subscribe", rc == SUCCESS, "rc was %d", rc);
+  assert("Granted QoS rc from subscribe", suback.grantedQoS == QOS2,
+                  "rc was %d", suback.grantedQoS);
+
+  check_subs_exist(&c, test_topic, 2);
+
+  rc = MQTTDisconnect(&c);
+  assert("Disconnect successful", rc == SUCCESS, "rc was %d", rc);
+  NetworkDisconnect(&n);
+
+  /* reconnect with cleansession true to clean up both server and client state */
+  data.cleansession = 1;
+  rc = NetworkConnect(&n, options.host, options.port);
+  assert("TCP connect successful",  rc == SUCCESS, "rc was %d", rc);
+  rc = MQTTConnectWithResults(&c, &data, &connack);
+  assert("Connect successful",  rc == SUCCESS, "rc was %d", rc);
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 0", connack.sessionPresent == 0,
+           "sessionPresent was %d", connack.sessionPresent);
+
+  rc = MQTTSubscribeWithResults(&c, test_topic, subsqos, messageArrived2, &suback);
+  assert("Good rc from subscribe", rc == SUCCESS, "rc was %d", rc);
+  assert("Granted QoS rc from subscribe", suback.grantedQoS == QOS2,
+                  "rc was %d", suback.grantedQoS);
+
+  check_subs_exist(&c, test_topic, 2);
+
+  rc = MQTTDisconnect(&c);
+  assert("Disconnect successful", rc == SUCCESS, "rc was %d", rc);
+  NetworkDisconnect(&n);
+
+exit:
+  MyLog(LOGA_INFO, "TEST2: test %s. %d tests run, %d failures.",
+      (failures == 0) ? "passed" : "failed", tests, failures);
+  write_test_result();
+  return failures;
+}
+
+#if 0
+/*********************************************************************
+
+Test 4: connectionLost and will message
+
+*********************************************************************/
+MQTTClient test6_c1, test6_c2;
+volatile int test6_will_message_arrived = 0;
+volatile int test6_connection_lost_called = 0;
+
+void test6_connectionLost(void* context, char* cause)
+{
+	MQTTClient c = (MQTTClient)context;
+	printf("%s -> Callback: connection lost\n", (c == test6_c1) ? "Client-1" : "Client-2");
+	test6_connection_lost_called = 1;
+}
+
+void test6_deliveryComplete(void* context, MQTTClient_deliveryToken token)
+{
+	printf("Client-2 -> Callback: publish complete for token %d\n", token);
+}
+
+char* test6_will_topic = "C Test 2: will topic";
+char* test6_will_message = "will message from Client-1";
+
+int test6_messageArrived(void* context, char* topicName, int topicLen, MQTTClient_message* m)
+{
+	MQTTClient c = (MQTTClient)context;
+	printf("%s -> Callback: message received on topic '%s' is '%.*s'.\n",
+			 (c == test6_c1) ? "Client-1" : "Client-2", topicName, m->payloadlen, (char*)(m->payload));
+	if (c == test6_c2 && strcmp(topicName, test6_will_topic) == 0 && memcmp(m->payload, test6_will_message, m->payloadlen) == 0)
+		test6_will_message_arrived = 1;
+	MQTTClient_free(topicName);
+	MQTTClient_freeMessage(&m);
+	return 1;
+}
+
+
+int test6(struct Options options)
+{
+	char* testname = "test6";
+	MQTTClient_connectOptions opts = MQTTClient_connectOptions_initializer;
+	MQTTClient_willOptions wopts =  MQTTClient_willOptions_initializer;
+	MQTTClient_connectOptions opts2 = MQTTClient_connectOptions_initializer;
+	int rc, count;
+	char* mqttsas_topic = "MQTTSAS topic";
+
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 6 - connectionLost and will messages");
+	fprintf(xml, "<testcase classname=\"test1\" name=\"connectionLost and will messages\"");
+	global_start_time = start_clock();
+
+	opts.keepAliveInterval = 2;
+	opts.cleansession = 1;
+	opts.MQTTVersion = MQTTVERSION_3_1_1;
+	opts.will = &wopts;
+	opts.will->message = test6_will_message;
+	opts.will->qos = 1;
+	opts.will->retained = 0;
+	opts.will->topicName = test6_will_topic;
+	if (options.haconnections != NULL)
+	{
+		opts.serverURIs = options.haconnections;
+		opts.serverURIcount = options.hacount;
+	}
+
+	/* Client-1 with Will options */
+	rc = MQTTClient_create(&test6_c1, options.proxy_connection, "Client_1", MQTTCLIENT_PERSISTENCE_DEFAULT, NULL);
+	assert("good rc from create", rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+	if (rc != MQTTCLIENT_SUCCESS)
+		goto exit;
+
+	rc = MQTTClient_setCallbacks(test6_c1, (void*)test6_c1, test6_connectionLost, test6_messageArrived, test6_deliveryComplete);
+	assert("good rc from setCallbacks",  rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+	if (rc != MQTTCLIENT_SUCCESS)
+		goto exit;
+
+	/* Connect to the broker */
+	rc = MQTTClient_connect(test6_c1, &opts);
+	assert("good rc from connect",  rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+	if (rc != MQTTCLIENT_SUCCESS)
+		goto exit;
+
+	/* Client - 2 (multi-threaded) */
+	rc = MQTTClient_create(&test6_c2, options.connection, "Client_2", MQTTCLIENT_PERSISTENCE_DEFAULT, NULL);
+	assert("good rc from create",  rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+
+	/* Set the callback functions for the client */
+	rc = MQTTClient_setCallbacks(test6_c2, (void*)test6_c2, test6_connectionLost, test6_messageArrived, test6_deliveryComplete);
+	assert("good rc from setCallbacks",  rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+
+	/* Connect to the broker */
+	opts2.keepAliveInterval = 20;
+	opts2.cleansession = 1;
+	MyLog(LOGA_INFO, "Connecting Client_2 ...");
+	rc = MQTTClient_connect(test6_c2, &opts2);
+	assert("Good rc from connect", rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+
+	rc = MQTTClient_subscribe(test6_c2, test6_will_topic, 2);
+	assert("Good rc from subscribe", rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+
+	/* now send the command which will break the connection and cause the will message to be sent */
+	rc = MQTTClient_publish(test6_c1, mqttsas_topic, (int)strlen("TERMINATE"), "TERMINATE", 0, 0, NULL);
+	assert("Good rc from publish", rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+
+	MyLog(LOGA_INFO, "Waiting to receive the will message");
+	count = 0;
+	while (++count < 40)
+	{
+		#if defined(WIN32)
+			Sleep(1000L);
+		#else
+			sleep(1);
+		#endif
+		if (test6_will_message_arrived == 1 && test6_connection_lost_called == 1)
+			break;
+	}
+	assert("will message arrived", test6_will_message_arrived == 1,
+							"will_message_arrived was %d\n", test6_will_message_arrived);
+	assert("connection lost called", test6_connection_lost_called == 1,
+			         "connection_lost_called %d\n", test6_connection_lost_called);
+
+	rc = MQTTClient_unsubscribe(test6_c2, test6_will_topic);
+	assert("Good rc from unsubscribe", rc == MQTTCLIENT_SUCCESS, "rc was %d", rc);
+
+	rc = MQTTClient_isConnected(test6_c2);
+	assert("Client-2 still connected", rc == 1, "isconnected is %d", rc);
+
+	rc = MQTTClient_isConnected(test6_c1);
+	assert("Client-1 not connected", rc == 0, "isconnected is %d", rc);
+
+	rc = MQTTClient_disconnect(test6_c2, 100L);
+	assert("Good rc from disconnect", rc == MQTTCLIENT_SUCCESS, "rc was %d", rc);
+
+	MQTTClient_destroy(&test6_c1);
+	MQTTClient_destroy(&test6_c2);
+
+exit:
+	MyLog(LOGA_INFO, "%s: test %s. %d tests run, %d failures.\n",
+			(failures == 0) ? "passed" : "failed", testname, tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test6a(struct Options options)
+{
+	char* testname = "test6a";
+	MQTTClient_connectOptions opts = MQTTClient_connectOptions_initializer;
+	MQTTClient_willOptions wopts =  MQTTClient_willOptions_initializer;
+	MQTTClient_connectOptions opts2 = MQTTClient_connectOptions_initializer;
+	int rc, count;
+	char* mqttsas_topic = "MQTTSAS topic";
+
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 6 - connectionLost and binary will messages");
+	fprintf(xml, "<testcase classname=\"test1\" name=\"connectionLost and binary will messages\"");
+	global_start_time = start_clock();
+
+	opts.keepAliveInterval = 2;
+	opts.cleansession = 1;
+	opts.MQTTVersion = MQTTVERSION_3_1_1;
+	opts.will = &wopts;
+	opts.will->payload.data = test6_will_message;
+	opts.will->payload.len = strlen(test6_will_message) + 1;
+	opts.will->qos = 1;
+	opts.will->retained = 0;
+	opts.will->topicName = test6_will_topic;
+	if (options.haconnections != NULL)
+	{
+		opts.serverURIs = options.haconnections;
+		opts.serverURIcount = options.hacount;
+	}
+
+	/* Client-1 with Will options */
+	rc = MQTTClient_create(&test6_c1, options.proxy_connection, "Client_1", MQTTCLIENT_PERSISTENCE_DEFAULT, NULL);
+	assert("good rc from create", rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+	if (rc != MQTTCLIENT_SUCCESS)
+		goto exit;
+
+	rc = MQTTClient_setCallbacks(test6_c1, (void*)test6_c1, test6_connectionLost, test6_messageArrived, test6_deliveryComplete);
+	assert("good rc from setCallbacks",  rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+	if (rc != MQTTCLIENT_SUCCESS)
+		goto exit;
+
+	/* Connect to the broker */
+	rc = MQTTClient_connect(test6_c1, &opts);
+	assert("good rc from connect",  rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+	if (rc != MQTTCLIENT_SUCCESS)
+		goto exit;
+
+	/* Client - 2 (multi-threaded) */
+	rc = MQTTClient_create(&test6_c2, options.connection, "Client_2", MQTTCLIENT_PERSISTENCE_DEFAULT, NULL);
+	assert("good rc from create",  rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+
+	/* Set the callback functions for the client */
+	rc = MQTTClient_setCallbacks(test6_c2, (void*)test6_c2, test6_connectionLost, test6_messageArrived, test6_deliveryComplete);
+	assert("good rc from setCallbacks",  rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+
+	/* Connect to the broker */
+	opts2.keepAliveInterval = 20;
+	opts2.cleansession = 1;
+	MyLog(LOGA_INFO, "Connecting Client_2 ...");
+	rc = MQTTClient_connect(test6_c2, &opts2);
+	assert("Good rc from connect", rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+
+	rc = MQTTClient_subscribe(test6_c2, test6_will_topic, 2);
+	assert("Good rc from subscribe", rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+
+	/* now send the command which will break the connection and cause the will message to be sent */
+	rc = MQTTClient_publish(test6_c1, mqttsas_topic, (int)strlen("TERMINATE"), "TERMINATE", 0, 0, NULL);
+	assert("Good rc from publish", rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+
+	MyLog(LOGA_INFO, "Waiting to receive the will message");
+	count = 0;
+	while (++count < 40)
+	{
+		#if defined(WIN32)
+			Sleep(1000L);
+		#else
+			sleep(1);
+		#endif
+		if (test6_will_message_arrived == 1 && test6_connection_lost_called == 1)
+			break;
+	}
+	assert("will message arrived", test6_will_message_arrived == 1,
+							"will_message_arrived was %d\n", test6_will_message_arrived);
+	assert("connection lost called", test6_connection_lost_called == 1,
+			         "connection_lost_called %d\n", test6_connection_lost_called);
+
+	rc = MQTTClient_unsubscribe(test6_c2, test6_will_topic);
+	assert("Good rc from unsubscribe", rc == MQTTCLIENT_SUCCESS, "rc was %d", rc);
+
+	rc = MQTTClient_isConnected(test6_c2);
+	assert("Client-2 still connected", rc == 1, "isconnected is %d", rc);
+
+	rc = MQTTClient_isConnected(test6_c1);
+	assert("Client-1 not connected", rc == 0, "isconnected is %d", rc);
+
+	rc = MQTTClient_disconnect(test6_c2, 100L);
+	assert("Good rc from disconnect", rc == MQTTCLIENT_SUCCESS, "rc was %d", rc);
+
+	MQTTClient_destroy(&test6_c1);
+	MQTTClient_destroy(&test6_c2);
+
+exit:
+	MyLog(LOGA_INFO, "%s: test %s. %d tests run, %d failures.\n",
+			(failures == 0) ? "passed" : "failed", testname, tests, failures);
+	write_test_result();
+	return failures;
+}
+#endif
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+ 	int (*tests[])() = {NULL, test1, test2, test3};
+	int i;
+
+	xml = fopen("TEST-test1.xml", "w");
+	fprintf(xml, "<testsuite name=\"test1\" tests=\"%d\">\n", (int)(ARRAY_SIZE(tests) - 1));
+
+	getopts(argc, argv);
+
+	for (i = 0; i < options.iterations; ++i)
+	{
+	 	if (options.test_no == 0)
+		{ /* run all the tests */
+ 		   	for (options.test_no = 1; options.test_no < ARRAY_SIZE(tests); ++options.test_no)
+				rc += tests[options.test_no](options); /* return number of failures.  0 = test succeeded */
+		}
+		else
+ 		   	rc = tests[options.test_no](options); /* run just the selected test */
+	}
+
+ 	if (rc == 0)
+		MyLog(LOGA_INFO, "verdict pass");
+	else
+		MyLog(LOGA_INFO, "verdict fail");
+
+	fprintf(xml, "</testsuite>\n");
+	fclose(xml);
+	return rc;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,21 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+project("paho-mqttclient" C)
+
+#ADD_SUBDIRECTORY(src)
+ADD_SUBDIRECTORY(samples)
+ADD_SUBDIRECTORY(test)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,17 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+ADD_SUBDIRECTORY(linux)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/arduino/Hello/Hello.ino
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/arduino/Hello/Hello.ino	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp. and others
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution. 
+ *
+ * The Eclipse Public License is available at 
+ *   http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at 
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial contribution
+ *    Benjamin Cabe - adapt to IPStack, and add Yun instructions
+ *******************************************************************************/
+
+#define MQTTCLIENT_QOS2 1
+
+#include <SPI.h>
+#include <Ethernet.h>
+#include <IPStack.h>
+#include <Countdown.h>
+#include <MQTTClient.h>
+
+char printbuf[100];
+
+int arrivedcount = 0;
+
+void messageArrived(MQTT::MessageData& md)
+{
+  MQTT::Message &message = md.message;
+  
+  sprintf(printbuf, "Message %d arrived: qos %d, retained %d, dup %d, packetid %d\n", 
+		++arrivedcount, message.qos, message.retained, message.dup, message.id);
+  Serial.print(printbuf);
+  sprintf(printbuf, "Payload %s\n", (char*)message.payload);
+  Serial.print(printbuf);
+}
+
+EthernetClient c; // replace by a YunClient if running on a Yun
+IPStack ipstack(c);
+MQTT::Client<IPStack, Countdown> client = MQTT::Client<IPStack, Countdown>(ipstack);
+
+byte mac[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };  // replace with your device's MAC
+const char* topic = "arduino-sample";
+
+void connect()
+{
+  char hostname[] = "iot.eclipse.org";
+  int port = 1883;
+  sprintf(printbuf, "Connecting to %s:%d\n", hostname, port);
+  Serial.print(printbuf);
+  int rc = ipstack.connect(hostname, port);
+  if (rc != 1)
+  {
+    sprintf(printbuf, "rc from TCP connect is %d\n", rc);
+    Serial.print(printbuf);
+  }
+ 
+  Serial.println("MQTT connecting");
+  MQTTPacket_connectData data = MQTTPacket_connectData_initializer;       
+  data.MQTTVersion = 3;
+  data.clientID.cstring = (char*)"arduino-sample";
+  rc = client.connect(data);
+  if (rc != 0)
+  {
+    sprintf(printbuf, "rc from MQTT connect is %d\n", rc);
+    Serial.print(printbuf);
+  }
+  Serial.println("MQTT connected");
+  
+  rc = client.subscribe(topic, MQTT::QOS2, messageArrived);   
+  if (rc != 0)
+  {
+    sprintf(printbuf, "rc from MQTT subscribe is %d\n", rc);
+    Serial.print(printbuf);
+  }
+  Serial.println("MQTT subscribed");
+}
+
+void setup()
+{
+  Serial.begin(9600);
+  Ethernet.begin(mac); // replace by Bridge.begin() if running on a Yun
+  Serial.println("MQTT Hello example");
+  connect();
+}
+
+void loop()
+{
+  if (!client.isConnected())
+    connect();
+  
+  MQTT::Message message;
+  
+  arrivedcount = 0;
+
+  // Send and receive QoS 0 message
+  char buf[100];
+  sprintf(buf, "Hello World! QoS 0 message");
+  Serial.println(buf);
+  message.qos = MQTT::QOS0;
+  message.retained = false;
+  message.dup = false;
+  message.payload = (void*)buf;
+  message.payloadlen = strlen(buf)+1;
+  int rc = client.publish(topic, message);
+  while (arrivedcount == 0)
+    client.yield(1000);
+        
+  // Send and receive QoS 1 message
+  sprintf(buf, "Hello World!  QoS 1 message");
+  Serial.println(buf);
+  message.qos = MQTT::QOS1;
+  message.payloadlen = strlen(buf)+1;
+  rc = client.publish(topic, message);
+  while (arrivedcount == 1)
+    client.yield(1000);
+        
+  // Send and receive QoS 2 message
+  sprintf(buf, "Hello World!  QoS 2 message");
+  Serial.println(buf);
+  message.qos = MQTT::QOS2;
+  message.payloadlen = strlen(buf)+1;
+  rc = client.publish(topic, message);
+  while (arrivedcount == 2)
+    client.yield(1000);
+    
+  delay(2000);
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/linux/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/linux/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,31 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+# Samples
+
+add_executable(
+  hello
+  hello.cpp
+)
+target_include_directories(hello PRIVATE "../../src" "../../src/linux")
+target_link_libraries(hello MQTTPacketClient)
+
+add_executable(
+  stdoutsub
+  stdoutsub.cpp
+)
+target_include_directories(stdoutsub PRIVATE "../../src" "../../src/linux")
+target_link_libraries(stdoutsub paho-embed-mqtt3c)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/linux/build.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/linux/build.sh	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,3 @@
+g++ hello.cpp -I ../../src/ -I ../../src/linux -I ../../../MQTTPacket/src ../../../MQTTPacket/src/MQTTPacket.c ../../../MQTTPacket/src/MQTTDeserializePublish.c ../../../MQTTPacket/src/MQTTConnectClient.c ../../../MQTTPacket/src/MQTTSubscribeClient.c ../../../MQTTPacket/src/MQTTSerializePublish.c ../../../MQTTPacket/src/MQTTUnsubscribeClient.c -o hello
+
+g++ -g stdoutsub.cpp -I ../../src -I ../../src/linux -I ../../../MQTTPacket/src ../../../MQTTPacket/src/MQTTFormat.c  ../../../MQTTPacket/src/MQTTPacket.c ../../../MQTTPacket/src/MQTTDeserializePublish.c ../../../MQTTPacket/src/MQTTConnectClient.c ../../../MQTTPacket/src/MQTTSubscribeClient.c ../../../MQTTPacket/src/MQTTSerializePublish.c -o stdoutsub ../../../MQTTPacket/src/MQTTConnectServer.c ../../../MQTTPacket/src/MQTTSubscribeServer.c ../../../MQTTPacket/src/MQTTUnsubscribeServer.c ../../../MQTTPacket/src/MQTTUnsubscribeClient.c  
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/linux/hello.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/linux/hello.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,104 @@
+#define MQTTCLIENT_QOS2 1
+
+#include <memory.h>
+
+#include "MQTTClient.h"
+
+#define DEFAULT_STACK_SIZE -1
+
+#include "linux.cpp"
+
+int arrivedcount = 0;
+
+void messageArrived(MQTT::MessageData& md)
+{
+    MQTT::Message &message = md.message;
+
+    printf("Message %d arrived: qos %d, retained %d, dup %d, packetid %d\n", 
+		++arrivedcount, message.qos, message.retained, message.dup, message.id);
+    printf("Payload %.*s\n", (int)message.payloadlen, (char*)message.payload);
+}
+
+
+int main(int argc, char* argv[])
+{   
+    IPStack ipstack = IPStack();
+    float version = 0.3;
+    const char* topic = "mbed-sample";
+    
+    printf("Version is %f\n", version);
+              
+    MQTT::Client<IPStack, Countdown> client = MQTT::Client<IPStack, Countdown>(ipstack);
+    
+    const char* hostname = "iot.eclipse.org";
+    int port = 1883;
+    printf("Connecting to %s:%d\n", hostname, port);
+    int rc = ipstack.connect(hostname, port);
+	if (rc != 0)
+	    printf("rc from TCP connect is %d\n", rc);
+ 
+	printf("MQTT connecting\n");
+    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;       
+    data.MQTTVersion = 3;
+    data.clientID.cstring = (char*)"mbed-icraggs";
+    rc = client.connect(data);
+	if (rc != 0)
+	    printf("rc from MQTT connect is %d\n", rc);
+	printf("MQTT connected\n");
+    
+    rc = client.subscribe(topic, MQTT::QOS2, messageArrived);   
+    if (rc != 0)
+        printf("rc from MQTT subscribe is %d\n", rc);
+
+    MQTT::Message message;
+
+    // QoS 0
+    char buf[100];
+    sprintf(buf, "Hello World!  QoS 0 message from app version %f", version);
+    message.qos = MQTT::QOS0;
+    message.retained = false;
+    message.dup = false;
+    message.payload = (void*)buf;
+    message.payloadlen = strlen(buf)+1;
+    rc = client.publish(topic, message);
+	if (rc != 0)
+		printf("Error %d from sending QoS 0 message\n", rc);
+    else while (arrivedcount == 0)
+        client.yield(100);
+        
+    // QoS 1
+	printf("Now QoS 1\n");
+    sprintf(buf, "Hello World!  QoS 1 message from app version %f", version);
+    message.qos = MQTT::QOS1;
+    message.payloadlen = strlen(buf)+1;
+    rc = client.publish(topic, message);
+	if (rc != 0)
+		printf("Error %d from sending QoS 1 message\n", rc);
+    else while (arrivedcount == 1)
+        client.yield(100);
+        
+    // QoS 2
+    sprintf(buf, "Hello World!  QoS 2 message from app version %f", version);
+    message.qos = MQTT::QOS2;
+    message.payloadlen = strlen(buf)+1;
+    rc = client.publish(topic, message);
+	if (rc != 0)
+		printf("Error %d from sending QoS 2 message\n", rc);
+    while (arrivedcount == 2)
+        client.yield(100);
+    
+    rc = client.unsubscribe(topic);
+    if (rc != 0)
+        printf("rc from unsubscribe was %d\n", rc);
+    
+    rc = client.disconnect();
+    if (rc != 0)
+        printf("rc from disconnect was %d\n", rc);
+    
+    ipstack.disconnect();
+    
+    printf("Finishing with %d messages received\n", arrivedcount);
+    
+    return 0;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/linux/main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/linux/main.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,291 @@
+
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include "MQTTClient.h"
+//#include "FP.cpp"
+
+#define DEFAULT_STACK_SIZE -1
+
+
+class IPStack 
+{
+public:    
+    IPStack()
+    {
+
+    }
+    
+	int Socket_error(const char* aString)
+	{
+
+		if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS && errno != EWOULDBLOCK)
+		{
+			if (strcmp(aString, "shutdown") != 0 || (errno != ENOTCONN && errno != ECONNRESET))
+				printf("Socket error %s in %s for socket %d\n", strerror(errno), aString, mysock);
+		}
+		return errno;
+	}
+
+    int connect(const char* hostname, int port)
+    {
+		int type = SOCK_STREAM;
+		struct sockaddr_in address;
+		int rc = -1;
+		sa_family_t family = AF_INET;
+		struct addrinfo *result = NULL;
+		struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL};
+
+		if ((rc = getaddrinfo(hostname, NULL, &hints, &result)) == 0)
+		{
+			struct addrinfo* res = result;
+
+			/* prefer ip4 addresses */
+			while (res)
+			{
+				if (res->ai_family == AF_INET)
+				{
+					result = res;
+					break;
+				}
+				res = res->ai_next;
+			}
+
+			if (result->ai_family == AF_INET)
+			{
+				address.sin_port = htons(port);
+				address.sin_family = family = AF_INET;
+				address.sin_addr = ((struct sockaddr_in*)(result->ai_addr))->sin_addr;
+			}
+			else
+				rc = -1;
+
+			freeaddrinfo(result);
+		}
+
+		if (rc == 0)
+		{
+			mysock = socket(family, type, 0);
+			if (mysock != -1)
+			{
+				int opt = 1;
+
+				//if (setsockopt(mysock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&opt, sizeof(opt)) != 0)
+				//	printf("Could not set SO_NOSIGPIPE for socket %d", mysock);
+				
+				rc = ::connect(mysock, (struct sockaddr*)&address, sizeof(address));
+			}
+		}
+
+        return rc;
+    }
+
+    int read(unsigned char* buffer, int len, int timeout_ms)
+    {
+		struct timeval interval = {timeout_ms / 1000, (timeout_ms % 1000) * 1000};
+		if (interval.tv_sec < 0 || (interval.tv_sec == 0 && interval.tv_usec <= 0))
+		{
+			interval.tv_sec = 0;
+			interval.tv_usec = 100;
+		}
+
+		setsockopt(mysock, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval, sizeof(struct timeval));
+
+		//printf("reading %d bytes\n", len);
+		int rc = ::recv(mysock, buffer, (size_t)len, 0);
+		if (rc == -1)
+			Socket_error("read");
+		//printf("read %d bytes\n", rc);
+		return rc;
+    }
+    
+    int write(unsigned char* buffer, int len, int timeout)
+    {
+		struct timeval tv;
+
+		tv.tv_sec = 0;  /* 30 Secs Timeout */
+		tv.tv_usec = timeout * 1000;  // Not init'ing this can cause strange errors
+
+		setsockopt(mysock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
+		int	rc = ::write(mysock, buffer, len);
+		//printf("write rc %d\n", rc);
+		return rc;
+    }
+
+	int disconnect()
+	{
+		return ::close(mysock);
+	}
+    
+private:
+
+    int mysock; 
+    
+};
+
+
+class Countdown
+{
+public:
+    Countdown()
+    { 
+	
+    }
+
+    Countdown(int ms)
+    { 
+		countdown_ms(ms);
+    }
+    
+
+    bool expired()
+    {
+		struct timeval now, res;
+		gettimeofday(&now, NULL);
+		timersub(&end_time, &now, &res);		
+		//printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000);
+		//if (res.tv_sec > 0 || res.tv_usec > 0)
+		//	printf("expired %d %d\n", res.tv_sec, res.tv_usec);
+        return res.tv_sec < 0 || (res.tv_sec == 0 && res.tv_usec <= 0);
+    }
+    
+
+    void countdown_ms(int ms)  
+    {
+		struct timeval now;
+		gettimeofday(&now, NULL);
+		struct timeval interval = {ms / 1000, (ms % 1000) * 1000};
+		//printf("interval %d %d\n", interval.tv_sec, interval.tv_usec);
+		timeradd(&now, &interval, &end_time);
+    }
+
+    
+    void countdown(int seconds)
+    {
+		struct timeval now;
+		gettimeofday(&now, NULL);
+		struct timeval interval = {seconds, 0};
+		timeradd(&now, &interval, &end_time);
+    }
+
+    
+    int left_ms()
+    {
+		struct timeval now, res;
+		gettimeofday(&now, NULL);
+		timersub(&end_time, &now, &res);
+		//printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000);
+        return (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000;
+    }
+    
+private:
+
+	struct timeval end_time;
+};
+
+
+int arrivedcount = 0;
+
+void messageArrived(MQTT::MessageData& md)
+{
+    MQTT::Message &message = md.message;
+
+	printf("Message %d arrived: qos %d, retained %d, dup %d, packetid %d\n", 
+		++arrivedcount, message.qos, message.retained, message.dup, message.id);
+    printf("Payload %.*s\n", message.payloadlen, (char*)message.payload);
+}
+
+
+int main(int argc, char* argv[])
+{   
+    IPStack ipstack = IPStack();
+    float version = 0.3;
+    const char* topic = "mbed-sample";
+    
+    printf("Version is %f\n", version);
+              
+    MQTT::Client<IPStack, Countdown> client = MQTT::Client<IPStack, Countdown>(ipstack);
+    
+    const char* hostname = "localhost"; //"m2m.eclipse.org";
+    int port = 1883;
+    printf("Connecting to %s:%d\n", hostname, port);
+    int rc = ipstack.connect(hostname, port);
+	if (rc != 0)
+	    printf("rc from TCP connect is %d\n", rc);
+ 
+	printf("MQTT connecting\n");
+    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;       
+    data.MQTTVersion = 3;
+    data.clientID.cstring = (char*)"mbed-icraggs";
+    rc = client.connect(&data);
+	if (rc != 0)
+	    printf("rc from MQTT connect is %d\n", rc);
+	printf("MQTT connected\n");
+    
+    rc = client.subscribe("+", MQTT::QOS2, messageArrived);   
+    if (rc != 0)
+        printf("rc from MQTT subscribe is %d\n", rc);
+
+    MQTT::Message message;
+
+    // QoS 0
+    char buf[100];
+    sprintf(buf, "Hello World!  QoS 0 message from app version %f", version);
+    message.qos = MQTT::QOS0;
+    message.retained = false;
+    message.dup = false;
+    message.payload = (void*)buf;
+    message.payloadlen = strlen(buf)+1;
+    rc = client.publish(topic, &message);
+    while (arrivedcount == 0)
+        client.yield(100);
+        
+    // QoS 1
+	printf("Now QoS 1\n");
+    sprintf(buf, "Hello World!  QoS 1 message from app version %f", version);
+    message.qos = MQTT::QOS1;
+    message.payloadlen = strlen(buf)+1;
+    rc = client.publish(topic, &message);
+    while (arrivedcount == 1)
+        client.yield(100);
+        
+    // QoS 2
+    sprintf(buf, "Hello World!  QoS 2 message from app version %f", version);
+    message.qos = MQTT::QOS2;
+    message.payloadlen = strlen(buf)+1;
+    rc = client.publish(topic, &message);
+    while (arrivedcount == 2)
+        client.yield(100);
+    
+    rc = client.unsubscribe(topic);
+    if (rc != 0)
+        printf("rc from unsubscribe was %d\n", rc);
+    
+    rc = client.disconnect();
+    if (rc != 0)
+        printf("rc from disconnect was %d\n", rc);
+    
+    ipstack.disconnect();
+    
+    printf("Finishing with %d messages received\n", arrivedcount);
+    
+    return 0;
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/linux/stdoutsub.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/samples/linux/stdoutsub.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,265 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution. 
+ *
+ * The Eclipse Public License is available at 
+ *   http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at 
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial contribution
+ *    Ian Craggs - change delimiter option from char to string
+ *******************************************************************************/
+
+/*
+ 
+ stdout subscriber
+ 
+ compulsory parameters:
+ 
+  topic to subscribe to
+ 
+ defaulted parameters:
+ 
+	--host localhost
+	--port 1883
+	--qos 2
+	--delimiter \n
+	--clientid stdout_subscriber
+	
+	--userid none
+	--password none
+ 
+*/
+#include <stdio.h>
+#include <memory.h>
+#define MQTT_DEBUG 1
+#include "MQTTClient.h"
+
+#define DEFAULT_STACK_SIZE -1
+
+#include "linux.cpp"
+
+#include <signal.h>
+#include <sys/time.h>
+#include <stdlib.h>
+
+
+volatile int toStop = 0;
+
+
+void usage()
+{
+	printf("MQTT stdout subscriber\n");
+	printf("Usage: stdoutsub topicname <options>, where options are:\n");
+	printf("  --host <hostname> (default is localhost)\n");
+	printf("  --port <port> (default is 1883)\n");
+	printf("  --qos <qos> (default is 2)\n");
+	printf("  --delimiter <delim> (default is \\n)\n");
+	printf("  --clientid <clientid> (default is hostname+timestamp)\n");
+	printf("  --username none\n");
+	printf("  --password none\n");
+	printf("  --showtopics <on or off> (default is on if the topic has a wildcard, else off)\n");
+	exit(-1);
+}
+
+
+void cfinish(int sig)
+{
+	signal(SIGINT, NULL);
+	toStop = 1;
+}
+
+
+struct opts_struct
+{
+	char* clientid;
+	int nodelimiter;
+	char* delimiter;
+	MQTT::QoS qos;
+	char* username;
+	char* password;
+	char* host;
+	int port;
+	int showtopics;
+} opts =
+{
+	(char*)"stdout-subscriber", 0, (char*)"\n", MQTT::QOS2, NULL, NULL, (char*)"localhost", 1883, 0
+};
+
+
+void getopts(int argc, char** argv)
+{
+	int count = 2;
+	
+	while (count < argc)
+	{
+		if (strcmp(argv[count], "--qos") == 0)
+		{
+			if (++count < argc)
+			{
+				if (strcmp(argv[count], "0") == 0)
+					opts.qos = MQTT::QOS0;
+				else if (strcmp(argv[count], "1") == 0)
+					opts.qos = MQTT::QOS1;
+				else if (strcmp(argv[count], "2") == 0)
+					opts.qos = MQTT::QOS2;
+				else
+					usage();
+			}
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--host") == 0)
+		{
+			if (++count < argc)
+				opts.host = argv[count];
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--port") == 0)
+		{
+			if (++count < argc)
+				opts.port = atoi(argv[count]);
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--clientid") == 0)
+		{
+			if (++count < argc)
+				opts.clientid = argv[count];
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--username") == 0)
+		{
+			if (++count < argc)
+				opts.username = argv[count];
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--password") == 0)
+		{
+			if (++count < argc)
+				opts.password = argv[count];
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--delimiter") == 0)
+		{
+			if (++count < argc)
+				opts.delimiter = argv[count];
+			else
+				opts.nodelimiter = 1;
+		}
+		else if (strcmp(argv[count], "--showtopics") == 0)
+		{
+			if (++count < argc)
+			{
+				if (strcmp(argv[count], "on") == 0)
+					opts.showtopics = 1;
+				else if (strcmp(argv[count], "off") == 0)
+					opts.showtopics = 0;
+				else
+					usage();
+			}
+			else
+				usage();
+		}
+		count++;
+	}
+	
+}
+
+
+void myconnect(IPStack& ipstack, MQTT::Client<IPStack, Countdown, 1000>& client, MQTTPacket_connectData& data)
+{
+	printf("Connecting to %s:%d\n", opts.host, opts.port);
+	int rc = ipstack.connect(opts.host, opts.port);
+	if (rc != 0)
+	    printf("rc from TCP connect is %d\n", rc);
+
+	rc = client.connect(data);
+	if (rc != 0)
+	{
+		printf("Failed to connect, return code %d\n", rc);
+		exit(-1);	
+	}
+	printf("Connected\n");
+}
+
+
+void messageArrived(MQTT::MessageData& md)
+{
+	MQTT::Message &message = md.message;
+
+	if (opts.showtopics)
+		printf("%.*s\t", md.topicName.lenstring.len, md.topicName.lenstring.data);
+	if (opts.nodelimiter)
+		printf("%.*s", (int)message.payloadlen, (char*)message.payload);
+	else
+		printf("%.*s%s", (int)message.payloadlen, (char*)message.payload, opts.delimiter);
+	fflush(stdout);
+}
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+	
+	if (argc < 2)
+		usage();
+	
+	char* topic = argv[1];
+
+	if (strchr(topic, '#') || strchr(topic, '+'))
+		opts.showtopics = 1;
+	if (opts.showtopics)
+		printf("topic is %s\n", topic);
+
+	getopts(argc, argv);	
+
+	IPStack ipstack = IPStack();
+	MQTT::Client<IPStack, Countdown, 1000> client = MQTT::Client<IPStack, Countdown, 1000>(ipstack);
+
+	signal(SIGINT, cfinish);
+	signal(SIGTERM, cfinish);
+ 
+	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;       
+	data.willFlag = 0;
+	data.MQTTVersion = 3;
+	data.clientID.cstring = opts.clientid;
+	data.username.cstring = opts.username;
+	data.password.cstring = opts.password;
+
+	data.keepAliveInterval = 10;
+	data.cleansession = 1;
+	printf("will flag %d\n", data.willFlag);
+	
+	myconnect(ipstack, client, data);
+    
+	rc = client.subscribe(topic, opts.qos, messageArrived);
+	printf("Subscribed %d\n", rc);
+
+	while (!toStop)
+	{
+		client.yield(1000);	
+
+		//if (!client.isconnected)
+		//	myconnect(ipstack, client, data);
+	}
+	
+	printf("Stopping\n");
+
+	rc = client.disconnect();
+
+	ipstack.disconnect();
+
+	return 0;
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/FP.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/FP.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2014 
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Sam Grove - initial API and implementation and/or initial documentation
+ *    Ian Craggs - added attached and detached member functions
+ *    Sam Grove - removed need for FP.cpp
+ *******************************************************************************/
+
+#ifndef FP_H
+#define FP_H
+
+/** Example using the FP Class with global functions
+ * @code
+ *  #include "mbed.h"
+ *  #include "FP.h"
+ *
+ *  FP<void,bool>fp;
+ *  DigitalOut myled(LED1);
+ *
+ *  void handler(bool value)
+ *  {
+ *      myled = value;
+ *      return;
+ *  }
+ *
+ *  int main()
+ *  {
+ *      fp.attach(&handler);
+ *
+ *      while(1)
+ *      {
+ *          fp(1);
+ *          wait(0.2);
+ *          fp(0);
+ *          wait(0.2);
+ *      }
+ *  }
+ * @endcode
+ */
+
+/** Example using the FP Class with different class member functions
+ * @code
+ *  #include "mbed.h"
+ *  #include "FP.h"
+ *
+ *  FP<void,bool>fp;
+ *  DigitalOut myled(LED4);
+ *
+ *  class Wrapper
+ *  {
+ *  public:
+ *      Wrapper(){}
+ *
+ *      void handler(bool value)
+ *      {
+ *          myled = value;
+ *          return;
+ *      }
+ *  };
+ *
+ *  int main()
+ *  {
+ *      Wrapper wrapped;
+ *      fp.attach(&wrapped, &Wrapper::handler);
+ *
+ *      while(1)
+ *      {
+ *          fp(1);
+ *          wait(0.2);
+ *          fp(0);
+ *          wait(0.2);
+ *      }
+ *  }
+ * @endcode
+ */
+
+/** Example using the FP Class with member FP and member function
+* @code
+*  #include "mbed.h"
+*  #include "FP.h"
+*
+*  DigitalOut myled(LED2);
+*
+*  class Wrapper
+*  {
+*  public:
+*      Wrapper()
+*      {
+*          fp.attach(this, &Wrapper::handler);
+*      }
+*
+*      void handler(bool value)
+*      {
+*          myled = value;
+*          return;
+*      }
+*
+*      FP<void,bool>fp;
+*  };
+*
+*  int main()
+*  {
+*      Wrapper wrapped;
+*
+*      while(1)
+*      {
+*          wrapped.fp(1);
+*          wait(0.2);
+*          wrapped.fp(0);
+*          wait(0.2);
+*      }
+*  }
+* @endcode
+*/
+
+/**
+ *  @class FP
+ *  @brief API for managing Function Pointers
+ */
+template<class retT, class argT>
+class FP
+{
+public:
+    /** Create the FP object - only one callback can be attached to the object, that is
+     *  a member function or a global function, not both at the same time
+     */
+    FP()
+    {
+        obj_callback = 0;
+        c_callback = 0;
+    }
+
+    /** Add a callback function to the object
+     *  @param item - Address of the initialized object
+     *  @param member - Address of the member function (dont forget the scope that the function is defined in)
+     */
+    template<class T>
+    void attach(T *item, retT (T::*method)(argT))
+    {
+        obj_callback = (FPtrDummy *)(item);
+        method_callback = (retT (FPtrDummy::*)(argT))(method);
+        return;
+    }
+
+    /** Add a callback function to the object
+     *  @param function - The address of a globally defined function
+     */
+    void attach(retT (*function)(argT))
+    {
+        c_callback = function;
+    }
+
+    /** Invoke the function attached to the class
+     *  @param arg - An argument that is passed into the function handler that is called
+     *  @return The return from the function hanlder called by this class
+     */
+    retT operator()(argT arg) const
+    {
+        if( 0 != c_callback ) {
+            return obj_callback ? (obj_callback->*method_callback)(arg) : (*c_callback)(arg);
+        }
+        return (retT)0;
+    }
+
+    /** Determine if an callback is currently hooked
+     *  @return 1 if a method is hooked, 0 otherwise
+     */
+    bool attached()
+    {
+        return obj_callback || c_callback;
+    }
+
+    /** Release a function from the callback hook
+     */
+    void detach()
+    {
+        obj_callback = 0;
+        c_callback = 0;
+    }
+
+private:
+
+    // empty type used for casting
+    class FPtrDummy;
+
+    FPtrDummy *obj_callback;
+
+    /**
+     *  @union Funciton
+     *  @brief Member or global callback function
+     */
+    union {
+        retT (*c_callback)(argT);                   /*!< Footprint for a global function */
+        retT (FPtrDummy::*method_callback)(argT);   /*!< Footprint for a member function */
+    };
+};
+
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/MQTTClient.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/MQTTClient.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,1072 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2017 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Ian Craggs - fix for bug 458512 - QoS 2 messages
+ *    Ian Craggs - fix for bug 460389 - send loop uses wrong length
+ *    Ian Craggs - fix for bug 464169 - clearing subscriptions
+ *    Ian Craggs - fix for bug 464551 - enums and ints can be different size
+ *    Mark Sonnentag - fix for bug 475204 - inefficient instantiation of Timer
+ *    Ian Craggs - fix for bug 475749 - packetid modified twice
+ *    Ian Craggs - add ability to set message handler separately #6
+ *******************************************************************************/
+
+#if !defined(MQTTCLIENT_H)
+#define MQTTCLIENT_H
+
+#include "FP.h"
+#include "MQTTPacket.h"
+#include <stdio.h>
+#include <string.h>
+#include "MQTTLogging.h"
+
+#if !defined(MQTTCLIENT_QOS1)
+    #define MQTTCLIENT_QOS1 1
+#endif
+#if !defined(MQTTCLIENT_QOS2)
+    #define MQTTCLIENT_QOS2 0
+#endif
+
+namespace MQTT
+{
+
+
+enum QoS { QOS0, QOS1, QOS2 };
+
+// all failure return codes must be negative
+enum returnCode { BUFFER_OVERFLOW = -2, FAILURE = -1, SUCCESS = 0 };
+
+
+struct Message
+{
+    enum QoS qos;
+    bool retained;
+    bool dup;
+    unsigned short id;
+    void *payload;
+    size_t payloadlen;
+};
+
+
+struct MessageData
+{
+    MessageData(MQTTString &aTopicName, struct Message &aMessage)  : message(aMessage), topicName(aTopicName)
+    { }
+
+    struct Message &message;
+    MQTTString &topicName;
+};
+
+
+struct connackData
+{
+    int rc;
+    bool sessionPresent;
+};
+
+
+struct subackData
+{
+    int grantedQoS;
+};
+
+
+class PacketId
+{
+public:
+    PacketId()
+    {
+        next = 0;
+    }
+
+    int getNext()
+    {
+        return next = (next == MAX_PACKET_ID) ? 1 : next + 1;
+    }
+
+private:
+    static const int MAX_PACKET_ID = 65535;
+    int next;
+};
+
+
+/**
+ * @class Client
+ * @brief blocking, non-threaded MQTT client API
+ *
+ * This version of the API blocks on all method calls, until they are complete.  This means that only one
+ * MQTT request can be in process at any one time.
+ * @param Network a network class which supports send, receive
+ * @param Timer a timer class with the methods:
+ */
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE = 100, int MAX_MESSAGE_HANDLERS = 5>
+class Client
+{
+
+public:
+
+    typedef void (*messageHandler)(MessageData&);
+
+    /** Construct the client
+     *  @param network - pointer to an instance of the Network class - must be connected to the endpoint
+     *      before calling MQTT connect
+     *  @param limits an instance of the Limit class - to alter limits as required
+     */
+    Client(Network& network, unsigned int command_timeout_ms = 30000);
+
+    /** Set the default message handling callback - used for any message which does not match a subscription message handler
+     *  @param mh - pointer to the callback function.  Set to 0 to remove.
+     */
+    void setDefaultMessageHandler(messageHandler mh)
+    {
+        if (mh != 0)
+            defaultMessageHandler.attach(mh);
+        else
+            defaultMessageHandler.detach();
+    }
+
+    /** Set a message handling callback.  This can be used outside of the the subscribe method.
+     *  @param topicFilter - a topic pattern which can include wildcards
+     *  @param mh - pointer to the callback function. If 0, removes the callback if any
+     */
+    int setMessageHandler(const char* topicFilter, messageHandler mh);
+
+    /** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack
+     *  The nework object must be connected to the network endpoint before calling this
+     *  Default connect options are used
+     *  @return success code -
+     */
+    int connect();
+
+    /** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack
+     *  The nework object must be connected to the network endpoint before calling this
+     *  @param options - connect options
+     *  @return success code -
+     */
+    int connect(MQTTPacket_connectData& options);
+
+    /** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack
+     *  The nework object must be connected to the network endpoint before calling this
+     *  @param options - connect options
+     *  @param connackData - connack data to be returned
+     *  @return success code -
+     */
+    int connect(MQTTPacket_connectData& options, connackData& data);
+
+    /** MQTT Publish - send an MQTT publish packet and wait for all acks to complete for all QoSs
+     *  @param topic - the topic to publish to
+     *  @param message - the message to send
+     *  @return success code -
+     */
+    int publish(const char* topicName, Message& message);
+
+    /** MQTT Publish - send an MQTT publish packet and wait for all acks to complete for all QoSs
+     *  @param topic - the topic to publish to
+     *  @param payload - the data to send
+     *  @param payloadlen - the length of the data
+     *  @param qos - the QoS to send the publish at
+     *  @param retained - whether the message should be retained
+     *  @return success code -
+     */
+    int publish(const char* topicName, void* payload, size_t payloadlen, enum QoS qos = QOS0, bool retained = false);
+
+    /** MQTT Publish - send an MQTT publish packet and wait for all acks to complete for all QoSs
+     *  @param topic - the topic to publish to
+     *  @param payload - the data to send
+     *  @param payloadlen - the length of the data
+     *  @param id - the packet id used - returned
+     *  @param qos - the QoS to send the publish at
+     *  @param retained - whether the message should be retained
+     *  @return success code -
+     */
+    int publish(const char* topicName, void* payload, size_t payloadlen, unsigned short& id, enum QoS qos = QOS1, bool retained = false);
+
+    /** MQTT Subscribe - send an MQTT subscribe packet and wait for the suback
+     *  @param topicFilter - a topic pattern which can include wildcards
+     *  @param qos - the MQTT QoS to subscribe at
+     *  @param mh - the callback function to be invoked when a message is received for this subscription
+     *  @return success code -
+     */
+    int subscribe(const char* topicFilter, enum QoS qos, messageHandler mh);
+
+    /** MQTT Subscribe - send an MQTT subscribe packet and wait for the suback
+     *  @param topicFilter - a topic pattern which can include wildcards
+     *  @param qos - the MQTT QoS to subscribe at©
+     *  @param mh - the callback function to be invoked when a message is received for this subscription
+     *  @param
+     *  @return success code -
+     */
+    int subscribe(const char* topicFilter, enum QoS qos, messageHandler mh, subackData &data);
+
+    /** MQTT Unsubscribe - send an MQTT unsubscribe packet and wait for the unsuback
+     *  @param topicFilter - a topic pattern which can include wildcards
+     *  @return success code -
+     */
+    int unsubscribe(const char* topicFilter);
+
+    /** MQTT Disconnect - send an MQTT disconnect packet, and clean up any state
+     *  @return success code -
+     */
+    int disconnect();
+
+    /** A call to this API must be made within the keepAlive interval to keep the MQTT connection alive
+     *  yield can be called if no other MQTT operation is needed.  This will also allow messages to be
+     *  received.
+     *  @param timeout_ms the time to wait, in milliseconds
+     *  @return success code - on failure, this means the client has disconnected
+     */
+    int yield(unsigned long timeout_ms = 1000L);
+
+    /** Is the client connected?
+     *  @return flag - is the client connected or not?
+     */
+    bool isConnected()
+    {
+        return isconnected;
+    }
+
+private:
+
+    void closeSession();
+    void cleanSession();
+    int cycle(Timer& timer);
+    int waitfor(int packet_type, Timer& timer);
+    int keepalive();
+    int publish(int len, Timer& timer, enum QoS qos);
+
+    int decodePacket(int* value, int timeout);
+    int readPacket(Timer& timer);
+    int sendPacket(int length, Timer& timer);
+    int deliverMessage(MQTTString& topicName, Message& message);
+    bool isTopicMatched(char* topicFilter, MQTTString& topicName);
+
+    Network& ipstack;
+    unsigned long command_timeout_ms;
+
+    unsigned char sendbuf[MAX_MQTT_PACKET_SIZE];
+    unsigned char readbuf[MAX_MQTT_PACKET_SIZE];
+
+    Timer last_sent, last_received;
+    unsigned int keepAliveInterval;
+    bool ping_outstanding;
+    bool cleansession;
+
+    PacketId packetid;
+
+    struct MessageHandlers
+    {
+        const char* topicFilter;
+        FP<void, MessageData&> fp;
+    } messageHandlers[MAX_MESSAGE_HANDLERS];      // Message handlers are indexed by subscription topic
+
+    FP<void, MessageData&> defaultMessageHandler;
+
+    bool isconnected;
+
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+    unsigned char pubbuf[MAX_MQTT_PACKET_SIZE];  // store the last publish for sending on reconnect
+    int inflightLen;
+    unsigned short inflightMsgid;
+    enum QoS inflightQoS;
+#endif
+
+#if MQTTCLIENT_QOS2
+    bool pubrel;
+    #if !defined(MAX_INCOMING_QOS2_MESSAGES)
+        #define MAX_INCOMING_QOS2_MESSAGES 10
+    #endif
+    unsigned short incomingQoS2messages[MAX_INCOMING_QOS2_MESSAGES];
+    bool isQoS2msgidFree(unsigned short id);
+    bool useQoS2msgid(unsigned short id);
+	void freeQoS2msgid(unsigned short id);
+#endif
+
+};
+
+}
+
+
+template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS>
+void MQTT::Client<Network, Timer, a, MAX_MESSAGE_HANDLERS>::cleanSession()
+{
+    for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+        messageHandlers[i].topicFilter = 0;
+
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+    inflightMsgid = 0;
+    inflightQoS = QOS0;
+#endif
+
+#if MQTTCLIENT_QOS2
+    pubrel = false;
+    for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
+        incomingQoS2messages[i] = 0;
+#endif
+}
+
+
+template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS>
+void MQTT::Client<Network, Timer, a, MAX_MESSAGE_HANDLERS>::closeSession()
+{
+    ping_outstanding = false;
+    isconnected = false;
+    if (cleansession)
+        cleanSession();
+}
+
+
+template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS>
+MQTT::Client<Network, Timer, a, MAX_MESSAGE_HANDLERS>::Client(Network& network, unsigned int command_timeout_ms)  : ipstack(network), packetid()
+{
+    this->command_timeout_ms = command_timeout_ms;
+    cleansession = true;
+	  closeSession();
+}
+
+
+#if MQTTCLIENT_QOS2
+template<class Network, class Timer, int a, int b>
+bool MQTT::Client<Network, Timer, a, b>::isQoS2msgidFree(unsigned short id)
+{
+    for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
+    {
+        if (incomingQoS2messages[i] == id)
+            return false;
+    }
+    return true;
+}
+
+
+template<class Network, class Timer, int a, int b>
+bool MQTT::Client<Network, Timer, a, b>::useQoS2msgid(unsigned short id)
+{
+    for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
+    {
+        if (incomingQoS2messages[i] == 0)
+        {
+            incomingQoS2messages[i] = id;
+            return true;
+        }
+    }
+    return false;
+}
+
+
+template<class Network, class Timer, int a, int b>
+void MQTT::Client<Network, Timer, a, b>::freeQoS2msgid(unsigned short id)
+{
+    for (int i = 0; i < MAX_INCOMING_QOS2_MESSAGES; ++i)
+    {
+        if (incomingQoS2messages[i] == id)
+        {
+            incomingQoS2messages[i] = 0;
+            return;
+        }
+    }
+}
+#endif
+
+
+template<class Network, class Timer, int a, int b>
+int MQTT::Client<Network, Timer, a, b>::sendPacket(int length, Timer& timer)
+{
+    int rc = FAILURE,
+        sent = 0;
+
+    while (sent < length)
+    {
+        rc = ipstack.write(&sendbuf[sent], length - sent, timer.left_ms());
+        if (rc < 0)  // there was an error writing the data
+            break;
+        sent += rc;
+        if (timer.expired()) // only check expiry after at least one attempt to write
+            break;
+    }
+    if (sent == length)
+    {
+        if (this->keepAliveInterval > 0)
+            last_sent.countdown(this->keepAliveInterval); // record the fact that we have successfully sent the packet
+        rc = SUCCESS;
+    }
+    else
+        rc = FAILURE;
+
+#if defined(MQTT_DEBUG)
+    char printbuf[150];
+    DEBUG("Rc %d from sending packet %s\r\n", rc,
+        MQTTFormat_toServerString(printbuf, sizeof(printbuf), sendbuf, length));
+#endif
+    return rc;
+}
+
+
+template<class Network, class Timer, int a, int b>
+int MQTT::Client<Network, Timer, a, b>::decodePacket(int* value, int timeout)
+{
+    unsigned char c;
+    int multiplier = 1;
+    int len = 0;
+    const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4;
+
+    *value = 0;
+    do
+    {
+        int rc = MQTTPACKET_READ_ERROR;
+
+        if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
+        {
+            rc = MQTTPACKET_READ_ERROR; /* bad data */
+            goto exit;
+        }
+        rc = ipstack.read(&c, 1, timeout);
+        if (rc != 1)
+            goto exit;
+        *value += (c & 127) * multiplier;
+        multiplier *= 128;
+    } while ((c & 128) != 0);
+exit:
+    return len;
+}
+
+
+/**
+ * If any read fails in this method, then we should disconnect from the network, as on reconnect
+ * the packets can be retried.
+ * @param timeout the max time to wait for the packet read to complete, in milliseconds
+ * @return the MQTT packet type, 0 if none, -1 if error
+ */
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::readPacket(Timer& timer)
+{
+    int rc = FAILURE;
+    MQTTHeader header = {0};
+    int len = 0;
+    int rem_len = 0;
+
+    /* 1. read the header byte.  This has the packet type in it */
+    rc = ipstack.read(readbuf, 1, timer.left_ms());
+    if (rc != 1)
+    {
+        rc = 0; // timed out reading packet
+        goto exit;
+    }
+
+    len = 1;
+    /* 2. read the remaining length.  This is variable in itself */
+    decodePacket(&rem_len, timer.left_ms());
+    len += MQTTPacket_encode(readbuf + 1, rem_len); /* put the original remaining length into the buffer */
+
+    if (rem_len > (MAX_MQTT_PACKET_SIZE - len))
+    {
+        rc = BUFFER_OVERFLOW;
+        goto exit;
+    }
+
+    /* 3. read the rest of the buffer using a callback to supply the rest of the data */
+    if (rem_len > 0 && (ipstack.read(readbuf + len, rem_len, timer.left_ms()) != rem_len))
+    {
+        rc = FAILURE;
+        goto exit;
+    }
+
+    header.byte = readbuf[0];
+    rc = header.bits.type;
+    if (this->keepAliveInterval > 0)
+        last_received.countdown(this->keepAliveInterval); // record the fact that we have successfully received a packet
+exit:
+
+#if defined(MQTT_DEBUG)
+    if (rc >= 0)
+    {
+        char printbuf[50];
+        DEBUG("Rc %d receiving packet %s\r\n", rc,
+            MQTTFormat_toClientString(printbuf, sizeof(printbuf), readbuf, len));
+    }
+#endif
+    return rc;
+}
+
+
+// assume topic filter and name is in correct format
+// # can only be at end
+// + and # can only be next to separator
+template<class Network, class Timer, int a, int b>
+bool MQTT::Client<Network, Timer, a, b>::isTopicMatched(char* topicFilter, MQTTString& topicName)
+{
+    char* curf = topicFilter;
+    char* curn = topicName.lenstring.data;
+    char* curn_end = curn + topicName.lenstring.len;
+
+    while (*curf && curn < curn_end)
+    {
+        if (*curn == '/' && *curf != '/')
+            break;
+        if (*curf != '+' && *curf != '#' && *curf != *curn)
+            break;
+        if (*curf == '+')
+        {   // skip until we meet the next separator, or end of string
+            char* nextpos = curn + 1;
+            while (nextpos < curn_end && *nextpos != '/')
+                nextpos = ++curn + 1;
+        }
+        else if (*curf == '#')
+            curn = curn_end - 1;    // skip until end of string
+        curf++;
+        curn++;
+    };
+
+    if(*curf != '\0')
+    {
+        //If our topic filter ends with a wildcard '/#' we need to account for that
+        if(*curf == '/')
+        {
+            curf++;
+            if(*curf == '#')
+                curf++;
+        }
+    }
+
+    return (curn == curn_end) && (*curf == '\0');
+}
+
+
+
+template<class Network, class Timer, int a, int MAX_MESSAGE_HANDLERS>
+int MQTT::Client<Network, Timer, a, MAX_MESSAGE_HANDLERS>::deliverMessage(MQTTString& topicName, Message& message)
+{
+    int rc = FAILURE;
+
+    // we have to find the right message handler - indexed by topic
+    for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+    {
+        if (messageHandlers[i].topicFilter != 0 && (MQTTPacket_equals(&topicName, (char*)messageHandlers[i].topicFilter) ||
+                isTopicMatched((char*)messageHandlers[i].topicFilter, topicName)))
+        {
+            if (messageHandlers[i].fp.attached())
+            {
+                MessageData md(topicName, message);
+                messageHandlers[i].fp(md);
+                rc = SUCCESS;
+            }
+        }
+    }
+
+    if (rc == FAILURE && defaultMessageHandler.attached())
+    {
+        MessageData md(topicName, message);
+        defaultMessageHandler(md);
+        rc = SUCCESS;
+    }
+
+    return rc;
+}
+
+
+
+template<class Network, class Timer, int a, int b>
+int MQTT::Client<Network, Timer, a, b>::yield(unsigned long timeout_ms)
+{
+    int rc = SUCCESS;
+    Timer timer;
+
+    timer.countdown_ms(timeout_ms);
+    while (!timer.expired())
+    {
+        if (cycle(timer) < 0)
+        {
+            rc = FAILURE;
+            break;
+        }
+    }
+
+    return rc;
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::cycle(Timer& timer)
+{
+    // get one piece of work off the wire and one pass through
+    int len = 0,
+        rc = SUCCESS;
+
+    int packet_type = readPacket(timer);    // read the socket, see what work is due
+
+    switch (packet_type)
+    {
+        default:
+            // no more data to read, unrecoverable. Or read packet fails due to unexpected network error
+            rc = packet_type;
+            goto exit;
+        case 0: // timed out reading packet
+            break;
+        case CONNACK:
+        case PUBACK:
+        case SUBACK:
+        case UNSUBACK:
+            break;
+        case PUBLISH:
+        {
+            MQTTString topicName = MQTTString_initializer;
+            Message msg;
+            int intQoS;
+            msg.payloadlen = 0; /* this is a size_t, but deserialize publish sets this as int */
+            if (MQTTDeserialize_publish((unsigned char*)&msg.dup, &intQoS, (unsigned char*)&msg.retained, (unsigned short*)&msg.id, &topicName,
+                                 (unsigned char**)&msg.payload, (int*)&msg.payloadlen, readbuf, MAX_MQTT_PACKET_SIZE) != 1) {
+                rc = FAILURE;
+                goto exit;
+            }
+            msg.qos = (enum QoS)intQoS;
+#if MQTTCLIENT_QOS2
+            if (msg.qos != QOS2)
+#endif
+                deliverMessage(topicName, msg);
+#if MQTTCLIENT_QOS2
+            else if (isQoS2msgidFree(msg.id))
+            {
+                if (useQoS2msgid(msg.id))
+                    deliverMessage(topicName, msg);
+                else
+                    WARN("Maximum number of incoming QoS2 messages exceeded");
+            }
+#endif
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+            if (msg.qos != QOS0)
+            {
+                if (msg.qos == QOS1)
+                    len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE, PUBACK, 0, msg.id);
+                else if (msg.qos == QOS2)
+                    len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE, PUBREC, 0, msg.id);
+                if (len <= 0)
+                    rc = FAILURE;
+                else
+                    rc = sendPacket(len, timer);
+                if (rc == FAILURE)
+                    goto exit; // there was a problem
+            }
+            break;
+#endif
+        }
+#if MQTTCLIENT_QOS2
+        case PUBREC:
+        case PUBREL:
+            unsigned short mypacketid;
+            unsigned char dup, type;
+            if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, MAX_MQTT_PACKET_SIZE) != 1)
+                rc = FAILURE;
+            else if ((len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE,
+						         (packet_type == PUBREC) ? PUBREL : PUBCOMP, 0, mypacketid)) <= 0)
+                rc = FAILURE;
+            else if ((rc = sendPacket(len, timer)) != SUCCESS) // send the PUBREL packet
+                rc = FAILURE; // there was a problem
+            if (rc == FAILURE)
+                goto exit; // there was a problem
+            if (packet_type == PUBREL)
+                freeQoS2msgid(mypacketid);
+            break;
+
+        case PUBCOMP:
+            break;
+#endif
+        case PINGRESP:
+            ping_outstanding = false;
+            break;
+    }
+
+    if (keepalive() != SUCCESS)
+        //check only keepalive FAILURE status so that previous FAILURE status can be considered as FAULT
+        rc = FAILURE;
+
+exit:
+    if (rc == SUCCESS)
+        rc = packet_type;
+    else if (isconnected)
+        closeSession();
+    return rc;
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::keepalive()
+{
+    int rc = SUCCESS;
+    static Timer ping_sent;
+
+    if (keepAliveInterval == 0)
+        goto exit;
+
+    if (ping_outstanding)
+    {
+        if (ping_sent.expired())
+        {
+            rc = FAILURE; // session failure
+            #if defined(MQTT_DEBUG)
+                DEBUG("PINGRESP not received in keepalive interval\r\n");
+            #endif
+        }
+    }
+    else if (last_sent.expired() || last_received.expired())
+    {
+        Timer timer(1000);
+        int len = MQTTSerialize_pingreq(sendbuf, MAX_MQTT_PACKET_SIZE);
+        if (len > 0 && (rc = sendPacket(len, timer)) == SUCCESS) // send the ping packet
+        {
+            ping_outstanding = true;
+            ping_sent.countdown(this->keepAliveInterval);
+        }
+    }
+exit:
+    return rc;
+}
+
+
+// only used in single-threaded mode where one command at a time is in process
+template<class Network, class Timer, int a, int b>
+int MQTT::Client<Network, Timer, a, b>::waitfor(int packet_type, Timer& timer)
+{
+    int rc = FAILURE;
+
+    do
+    {
+        if (timer.expired())
+            break; // we timed out
+        rc = cycle(timer);
+    }
+    while (rc != packet_type && rc >= 0);
+
+    return rc;
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::connect(MQTTPacket_connectData& options, connackData& data)
+{
+    Timer connect_timer(command_timeout_ms);
+    int rc = FAILURE;
+    int len = 0;
+
+    if (isconnected) // don't send connect packet again if we are already connected
+        goto exit;
+
+    this->keepAliveInterval = options.keepAliveInterval;
+    this->cleansession = options.cleansession;
+    if ((len = MQTTSerialize_connect(sendbuf, MAX_MQTT_PACKET_SIZE, &options)) <= 0)
+        goto exit;
+    if ((rc = sendPacket(len, connect_timer)) != SUCCESS)  // send the connect packet
+        goto exit; // there was a problem
+
+    if (this->keepAliveInterval > 0)
+        last_received.countdown(this->keepAliveInterval);
+    // this will be a blocking call, wait for the connack
+    if (waitfor(CONNACK, connect_timer) == CONNACK)
+    {
+        data.rc = 0;
+        data.sessionPresent = false;
+        if (MQTTDeserialize_connack((unsigned char*)&data.sessionPresent,
+                            (unsigned char*)&data.rc, readbuf, MAX_MQTT_PACKET_SIZE) == 1)
+            rc = data.rc;
+        else
+            rc = FAILURE;
+    }
+    else
+        rc = FAILURE;
+
+#if MQTTCLIENT_QOS2
+    // resend any inflight publish
+    if (inflightMsgid > 0 && inflightQoS == QOS2 && pubrel)
+    {
+        if ((len = MQTTSerialize_ack(sendbuf, MAX_MQTT_PACKET_SIZE, PUBREL, 0, inflightMsgid)) <= 0)
+            rc = FAILURE;
+        else
+            rc = publish(len, connect_timer, inflightQoS);
+    }
+    else
+#endif
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+    if (inflightMsgid > 0)
+    {
+        memcpy(sendbuf, pubbuf, MAX_MQTT_PACKET_SIZE);
+        rc = publish(inflightLen, connect_timer, inflightQoS);
+    }
+#endif
+
+exit:
+    if (rc == SUCCESS)
+    {
+        isconnected = true;
+        ping_outstanding = false;
+    }
+    return rc;
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::connect(MQTTPacket_connectData& options)
+{
+    connackData data;
+    return connect(options, data);
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::connect()
+{
+    MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer;
+    return connect(default_options);
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int MAX_MESSAGE_HANDLERS>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, MAX_MESSAGE_HANDLERS>::setMessageHandler(const char* topicFilter, messageHandler messageHandler)
+{
+    int rc = FAILURE;
+    int i = -1;
+
+    // first check for an existing matching slot
+    for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+    {
+        if (messageHandlers[i].topicFilter != 0 && strcmp(messageHandlers[i].topicFilter, topicFilter) == 0)
+        {
+            if (messageHandler == 0) // remove existing
+            {
+                messageHandlers[i].topicFilter = 0;
+                messageHandlers[i].fp.detach();
+            }
+            rc = SUCCESS; // return i when adding new subscription
+            break;
+        }
+    }
+    // if no existing, look for empty slot (unless we are removing)
+    if (messageHandler != 0) {
+        if (rc == FAILURE)
+        {
+            for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+            {
+                if (messageHandlers[i].topicFilter == 0)
+                {
+                    rc = SUCCESS;
+                    break;
+                }
+            }
+        }
+        if (i < MAX_MESSAGE_HANDLERS)
+        {
+            messageHandlers[i].topicFilter = topicFilter;
+            messageHandlers[i].fp.attach(messageHandler);
+        }
+    }
+    return rc;
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int MAX_MESSAGE_HANDLERS>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, MAX_MESSAGE_HANDLERS>::subscribe(const char* topicFilter,
+     enum QoS qos, messageHandler messageHandler, subackData& data)
+{
+    int rc = FAILURE;
+    Timer timer(command_timeout_ms);
+    int len = 0;
+    MQTTString topic = {(char*)topicFilter, {0, 0}};
+
+    if (!isconnected)
+        goto exit;
+
+    len = MQTTSerialize_subscribe(sendbuf, MAX_MQTT_PACKET_SIZE, 0, packetid.getNext(), 1, &topic, (int*)&qos);
+    if (len <= 0)
+        goto exit;
+    if ((rc = sendPacket(len, timer)) != SUCCESS) // send the subscribe packet
+        goto exit;             // there was a problem
+
+    if (waitfor(SUBACK, timer) == SUBACK)      // wait for suback
+    {
+        int count = 0;
+        unsigned short mypacketid;
+        data.grantedQoS = 0;
+        if (MQTTDeserialize_suback(&mypacketid, 1, &count, &data.grantedQoS, readbuf, MAX_MQTT_PACKET_SIZE) == 1)
+        {
+            if (data.grantedQoS != 0x80)
+                rc = setMessageHandler(topicFilter, messageHandler);
+        }
+    }
+    else
+        rc = FAILURE;
+
+exit:
+    if (rc == FAILURE)
+        closeSession();
+    return rc;
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int MAX_MESSAGE_HANDLERS>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, MAX_MESSAGE_HANDLERS>::subscribe(const char* topicFilter, enum QoS qos, messageHandler messageHandler)
+{
+    subackData data;
+    return subscribe(topicFilter, qos, messageHandler, data);
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int MAX_MESSAGE_HANDLERS>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, MAX_MESSAGE_HANDLERS>::unsubscribe(const char* topicFilter)
+{
+    int rc = FAILURE;
+    Timer timer(command_timeout_ms);
+    MQTTString topic = {(char*)topicFilter, {0, 0}};
+    int len = 0;
+
+    if (!isconnected)
+        goto exit;
+
+    if ((len = MQTTSerialize_unsubscribe(sendbuf, MAX_MQTT_PACKET_SIZE, 0, packetid.getNext(), 1, &topic)) <= 0)
+        goto exit;
+    if ((rc = sendPacket(len, timer)) != SUCCESS) // send the unsubscribe packet
+        goto exit; // there was a problem
+
+    if (waitfor(UNSUBACK, timer) == UNSUBACK)
+    {
+        unsigned short mypacketid;  // should be the same as the packetid above
+        if (MQTTDeserialize_unsuback(&mypacketid, readbuf, MAX_MQTT_PACKET_SIZE) == 1)
+        {
+            // remove the subscription message handler associated with this topic, if there is one
+            setMessageHandler(topicFilter, 0);
+        }
+    }
+    else
+        rc = FAILURE;
+
+exit:
+    if (rc != SUCCESS)
+        closeSession();
+    return rc;
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::publish(int len, Timer& timer, enum QoS qos)
+{
+    int rc;
+
+    if ((rc = sendPacket(len, timer)) != SUCCESS) // send the publish packet
+        goto exit; // there was a problem
+
+#if MQTTCLIENT_QOS1
+    if (qos == QOS1)
+    {
+        if (waitfor(PUBACK, timer) == PUBACK)
+        {
+            unsigned short mypacketid;
+            unsigned char dup, type;
+            if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, MAX_MQTT_PACKET_SIZE) != 1)
+                rc = FAILURE;
+            else if (inflightMsgid == mypacketid)
+                inflightMsgid = 0;
+        }
+        else
+            rc = FAILURE;
+    }
+#endif
+#if MQTTCLIENT_QOS2
+    else if (qos == QOS2)
+    {
+        if (waitfor(PUBCOMP, timer) == PUBCOMP)
+        {
+            unsigned short mypacketid;
+            unsigned char dup, type;
+            if (MQTTDeserialize_ack(&type, &dup, &mypacketid, readbuf, MAX_MQTT_PACKET_SIZE) != 1)
+                rc = FAILURE;
+            else if (inflightMsgid == mypacketid)
+                inflightMsgid = 0;
+        }
+        else
+            rc = FAILURE;
+    }
+#endif
+
+exit:
+    if (rc != SUCCESS)
+        closeSession();
+    return rc;
+}
+
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::publish(const char* topicName, void* payload, size_t payloadlen, unsigned short& id, enum QoS qos, bool retained)
+{
+    int rc = FAILURE;
+    Timer timer(command_timeout_ms);
+    MQTTString topicString = MQTTString_initializer;
+    int len = 0;
+
+    if (!isconnected)
+        goto exit;
+
+    topicString.cstring = (char*)topicName;
+
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+    if (qos == QOS1 || qos == QOS2)
+        id = packetid.getNext();
+#endif
+
+    len = MQTTSerialize_publish(sendbuf, MAX_MQTT_PACKET_SIZE, 0, qos, retained, id,
+              topicString, (unsigned char*)payload, payloadlen);
+    if (len <= 0)
+        goto exit;
+
+#if MQTTCLIENT_QOS1 || MQTTCLIENT_QOS2
+    if (!cleansession)
+    {
+        memcpy(pubbuf, sendbuf, len);
+        inflightMsgid = id;
+        inflightLen = len;
+        inflightQoS = qos;
+#if MQTTCLIENT_QOS2
+        pubrel = false;
+#endif
+    }
+#endif
+
+    rc = publish(len, timer, qos);
+exit:
+    return rc;
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::publish(const char* topicName, void* payload, size_t payloadlen, enum QoS qos, bool retained)
+{
+    unsigned short id = 0;  // dummy - not used for anything
+    return publish(topicName, payload, payloadlen, id, qos, retained);
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::publish(const char* topicName, Message& message)
+{
+    return publish(topicName, message.payload, message.payloadlen, message.qos, message.retained);
+}
+
+
+template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE, int b>
+int MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::disconnect()
+{
+    int rc = FAILURE;
+    Timer timer(command_timeout_ms);     // we might wait for incomplete incoming publishes to complete
+    int len = MQTTSerialize_disconnect(sendbuf, MAX_MQTT_PACKET_SIZE);
+    if (len > 0)
+        rc = sendPacket(len, timer);            // send the disconnect packet
+    closeSession();
+    return rc;
+}
+
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/MQTTLogging.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/MQTTLogging.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#if !defined(MQTT_LOGGING_H)
+#define MQTT_LOGGING_H
+
+#define STREAM      stdout
+#if !defined(DEBUG)
+#define DEBUG(...)    \
+    {\
+    fprintf(STREAM, "DEBUG:   %s L#%d ", __PRETTY_FUNCTION__, __LINE__);  \
+    fprintf(STREAM, ##__VA_ARGS__); \
+    fflush(STREAM); \
+    }
+#endif
+#if !defined(LOG)
+#define LOG(...)    \
+    {\
+    fprintf(STREAM, "LOG:   %s L#%d ", __PRETTY_FUNCTION__, __LINE__);  \
+    fprintf(STREAM, ##__VA_ARGS__); \
+    fflush(STREAM); \
+    }
+#endif
+#if !defined(WARN)
+#define WARN(...)   \
+    { \
+    fprintf(STREAM, "WARN:  %s L#%d ", __PRETTY_FUNCTION__, __LINE__);  \
+    fprintf(STREAM, ##__VA_ARGS__); \
+    fflush(STREAM); \
+    }
+#endif 
+#if !defined(ERROR)
+#define ERROR(...)  \
+    { \
+    fprintf(STREAM, "ERROR: %s L#%d ", __PRETTY_FUNCTION__, __LINE__); \
+    fprintf(STREAM, ##__VA_ARGS__); \
+    fflush(STREAM); \
+    exit(1); \
+    }
+#endif
+
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/arduino/Countdown.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/arduino/Countdown.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#if !defined(COUNTDOWN_H)
+#define COUNTDOWN_H
+
+class Countdown
+{
+public:
+    Countdown()
+    {  
+		interval_end_ms = 0L;
+    }
+    
+    Countdown(int ms)
+    {
+        countdown_ms(ms);   
+    }
+    
+    bool expired()
+    {
+        return (interval_end_ms > 0L) && (millis() >= interval_end_ms);
+    }
+    
+    void countdown_ms(unsigned long ms)  
+    {
+        interval_end_ms = millis() + ms;
+    }
+    
+    void countdown(int seconds)
+    {
+        countdown_ms((unsigned long)seconds * 1000L);
+    }
+    
+    int left_ms()
+    {
+        return interval_end_ms - millis();
+    }
+    
+private:
+    unsigned long interval_end_ms; 
+};
+
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/arduino/IPStack.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/arduino/IPStack.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2017 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Benjamin Cabe - generic IPStack
+ *******************************************************************************/
+
+#if !defined(IPSTACK_H)
+#define IPSTACK_H
+
+#ifndef WiFi_h
+  #include <SPI.h>
+#endif
+
+#include <Client.h>
+
+class IPStack
+{
+public:
+    IPStack(Client& client) : client(&client)
+    {
+
+    }
+
+    int connect(char* hostname, int port)
+    {
+        return client->connect(hostname, port);
+    }
+
+    int connect(uint32_t hostname, int port)
+    {
+        return client->connect(hostname, port);
+    }
+
+    int read(unsigned char* buffer, int len, int timeout)
+    {
+        int interval = 10;  // all times are in milliseconds
+		int total = 0, rc = -1;
+
+		if (timeout < 30)
+			interval = 2;
+		while (client->available() < len && total < timeout)
+		{
+			delay(interval);
+			total += interval;
+		}
+		if (client->available() >= len)
+			rc = client->readBytes((char*)buffer, len);
+		return rc;
+    }
+
+    int write(unsigned char* buffer, int len, int timeout)
+    {
+        client->setTimeout(timeout);
+		return client->write((uint8_t*)buffer, len);
+    }
+
+    int disconnect()
+    {
+        client->stop();
+        return 0;
+    }
+
+private:
+
+    Client* client;
+};
+
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/arduino/WifiIPStack.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/arduino/WifiIPStack.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#ifndef ARDUINOWIFIIPSTACK_H
+#define ARDUINOWIFIIPSTACK_H
+
+#include <WiFi.h>
+
+class WifiIPStack 
+{
+public:    
+    WifiIPStack()
+    {
+        //WiFi.begin();              // Use DHCP
+        iface.setTimeout(1000);    // 1 second Timeout 
+    }
+    
+    int connect(char* hostname, int port)
+    {
+        return iface.connect(hostname, port);
+    }
+
+    int connect(uint32_t hostname, int port)
+    {
+        return iface.connect(hostname, port);
+    }
+
+    int read(char* buffer, int len, int timeout)
+    {
+        iface.setTimeout(timeout);
+        while(!iface.available());
+        return iface.readBytes(buffer, len);
+    }
+    
+    int write(char* buffer, int len, int timeout)
+    {
+        iface.setTimeout(timeout);  
+        return iface.write((uint8_t*)buffer, len);
+    }
+    
+    int disconnect()
+    {
+        iface.stop();
+        return 0;
+    }
+    
+private:
+
+    WiFiClient iface;
+    
+};
+
+#endif
+
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/linux/linux.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/linux/linux.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2017 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Ian Craggs - ensure read returns if no bytes read
+ *******************************************************************************/
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+
+class IPStack
+{
+public:
+  IPStack()
+  {
+
+  }
+
+  int connect(const char* hostname, int port)
+  {
+		int type = SOCK_STREAM;
+		struct sockaddr_in address;
+		int rc = -1;
+		sa_family_t family = AF_INET;
+		struct addrinfo *result = NULL;
+		struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL};
+
+		if ((rc = getaddrinfo(hostname, NULL, &hints, &result)) == 0)
+		{
+			struct addrinfo* res = result;
+
+			/* prefer ip4 addresses */
+			while (res)
+			{
+				if (res->ai_family == AF_INET)
+				{
+					result = res;
+					break;
+				}
+				res = res->ai_next;
+			}
+
+			if (result->ai_family == AF_INET)
+			{
+				address.sin_port = htons(port);
+				address.sin_family = family = AF_INET;
+				address.sin_addr = ((struct sockaddr_in*)(result->ai_addr))->sin_addr;
+			}
+			else
+				rc = -1;
+
+			freeaddrinfo(result);
+		}
+
+		if (rc == 0)
+		{
+			mysock = socket(family, type, 0);
+			if (mysock != -1)
+			{
+				int opt = 1;
+
+				//if (setsockopt(mysock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&opt, sizeof(opt)) != 0)
+				//	printf("Could not set SO_NOSIGPIPE for socket %d", mysock);
+
+				rc = ::connect(mysock, (struct sockaddr*)&address, sizeof(address));
+			}
+		}
+
+        return rc;
+    }
+
+  // return -1 on error, or the number of bytes read
+  // which could be 0 on a read timeout
+  int read(unsigned char* buffer, int len, int timeout_ms)
+  {
+		struct timeval interval = {timeout_ms / 1000, (timeout_ms % 1000) * 1000};
+		if (interval.tv_sec < 0 || (interval.tv_sec == 0 && interval.tv_usec <= 0))
+		{
+			interval.tv_sec = 0;
+			interval.tv_usec = 100;
+		}
+
+		setsockopt(mysock, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval, sizeof(struct timeval));
+
+		int bytes = 0;
+    int i = 0; const int max_tries = 10;
+		while (bytes < len)
+		{
+			int rc = ::recv(mysock, &buffer[bytes], (size_t)(len - bytes), 0);
+			if (rc == -1)
+			{
+        if (errno != EAGAIN && errno != EWOULDBLOCK)
+          bytes = -1;
+        break;
+			}
+			else
+				bytes += rc;
+      if (++i >= max_tries)
+        break;
+      if (rc == 0)
+        break;
+		}
+		return bytes;
+  }
+
+  int write(unsigned char* buffer, int len, int timeout)
+  {
+		struct timeval tv;
+
+		tv.tv_sec = 0;  /* 30 Secs Timeout */
+		tv.tv_usec = timeout * 1000;  // Not init'ing this can cause strange errors
+
+		setsockopt(mysock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv,sizeof(struct timeval));
+		int	rc = ::write(mysock, buffer, len);
+		//printf("write rc %d\n", rc);
+		return rc;
+  }
+
+	int disconnect()
+	{
+		return ::close(mysock);
+	}
+
+private:
+
+    int mysock;
+};
+
+
+class Countdown
+{
+public:
+  Countdown()
+  {
+
+  }
+
+  Countdown(int ms)
+  {
+		countdown_ms(ms);
+  }
+
+
+  bool expired()
+  {
+		struct timeval now, res;
+		gettimeofday(&now, NULL);
+		timersub(&end_time, &now, &res);
+		//printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000);
+		//if (res.tv_sec > 0 || res.tv_usec > 0)
+		//	printf("expired %d %d\n", res.tv_sec, res.tv_usec);
+        return res.tv_sec < 0 || (res.tv_sec == 0 && res.tv_usec <= 0);
+  }
+
+
+  void countdown_ms(int ms)
+  {
+		struct timeval now;
+		gettimeofday(&now, NULL);
+		struct timeval interval = {ms / 1000, (ms % 1000) * 1000};
+		//printf("interval %d %d\n", interval.tv_sec, interval.tv_usec);
+		timeradd(&now, &interval, &end_time);
+  }
+
+
+  void countdown(int seconds)
+  {
+		struct timeval now;
+		gettimeofday(&now, NULL);
+		struct timeval interval = {seconds, 0};
+		timeradd(&now, &interval, &end_time);
+  }
+
+
+  int left_ms()
+  {
+		struct timeval now, res;
+		gettimeofday(&now, NULL);
+		timersub(&end_time, &now, &res);
+		//printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000);
+        return (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000;
+  }
+
+private:
+
+	struct timeval end_time;
+};
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/mbed/MQTTEthernet.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/mbed/MQTTEthernet.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,29 @@
+
+#if !defined(MQTTETHERNET_H)
+#define MQTTETHERNET_H
+
+#include "MQTTmbed.h"
+#include "EthernetInterface.h"
+#include "MQTTSocket.h"
+
+class MQTTEthernet : public MQTTSocket
+{
+public:    
+    MQTTEthernet() : MQTTSocket(&eth)
+    {
+        eth.connect();
+    }
+    
+    EthernetInterface& getEth()
+    {
+        return eth;
+    }
+    
+private:
+
+    EthernetInterface eth;
+    
+};
+
+
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/mbed/MQTTSocket.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/mbed/MQTTSocket.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,97 @@
+#if !defined(MQTTSOCKET_H)
+#define MQTTSOCKET_H
+
+#include "MQTTmbed.h"
+#include <EthernetInterface.h>
+#include <Timer.h>
+
+class MQTTSocket
+{
+public:
+    MQTTSocket(EthernetInterface *anet)
+    {
+        net = anet;
+        open = false;
+    }
+    
+    int connect(char* hostname, int port, int timeout=1000)
+    {
+        if (open)
+            disconnect();
+        nsapi_error_t rc = mysock.open(net);
+        open = true;
+        mysock.set_blocking(true);
+        mysock.set_timeout((unsigned int)timeout);  
+        rc = mysock.connect(hostname, port);
+        mysock.set_blocking(false);  // blocking timeouts seem not to work
+        return rc;
+    }
+
+    // common read/write routine, avoiding blocking timeouts
+    int common(unsigned char* buffer, int len, int timeout, bool read)
+    {
+        timer.start();
+        mysock.set_blocking(false); // blocking timeouts seem not to work
+        int bytes = 0;
+        bool first = true;
+        do 
+        {
+            if (first)
+                first = false;
+            else
+                wait_ms(timeout < 100 ? timeout : 100);
+            int rc;
+            if (read)
+                rc = mysock.recv((char*)buffer, len);
+            else
+                rc = mysock.send((char*)buffer, len);
+            if (rc < 0)
+            {
+                if (rc != NSAPI_ERROR_WOULD_BLOCK)
+                {
+                    bytes = -1;
+                    break;
+                }
+            } 
+            else
+                bytes += rc;
+        }
+        while (bytes < len && timer.read_ms() < timeout);
+        timer.stop();
+        return bytes;
+    }
+
+    /* returns the number of bytes read, which could be 0.
+       -1 if there was an error on the socket
+    */
+    int read(unsigned char* buffer, int len, int timeout)
+    {
+        return common(buffer, len, timeout, true);
+    }
+
+    int write(unsigned char* buffer, int len, int timeout)
+    {
+        return common(buffer, len, timeout, false);
+    }
+
+    int disconnect()
+    {
+        open = false;
+        return mysock.close();
+    }
+
+    /*bool is_connected()
+    {
+        return mysock.is_connected();
+    }*/
+
+private:
+
+    bool open;
+    TCPSocket mysock;
+    EthernetInterface *net;
+    Timer timer;
+
+};
+
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/mbed/MQTTmbed.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/src/mbed/MQTTmbed.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2017 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Ian Craggs - change Timer member initialization to avoid copy constructor
+ *******************************************************************************/
+
+#if !defined(MQTT_MBED_H)
+#define MQTT_MBED_H
+
+#include "mbed.h"
+
+class Countdown
+{
+public:
+    Countdown() : t()
+    {
+
+    }
+
+    Countdown(int ms) : t()
+    {
+        countdown_ms(ms);
+    }
+
+
+    bool expired()
+    {
+        return t.read_ms() >= interval_end_ms;
+    }
+
+    void countdown_ms(unsigned long ms)
+    {
+        t.stop();
+        interval_end_ms = ms;
+        t.reset();
+        t.start();
+    }
+
+    void countdown(int seconds)
+    {
+        countdown_ms((unsigned long)seconds * 1000L);
+    }
+
+    int left_ms()
+    {
+        return interval_end_ms - t.read_ms();
+    }
+
+private:
+    Timer t;
+    unsigned long interval_end_ms;
+};
+
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/test/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/test/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,20 @@
+PROJECT(mqttcpp-tests)
+
+SET(MQTT_TEST_BROKER_HOST "localhost" CACHE STRING "Hostname of a test MQTT broker to use")
+SET(MQTT_TEST_PROXY_PORT "1884" CACHE STRING "Port of the test proxy to use")
+SET(MQTT_SSL_HOSTNAME "localhost" CACHE STRING "Hostname of a test SSL MQTT broker to use")
+SET(CERTDIR $ENV{TRAVIS_BUILD_DIR}/test/ssl)
+
+ADD_EXECUTABLE(
+	testcpp1
+	test1.cpp
+)
+
+target_compile_definitions(testcpp1 PRIVATE MQTTCLIENT_QOS1=1 MQTTCLIENT_QOS2=1)
+target_include_directories(testcpp1 PRIVATE "../src" "../src/linux")
+target_link_libraries(testcpp1 MQTTPacketClient  MQTTPacketServer)
+
+ADD_TEST(
+	NAME testcpp1
+	COMMAND "testcpp1" "--host" ${MQTT_TEST_BROKER_HOST}
+)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/test/test1.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTClient/test/test1.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,943 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2017 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial implementation for embedded C client
+ *******************************************************************************/
+
+
+/**
+ * @file
+ * Tests for the Paho embedded C "high" level client
+ */
+
+ #include <stdio.h>
+ #include <string.h>
+ #include <memory.h>
+ //#define MQTT_DEBUG
+ #include "MQTTClient.h"
+
+ #define DEFAULT_STACK_SIZE -1
+
+ #include "linux.cpp"
+
+ #include <sys/time.h>
+ #include <stdlib.h>
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+void usage(void)
+{
+	printf("help!!\n");
+	exit(EXIT_FAILURE);
+}
+
+struct Options
+{
+	char* host;         /**< connection to system under test. */
+  int port;
+	char* proxy_host;
+  int proxy_port;
+	int verbose;
+	int test_no;
+	int MQTTVersion;
+	int iterations;
+} options =
+{
+	(char*)"localhost",
+  1883,
+	(char*)"localhost",
+  1885,
+	0,
+	0,
+	4,
+	1,
+};
+
+void getopts(int argc, char** argv)
+{
+	int count = 1;
+
+	while (count < argc)
+	{
+		if (strcmp(argv[count], "--test_no") == 0)
+		{
+			if (++count < argc)
+				options.test_no = atoi(argv[count]);
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--host") == 0)
+		{
+			if (++count < argc)
+			{
+				options.host = argv[count];
+				printf("\nSetting host to %s\n", options.host);
+			}
+			else
+				usage();
+		}
+    else if (strcmp(argv[count], "--port") == 0)
+    {
+      if (++count < argc)
+      {
+        options.port = atoi(argv[count]);
+        printf("\nSetting port to %d\n", options.port);
+      }
+      else
+        usage();
+    }
+		else if (strcmp(argv[count], "--proxy_host") == 0)
+		{
+			if (++count < argc)
+				options.proxy_host = argv[count];
+			else
+				usage();
+		}
+    else if (strcmp(argv[count], "--proxy_port") == 0)
+    {
+      if (++count < argc)
+      {
+        options.proxy_port = atoi(argv[count]);
+        printf("\nSetting proxy port to %d\n", options.proxy_port);
+      }
+      else
+        usage();
+    }
+		else if (strcmp(argv[count], "--MQTTversion") == 0)
+		{
+			if (++count < argc)
+			{
+				options.MQTTVersion = atoi(argv[count]);
+				printf("setting MQTT version to %d\n", options.MQTTVersion);
+			}
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--iterations") == 0)
+		{
+			if (++count < argc)
+				options.iterations = atoi(argv[count]);
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--verbose") == 0)
+		{
+			options.verbose = 1;
+			printf("\nSetting verbose on\n");
+		}
+		count++;
+	}
+}
+
+
+#define LOGA_DEBUG 0
+#define LOGA_INFO 1
+#include <stdarg.h>
+#include <time.h>
+#include <sys/timeb.h>
+void MyLog(int LOGA_level, const char* format, ...)
+{
+	static char msg_buf[256];
+	va_list args;
+	struct timeb ts;
+
+	struct tm *timeinfo;
+
+	if (LOGA_level == LOGA_DEBUG && options.verbose == 0)
+	  return;
+
+	ftime(&ts);
+	timeinfo = localtime(&ts.time);
+	strftime(msg_buf, 80, "%Y%m%d %H%M%S", timeinfo);
+
+	sprintf(&msg_buf[strlen(msg_buf)], ".%.3hu ", ts.millitm);
+
+	va_start(args, format);
+	vsnprintf(&msg_buf[strlen(msg_buf)], sizeof(msg_buf) - strlen(msg_buf), format, args);
+	va_end(args);
+
+	printf("%s\n", msg_buf);
+	fflush(stdout);
+}
+
+
+#if defined(WIN32) || defined(_WINDOWS)
+#define mqsleep(A) Sleep(1000*A)
+#define START_TIME_TYPE DWORD
+static DWORD start_time = 0;
+START_TIME_TYPE start_clock(void)
+{
+	return GetTickCount();
+}
+#elif defined(AIX)
+#define mqsleep sleep
+#define START_TIME_TYPE struct timespec
+START_TIME_TYPE start_clock(void)
+{
+	static struct timespec start;
+	clock_gettime(CLOCK_REALTIME, &start);
+	return start;
+}
+#else
+#define mqsleep sleep
+#define START_TIME_TYPE struct timeval
+/* TODO - unused - remove? static struct timeval start_time; */
+START_TIME_TYPE start_clock(void)
+{
+	struct timeval start_time;
+	gettimeofday(&start_time, NULL);
+	return start_time;
+}
+#endif
+
+
+#if defined(WIN32)
+long elapsed(START_TIME_TYPE start_time)
+{
+	return GetTickCount() - start_time;
+}
+#elif defined(AIX)
+#define assert(a)
+long elapsed(struct timespec start)
+{
+	struct timespec now, res;
+
+	clock_gettime(CLOCK_REALTIME, &now);
+	ntimersub(now, start, res);
+	return (res.tv_sec)*1000L + (res.tv_nsec)/1000000L;
+}
+#else
+long elapsed(START_TIME_TYPE start_time)
+{
+	struct timeval now, res;
+
+	gettimeofday(&now, NULL);
+	timersub(&now, &start_time, &res);
+	return (res.tv_sec)*1000 + (res.tv_usec)/1000;
+}
+#endif
+
+
+#define assert(a, b, c, d) myassert(__FILE__, __LINE__, a, b, c, d)
+#define assert1(a, b, c, d, e) myassert(__FILE__, __LINE__, a, b, c, d, e)
+
+int tests = 0;
+int failures = 0;
+FILE* xml;
+START_TIME_TYPE global_start_time;
+char output[3000];
+char* cur_output = output;
+
+
+void write_test_result(void)
+{
+	long duration = elapsed(global_start_time);
+
+	fprintf(xml, " time=\"%ld.%.3ld\" >\n", duration / 1000, duration % 1000);
+	if (cur_output != output)
+	{
+		fprintf(xml, "%s", output);
+		cur_output = output;
+	}
+	fprintf(xml, "</testcase>\n");
+}
+
+
+void myassert(const char* filename, int lineno, const char* description, int value, const char* format, ...)
+{
+	++tests;
+	if (!value)
+	{
+		va_list args;
+
+		++failures;
+		MyLog(LOGA_INFO, (char*)"Assertion failed, file %s, line %d, description: %s\n", filename, lineno, description);
+
+		va_start(args, format);
+		vprintf(format, args);
+		va_end(args);
+
+		cur_output += sprintf(cur_output, "<failure type=\"%s\">file %s, line %d </failure>\n",
+                        description, filename, lineno);
+	}
+	else
+		MyLog(LOGA_DEBUG, "Assertion succeeded, file %s, line %d, description: %s", filename, lineno, description);
+}
+
+
+static volatile MQTT::MessageData* test1_message_data = NULL;
+static MQTT::Message pubmsg;
+
+void messageArrived(MQTT::MessageData& md)
+{
+    test1_message_data = &md;
+	  MQTT::Message &m = md.message;
+
+    assert("Good message lengths", pubmsg.payloadlen == m.payloadlen,
+         "payloadlen was %d", m.payloadlen);
+
+    if (pubmsg.payloadlen == m.payloadlen)
+        assert("Good message contents", memcmp(m.payload, pubmsg.payload, m.payloadlen) == 0,
+          "payload was %s", m.payload);
+}
+
+
+/*********************************************************************
+
+Test1: single-threaded client
+
+*********************************************************************/
+void test1_sendAndReceive(MQTT::Client<IPStack, Countdown, 1000>& client, int qos, const char* test_topic)
+{
+	char* topicName = NULL;
+	int topicLen;
+	int i = 0;
+	int iterations = 50;
+	int rc;
+  int wait_seconds;
+
+	MyLog(LOGA_DEBUG, "%d messages at QoS %d", iterations, qos);
+  memset(&pubmsg, '\0', sizeof(pubmsg));
+	pubmsg.payload = (void*)"a much longer message that we can shorten to the extent that we need to payload up to 11";
+	pubmsg.payloadlen = 11;
+	pubmsg.qos = (MQTT::QoS)qos;
+	pubmsg.retained = false;
+  pubmsg.dup = false;
+
+	for (i = 0; i < iterations; ++i)
+	{
+    test1_message_data = NULL;
+		rc = client.publish(test_topic, pubmsg);
+		assert("Good rc from publish", rc == MQTT::SUCCESS, "rc was %d", rc);
+
+    /* wait for the message to be received */
+    wait_seconds = 10;
+		while ((test1_message_data == NULL) && (wait_seconds-- > 0))
+		{
+      client.yield(100);
+		}
+		assert("Message Arrived", wait_seconds > 0, "Time out waiting for message %d\n", i);
+
+		if (!test1_message_data)
+			printf("No message received within timeout period\n");
+	}
+
+	/* wait to receive any outstanding messages */
+  wait_seconds = 2;
+  while (wait_seconds-- > 0)
+  {
+      client.yield(1000);
+  }
+}
+
+
+int test1(struct Options options)
+{
+	MQTT::QoS subsqos = MQTT::QOS2;
+	int rc = 0;
+	const char* test_topic = "C client test1";
+
+	fprintf(xml, "<testcase classname=\"test1\" name=\"single threaded client using receive\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 1 - single threaded client using receive");
+
+  IPStack ipstack = IPStack();
+	MQTT::Client<IPStack, Countdown, 1000> client = MQTT::Client<IPStack, Countdown, 1000>(ipstack);
+
+  MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+  data.willFlag = 1;
+  data.MQTTVersion = options.MQTTVersion;
+  data.clientID.cstring = (char*)"single-threaded-test";
+  data.username.cstring = (char*)"testuser";
+  data.password.cstring = (char*)"testpassword";
+
+  data.keepAliveInterval = 20;
+  data.cleansession = 1;
+
+	data.will.message.cstring = (char*)"will message";
+	data.will.qos = 1;
+	data.will.retained = 0;
+	data.will.topicName.cstring = (char*)"will topic";
+
+	MyLog(LOGA_DEBUG, "Connecting");
+  rc = ipstack.connect(options.host, options.port);
+  assert("Good rc from TCP connect", rc == MQTT::SUCCESS, "rc was %d", rc);
+  if (rc != MQTT::SUCCESS)
+    goto exit;
+
+  rc = client.connect(data);
+	assert("Good rc from connect", rc == MQTT::SUCCESS, "rc was %d", rc);
+	if (rc != MQTT::SUCCESS)
+		goto exit;
+
+	rc = client.subscribe(test_topic, subsqos, messageArrived);
+	assert("Good rc from subscribe", rc == MQTT::SUCCESS, "rc was %d", rc);
+
+	test1_sendAndReceive(client, 0, test_topic);
+	test1_sendAndReceive(client, 1, test_topic);
+	test1_sendAndReceive(client, 2, test_topic);
+
+	MyLog(LOGA_DEBUG, "Stopping\n");
+
+	rc = client.unsubscribe(test_topic);
+	assert("Unsubscribe successful", rc == MQTT::SUCCESS, "rc was %d", rc);
+	rc = client.disconnect();
+	assert("Disconnect successful", rc == MQTT::SUCCESS, "rc was %d", rc);
+  ipstack.disconnect();
+
+	/* Just to make sure we can connect again */
+  rc = ipstack.connect(options.host, options.port);
+  assert("TCP connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+  rc = client.connect(data);
+	assert("Connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+	rc = client.disconnect();
+	assert("Disconnect successful", rc == MQTT::SUCCESS, "rc was %d", rc);
+  ipstack.disconnect();
+
+exit:
+	MyLog(LOGA_INFO, "TEST1: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+/*********************************************************************
+
+Test 2: connack return data
+
+*********************************************************************/
+int test2(struct Options options)
+{
+  MQTT::QoS subsqos = MQTT::QOS2;
+	int rc;
+  const char* test_topic = "C client test2";
+
+  fprintf(xml, "<testcase classname=\"test2\" name=\"connack return data\"");
+  global_start_time = start_clock();
+  failures = 0;
+  MyLog(LOGA_INFO, "Starting test 2 - connack return data");
+
+  IPStack ipstack = IPStack();
+  MQTT::Client<IPStack, Countdown, 1000> client = MQTT::Client<IPStack, Countdown, 1000>(ipstack);
+
+  MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+  data.willFlag = 1;
+  data.MQTTVersion = options.MQTTVersion;
+  data.clientID.cstring = (char*)"connack-return-data";
+  data.username.cstring = (char*)"testuser";
+  data.password.cstring = (char*)"testpassword";
+
+  data.keepAliveInterval = 20;
+  data.cleansession = 1;
+
+  data.will.message.cstring = (char*)"will message";
+  data.will.qos = 1;
+  data.will.retained = 0;
+  data.will.topicName.cstring = (char*)"will topic";
+
+  MyLog(LOGA_DEBUG, "Connecting");
+  rc = ipstack.connect(options.host, options.port);
+  assert("Good rc from TCP connect", rc == MQTT::SUCCESS, "rc was %d", rc);
+  if (rc != MQTT::SUCCESS)
+    goto exit;
+
+  MQTT::connackData connack;
+  rc = client.connect(data, connack);
+  assert("Good rc from connect", rc == MQTT::SUCCESS, "rc was %d", rc);
+  if (rc != MQTT::SUCCESS)
+    goto exit;
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 0", connack.sessionPresent == 0,
+         "sessionPresent was %d", connack.sessionPresent);
+
+  rc = client.disconnect();
+  assert("Disconnect successful", rc == MQTT::SUCCESS, "rc was %d", rc);
+  ipstack.disconnect();
+
+  /* reconnect with cleansession false */
+  data.cleansession = 0;
+  rc = ipstack.connect(options.host, options.port);
+  assert("TCP connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+  rc = client.connect(data, connack);
+  assert("Connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 0", connack.sessionPresent == 0,
+           "sessionPresent was %d", connack.sessionPresent);
+
+  MQTT::subackData suback;
+  rc = client.subscribe(test_topic, subsqos, messageArrived, suback);
+  assert("Good rc from subscribe", rc == MQTT::SUCCESS, "rc was %d", rc);
+  assert("Granted QoS rc from subscribe", suback.grantedQoS == MQTT::QOS2,
+         "rc was %d", suback.grantedQoS);
+
+  rc = client.disconnect();
+  assert("Disconnect successful", rc == MQTT::SUCCESS, "rc was %d", rc);
+  ipstack.disconnect();
+
+  /* reconnect with cleansession false */
+  data.cleansession = 0;
+  rc = ipstack.connect(options.host, options.port);
+  assert("TCP connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+  rc = client.connect(data, connack);
+  assert("Connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 1", connack.sessionPresent == 1,
+           "sessionPresent was %d", connack.sessionPresent);
+
+  rc = client.disconnect();
+  assert("Disconnect successful", rc == MQTT::SUCCESS, "rc was %d", rc);
+  ipstack.disconnect();
+
+  /* reconnect with cleansession true */
+  data.cleansession = 1;
+  rc = ipstack.connect(options.host, options.port);
+  assert("TCP connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+  rc = client.connect(data, connack);
+  assert("Connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 0", connack.sessionPresent == 0,
+           "sessionPresent was %d", connack.sessionPresent);
+
+  rc = client.disconnect();
+  assert("Disconnect successful", rc == MQTT::SUCCESS, "rc was %d", rc);
+  ipstack.disconnect();
+
+exit:
+  MyLog(LOGA_INFO, "TEST2: test %s. %d tests run, %d failures.",
+      (failures == 0) ? "passed" : "failed", tests, failures);
+  write_test_result();
+  return failures;
+}
+
+
+/*********************************************************************
+
+Test 3: client session state
+
+*********************************************************************/
+static volatile MQTT::MessageData* test2_message_data = NULL;
+
+void messageArrived2(MQTT::MessageData& md)
+{
+    test2_message_data = &md;
+	  MQTT::Message &m = md.message;
+
+    assert("Good message lengths", pubmsg.payloadlen == m.payloadlen,
+         "payloadlen was %d", m.payloadlen);
+
+    if (pubmsg.payloadlen == m.payloadlen)
+        assert("Good message contents", memcmp(m.payload, pubmsg.payload, m.payloadlen) == 0,
+          "payload was %s", m.payload);
+}
+
+
+int check_subs_exist(MQTT::Client<IPStack, Countdown, 1000>& client, const char* test_topic, int which)
+{
+    int rc = MQTT::FAILURE;
+    int wait_seconds = 0;
+
+    memset(&pubmsg, '\0', sizeof(pubmsg));
+    pubmsg.payload = (void*)"a much longer message that we can shorten to the extent that we need to payload up to 11";
+    pubmsg.payloadlen = 11;
+    pubmsg.qos = MQTT::QOS2;
+    pubmsg.retained = false;
+    pubmsg.dup = false;
+
+    test1_message_data = test2_message_data = NULL;
+    rc = client.publish(test_topic, pubmsg);
+    assert("Good rc from publish", rc == MQTT::SUCCESS, "rc was %d", rc);
+
+    /* wait for the message to be received */
+    wait_seconds = 10;
+    while (wait_seconds-- > 0)
+    {
+        client.yield(100);
+    }
+
+    rc = (((which == 1 || which == 3) && test1_message_data) ||
+         (which == 2 && test1_message_data == NULL)) ? MQTT::SUCCESS : MQTT::FAILURE;
+    assert("test1 subscription", rc == MQTT::SUCCESS, "test1_message_data %p\n",
+            test1_message_data);
+    rc = (((which == 2 || which == 3) && test2_message_data) ||
+         (which == 1 && test2_message_data == NULL)) ? MQTT::SUCCESS : MQTT::FAILURE;
+    assert("test2 subscription", rc == MQTT::SUCCESS, "test2_message_data %p\n",
+             test2_message_data);
+    return rc;
+}
+
+
+int test3(struct Options options)
+{
+  MQTT::QoS subsqos = MQTT::QOS2;
+	int rc;
+  const char* test_topic = "C client test3";
+  int wait_seconds = 0;
+
+  fprintf(xml, "<testcase classname=\"test3\" name=\"session state\"");
+  global_start_time = start_clock();
+  failures = 0;
+  MyLog(LOGA_INFO, "Starting test 3 - session state");
+
+  IPStack ipstack = IPStack();
+  MQTT::Client<IPStack, Countdown, 1000> client = MQTT::Client<IPStack, Countdown, 1000>(ipstack);
+
+  MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+  data.willFlag = 1;
+  data.MQTTVersion = options.MQTTVersion;
+  data.clientID.cstring = (char*)"connack-return-data";
+  data.username.cstring = (char*)"testuser";
+  data.password.cstring = (char*)"testpassword";
+
+  data.keepAliveInterval = 10;
+  data.cleansession = 1;
+
+  data.will.message.cstring = (char*)"will message";
+  data.will.qos = 1;
+  data.will.retained = 0;
+  data.will.topicName.cstring = (char*)"will topic";
+
+  assert("Good rc in connack", client.isConnected() == false,
+         "isconnected was %d", client.isConnected());
+
+  MyLog(LOGA_DEBUG, "Connecting");
+  rc = ipstack.connect(options.host, options.port);
+  assert("Good rc from TCP connect", rc == MQTT::SUCCESS, "rc was %d", rc);
+  if (rc != MQTT::SUCCESS)
+    goto exit;
+
+  MQTT::connackData connack;
+  rc = client.connect(data, connack);
+  assert("Good rc from connect", rc == MQTT::SUCCESS, "rc was %d", rc);
+  if (rc != MQTT::SUCCESS)
+    goto exit;
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 0", connack.sessionPresent == 0,
+         "sessionPresent was %d", connack.sessionPresent);
+
+  assert("Good rc in connack", client.isConnected() == true,
+                "isconnected was %d", client.isConnected());
+
+  rc = client.disconnect();
+  assert("Disconnect successful", rc == MQTT::SUCCESS, "rc was %d", rc);
+  ipstack.disconnect();
+
+  /* reconnect with cleansession false */
+  data.cleansession = 0;
+  rc = ipstack.connect(options.proxy_host, options.proxy_port);
+  assert("TCP connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+  rc = client.connect(data, connack);
+  assert("Connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 0", connack.sessionPresent == 0,
+           "sessionPresent was %d", connack.sessionPresent);
+
+  MQTT::subackData suback;
+  rc = client.subscribe(test_topic, subsqos, messageArrived, suback);
+  assert("Good rc from subscribe", rc == MQTT::SUCCESS, "rc was %d", rc);
+  assert("Granted QoS rc from subscribe", suback.grantedQoS == MQTT::QOS2,
+         "rc was %d", suback.grantedQoS);
+
+  check_subs_exist(client, test_topic, 1);
+
+  rc = client.subscribe(test_topic, subsqos, messageArrived2, suback);
+  assert("Good rc from subscribe", rc == MQTT::SUCCESS, "rc was %d", rc);
+  assert("Granted QoS rc from subscribe", suback.grantedQoS == MQTT::QOS2,
+                  "rc was %d", suback.grantedQoS);
+
+  check_subs_exist(client, test_topic, 2);
+
+  rc = client.disconnect();
+  assert("Disconnect successful", rc == MQTT::SUCCESS, "rc was %d", rc);
+  ipstack.disconnect();
+
+  /* reconnect with cleansession false */
+  data.cleansession = 0;
+  rc = ipstack.connect(options.proxy_host, options.proxy_port);
+  assert("TCP connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+  rc = client.connect(data, connack);
+  assert("Connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 1", connack.sessionPresent == 1,
+           "sessionPresent was %d", connack.sessionPresent);
+
+  check_subs_exist(client, test_topic, 2);
+
+  rc = client.subscribe(test_topic, subsqos, messageArrived, suback);
+  assert("Good rc from subscribe", rc == MQTT::SUCCESS, "rc was %d", rc);
+  assert("Granted QoS rc from subscribe", suback.grantedQoS == MQTT::QOS2,
+            "rc was %d", suback.grantedQoS);
+
+  check_subs_exist(client, test_topic, 1);
+
+  // cause a connection FAILURE
+  memset(&pubmsg, '\0', sizeof(pubmsg));
+  pubmsg.payload = (void*)"TERMINATE";
+  pubmsg.payloadlen = strlen((char*)pubmsg.payload);
+  pubmsg.qos = MQTT::QOS0;
+  pubmsg.retained = false;
+  pubmsg.dup = false;
+  rc = client.publish("MQTTSAS topic", pubmsg);
+  assert("Good rc from publish", rc == MQTT::SUCCESS, "rc was %d", rc);
+
+  // wait for failure to be noticed by keepalive
+  wait_seconds = 20;
+  while (client.isConnected() && (wait_seconds-- > 0))
+  {
+      client.yield(1000);
+  }
+  assert("Disconnected", !client.isConnected(), "isConnected was %d",
+         client.isConnected());
+  ipstack.disconnect();
+
+  /* reconnect with cleansession false */
+  data.cleansession = 0;
+  rc = ipstack.connect(options.host, options.port);
+  assert("TCP connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+  rc = client.connect(data, connack);
+  assert("Connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 1", connack.sessionPresent == 1,
+           "sessionPresent was %d", connack.sessionPresent);
+
+  check_subs_exist(client, test_topic, 1);
+
+  rc = client.subscribe(test_topic, subsqos, messageArrived2, suback);
+  assert("Good rc from subscribe", rc == MQTT::SUCCESS, "rc was %d", rc);
+  assert("Granted QoS rc from subscribe", suback.grantedQoS == MQTT::QOS2,
+                  "rc was %d", suback.grantedQoS);
+
+  check_subs_exist(client, test_topic, 2);
+
+  rc = client.disconnect();
+  assert("Disconnect successful", rc == MQTT::SUCCESS, "rc was %d", rc);
+  ipstack.disconnect();
+
+  /* reconnect with cleansession true to clean up both server and client state */
+  data.cleansession = 1;
+  rc = ipstack.connect(options.host, options.port);
+  assert("TCP connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+  rc = client.connect(data, connack);
+  assert("Connect successful",  rc == MQTT::SUCCESS, "rc was %d", rc);
+
+  assert("Good rc in connack", connack.rc == 0, "rc was %d", connack.rc);
+  assert("Session present is 0", connack.sessionPresent == 0,
+           "sessionPresent was %d", connack.sessionPresent);
+
+  rc = client.subscribe(test_topic, subsqos, messageArrived2, suback);
+  assert("Good rc from subscribe", rc == MQTT::SUCCESS, "rc was %d", rc);
+  assert("Granted QoS rc from subscribe", suback.grantedQoS == MQTT::QOS2,
+                  "rc was %d", suback.grantedQoS);
+
+  check_subs_exist(client, test_topic, 2);
+
+  rc = client.disconnect();
+  assert("Disconnect successful", rc == MQTT::SUCCESS, "rc was %d", rc);
+  ipstack.disconnect();
+
+exit:
+  MyLog(LOGA_INFO, "TEST2: test %s. %d tests run, %d failures.",
+      (failures == 0) ? "passed" : "failed", tests, failures);
+  write_test_result();
+  return failures;
+}
+
+
+#if 0
+/*********************************************************************
+
+Test 4: connectionLost and will message
+
+*********************************************************************/
+MQTTClient test6_c1, test6_c2;
+volatile int test6_will_message_arrived = 0;
+volatile int test6_connection_lost_called = 0;
+
+void test6_connectionLost(void* context, char* cause)
+{
+	MQTTClient c = (MQTTClient)context;
+	printf("%s -> Callback: connection lost\n", (c == test6_c1) ? "Client-1" : "Client-2");
+	test6_connection_lost_called = 1;
+}
+
+void test6_deliveryComplete(void* context, MQTTClient_deliveryToken token)
+{
+	printf("Client-2 -> Callback: publish complete for token %d\n", token);
+}
+
+char* test6_will_topic = "C Test 2: will topic";
+char* test6_will_message = "will message from Client-1";
+
+int test6_messageArrived(void* context, char* topicName, int topicLen, MQTTClient_message* m)
+{
+	MQTTClient c = (MQTTClient)context;
+	printf("%s -> Callback: message received on topic '%s' is '%.*s'.\n",
+			 (c == test6_c1) ? "Client-1" : "Client-2", topicName, m->payloadlen, (char*)(m->payload));
+	if (c == test6_c2 && strcmp(topicName, test6_will_topic) == 0 && memcmp(m->payload, test6_will_message, m->payloadlen) == 0)
+		test6_will_message_arrived = 1;
+	MQTTClient_free(topicName);
+	MQTTClient_freeMessage(&m);
+	return 1;
+}
+
+
+int test6(struct Options options)
+{
+	char* testname = "test6";
+	MQTTClient_connectOptions opts = MQTTClient_connectOptions_initializer;
+	MQTTClient_willOptions wopts =  MQTTClient_willOptions_initializer;
+	MQTTClient_connectOptions opts2 = MQTTClient_connectOptions_initializer;
+	int rc, count;
+	char* mqttsas_topic = "MQTTSAS topic";
+
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 6 - connectionLost and will messages");
+	fprintf(xml, "<testcase classname=\"test1\" name=\"connectionLost and will messages\"");
+	global_start_time = start_clock();
+
+	opts.keepAliveInterval = 2;
+	opts.cleansession = 1;
+	opts.MQTTVersion = MQTTVERSION_3_1_1;
+	opts.will = &wopts;
+	opts.will->message = test6_will_message;
+	opts.will->qos = 1;
+	opts.will->retained = 0;
+	opts.will->topicName = test6_will_topic;
+	if (options.haconnections != NULL)
+	{
+		opts.serverURIs = options.haconnections;
+		opts.serverURIcount = options.hacount;
+	}
+
+	/* Client-1 with Will options */
+	rc = MQTTClient_create(&test6_c1, options.proxy_connection, "Client_1", MQTTCLIENT_PERSISTENCE_DEFAULT, NULL);
+	assert("good rc from create", rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+	if (rc != MQTTCLIENT_SUCCESS)
+		goto exit;
+
+	rc = MQTTClient_setCallbacks(test6_c1, (void*)test6_c1, test6_connectionLost, test6_messageArrived, test6_deliveryComplete);
+	assert("good rc from setCallbacks",  rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+	if (rc != MQTTCLIENT_SUCCESS)
+		goto exit;
+
+	/* Connect to the broker */
+	rc = MQTTClient_connect(test6_c1, &opts);
+	assert("good rc from connect",  rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+	if (rc != MQTTCLIENT_SUCCESS)
+		goto exit;
+
+	/* Client - 2 (multi-threaded) */
+	rc = MQTTClient_create(&test6_c2, options.connection, "Client_2", MQTTCLIENT_PERSISTENCE_DEFAULT, NULL);
+	assert("good rc from create",  rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+
+	/* Set the callback functions for the client */
+	rc = MQTTClient_setCallbacks(test6_c2, (void*)test6_c2, test6_connectionLost, test6_messageArrived, test6_deliveryComplete);
+	assert("good rc from setCallbacks",  rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+
+	/* Connect to the broker */
+	opts2.keepAliveInterval = 20;
+	opts2.cleansession = 1;
+	MyLog(LOGA_INFO, "Connecting Client_2 ...");
+	rc = MQTTClient_connect(test6_c2, &opts2);
+	assert("Good rc from connect", rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+
+	rc = MQTTClient_subscribe(test6_c2, test6_will_topic, 2);
+	assert("Good rc from subscribe", rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+
+	/* now send the command which will break the connection and cause the will message to be sent */
+	rc = MQTTClient_publish(test6_c1, mqttsas_topic, (int)strlen("TERMINATE"), "TERMINATE", 0, 0, NULL);
+	assert("Good rc from publish", rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc);
+
+	MyLog(LOGA_INFO, "Waiting to receive the will message");
+	count = 0;
+	while (++count < 40)
+	{
+		#if defined(WIN32)
+			Sleep(1000L);
+		#else
+			sleep(1);
+		#endif
+		if (test6_will_message_arrived == 1 && test6_connection_lost_called == 1)
+			break;
+	}
+	assert("will message arrived", test6_will_message_arrived == 1,
+							"will_message_arrived was %d\n", test6_will_message_arrived);
+	assert("connection lost called", test6_connection_lost_called == 1,
+			         "connection_lost_called %d\n", test6_connection_lost_called);
+
+	rc = MQTTClient_unsubscribe(test6_c2, test6_will_topic);
+	assert("Good rc from unsubscribe", rc == MQTTCLIENT_SUCCESS, "rc was %d", rc);
+
+	rc = MQTTClient_isConnected(test6_c2);
+	assert("Client-2 still connected", rc == 1, "isconnected is %d", rc);
+
+	rc = MQTTClient_isConnected(test6_c1);
+	assert("Client-1 not connected", rc == 0, "isconnected is %d", rc);
+
+	rc = MQTTClient_disconnect(test6_c2, 100L);
+	assert("Good rc from disconnect", rc == MQTTCLIENT_SUCCESS, "rc was %d", rc);
+
+	MQTTClient_destroy(&test6_c1);
+	MQTTClient_destroy(&test6_c2);
+
+exit:
+	MyLog(LOGA_INFO, "%s: test %s. %d tests run, %d failures.\n",
+			(failures == 0) ? "passed" : "failed", testname, tests, failures);
+	write_test_result();
+	return failures;
+}
+#endif
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+ 	int (*tests[])(Options) = {NULL, test1, test2, test3, /*test4, test5, test6, test6a*/};
+	int i;
+
+	xml = fopen("TEST-test1.xml", "w");
+	fprintf(xml, "<testsuite name=\"test1\" tests=\"%d\">\n", (int)(ARRAY_SIZE(tests) - 1));
+
+	//setenv("MQTT_C_CLIENT_TRACE", "ON", 1);
+	//setenv("MQTT_C_CLIENT_TRACE_LEVEL", "ERROR", 0);
+
+	getopts(argc, argv);
+
+	for (i = 0; i < options.iterations; ++i)
+	{
+	 	if (options.test_no == 0)
+		{ /* run all the tests */
+ 		   	for (options.test_no = 1; options.test_no < ARRAY_SIZE(tests); ++options.test_no)
+				rc += tests[options.test_no](options); /* return number of failures.  0 = test succeeded */
+		}
+		else
+ 		   	rc = tests[options.test_no](options); /* run just the selected test */
+	}
+
+ 	if (rc == 0)
+		MyLog(LOGA_INFO, "verdict pass");
+	else
+		MyLog(LOGA_INFO, "verdict fail");
+
+	fprintf(xml, "</testsuite>\n");
+	fclose(xml);
+	return rc;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,21 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+project("paho-mqttpacket" C)
+
+ADD_SUBDIRECTORY(src)
+ADD_SUBDIRECTORY(samples)
+ADD_SUBDIRECTORY(test)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,37 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+# Samples
+
+include_directories(../src)
+
+add_executable(
+  pub0sub1
+  pub0sub1.c transport.c
+)
+target_link_libraries(pub0sub1 paho-embed-mqtt3c)
+
+add_executable(
+  pub0sub1_nb
+  pub0sub1_nb.c transport.c
+)
+target_link_libraries(pub0sub1_nb paho-embed-mqtt3c)
+
+add_executable(
+  qos0pub
+  qos0pub.c transport.c
+)
+target_link_libraries(qos0pub paho-embed-mqtt3c)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/baremetalserial/build
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/baremetalserial/build	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,3 @@
+gcc -g -Wall pub0sub1_nb.c transport.c -I ../../src ../../src/MQTTConnectClient.c ../../src/MQTTSerializePublish.c ../../src/MQTTPacket.c ../../src/MQTTSubscribeClient.c -o pub0sub1_nb ../../src/MQTTDeserializePublish.c ../../src/MQTTConnectServer.c ../../src/MQTTSubscribeServer.c ../../src/MQTTUnsubscribeServer.c ../../src/MQTTUnsubscribeClient.c
+gcc -g -Wall ping_nb.c transport.c -I ../../src ../../src/MQTTConnectClient.c ../../src/MQTTPacket.c -o ping_nb
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/baremetalserial/ping_nb.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/baremetalserial/ping_nb.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,267 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Sergio R. Caprile
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTPacket.h"
+#include "transport.h"
+
+#define KEEPALIVE_INTERVAL 20
+
+/* This is to get a timebase in seconds to test the sample */
+#include <time.h>
+time_t old_t;
+void start_ping_timer(void)
+{
+	time(&old_t);
+	old_t += KEEPALIVE_INTERVAL/2 + 1;
+}
+
+int time_to_ping(void)
+{
+time_t t;
+
+	time(&t);
+	if(t >= old_t)
+	  	return 1;
+	return 0;
+}
+
+/* This is in order to get an asynchronous signal to stop the sample,
+as the code loops waiting for msgs on the subscribed topic.
+Your actual code will depend on your hw and approach, but this sample can be
+run on Linux so debugging of the non-hardware specific bare metal code is easier.
+See at bottom of file for details */
+#include <signal.h>
+
+int toStop = 0;
+
+void stop_init(void);
+/* */
+
+/* Same as above, we provide a set of functions to test/debug on a friendlier system;
+the init() and  close() actions on the serial are just for this, you will probably
+handle this on whatever handles your media in your application */
+void sampleserial_init(void);
+void sampleserial_close(void);
+int samplesend(unsigned char *address, unsigned int bytes);
+int samplerecv(unsigned char *address, unsigned int maxbytes);
+/* */
+
+/* You will use your hardware specifics here, see transport.h. */
+static transport_iofunctions_t iof = {samplesend, samplerecv};
+
+enum states { IDLE, SENDPING, GETPONG };
+
+int main(int argc, char *argv[])
+{
+	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+	int rc = 0;
+	int mysock = 0;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	int len = 0;
+	MQTTTransport mytransport;
+	int state;
+
+	stop_init();
+	sampleserial_init();
+
+	mysock = transport_open(&iof);
+	if(mysock < 0)
+		return mysock;
+	/* You will (or already are) 'somehow' connect(ed) to host:port via your hardware specifics. E.g.:
+		you have a serial (RS-232/UART) link
+		you have a cell modem and you issue your AT+ magic
+		you have some TCP/IP which is not lwIP (nor a full-fledged socket compliant one)
+		 and you TCP connect
+	*/
+
+	mytransport.sck = &mysock;
+	mytransport.getfn = transport_getdatanb;
+	mytransport.state = 0;
+	data.clientID.cstring = "me";
+	data.keepAliveInterval = KEEPALIVE_INTERVAL;
+	data.cleansession = 1;
+	data.username.cstring = "testuser";
+	data.password.cstring = "testpassword";
+
+	len = MQTTSerialize_connect(buf, buflen, &data);
+	/* This one blocks until it finishes sending, you will probably not want this in real life,
+	in such a case replace this call by a scheme similar to the one you'll see in the main loop */
+	rc = transport_sendPacketBuffer(mysock, buf, len);
+
+	printf("Sent MQTT connect\n");
+	/* wait for connack */
+	do {
+		int frc;
+		if ((frc=MQTTPacket_readnb(buf, buflen, &mytransport)) == CONNACK){
+			unsigned char sessionPresent, connack_rc;
+			if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) != 1 || connack_rc != 0){
+				printf("Unable to connect, return code %d\n", connack_rc);
+				goto exit;
+			}
+			break;
+		}
+		else if (frc == -1)
+			goto exit;
+	} while (1); /* handle timeouts here */
+
+	printf("MQTT connected\n");
+	start_ping_timer();
+	state = IDLE;
+	while (!toStop)	{
+		switch(state){
+		case IDLE:
+			if(time_to_ping()){
+				len = MQTTSerialize_pingreq(buf, buflen);
+				transport_sendPacketBuffernb_start(mysock, buf, len);
+				state = SENDPING;
+			}
+			break;
+		case SENDPING:
+			switch(transport_sendPacketBuffernb(mysock)){
+			case TRANSPORT_DONE:
+				printf("Ping...");
+				start_ping_timer();
+				state = GETPONG;
+				break;
+			case TRANSPORT_ERROR:
+				/* handle any I/O errors here */
+				goto exit;
+				break;
+			case TRANSPORT_AGAIN:
+			default:
+				/* handle timeouts here, not probable unless there is a hardware problem */
+				break;
+			}
+			break;
+		case GETPONG:
+			if((rc=MQTTPacket_readnb(buf, buflen, &mytransport)) == PINGRESP){
+				printf("Pong\n");
+				start_ping_timer();
+				state = IDLE;
+			} else if(rc == -1){
+				/* handle I/O errors here */
+				printf("OOPS\n");
+				goto exit;
+			}	/* handle timeouts here */
+			break;
+		}
+	}
+
+	printf("disconnecting\n");
+	len = MQTTSerialize_disconnect(buf, buflen);
+	/* Same blocking related stuff here */
+	rc = transport_sendPacketBuffer(mysock, buf, len);
+
+exit:
+	transport_close(mysock);
+	
+	sampleserial_close();
+	return 0;
+}
+
+
+/* To stop the sample */
+void cfinish(int sig)
+{
+	signal(SIGINT, NULL);
+	toStop = 1;
+}
+
+void stop_init(void)
+{
+	signal(SIGINT, cfinish);
+	signal(SIGTERM, cfinish);
+}
+
+/* Serial hack:
+Simulate serial transfers on an established TCP connection
+ */
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h> 
+#include <fcntl.h>
+
+static int sockfd;
+
+void sampleserial_init(void)
+{
+struct sockaddr_in serv_addr;
+
+
+	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+	  perror(NULL);
+	  exit(2);
+	}
+	serv_addr.sin_family = AF_INET;
+	serv_addr.sin_addr.s_addr = inet_addr("198.41.30.241");
+	serv_addr.sin_port = htons(1883);
+	if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
+		printf("ERROR connecting\n");
+		exit(-1);
+	}
+	printf("- TCP Connected to Eclipse\n");
+        /* set to non-blocking */
+	fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
+}
+
+void sampleserial_close(void)
+{
+	close(sockfd);
+}
+
+int samplesend(unsigned char *address, unsigned int bytes)
+{
+int len;
+
+	if(rand() > (RAND_MAX/2))	// 50% probability of being busy
+		return 0;
+	if(rand() > (RAND_MAX/2)){	// 50% probability of sending half the requested data (no room in buffer)
+		if(bytes > 1)
+			bytes /= 2;
+	}
+	if((len = write(sockfd, address, bytes)) >= 0)
+		return len;
+	if(errno == EAGAIN)
+		return 0;
+	return -1;
+}
+
+int samplerecv(unsigned char *address, unsigned int maxbytes)
+{
+int len;
+
+	if(rand() > (RAND_MAX/2))	// 50% probability of no data
+		return 0;
+	if(rand() > (RAND_MAX/2)){	// 50% probability of getting half the requested data (not arrived yet)
+		if(maxbytes > 1){
+			maxbytes /= 2;
+		}
+	}
+	if((len = read(sockfd, address, maxbytes)) >= 0)
+		return len;
+	if(errno == EAGAIN)
+		return 0;
+	return -1;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/baremetalserial/pub0sub1_nb.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/baremetalserial/pub0sub1_nb.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,285 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - port to the bare metal environment
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTPacket.h"
+#include "transport.h"
+
+/* This is in order to get an asynchronous signal to stop the sample,
+as the code loops waiting for msgs on the subscribed topic.
+Your actual code will depend on your hw and approach, but this sample can be
+run on Linux so debugging of the non-hardware specific bare metal code is easier.
+See at bottom of file for details */
+#include <signal.h>
+
+int toStop = 0;
+
+void stop_init(void);
+/* */
+
+/* Same as above, we provide a set of functions to test/debug on a friendlier system;
+the init() and  close() actions on the serial are just for this, you will probably
+handle this on whatever handles your media in your application */
+void sampleserial_init(void);
+void sampleserial_close(void);
+int samplesend(unsigned char *address, unsigned int bytes);
+int samplerecv(unsigned char *address, unsigned int maxbytes);
+/* */
+
+/* You will use your hardware specifics here, see transport.h. */
+static transport_iofunctions_t iof = {samplesend, samplerecv};
+
+enum states { READING, PUBLISHING };
+
+int main(int argc, char *argv[])
+{
+	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+	int rc = 0;
+	int mysock = 0;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	int msgid = 1;
+	MQTTString topicString = MQTTString_initializer;
+	int req_qos = 0;
+	char* payload = "mypayload";
+	int payloadlen = strlen(payload);
+	int len = 0;
+	MQTTTransport mytransport;
+	int state = READING;
+
+	stop_init();
+	sampleserial_init();
+
+	mysock = transport_open(&iof);
+	if(mysock < 0)
+		return mysock;
+	/* You will (or already are) 'somehow' connect(ed) to host:port via your hardware specifics. E.g.:
+		you have a serial (RS-232/UART) link
+		you have a cell modem and you issue your AT+ magic
+		you have some TCP/IP which is not lwIP (nor a full-fledged socket compliant one)
+		 and you TCP connect
+	*/
+
+	mytransport.sck = &mysock;
+	mytransport.getfn = transport_getdatanb;
+	mytransport.state = 0;
+	data.clientID.cstring = "me";
+	data.keepAliveInterval = 20;
+	data.cleansession = 1;
+	data.username.cstring = "testuser";
+	data.password.cstring = "testpassword";
+
+	len = MQTTSerialize_connect(buf, buflen, &data);
+	/* This one blocks until it finishes sending, you will probably not want this in real life,
+	in such a case replace this call by a scheme similar to the one you'll see in the main loop */
+	rc = transport_sendPacketBuffer(mysock, buf, len);
+
+	printf("Sent MQTT connect\n");
+	/* wait for connack */
+	do {
+		int frc;
+		if ((frc=MQTTPacket_readnb(buf, buflen, &mytransport)) == CONNACK){
+			unsigned char sessionPresent, connack_rc;
+			if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) != 1 || connack_rc != 0){
+				printf("Unable to connect, return code %d\n", connack_rc);
+				goto exit;
+			}
+			break;
+		}
+		else if (frc == -1)
+			goto exit;
+	} while (1); /* handle timeouts here */
+
+	printf("MQTT connected\n");
+	/* subscribe */
+	topicString.cstring = "substopic";
+	len = MQTTSerialize_subscribe(buf, buflen, 0, msgid, 1, &topicString, &req_qos);
+
+	/* This is equivalent to the one above, but using the non-blocking functions. You will probably not want this in real life,
+	in such a case replace this call by a scheme similar to the one you'll see in the main loop */
+	transport_sendPacketBuffernb_start(mysock, buf, len);
+	while((rc=transport_sendPacketBuffernb(mysock)) != TRANSPORT_DONE);
+	do {
+		int frc;
+		if ((frc=MQTTPacket_readnb(buf, buflen, &mytransport)) == SUBACK){ /* wait for suback */
+			unsigned short submsgid;
+			int subcount;
+			int granted_qos;
+
+			rc = MQTTDeserialize_suback(&submsgid, 1, &subcount, &granted_qos, buf, buflen);
+			if (granted_qos != 0){
+				printf("granted qos != 0, %d\n", granted_qos);
+				goto exit;
+			}
+			break;
+		}
+		else if (frc == -1)
+			goto exit;
+	} while (1); /* handle timeouts here */
+	printf("Subscribed\n");
+
+	/* loop getting msgs on subscribed topic */
+	topicString.cstring = "pubtopic";
+	state = READING;
+	while (!toStop)	{
+		/* do other stuff here */
+		switch(state){
+		case READING:
+			if((rc=MQTTPacket_readnb(buf, buflen, &mytransport)) == PUBLISH){
+				unsigned char dup;
+				int qos;
+				unsigned char retained;
+				unsigned short msgid;
+				int payloadlen_in;
+				unsigned char* payload_in;
+				int rc;
+				MQTTString receivedTopic;
+	
+				rc = MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &receivedTopic,
+						&payload_in, &payloadlen_in, buf, buflen);
+				printf("message arrived %.*s\n", payloadlen_in, payload_in);
+				printf("publishing reading\n");
+				state = PUBLISHING;
+				len = MQTTSerialize_publish(buf, buflen, 0, 0, 0, 0, topicString, (unsigned char*)payload, payloadlen);
+				transport_sendPacketBuffernb_start(mysock, buf, len);
+			} else if(rc == -1){
+				/* handle I/O errors here */
+				goto exit;
+			}	/* handle timeouts here */
+			break;
+		case PUBLISHING:
+			switch(transport_sendPacketBuffernb(mysock)){
+			case TRANSPORT_DONE:
+				printf("Published\n");
+				state = READING;
+				break;
+			case TRANSPORT_ERROR:
+				/* handle any I/O errors here */
+				goto exit;
+				break;
+			case TRANSPORT_AGAIN:
+			default:
+				/* handle timeouts here, not probable unless there is a hardware problem */
+				break;
+			}
+			break;
+		}
+	}
+
+	printf("disconnecting\n");
+	len = MQTTSerialize_disconnect(buf, buflen);
+	/* Same blocking related stuff here */
+	rc = transport_sendPacketBuffer(mysock, buf, len);
+
+exit:
+	transport_close(mysock);
+	
+	sampleserial_close();
+	return 0;
+}
+
+
+/* To stop the sample */
+void cfinish(int sig)
+{
+	signal(SIGINT, NULL);
+	toStop = 1;
+}
+
+void stop_init(void)
+{
+	signal(SIGINT, cfinish);
+	signal(SIGTERM, cfinish);
+}
+
+/* Serial hack:
+Simulate serial transfers on an established TCP connection
+ */
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h> 
+#include <fcntl.h>
+
+static int sockfd;
+
+void sampleserial_init(void)
+{
+struct sockaddr_in serv_addr;
+
+
+	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+	  perror(NULL);
+	  exit(2);
+	}
+	serv_addr.sin_family = AF_INET;
+	serv_addr.sin_addr.s_addr = inet_addr("198.41.30.241");
+	serv_addr.sin_port = htons(1883);
+	if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
+		printf("ERROR connecting\n");
+		exit(-1);
+	}
+	printf("- TCP Connected to Eclipse\n");
+        /* set to non-blocking */
+	fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
+}
+
+void sampleserial_close(void)
+{
+	close(sockfd);
+}
+
+int samplesend(unsigned char *address, unsigned int bytes)
+{
+int len;
+
+	if(rand() > (RAND_MAX/2))	// 50% probability of being busy
+		return 0;
+	if(rand() > (RAND_MAX/2)){	// 50% probability of sending half the requested data (no room in buffer)
+		if(bytes > 1)
+			bytes /= 2;
+	}
+	if((len = write(sockfd, address, bytes)) >= 0)
+		return len;
+	if(errno == EAGAIN)
+		return 0;
+	return -1;
+}
+
+int samplerecv(unsigned char *address, unsigned int maxbytes)
+{
+int len;
+
+	if(rand() > (RAND_MAX/2))	// 50% probability of no data
+		return 0;
+	if(rand() > (RAND_MAX/2)){	// 50% probability of getting half the requested data (not arrived yet)
+		if(maxbytes > 1){
+			maxbytes /= 2;
+		}
+	}
+	if((len = read(sockfd, address, maxbytes)) >= 0)
+		return len;
+	if(errno == EAGAIN)
+		return 0;
+	return -1;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/baremetalserial/transport.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/baremetalserial/transport.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - port to the bare metal environment and serial media specifics
+ *******************************************************************************/
+
+/** By the way, this is a nice bare bones example, easier to expand to whatever non-OS
+media you might have */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "transport.h"
+
+/**
+This simple low-level implementation assumes a single connection for a single thread. Thus, single static
+variables are used for that connection.
+On other scenarios, you might want to put all these variables into a structure and index via the 'sock'
+parameter, as some functions show in the comments
+The blocking rx function is not supported.
+If you plan on writing one, take into account that the current implementation of
+MQTTPacket_read() has a function pointer for a function call to get the data to a buffer, but no provisions
+to know the caller or other indicator (the socket id): int (*getfn)(unsigned char*, int)
+*/
+static transport_iofunctions_t *io = NULL;
+static unsigned char *from = NULL;		// to keep track of data sending
+static int howmany;				// ditto
+
+
+void transport_sendPacketBuffernb_start(int sock, unsigned char* buf, int buflen)
+{
+	from = buf;			// from[sock] or mystruct[sock].from
+	howmany = buflen;		// myhowmany[sock] or mystruct[sock].howmany
+}
+
+int transport_sendPacketBuffernb(int sock)
+{
+transport_iofunctions_t *myio = io;	// io[sock] or mystruct[sock].io
+int len;
+
+	/* you should have called open() with a valid pointer to a valid struct and 
+	called sendPacketBuffernb_start with a valid buffer, before calling this */
+	assert((myio != NULL) && (myio->send != NULL) && (from != NULL));
+	if((len = myio->send(from, howmany)) > 0){
+		from += len;
+		if((howmany -= len) <= 0){
+			return TRANSPORT_DONE;
+		}
+	} else if(len < 0){
+		return TRANSPORT_ERROR;
+	}
+	return TRANSPORT_AGAIN;
+}
+
+int transport_sendPacketBuffer(int sock, unsigned char* buf, int buflen)
+{
+int rc;
+
+	transport_sendPacketBuffernb_start(sock, buf, buflen);
+	while((rc=transport_sendPacketBuffernb(sock)) == TRANSPORT_AGAIN){
+		/* this is unlikely to loop forever unless there is a hardware problem */
+	}
+	if(rc == TRANSPORT_DONE){
+		return buflen;
+	}
+	return TRANSPORT_ERROR;
+}
+
+
+int transport_getdata(unsigned char* buf, int count)
+{
+	assert(0);		/* This function is NOT supported, it is just here to tease you */
+	return TRANSPORT_ERROR;	/* nah, it is here for similarity with other transport examples */
+}
+
+int transport_getdatanb(void *sck, unsigned char* buf, int count)
+{
+//int sock = *((int *)sck); 		/* sck: pointer to whatever the system may use to identify the transport */
+transport_iofunctions_t *myio = io;	// io[sock] or mystruct[sock].io
+int len;
+	
+	/* you should have called open() with a valid pointer to a valid struct before calling this */
+	assert((myio != NULL) && (myio->recv != NULL));
+	/* this call will return immediately if no bytes, or return whatever outstanding bytes we have,
+	 upto count */
+	if((len = myio->recv(buf, count)) >= 0)
+		return len;
+	return TRANSPORT_ERROR;
+}
+
+/**
+return >=0 for a connection descriptor, <0 for an error code
+*/
+int transport_open(transport_iofunctions_t *thisio)
+{
+int idx=0;	// for multiple connections, you might, basically turn myio into myio[MAX_CONNECTIONS],
+
+	//if((idx=assignidx()) >= MAX_CONNECTIONS)	// somehow assign an index,
+	//	return TRANSPORT_ERROR;
+	io = thisio;					// store myio[idx] = thisio, or mystruct[idx].io = thisio, 
+	return idx;					// and return the index used
+}
+
+int transport_close(int sock)
+{
+int rc=TRANSPORT_DONE;
+
+	return rc;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/baremetalserial/transport.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/baremetalserial/transport.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - media specifics, nice api doc :^)
+ *******************************************************************************/
+
+typedef struct {
+	int (*send)(unsigned char *address, unsigned int bytes); 	///< pointer to function to send 'bytes' bytes, returns the actual number of bytes sent
+	int (*recv)(unsigned char *address, unsigned int maxbytes); 	///< pointer to function to receive upto 'maxbytes' bytes, returns the actual number of bytes copied
+} transport_iofunctions_t;
+
+#define TRANSPORT_DONE	1
+#define TRANSPORT_AGAIN	0
+#define TRANSPORT_ERROR	-1
+/**
+@note Blocks until requested buflen is sent
+*/
+int transport_sendPacketBuffer(int sock, unsigned char* buf, int buflen);
+/**
+@note Blocks until requested count is received, as MQTTPacket_read() expects
+@warning This function is not supported (not implemented)
+@warning unless you provide a timeout, this function can block forever. Socket based systems do have
+a built in timeout, if your system can provide this, do modify this function, otherwise use getdatanb() instead
+@returns number of bytes read
+*/
+int transport_getdata(unsigned char* buf, int count);
+
+/**
+This is a bare metal implementation, so we must have non-blocking functions,
+the process of pumping to serial lines can result a bit slow and we don't want to busy wait.
+This function starts the process, you will call sendPacketBuffernb() until it reports success (or error)
+*/
+void transport_sendPacketBuffernb_start(int sock, unsigned char* buf, int buflen);
+/**
+This is a bare metal implementation, so we must have non-blocking functions,
+the process of pumping to serial lines can result a bit slow and we don't want to busy wait
+@returns TRANSPORT_DONE if finished, TRANSPORT_AGAIN for call again, or TRANSPORT_ERROR on error
+@note you will call again until it finishes (this is stream)
+*/
+int transport_sendPacketBuffernb(int sock);
+
+/**
+This is a bare metal implementation, so we must have non-blocking functions,
+the process of sucking from serial lines can result a bit slow and we don't want to busy wait
+@return the actual number of bytes read, 0 for none, or TRANSPORT_ERROR on error
+@note you will call again until total number of expected bytes is read (this is stream)
+*/
+int transport_getdatanb(void *sck, unsigned char* buf, int count);
+
+/**
+We assume whatever connection needs to be done, it is externally established by the specifics of the hardware
+E.g.:
+A cell modem: you will call AT+whatever and put the modem in transparent mode, OR, you will embed
+the AT+xSENDx / AT+xRECVx commands into the former sendPacketBuffer() and getdatanb() functions
+@param	thisio	pointer to a structure containing all necessary stuff to handle direct serial I/O
+@returns	whatever indicator the system assigns to this link, if any. (a.k.a. : 'sock'), or TRANSPORT_ERROR for error
+*/
+int transport_open(transport_iofunctions_t *thisio);
+int transport_close(int sock);
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/build
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/build	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,6 @@
+gcc -Wall -c transport.c -Os -s
+gcc qos0pub.c transport.o -I ../src ../src/MQTTConnectClient.c ../src/MQTTSerializePublish.c ../src/MQTTPacket.c -o qos0pub -Os -s
+
+gcc pub0sub1.c transport.o -I ../src ../src/MQTTConnectClient.c ../src/MQTTSerializePublish.c ../src/MQTTPacket.c ../src/MQTTSubscribeClient.c -o pub0sub1 ../src/MQTTDeserializePublish.c -Os -s ../src/MQTTConnectServer.c ../src/MQTTSubscribeServer.c ../src/MQTTUnsubscribeServer.c ../src/MQTTUnsubscribeClient.c -ggdb
+gcc pub0sub1_nb.c transport.o -I ../src ../src/MQTTConnectClient.c ../src/MQTTSerializePublish.c ../src/MQTTPacket.c ../src/MQTTSubscribeClient.c -o pub0sub1_nb ../src/MQTTDeserializePublish.c -Os -s ../src/MQTTConnectServer.c ../src/MQTTSubscribeServer.c ../src/MQTTUnsubscribeServer.c ../src/MQTTUnsubscribeClient.c -ggdb
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/null.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/null.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,4 @@
+int main(int argc, char** argv)
+{
+  return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/ping.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/ping.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - port
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTPacket.h"
+#include "transport.h"
+
+#define KEEPALIVE_INTERVAL 20
+
+/* This is to get a timebase in seconds to test the sample */
+#include <time.h>
+time_t old_t;
+void start_ping_timer(void)
+{
+	time(&old_t);
+	old_t += KEEPALIVE_INTERVAL/2 + 1;
+}
+
+int time_to_ping(void)
+{
+time_t t;
+
+	time(&t);
+	if(t >= old_t)
+	  	return 1;
+	return 0;
+}
+
+/* This is in order to get an asynchronous signal to stop the sample,
+as the code loops waiting for msgs on the subscribed topic.
+Your actual code will depend on your hw and approach*/
+#include <signal.h>
+
+int toStop = 0;
+
+void cfinish(int sig)
+{
+	signal(SIGINT, NULL);
+	toStop = 1;
+}
+
+void stop_init(void)
+{
+	signal(SIGINT, cfinish);
+	signal(SIGTERM, cfinish);
+}
+/* */
+
+int main(int argc, char *argv[])
+{
+	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+	int rc = 0;
+	int mysock = 0;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	int len = 0;
+	char *host = "m2m.eclipse.org";
+	int port = 1883;
+
+	stop_init();
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	mysock = transport_open(host, port);
+	if(mysock < 0)
+		return mysock;
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	data.clientID.cstring = "me";
+	data.keepAliveInterval = KEEPALIVE_INTERVAL;
+	data.cleansession = 1;
+	data.username.cstring = "testuser";
+	data.password.cstring = "testpassword";
+
+	len = MQTTSerialize_connect(buf, buflen, &data);
+	rc = transport_sendPacketBuffer(mysock, buf, len);
+
+	printf("Sent MQTT connect\n");
+	/* wait for connack */
+	if (MQTTPacket_read(buf, buflen, transport_getdata) == CONNACK)
+	{
+		unsigned char sessionPresent, connack_rc;
+
+		if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) != 1 || connack_rc != 0)
+		{
+			printf("Unable to connect, return code %d\n", connack_rc);
+			goto exit;
+		}
+	}
+	else
+		goto exit;
+
+	printf("MQTT connected\n");
+	start_ping_timer();
+
+	while (!toStop)
+	{
+		while(!time_to_ping());
+		len = MQTTSerialize_pingreq(buf, buflen);
+		transport_sendPacketBuffer(mysock, buf, len);
+		printf("Ping...");
+		if (MQTTPacket_read(buf, buflen, transport_getdata) == PINGRESP){
+			printf("Pong\n");
+			start_ping_timer();
+		}
+		else {
+			printf("OOPS\n");
+			goto exit;
+		}
+		
+	}
+
+	printf("disconnecting\n");
+	len = MQTTSerialize_disconnect(buf, buflen);
+	rc = transport_sendPacketBuffer(mysock, buf, len);
+
+exit:
+	transport_close(mysock);
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/ping_nb.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/ping_nb.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - port and nonblocking
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTPacket.h"
+#include "transport.h"
+
+#define KEEPALIVE_INTERVAL 20
+
+/* This is to get a timebase in seconds to test the sample */
+#include <time.h>
+time_t old_t;
+void start_ping_timer(void)
+{
+	time(&old_t);
+	old_t += KEEPALIVE_INTERVAL/2 + 1;
+}
+
+int time_to_ping(void)
+{
+time_t t;
+
+	time(&t);
+	if(t >= old_t)
+	  	return 1;
+	return 0;
+}
+
+/* This is in order to get an asynchronous signal to stop the sample,
+as the code loops waiting for msgs on the subscribed topic.
+Your actual code will depend on your hw and approach*/
+#include <signal.h>
+
+int toStop = 0;
+
+void cfinish(int sig)
+{
+	signal(SIGINT, NULL);
+	toStop = 1;
+}
+
+void stop_init(void)
+{
+	signal(SIGINT, cfinish);
+	signal(SIGTERM, cfinish);
+}
+/* */
+
+enum states { IDLE, GETPONG };
+
+int main(int argc, char *argv[])
+{
+	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+	int rc = 0;
+	int mysock = 0;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	int len = 0;
+	char *host = "m2m.eclipse.org";
+	int port = 1883;
+	MQTTTransport mytransport;
+	int state;
+
+	stop_init();
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	mysock = transport_open(host, port);
+	if(mysock < 0)
+		return mysock;
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	mytransport.sck = &mysock;
+	mytransport.getfn = transport_getdatanb;
+	mytransport.state = 0;
+	data.clientID.cstring = "me";
+	data.keepAliveInterval = KEEPALIVE_INTERVAL;
+	data.cleansession = 1;
+	data.username.cstring = "testuser";
+	data.password.cstring = "testpassword";
+
+	len = MQTTSerialize_connect(buf, buflen, &data);
+	rc = transport_sendPacketBuffer(mysock, buf, len);
+
+	printf("Sent MQTT connect\n");
+	/* wait for connack */
+	do {
+		int frc;
+		if ((frc=MQTTPacket_readnb(buf, buflen, &mytransport)) == CONNACK){
+			unsigned char sessionPresent, connack_rc;
+			if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) != 1 || connack_rc != 0){
+				printf("Unable to connect, return code %d\n", connack_rc);
+				goto exit;
+			}
+			break;
+		}
+		else if (frc == -1)
+			goto exit;
+	} while (1); /* handle timeouts here */
+
+	printf("MQTT connected\n");
+	start_ping_timer();
+	
+	state = IDLE;
+	while (!toStop)	{
+		switch(state){
+		case IDLE:
+			if(time_to_ping()){
+				len = MQTTSerialize_pingreq(buf, buflen);
+				transport_sendPacketBuffer(mysock, buf, len);
+				printf("Ping...");
+				state = GETPONG;
+			}
+			break;
+		case GETPONG:
+			if((rc=MQTTPacket_readnb(buf, buflen, &mytransport)) == PINGRESP){
+				printf("Pong\n");
+				start_ping_timer();
+				state = IDLE;
+			} else if(rc == -1){
+				printf("OOPS\n");
+				goto exit;
+			}
+			break;
+		}
+	}
+
+	printf("disconnecting\n");
+	len = MQTTSerialize_disconnect(buf, buflen);
+	rc = transport_sendPacketBuffer(mysock, buf, len);
+
+exit:
+	transport_close(mysock);
+	
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/pub0sub1.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/pub0sub1.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - clarifications and/or documentation extension
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTPacket.h"
+#include "transport.h"
+
+/* This is in order to get an asynchronous signal to stop the sample,
+as the code loops waiting for msgs on the subscribed topic.
+Your actual code will depend on your hw and approach*/
+#include <signal.h>
+
+int toStop = 0;
+
+void cfinish(int sig)
+{
+	signal(SIGINT, NULL);
+	toStop = 1;
+}
+
+void stop_init(void)
+{
+	signal(SIGINT, cfinish);
+	signal(SIGTERM, cfinish);
+}
+/* */
+
+int main(int argc, char *argv[])
+{
+	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+	int rc = 0;
+	int mysock = 0;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	int msgid = 1;
+	MQTTString topicString = MQTTString_initializer;
+	int req_qos = 0;
+	char* payload = "mypayload";
+	int payloadlen = strlen(payload);
+	int len = 0;
+	char *host = "m2m.eclipse.org";
+	int port = 1883;
+
+	stop_init();
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	mysock = transport_open(host, port);
+	if(mysock < 0)
+		return mysock;
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	data.clientID.cstring = "me";
+	data.keepAliveInterval = 20;
+	data.cleansession = 1;
+	data.username.cstring = "testuser";
+	data.password.cstring = "testpassword";
+
+	len = MQTTSerialize_connect(buf, buflen, &data);
+	rc = transport_sendPacketBuffer(mysock, buf, len);
+
+	/* wait for connack */
+	if (MQTTPacket_read(buf, buflen, transport_getdata) == CONNACK)
+	{
+		unsigned char sessionPresent, connack_rc;
+
+		if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) != 1 || connack_rc != 0)
+		{
+			printf("Unable to connect, return code %d\n", connack_rc);
+			goto exit;
+		}
+	}
+	else
+		goto exit;
+
+	/* subscribe */
+	topicString.cstring = "substopic";
+	len = MQTTSerialize_subscribe(buf, buflen, 0, msgid, 1, &topicString, &req_qos);
+
+	rc = transport_sendPacketBuffer(mysock, buf, len);
+	if (MQTTPacket_read(buf, buflen, transport_getdata) == SUBACK) 	/* wait for suback */
+	{
+		unsigned short submsgid;
+		int subcount;
+		int granted_qos;
+
+		rc = MQTTDeserialize_suback(&submsgid, 1, &subcount, &granted_qos, buf, buflen);
+		if (granted_qos != 0)
+		{
+			printf("granted qos != 0, %d\n", granted_qos);
+			goto exit;
+		}
+	}
+	else
+		goto exit;
+
+	/* loop getting msgs on subscribed topic */
+	topicString.cstring = "pubtopic";
+	while (!toStop)
+	{
+		/* transport_getdata() has a built-in 1 second timeout,
+		your mileage will vary */
+		if (MQTTPacket_read(buf, buflen, transport_getdata) == PUBLISH)
+		{
+			unsigned char dup;
+			int qos;
+			unsigned char retained;
+			unsigned short msgid;
+			int payloadlen_in;
+			unsigned char* payload_in;
+			int rc;
+			MQTTString receivedTopic;
+
+			rc = MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &receivedTopic,
+					&payload_in, &payloadlen_in, buf, buflen);
+			printf("message arrived %.*s\n", payloadlen_in, payload_in);
+		}
+
+		printf("publishing reading\n");
+		len = MQTTSerialize_publish(buf, buflen, 0, 0, 0, 0, topicString, (unsigned char*)payload, payloadlen);
+		rc = transport_sendPacketBuffer(mysock, buf, len);
+	}
+
+	printf("disconnecting\n");
+	len = MQTTSerialize_disconnect(buf, buflen);
+	rc = transport_sendPacketBuffer(mysock, buf, len);
+
+exit:
+	transport_close(mysock);
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/pub0sub1_nb.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/pub0sub1_nb.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - clarifications and/or documentation extension
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTPacket.h"
+#include "transport.h"
+
+/* This is in order to get an asynchronous signal to stop the sample,
+as the code loops waiting for msgs on the subscribed topic.
+Your actual code will depend on your hw and approach*/
+#include <signal.h>
+
+int toStop = 0;
+
+void cfinish(int sig)
+{
+	signal(SIGINT, NULL);
+	toStop = 1;
+}
+
+void stop_init(void)
+{
+	signal(SIGINT, cfinish);
+	signal(SIGTERM, cfinish);
+}
+/* */
+
+int main(int argc, char *argv[])
+{
+	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+	int rc = 0;
+	int mysock = 0;
+	unsigned char buf[200];
+	int buflen = sizeof(buf);
+	int msgid = 1;
+	MQTTString topicString = MQTTString_initializer;
+	int req_qos = 0;
+	char* payload = "mypayload";
+	int payloadlen = strlen(payload);
+	int len = 0;
+	char *host = "m2m.eclipse.org";
+	int port = 1883;
+	MQTTTransport mytransport;
+
+	stop_init();
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	mysock = transport_open(host, port);
+	if(mysock < 0)
+		return mysock;
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	mytransport.sck = &mysock;
+	mytransport.getfn = transport_getdatanb;
+	mytransport.state = 0;
+	data.clientID.cstring = "me";
+	data.keepAliveInterval = 20;
+	data.cleansession = 1;
+	data.username.cstring = "testuser";
+	data.password.cstring = "testpassword";
+
+	len = MQTTSerialize_connect(buf, buflen, &data);
+	rc = transport_sendPacketBuffer(mysock, buf, len);
+
+	/* wait for connack */
+	if (MQTTPacket_read(buf, buflen, transport_getdata) == CONNACK)
+	{
+		unsigned char sessionPresent, connack_rc;
+
+		if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) != 1 || connack_rc != 0)
+		{
+			printf("Unable to connect, return code %d\n", connack_rc);
+			goto exit;
+		}
+	}
+	else
+		goto exit;
+
+	/* subscribe */
+	topicString.cstring = "substopic";
+	len = MQTTSerialize_subscribe(buf, buflen, 0, msgid, 1, &topicString, &req_qos);
+
+	rc = transport_sendPacketBuffer(mysock, buf, len);
+	do {
+		int frc;
+		if ((frc=MQTTPacket_readnb(buf, buflen, &mytransport)) == SUBACK) /* wait for suback */
+		{
+			unsigned short submsgid;
+			int subcount;
+			int granted_qos;
+
+			rc = MQTTDeserialize_suback(&submsgid, 1, &subcount, &granted_qos, buf, buflen);
+			if (granted_qos != 0)
+			{
+				printf("granted qos != 0, %d\n", granted_qos);
+				goto exit;
+			}
+			break;
+		}
+		else if (frc == -1)
+			goto exit;
+	} while (1); /* handle timeouts here */
+	/* loop getting msgs on subscribed topic */
+	topicString.cstring = "pubtopic";
+	while (!toStop)
+	{
+		/* handle timeouts */
+		if (MQTTPacket_readnb(buf, buflen, &mytransport) == PUBLISH)
+		{
+			unsigned char dup;
+			int qos;
+			unsigned char retained;
+			unsigned short msgid;
+			int payloadlen_in;
+			unsigned char* payload_in;
+			int rc;
+			MQTTString receivedTopic;
+
+			rc = MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &receivedTopic,
+					&payload_in, &payloadlen_in, buf, buflen);
+			printf("message arrived %.*s\n", payloadlen_in, payload_in);
+			printf("publishing reading\n");
+			len = MQTTSerialize_publish(buf, buflen, 0, 0, 0, 0, topicString, (unsigned char*)payload, payloadlen);
+			rc = transport_sendPacketBuffer(mysock, buf, len);
+		}
+	}
+
+	printf("disconnecting\n");
+	len = MQTTSerialize_disconnect(buf, buflen);
+	rc = transport_sendPacketBuffer(mysock, buf, len);
+
+exit:
+	transport_close(mysock);
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/qos0pub.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/qos0pub.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - clarifications and/or documentation extension
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MQTTPacket.h"
+#include "transport.h"
+
+
+int main(int argc, char *argv[])
+{
+	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+	int rc = 0;
+	char buf[200];
+	int buflen = sizeof(buf);
+	int mysock = 0;
+	MQTTString topicString = MQTTString_initializer;
+	char* payload = "mypayload";
+	int payloadlen = strlen(payload);
+	int len = 0;
+	char *host = "m2m.eclipse.org";
+	int port = 1883;
+
+	if (argc > 1)
+		host = argv[1];
+
+	if (argc > 2)
+		port = atoi(argv[2]);
+
+	mysock = transport_open(host,port);
+	if(mysock < 0)
+		return mysock;
+
+	printf("Sending to hostname %s port %d\n", host, port);
+
+	data.clientID.cstring = "me";
+	data.keepAliveInterval = 20;
+	data.cleansession = 1;
+	data.username.cstring = "testuser";
+	data.password.cstring = "testpassword";
+	data.MQTTVersion = 4;
+
+	len = MQTTSerialize_connect((unsigned char *)buf, buflen, &data);
+
+	topicString.cstring = "mytopic";
+	len += MQTTSerialize_publish((unsigned char *)(buf + len), buflen - len, 0, 0, 0, 0, topicString, (unsigned char *)payload, payloadlen);
+
+	len += MQTTSerialize_disconnect((unsigned char *)(buf + len), buflen - len);
+
+	rc = transport_sendPacketBuffer(mysock, (unsigned char*)buf, len);
+	if (rc == len)
+		printf("Successfully published\n");
+	else
+		printf("Publish failed\n");
+
+exit:
+	transport_close(mysock);
+
+	return 0;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/transport.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/transport.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - "commonalization" from prior samples and/or documentation extension
+ *******************************************************************************/
+
+#include <sys/types.h>
+
+#if !defined(SOCKET_ERROR)
+	/** error in socket operation */
+	#define SOCKET_ERROR -1
+#endif
+
+#if defined(WIN32)
+/* default on Windows is 64 - increase to make Linux and Windows the same */
+#define FD_SETSIZE 1024
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define MAXHOSTNAMELEN 256
+#define EAGAIN WSAEWOULDBLOCK
+#define EINTR WSAEINTR
+#define EINVAL WSAEINVAL
+#define EINPROGRESS WSAEINPROGRESS
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define ENOTCONN WSAENOTCONN
+#define ECONNRESET WSAECONNRESET
+#define ioctl ioctlsocket
+#define socklen_t int
+#else
+#define INVALID_SOCKET SOCKET_ERROR
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#endif
+
+#if defined(WIN32)
+#include <Iphlpapi.h>
+#else
+#include <sys/ioctl.h>
+#include <net/if.h>
+#endif
+
+/**
+This simple low-level implementation assumes a single connection for a single thread. Thus, a static
+variable is used for that connection.
+On other scenarios, the user must solve this by taking into account that the current implementation of
+MQTTPacket_read() has a function pointer for a function call to get the data to a buffer, but no provisions
+to know the caller or other indicator (the socket id): int (*getfn)(unsigned char*, int)
+*/
+static int mysock = INVALID_SOCKET;
+
+
+int transport_sendPacketBuffer(int sock, unsigned char* buf, int buflen)
+{
+	int rc = 0;
+	rc = write(sock, buf, buflen);
+	return rc;
+}
+
+
+int transport_getdata(unsigned char* buf, int count)
+{
+	int rc = recv(mysock, buf, count, 0);
+	//printf("received %d bytes count %d\n", rc, (int)count);
+	return rc;
+}
+
+int transport_getdatanb(void *sck, unsigned char* buf, int count)
+{
+	int sock = *((int *)sck); 	/* sck: pointer to whatever the system may use to identify the transport */
+	/* this call will return after the timeout set on initialization if no bytes;
+	   in your system you will use whatever you use to get whichever outstanding
+	   bytes your socket equivalent has ready to be extracted right now, if any,
+	   or return immediately */
+	int rc = recv(sock, buf, count, 0);	
+	if (rc == -1) {
+		/* check error conditions from your system here, and return -1 */
+		return 0;
+	}
+	return rc;
+}
+
+/**
+return >=0 for a socket descriptor, <0 for an error code
+@todo Basically moved from the sample without changes, should accomodate same usage for 'sock' for clarity,
+removing indirections
+*/
+int transport_open(char* addr, int port)
+{
+int* sock = &mysock;
+	int type = SOCK_STREAM;
+	struct sockaddr_in address;
+#if defined(AF_INET6)
+	struct sockaddr_in6 address6;
+#endif
+	int rc = -1;
+#if defined(WIN32)
+	short family;
+#else
+	sa_family_t family = AF_INET;
+#endif
+	struct addrinfo *result = NULL;
+	struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL};
+	static struct timeval tv;
+
+	*sock = -1;
+	if (addr[0] == '[')
+	  ++addr;
+
+	if ((rc = getaddrinfo(addr, NULL, &hints, &result)) == 0)
+	{
+		struct addrinfo* res = result;
+
+		/* prefer ip4 addresses */
+		while (res)
+		{
+			if (res->ai_family == AF_INET)
+			{
+				result = res;
+				break;
+			}
+			res = res->ai_next;
+		}
+
+#if defined(AF_INET6)
+		if (result->ai_family == AF_INET6)
+		{
+			address6.sin6_port = htons(port);
+			address6.sin6_family = family = AF_INET6;
+			address6.sin6_addr = ((struct sockaddr_in6*)(result->ai_addr))->sin6_addr;
+		}
+		else
+#endif
+		if (result->ai_family == AF_INET)
+		{
+			address.sin_port = htons(port);
+			address.sin_family = family = AF_INET;
+			address.sin_addr = ((struct sockaddr_in*)(result->ai_addr))->sin_addr;
+		}
+		else
+			rc = -1;
+
+		freeaddrinfo(result);
+	}
+
+	if (rc == 0)
+	{
+		*sock =	socket(family, type, 0);
+		if (*sock != -1)
+		{
+#if defined(NOSIGPIPE)
+			int opt = 1;
+
+			if (setsockopt(*sock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&opt, sizeof(opt)) != 0)
+				Log(TRACE_MIN, -1, "Could not set SO_NOSIGPIPE for socket %d", *sock);
+#endif
+
+			if (family == AF_INET)
+				rc = connect(*sock, (struct sockaddr*)&address, sizeof(address));
+	#if defined(AF_INET6)
+			else
+				rc = connect(*sock, (struct sockaddr*)&address6, sizeof(address6));
+	#endif
+		}
+	}
+	if (mysock == INVALID_SOCKET)
+		return rc;
+
+	tv.tv_sec = 1;  /* 1 second Timeout */
+	tv.tv_usec = 0;  
+	setsockopt(mysock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
+	return mysock;
+}
+
+int transport_close(int sock)
+{
+int rc;
+
+	rc = shutdown(sock, SHUT_WR);
+	rc = recv(sock, NULL, (size_t)0, 0);
+	rc = close(sock);
+
+	return rc;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/transport.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/samples/transport.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - "commonalization" from prior samples and/or documentation extension
+ *******************************************************************************/
+
+int transport_sendPacketBuffer(int sock, unsigned char* buf, int buflen);
+int transport_getdata(unsigned char* buf, int count);
+int transport_getdatanb(void *sck, unsigned char* buf, int count);
+int transport_open(char* host, int port);
+int transport_close(int sock);
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,31 @@
+#*******************************************************************************
+#  Copyright (c) 2017 IBM Corp.
+#
+#  All rights reserved. This program and the accompanying materials
+#  are made available under the terms of the Eclipse Public License v1.0
+#  and Eclipse Distribution License v1.0 which accompany this distribution.
+#
+#  The Eclipse Public License is available at
+#     http://www.eclipse.org/legal/epl-v10.html
+#  and the Eclipse Distribution License is available at
+#    http://www.eclipse.org/org/documents/edl-v10.php.
+#
+#  Contributors:
+#     Ian Craggs - initial version
+#*******************************************************************************/
+
+# MQTTPacket Library
+file(GLOB SOURCES "*.c")
+add_library(paho-embed-mqtt3c SHARED ${SOURCES})
+install(TARGETS paho-embed-mqtt3c DESTINATION /usr/lib)
+target_compile_definitions(paho-embed-mqtt3c PRIVATE MQTT_SERVER MQTT_CLIENT)
+
+add_library(MQTTPacketClient SHARED MQTTFormat MQTTPacket
+            MQTTSerializePublish MQTTDeserializePublish
+            MQTTConnectClient MQTTSubscribeClient MQTTUnsubscribeClient)
+target_compile_definitions(MQTTPacketClient PRIVATE MQTT_CLIENT)
+
+add_library(MQTTPacketServer SHARED MQTTFormat MQTTPacket
+            MQTTSerializePublish MQTTDeserializePublish
+            MQTTConnectServer MQTTSubscribeServer MQTTUnsubscribeServer)
+target_compile_definitions(MQTTPacketServer PRIVATE MQTT_SERVER)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTConnect.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTConnect.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2017 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Ian Craggs - add connack return code definitions 
+ *    Xiang Rong - 442039 Add makefile to Embedded C client
+ *    Ian Craggs - fix for issue #64, bit order in connack response
+ *******************************************************************************/
+
+#ifndef MQTTCONNECT_H_
+#define MQTTCONNECT_H_
+
+enum connack_return_codes
+{
+    MQTT_CONNECTION_ACCEPTED = 0,
+    MQTT_UNNACCEPTABLE_PROTOCOL = 1,
+    MQTT_CLIENTID_REJECTED = 2,
+    MQTT_SERVER_UNAVAILABLE = 3,
+    MQTT_BAD_USERNAME_OR_PASSWORD = 4,
+    MQTT_NOT_AUTHORIZED = 5,
+};
+
+#if !defined(DLLImport)
+  #define DLLImport
+#endif
+#if !defined(DLLExport)
+  #define DLLExport
+#endif
+
+
+typedef union
+{
+	unsigned char all;	/**< all connect flags */
+#if defined(REVERSED)
+	struct
+	{
+		unsigned int username : 1;			/**< 3.1 user name */
+		unsigned int password : 1; 			/**< 3.1 password */
+		unsigned int willRetain : 1;		/**< will retain setting */
+		unsigned int willQoS : 2;				/**< will QoS value */
+		unsigned int will : 1;			    /**< will flag */
+		unsigned int cleansession : 1;	  /**< clean session flag */
+		unsigned int : 1;	  	          /**< unused */
+	} bits;
+#else
+	struct
+	{
+		unsigned int : 1;	     					/**< unused */
+		unsigned int cleansession : 1;	  /**< cleansession flag */
+		unsigned int will : 1;			    /**< will flag */
+		unsigned int willQoS : 2;				/**< will QoS value */
+		unsigned int willRetain : 1;		/**< will retain setting */
+		unsigned int password : 1; 			/**< 3.1 password */
+		unsigned int username : 1;			/**< 3.1 user name */
+	} bits;
+#endif
+} MQTTConnectFlags;	/**< connect flags byte */
+
+
+
+/**
+ * Defines the MQTT "Last Will and Testament" (LWT) settings for
+ * the connect packet.
+ */
+typedef struct
+{
+	/** The eyecatcher for this structure.  must be MQTW. */
+	char struct_id[4];
+	/** The version number of this structure.  Must be 0 */
+	int struct_version;
+	/** The LWT topic to which the LWT message will be published. */
+	MQTTString topicName;
+	/** The LWT payload. */
+	MQTTString message;
+	/**
+      * The retained flag for the LWT message (see MQTTAsync_message.retained).
+      */
+	unsigned char retained;
+	/**
+      * The quality of service setting for the LWT message (see
+      * MQTTAsync_message.qos and @ref qos).
+      */
+	char qos;
+} MQTTPacket_willOptions;
+
+
+#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 }
+
+
+typedef struct
+{
+	/** The eyecatcher for this structure.  must be MQTC. */
+	char struct_id[4];
+	/** The version number of this structure.  Must be 0 */
+	int struct_version;
+	/** Version of MQTT to be used.  3 = 3.1 4 = 3.1.1
+	  */
+	unsigned char MQTTVersion;
+	MQTTString clientID;
+	unsigned short keepAliveInterval;
+	unsigned char cleansession;
+	unsigned char willFlag;
+	MQTTPacket_willOptions will;
+	MQTTString username;
+	MQTTString password;
+} MQTTPacket_connectData;
+
+typedef union
+{
+	unsigned char all;	/**< all connack flags */
+#if defined(REVERSED)
+	struct
+	{
+    unsigned int reserved : 7;	  	    /**< unused */
+		unsigned int sessionpresent : 1;    /**< session present flag */
+	} bits;
+#else
+	struct
+	{
+		unsigned int sessionpresent : 1;    /**< session present flag */
+    unsigned int reserved: 7;	     			/**< unused */
+	} bits;
+#endif
+} MQTTConnackFlags;	/**< connack flags byte */
+
+#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \
+		MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} }
+
+DLLExport int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options);
+DLLExport int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len);
+
+DLLExport int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent);
+DLLExport int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen);
+
+DLLExport int MQTTSerialize_disconnect(unsigned char* buf, int buflen);
+DLLExport int MQTTSerialize_pingreq(unsigned char* buf, int buflen);
+
+#endif /* MQTTCONNECT_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTConnectClient.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTConnectClient.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,214 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+  * Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
+  * @param options the options to be used to build the connect packet
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int MQTTSerialize_connectLength(MQTTPacket_connectData* options)
+{
+	int len = 0;
+
+	FUNC_ENTRY;
+
+	if (options->MQTTVersion == 3)
+		len = 12; /* variable depending on MQTT or MQIsdp */
+	else if (options->MQTTVersion == 4)
+		len = 10;
+
+	len += MQTTstrlen(options->clientID)+2;
+	if (options->willFlag)
+		len += MQTTstrlen(options->will.topicName)+2 + MQTTstrlen(options->will.message)+2;
+	if (options->username.cstring || options->username.lenstring.data)
+		len += MQTTstrlen(options->username)+2;
+	if (options->password.cstring || options->password.lenstring.data)
+		len += MQTTstrlen(options->password)+2;
+
+	FUNC_EXIT_RC(len);
+	return len;
+}
+
+
+/**
+  * Serializes the connect options into the buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param len the length in bytes of the supplied buffer
+  * @param options the options to be used to build the connect packet
+  * @return serialized length, or error if 0
+  */
+int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options)
+{
+	unsigned char *ptr = buf;
+	MQTTHeader header = {0};
+	MQTTConnectFlags flags = {0};
+	int len = 0;
+	int rc = -1;
+
+	FUNC_ENTRY;
+	if (MQTTPacket_len(len = MQTTSerialize_connectLength(options)) > buflen)
+	{
+		rc = MQTTPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	header.byte = 0;
+	header.bits.type = CONNECT;
+	writeChar(&ptr, header.byte); /* write header */
+
+	ptr += MQTTPacket_encode(ptr, len); /* write remaining length */
+
+	if (options->MQTTVersion == 4)
+	{
+		writeCString(&ptr, "MQTT");
+		writeChar(&ptr, (char) 4);
+	}
+	else
+	{
+		writeCString(&ptr, "MQIsdp");
+		writeChar(&ptr, (char) 3);
+	}
+
+	flags.all = 0;
+	flags.bits.cleansession = options->cleansession;
+	flags.bits.will = (options->willFlag) ? 1 : 0;
+	if (flags.bits.will)
+	{
+		flags.bits.willQoS = options->will.qos;
+		flags.bits.willRetain = options->will.retained;
+	}
+
+	if (options->username.cstring || options->username.lenstring.data)
+		flags.bits.username = 1;
+	if (options->password.cstring || options->password.lenstring.data)
+		flags.bits.password = 1;
+
+	writeChar(&ptr, flags.all);
+	writeInt(&ptr, options->keepAliveInterval);
+	writeMQTTString(&ptr, options->clientID);
+	if (options->willFlag)
+	{
+		writeMQTTString(&ptr, options->will.topicName);
+		writeMQTTString(&ptr, options->will.message);
+	}
+	if (flags.bits.username)
+		writeMQTTString(&ptr, options->username);
+	if (flags.bits.password)
+		writeMQTTString(&ptr, options->password);
+
+	rc = ptr - buf;
+
+	exit: FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into connack data - return code
+  * @param sessionPresent the session present flag returned (only for MQTT 3.1.1)
+  * @param connack_rc returned integer value of the connack return code
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen)
+{
+	MQTTHeader header = {0};
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen;
+	MQTTConnackFlags flags = {0};
+
+	FUNC_ENTRY;
+	header.byte = readChar(&curdata);
+	if (header.bits.type != CONNACK)
+		goto exit;
+
+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+	enddata = curdata + mylen;
+	if (enddata - curdata < 2)
+		goto exit;
+
+	flags.all = readChar(&curdata);
+	*sessionPresent = flags.bits.sessionpresent;
+	*connack_rc = readChar(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer, to avoid overruns
+  * @param packettype the message type
+  * @return serialized length, or error if 0
+  */
+int MQTTSerialize_zero(unsigned char* buf, int buflen, unsigned char packettype)
+{
+	MQTTHeader header = {0};
+	int rc = -1;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 2)
+	{
+		rc = MQTTPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	header.byte = 0;
+	header.bits.type = packettype;
+	writeChar(&ptr, header.byte); /* write header */
+
+	ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer, to avoid overruns
+  * @return serialized length, or error if 0
+  */
+int MQTTSerialize_disconnect(unsigned char* buf, int buflen)
+{
+	return MQTTSerialize_zero(buf, buflen, DISCONNECT);
+}
+
+
+/**
+  * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer, to avoid overruns
+  * @return serialized length, or error if 0
+  */
+int MQTTSerialize_pingreq(unsigned char* buf, int buflen)
+{
+	return MQTTSerialize_zero(buf, buflen, PINGREQ);
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTConnectServer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTConnectServer.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+#include <string.h>
+
+#define min(a, b) ((a < b) ? a : b)
+
+
+/**
+  * Validates MQTT protocol name and version combinations
+  * @param protocol the MQTT protocol name as an MQTTString
+  * @param version the MQTT protocol version number, as in the connect packet
+  * @return correct MQTT combination?  1 is true, 0 is false
+  */
+int MQTTPacket_checkVersion(MQTTString* protocol, int version)
+{
+	int rc = 0;
+
+	if (version == 3 && memcmp(protocol->lenstring.data, "MQIsdp",
+			min(6, protocol->lenstring.len)) == 0)
+		rc = 1;
+	else if (version == 4 && memcmp(protocol->lenstring.data, "MQTT",
+			min(4, protocol->lenstring.len)) == 0)
+		rc = 1;
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into connect data structure
+  * @param data the connect data structure to be filled out
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len)
+{
+	MQTTHeader header = {0};
+	MQTTConnectFlags flags = {0};
+	unsigned char* curdata = buf;
+	unsigned char* enddata = &buf[len];
+	int rc = 0;
+	MQTTString Protocol;
+	int version;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	header.byte = readChar(&curdata);
+	if (header.bits.type != CONNECT)
+		goto exit;
+
+	curdata += MQTTPacket_decodeBuf(curdata, &mylen); /* read remaining length */
+
+	if (!readMQTTLenString(&Protocol, &curdata, enddata) ||
+		enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
+		goto exit;
+
+	version = (int)readChar(&curdata); /* Protocol version */
+	/* If we don't recognize the protocol version, we don't parse the connect packet on the
+	 * basis that we don't know what the format will be.
+	 */
+	if (MQTTPacket_checkVersion(&Protocol, version))
+	{
+		flags.all = readChar(&curdata);
+		data->cleansession = flags.bits.cleansession;
+		data->keepAliveInterval = readInt(&curdata);
+		if (!readMQTTLenString(&data->clientID, &curdata, enddata))
+			goto exit;
+		data->willFlag = flags.bits.will;
+		if (flags.bits.will)
+		{
+			data->will.qos = flags.bits.willQoS;
+			data->will.retained = flags.bits.willRetain;
+			if (!readMQTTLenString(&data->will.topicName, &curdata, enddata) ||
+				  !readMQTTLenString(&data->will.message, &curdata, enddata))
+				goto exit;
+		}
+		if (flags.bits.username)
+		{
+			if (enddata - curdata < 3 || !readMQTTLenString(&data->username, &curdata, enddata))
+				goto exit; /* username flag set, but no username supplied - invalid */
+			if (flags.bits.password &&
+				(enddata - curdata < 3 || !readMQTTLenString(&data->password, &curdata, enddata)))
+				goto exit; /* password flag set, but no password supplied - invalid */
+		}
+		else if (flags.bits.password)
+			goto exit; /* password flag set without username - invalid */
+		rc = 1;
+	}
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes the connack packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param connack_rc the integer connack return code to be used 
+  * @param sessionPresent the MQTT 3.1.1 sessionPresent flag
+  * @return serialized length, or error if 0
+  */
+int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent)
+{
+	MQTTHeader header = {0};
+	int rc = 0;
+	unsigned char *ptr = buf;
+	MQTTConnackFlags flags = {0};
+
+	FUNC_ENTRY;
+	if (buflen < 2)
+	{
+		rc = MQTTPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	header.byte = 0;
+	header.bits.type = CONNACK;
+	writeChar(&ptr, header.byte); /* write header */
+
+	ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
+
+	flags.all = 0;
+	flags.bits.sessionpresent = sessionPresent;
+	writeChar(&ptr, flags.all); 
+	writeChar(&ptr, connack_rc);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTDeserializePublish.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTDeserializePublish.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+#include <string.h>
+
+#define min(a, b) ((a < b) ? 1 : 0)
+
+/**
+  * Deserializes the supplied (wire) buffer into publish data
+  * @param dup returned integer - the MQTT dup flag
+  * @param qos returned integer - the MQTT QoS value
+  * @param retained returned integer - the MQTT retained flag
+  * @param packetid returned integer - the MQTT packet identifier
+  * @param topicName returned MQTTString - the MQTT topic in the publish
+  * @param payload returned byte buffer - the MQTT publish payload
+  * @param payloadlen returned integer - the length of the MQTT payload
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success
+  */
+int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
+		unsigned char** payload, int* payloadlen, unsigned char* buf, int buflen)
+{
+	MQTTHeader header = {0};
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	header.byte = readChar(&curdata);
+	if (header.bits.type != PUBLISH)
+		goto exit;
+	*dup = header.bits.dup;
+	*qos = header.bits.qos;
+	*retained = header.bits.retain;
+
+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+	enddata = curdata + mylen;
+
+	if (!readMQTTLenString(topicName, &curdata, enddata) ||
+		enddata - curdata < 0) {/* do we have enough data to read the protocol version byte? */
+		rc = 0;
+		goto exit;
+	}
+
+	if (*qos > 0)
+		*packetid = readInt(&curdata);
+
+	*payloadlen = enddata - curdata;
+	*payload = curdata;
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+
+/**
+  * Deserializes the supplied (wire) buffer into an ack
+  * @param packettype returned integer - the MQTT packet type
+  * @param dup returned integer - the MQTT dup flag
+  * @param packetid returned integer - the MQTT packet identifier
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen)
+{
+	MQTTHeader header = {0};
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen;
+
+	FUNC_ENTRY;
+	header.byte = readChar(&curdata);
+	*dup = header.bits.dup;
+	*packettype = header.bits.type;
+
+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+	enddata = curdata + mylen;
+
+	if (enddata - curdata < 2)
+		goto exit;
+	*packetid = readInt(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTFormat.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTFormat.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,262 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+
+#include <string.h>
+
+
+const char* MQTTPacket_names[] =
+{
+	"RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL",
+	"PUBCOMP", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK",
+	"PINGREQ", "PINGRESP", "DISCONNECT"
+};
+
+
+const char* MQTTPacket_getName(unsigned short packetid)
+{
+	return MQTTPacket_names[packetid];
+}
+
+
+int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data)
+{
+	int strindex = 0;
+
+	strindex = snprintf(strbuf, strbuflen,
+			"CONNECT MQTT version %d, client id %.*s, clean session %d, keep alive %d",
+			(int)data->MQTTVersion, data->clientID.lenstring.len, data->clientID.lenstring.data,
+			(int)data->cleansession, data->keepAliveInterval);
+	if (data->willFlag)
+		strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
+				", will QoS %d, will retain %d, will topic %.*s, will message %.*s",
+				data->will.qos, data->will.retained,
+				data->will.topicName.lenstring.len, data->will.topicName.lenstring.data,
+				data->will.message.lenstring.len, data->will.message.lenstring.data);
+	if (data->username.lenstring.data && data->username.lenstring.len > 0)
+		strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
+				", user name %.*s", data->username.lenstring.len, data->username.lenstring.data);
+	if (data->password.lenstring.data && data->password.lenstring.len > 0)
+		strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
+				", password %.*s", data->password.lenstring.len, data->password.lenstring.data);
+	return strindex;
+}
+
+
+int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent)
+{
+	int strindex = snprintf(strbuf, strbuflen, "CONNACK session present %d, rc %d", sessionPresent, connack_rc);
+	return strindex;
+}
+
+
+int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
+		unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen)
+{
+	int strindex = snprintf(strbuf, strbuflen,
+				"PUBLISH dup %d, QoS %d, retained %d, packet id %d, topic %.*s, payload length %d, payload %.*s",
+				dup, qos, retained, packetid,
+				(topicName.lenstring.len < 20) ? topicName.lenstring.len : 20, topicName.lenstring.data,
+				payloadlen, (payloadlen < 20) ? payloadlen : 20, payload);
+	return strindex;
+}
+
+
+int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
+{
+	int strindex = snprintf(strbuf, strbuflen, "%s, packet id %d", MQTTPacket_names[packettype], packetid);
+	if (dup)
+		strindex += snprintf(strbuf + strindex, strbuflen - strindex, ", dup %d", dup);
+	return strindex;
+}
+
+
+int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
+		MQTTString topicFilters[], int requestedQoSs[])
+{
+	return snprintf(strbuf, strbuflen,
+		"SUBSCRIBE dup %d, packet id %d count %d topic %.*s qos %d",
+		dup, packetid, count,
+		topicFilters[0].lenstring.len, topicFilters[0].lenstring.data,
+		requestedQoSs[0]);
+}
+
+
+int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs)
+{
+	return snprintf(strbuf, strbuflen,
+		"SUBACK packet id %d count %d granted qos %d", packetid, count, grantedQoSs[0]);
+}
+
+
+int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
+		int count, MQTTString topicFilters[])
+{
+	return snprintf(strbuf, strbuflen,
+					"UNSUBSCRIBE dup %d, packet id %d count %d topic %.*s",
+					dup, packetid, count,
+					topicFilters[0].lenstring.len, topicFilters[0].lenstring.data);
+}
+
+
+#if defined(MQTT_CLIENT)
+char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
+{
+	int index = 0;
+	int rem_length = 0;
+	MQTTHeader header = {0};
+	int strindex = 0;
+
+	header.byte = buf[index++];
+	index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
+
+	switch (header.bits.type)
+	{
+
+	case CONNACK:
+	{
+		unsigned char sessionPresent, connack_rc;
+		if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) == 1)
+			strindex = MQTTStringFormat_connack(strbuf, strbuflen, connack_rc, sessionPresent);
+	}
+	break;
+	case PUBLISH:
+	{
+		unsigned char dup, retained, *payload;
+		unsigned short packetid;
+		int qos, payloadlen;
+		MQTTString topicName = MQTTString_initializer;
+		if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
+				&payload, &payloadlen, buf, buflen) == 1)
+			strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
+					topicName, payload, payloadlen);
+	}
+	break;
+	case PUBACK:
+	case PUBREC:
+	case PUBREL:
+	case PUBCOMP:
+	{
+		unsigned char packettype, dup;
+		unsigned short packetid;
+		if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
+			strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
+	}
+	break;
+	case SUBACK:
+	{
+		unsigned short packetid;
+		int maxcount = 1, count = 0;
+		int grantedQoSs[1];
+		if (MQTTDeserialize_suback(&packetid, maxcount, &count, grantedQoSs, buf, buflen) == 1)
+			strindex = MQTTStringFormat_suback(strbuf, strbuflen, packetid, count, grantedQoSs);
+	}
+	break;
+	case UNSUBACK:
+	{
+		unsigned short packetid;
+		if (MQTTDeserialize_unsuback(&packetid, buf, buflen) == 1)
+			strindex = MQTTStringFormat_ack(strbuf, strbuflen, UNSUBACK, 0, packetid);
+	}
+	break;
+	case PINGREQ:
+	case PINGRESP:
+	case DISCONNECT:
+		strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
+		break;
+	}
+	return strbuf;
+}
+#endif
+
+#if defined(MQTT_SERVER)
+char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
+{
+	int index = 0;
+	int rem_length = 0;
+	MQTTHeader header = {0};
+	int strindex = 0;
+
+	header.byte = buf[index++];
+	index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
+
+	switch (header.bits.type)
+	{
+	case CONNECT:
+	{
+		MQTTPacket_connectData data;
+		int rc;
+		if ((rc = MQTTDeserialize_connect(&data, buf, buflen)) == 1)
+			strindex = MQTTStringFormat_connect(strbuf, strbuflen, &data);
+	}
+	break;
+	case PUBLISH:
+	{
+		unsigned char dup, retained, *payload;
+		unsigned short packetid;
+		int qos, payloadlen;
+		MQTTString topicName = MQTTString_initializer;
+		if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
+				&payload, &payloadlen, buf, buflen) == 1)
+			strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
+					topicName, payload, payloadlen);
+	}
+	break;
+	case PUBACK:
+	case PUBREC:
+	case PUBREL:
+	case PUBCOMP:
+	{
+		unsigned char packettype, dup;
+		unsigned short packetid;
+		if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
+			strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
+	}
+	break;
+	case SUBSCRIBE:
+	{
+		unsigned char dup;
+		unsigned short packetid;
+		int maxcount = 1, count = 0;
+		MQTTString topicFilters[1];
+		int requestedQoSs[1];
+		if (MQTTDeserialize_subscribe(&dup, &packetid, maxcount, &count,
+				topicFilters, requestedQoSs, buf, buflen) == 1)
+			strindex = MQTTStringFormat_subscribe(strbuf, strbuflen, dup, packetid, count, topicFilters, requestedQoSs);;
+	}
+	break;
+	case UNSUBSCRIBE:
+	{
+		unsigned char dup;
+		unsigned short packetid;
+		int maxcount = 1, count = 0;
+		MQTTString topicFilters[1];
+		if (MQTTDeserialize_unsubscribe(&dup, &packetid, maxcount, &count, topicFilters, buf, buflen) == 1)
+			strindex =  MQTTStringFormat_unsubscribe(strbuf, strbuflen, dup, packetid, count, topicFilters);
+	}
+	break;
+	case PINGREQ:
+	case PINGRESP:
+	case DISCONNECT:
+		strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
+		break;
+	}
+	strbuf[strbuflen] = '\0';
+	return strbuf;
+}
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTFormat.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTFormat.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#if !defined(MQTTFORMAT_H)
+#define MQTTFORMAT_H
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+
+const char* MQTTPacket_getName(unsigned short packetid);
+int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data);
+int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent);
+int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
+		unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen);
+int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid);
+int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
+		MQTTString topicFilters[], int requestedQoSs[]);
+int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs);
+int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
+		int count, MQTTString topicFilters[]);
+char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
+char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
+
+#endif
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTPacket.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTPacket.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,410 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - non-blocking packet read functions for stream transport
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+
+#include <string.h>
+
+/**
+ * Encodes the message length according to the MQTT algorithm
+ * @param buf the buffer into which the encoded data is written
+ * @param length the length to be encoded
+ * @return the number of bytes written to buffer
+ */
+int MQTTPacket_encode(unsigned char* buf, int length)
+{
+	int rc = 0;
+
+	FUNC_ENTRY;
+	do
+	{
+		char d = length % 128;
+		length /= 128;
+		/* if there are more digits to encode, set the top bit of this digit */
+		if (length > 0)
+			d |= 0x80;
+		buf[rc++] = d;
+	} while (length > 0);
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+ * Decodes the message length according to the MQTT algorithm
+ * @param getcharfn pointer to function to read the next character from the data source
+ * @param value the decoded length returned
+ * @return the number of bytes read from the socket
+ */
+int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value)
+{
+	unsigned char c;
+	int multiplier = 1;
+	int len = 0;
+#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4
+
+	FUNC_ENTRY;
+	*value = 0;
+	do
+	{
+		int rc = MQTTPACKET_READ_ERROR;
+
+		if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
+		{
+			rc = MQTTPACKET_READ_ERROR;	/* bad data */
+			goto exit;
+		}
+		rc = (*getcharfn)(&c, 1);
+		if (rc != 1)
+			goto exit;
+		*value += (c & 127) * multiplier;
+		multiplier *= 128;
+	} while ((c & 128) != 0);
+exit:
+	FUNC_EXIT_RC(len);
+	return len;
+}
+
+
+int MQTTPacket_len(int rem_len)
+{
+	rem_len += 1; /* header byte */
+
+	/* now remaining_length field */
+	if (rem_len < 128)
+		rem_len += 1;
+	else if (rem_len < 16384)
+		rem_len += 2;
+	else if (rem_len < 2097151)
+		rem_len += 3;
+	else
+		rem_len += 4;
+	return rem_len;
+}
+
+
+static unsigned char* bufptr;
+
+int bufchar(unsigned char* c, int count)
+{
+	int i;
+
+	for (i = 0; i < count; ++i)
+		*c = *bufptr++;
+	return count;
+}
+
+
+int MQTTPacket_decodeBuf(unsigned char* buf, int* value)
+{
+	bufptr = buf;
+	return MQTTPacket_decode(bufchar, value);
+}
+
+/**
+ * Calculates an integer from two bytes read from the input buffer
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the integer value calculated
+ */
+int readInt(unsigned char** pptr)
+{
+	unsigned char* ptr = *pptr;
+	int len = 256*(*ptr) + (*(ptr+1));
+	*pptr += 2;
+	return len;
+}
+
+
+/**
+ * Reads one character from the input buffer.
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the character read
+ */
+char readChar(unsigned char** pptr)
+{
+	char c = **pptr;
+	(*pptr)++;
+	return c;
+}
+
+
+/**
+ * Writes one character to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param c the character to write
+ */
+void writeChar(unsigned char** pptr, char c)
+{
+	**pptr = c;
+	(*pptr)++;
+}
+
+
+/**
+ * Writes an integer as 2 bytes to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param anInt the integer to write
+ */
+void writeInt(unsigned char** pptr, int anInt)
+{
+	**pptr = (unsigned char)(anInt / 256);
+	(*pptr)++;
+	**pptr = (unsigned char)(anInt % 256);
+	(*pptr)++;
+}
+
+
+/**
+ * Writes a "UTF" string to an output buffer.  Converts C string to length-delimited.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param string the C string to write
+ */
+void writeCString(unsigned char** pptr, const char* string)
+{
+	int len = strlen(string);
+	writeInt(pptr, len);
+	memcpy(*pptr, string, len);
+	*pptr += len;
+}
+
+
+int getLenStringLen(char* ptr)
+{
+	int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
+	return len;
+}
+
+void writeMQTTString(unsigned char** pptr, MQTTString mqttstring)
+{
+	if (mqttstring.lenstring.len > 0)
+	{
+		writeInt(pptr, mqttstring.lenstring.len);
+		memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len);
+		*pptr += mqttstring.lenstring.len;
+	}
+	else if (mqttstring.cstring)
+		writeCString(pptr, mqttstring.cstring);
+	else
+		writeInt(pptr, 0);
+}
+
+
+/**
+ * @param mqttstring the MQTTString structure into which the data is to be read
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param enddata pointer to the end of the data: do not read beyond
+ * @return 1 if successful, 0 if not
+ */
+int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata)
+{
+	int rc = 0;
+
+	FUNC_ENTRY;
+	/* the first two bytes are the length of the string */
+	if (enddata - (*pptr) > 1) /* enough length to read the integer? */
+	{
+		mqttstring->lenstring.len = readInt(pptr); /* increments pptr to point past length */
+		if (&(*pptr)[mqttstring->lenstring.len] <= enddata)
+		{
+			mqttstring->lenstring.data = (char*)*pptr;
+			*pptr += mqttstring->lenstring.len;
+			rc = 1;
+		}
+	}
+	mqttstring->cstring = NULL;
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+ * Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string
+ * @param mqttstring the string to return the length of
+ * @return the length of the string
+ */
+int MQTTstrlen(MQTTString mqttstring)
+{
+	int rc = 0;
+
+	if (mqttstring.cstring)
+		rc = strlen(mqttstring.cstring);
+	else
+		rc = mqttstring.lenstring.len;
+	return rc;
+}
+
+
+/**
+ * Compares an MQTTString to a C string
+ * @param a the MQTTString to compare
+ * @param bptr the C string to compare
+ * @return boolean - equal or not
+ */
+int MQTTPacket_equals(MQTTString* a, char* bptr)
+{
+	int alen = 0,
+		blen = 0;
+	char *aptr;
+	
+	if (a->cstring)
+	{
+		aptr = a->cstring;
+		alen = strlen(a->cstring);
+	}
+	else
+	{
+		aptr = a->lenstring.data;
+		alen = a->lenstring.len;
+	}
+	blen = strlen(bptr);
+	
+	return (alen == blen) && (strncmp(aptr, bptr, alen) == 0);
+}
+
+
+/**
+ * Helper function to read packet data from some source into a buffer
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param getfn pointer to a function which will read any number of bytes from the needed source
+ * @return integer MQTT packet type, or -1 on error
+ * @note  the whole message must fit into the caller's buffer
+ */
+int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int))
+{
+	int rc = -1;
+	MQTTHeader header = {0};
+	int len = 0;
+	int rem_len = 0;
+
+	/* 1. read the header byte.  This has the packet type in it */
+	if ((*getfn)(buf, 1) != 1)
+		goto exit;
+
+	len = 1;
+	/* 2. read the remaining length.  This is variable in itself */
+	MQTTPacket_decode(getfn, &rem_len);
+	len += MQTTPacket_encode(buf + 1, rem_len); /* put the original remaining length back into the buffer */
+
+	/* 3. read the rest of the buffer using a callback to supply the rest of the data */
+	if((rem_len + len) > buflen)
+		goto exit;
+	if (rem_len && ((*getfn)(buf + len, rem_len) != rem_len))
+		goto exit;
+
+	header.byte = buf[0];
+	rc = header.bits.type;
+exit:
+	return rc;
+}
+
+/**
+ * Decodes the message length according to the MQTT algorithm, non-blocking
+ * @param trp pointer to a transport structure holding what is needed to solve getting data from it
+ * @param value the decoded length returned
+ * @return integer the number of bytes read from the socket, 0 for call again, or -1 on error
+ */
+static int MQTTPacket_decodenb(MQTTTransport *trp)
+{
+	unsigned char c;
+	int rc = MQTTPACKET_READ_ERROR;
+
+	FUNC_ENTRY;
+	if(trp->len == 0){		/* initialize on first call */
+		trp->multiplier = 1;
+		trp->rem_len = 0;
+	}
+	do {
+		int frc;
+		if (trp->len >= MAX_NO_OF_REMAINING_LENGTH_BYTES)
+			goto exit;
+		if ((frc=(*trp->getfn)(trp->sck, &c, 1)) == -1)
+			goto exit;
+		if (frc == 0){
+			rc = 0;
+			goto exit;
+		}
+		++(trp->len);
+		trp->rem_len += (c & 127) * trp->multiplier;
+		trp->multiplier *= 128;
+	} while ((c & 128) != 0);
+	rc = trp->len;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+/**
+ * Helper function to read packet data from some source into a buffer, non-blocking
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param trp pointer to a transport structure holding what is needed to solve getting data from it
+ * @return integer MQTT packet type, 0 for call again, or -1 on error
+ * @note  the whole message must fit into the caller's buffer
+ */
+int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp)
+{
+	int rc = -1, frc;
+	MQTTHeader header = {0};
+
+	switch(trp->state){
+	default:
+		trp->state = 0;
+		/*FALLTHROUGH*/
+	case 0:
+		/* read the header byte.  This has the packet type in it */
+		if ((frc=(*trp->getfn)(trp->sck, buf, 1)) == -1)
+			goto exit;
+		if (frc == 0)
+			return 0;
+		trp->len = 0;
+		++trp->state;
+		/*FALLTHROUGH*/
+		/* read the remaining length.  This is variable in itself */
+	case 1:
+		if((frc=MQTTPacket_decodenb(trp)) == MQTTPACKET_READ_ERROR)
+			goto exit;
+		if(frc == 0)
+			return 0;
+		trp->len = 1 + MQTTPacket_encode(buf + 1, trp->rem_len); /* put the original remaining length back into the buffer */
+		if((trp->rem_len + trp->len) > buflen)
+			goto exit;
+		++trp->state;
+		/*FALLTHROUGH*/
+	case 2:
+		if(trp->rem_len){
+			/* read the rest of the buffer using a callback to supply the rest of the data */
+			if ((frc=(*trp->getfn)(trp->sck, buf + trp->len, trp->rem_len)) == -1)
+				goto exit;
+			if (frc == 0)
+				return 0;
+			trp->rem_len -= frc;
+			trp->len += frc;
+			if(trp->rem_len)
+				return 0;
+		}
+		header.byte = buf[0];
+		rc = header.bits.type;
+		break;
+	}
+
+exit:
+	trp->state = 0;
+	return rc;
+}
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTPacket.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTPacket.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTPACKET_H_
+#define MQTTPACKET_H_
+
+#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
+extern "C" {
+#endif
+
+#if defined(WIN32_DLL) || defined(WIN64_DLL)
+  #define DLLImport __declspec(dllimport)
+  #define DLLExport __declspec(dllexport)
+#elif defined(LINUX_SO)
+  #define DLLImport extern
+  #define DLLExport  __attribute__ ((visibility ("default")))
+#else
+  #define DLLImport
+  #define DLLExport  
+#endif
+
+enum errorsMqtt
+{
+	MQTTPACKET_BUFFER_TOO_SHORT = -2,
+	MQTTPACKET_READ_ERROR = -1,
+	MQTTPACKET_READ_COMPLETE
+};
+
+enum msgTypes
+{
+	CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL,
+	PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK,
+	PINGREQ, PINGRESP, DISCONNECT
+};
+
+/**
+ * Bitfields for the MQTT header byte.
+ */
+typedef union
+{
+	unsigned char byte;	                /**< the whole byte */
+#if defined(REVERSED)
+	struct
+	{
+		unsigned int type : 4;			/**< message type nibble */
+		unsigned int dup : 1;				/**< DUP flag bit */
+		unsigned int qos : 2;				/**< QoS value, 0, 1 or 2 */
+		unsigned int retain : 1;		/**< retained flag bit */
+	} bits;
+#else
+	struct
+	{
+		unsigned int retain : 1;		/**< retained flag bit */
+		unsigned int qos : 2;				/**< QoS value, 0, 1 or 2 */
+		unsigned int dup : 1;				/**< DUP flag bit */
+		unsigned int type : 4;			/**< message type nibble */
+	} bits;
+#endif
+} MQTTHeader;
+
+typedef struct
+{
+	int len;
+	char* data;
+} MQTTLenString;
+
+typedef struct
+{
+	char* cstring;
+	MQTTLenString lenstring;
+} MQTTString;
+
+#define MQTTString_initializer {NULL, {0, NULL}}
+
+int MQTTstrlen(MQTTString mqttstring);
+
+#include "MQTTConnect.h"
+#include "MQTTPublish.h"
+#include "MQTTSubscribe.h"
+#include "MQTTUnsubscribe.h"
+#include "MQTTFormat.h"
+
+DLLExport int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char type, unsigned char dup, unsigned short packetid);
+DLLExport int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen);
+
+int MQTTPacket_len(int rem_len);
+DLLExport int MQTTPacket_equals(MQTTString* a, char* b);
+
+DLLExport int MQTTPacket_encode(unsigned char* buf, int length);
+int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value);
+int MQTTPacket_decodeBuf(unsigned char* buf, int* value);
+
+int readInt(unsigned char** pptr);
+char readChar(unsigned char** pptr);
+void writeChar(unsigned char** pptr, char c);
+void writeInt(unsigned char** pptr, int anInt);
+int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata);
+void writeCString(unsigned char** pptr, const char* string);
+void writeMQTTString(unsigned char** pptr, MQTTString mqttstring);
+
+DLLExport int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int));
+
+typedef struct {
+	int (*getfn)(void *, unsigned char*, int); /* must return -1 for error, 0 for call again, or the number of bytes read */
+	void *sck;	/* pointer to whatever the system may use to identify the transport */
+	int multiplier;
+	int rem_len;
+	int len;
+	char state;
+}MQTTTransport;
+
+int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp);
+
+#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
+}
+#endif
+
+
+#endif /* MQTTPACKET_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTPublish.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTPublish.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTPUBLISH_H_
+#define MQTTPUBLISH_H_
+
+#if !defined(DLLImport)
+  #define DLLImport 
+#endif
+#if !defined(DLLExport)
+  #define DLLExport
+#endif
+
+DLLExport int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
+		MQTTString topicName, unsigned char* payload, int payloadlen);
+
+DLLExport int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
+		unsigned char** payload, int* payloadlen, unsigned char* buf, int len);
+
+DLLExport int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid);
+DLLExport int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid);
+DLLExport int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid);
+
+#endif /* MQTTPUBLISH_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTSerializePublish.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTSerializePublish.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Ian Craggs - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=453144
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+
+/**
+  * Determines the length of the MQTT publish packet that would be produced using the supplied parameters
+  * @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0)
+  * @param topicName the topic name to be used in the publish  
+  * @param payloadlen the length of the payload to be sent
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int MQTTSerialize_publishLength(int qos, MQTTString topicName, int payloadlen)
+{
+	int len = 0;
+
+	len += 2 + MQTTstrlen(topicName) + payloadlen;
+	if (qos > 0)
+		len += 2; /* packetid */
+	return len;
+}
+
+
+/**
+  * Serializes the supplied publish data into the supplied buffer, ready for sending
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param dup integer - the MQTT dup flag
+  * @param qos integer - the MQTT QoS value
+  * @param retained integer - the MQTT retained flag
+  * @param packetid integer - the MQTT packet identifier
+  * @param topicName MQTTString - the MQTT topic in the publish
+  * @param payload byte buffer - the MQTT publish payload
+  * @param payloadlen integer - the length of the MQTT payload
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
+		MQTTString topicName, unsigned char* payload, int payloadlen)
+{
+	unsigned char *ptr = buf;
+	MQTTHeader header = {0};
+	int rem_len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if (MQTTPacket_len(rem_len = MQTTSerialize_publishLength(qos, topicName, payloadlen)) > buflen)
+	{
+		rc = MQTTPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	header.bits.type = PUBLISH;
+	header.bits.dup = dup;
+	header.bits.qos = qos;
+	header.bits.retain = retained;
+	writeChar(&ptr, header.byte); /* write header */
+
+	ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
+
+	writeMQTTString(&ptr, topicName);
+
+	if (qos > 0)
+		writeInt(&ptr, packetid);
+
+	memcpy(ptr, payload, payloadlen);
+	ptr += payloadlen;
+
+	rc = ptr - buf;
+
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+
+/**
+  * Serializes the ack packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param type the MQTT packet type
+  * @param dup the MQTT dup flag
+  * @param packetid the MQTT packet identifier
+  * @return serialized length, or error if 0
+  */
+int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
+{
+	MQTTHeader header = {0};
+	int rc = 0;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 4)
+	{
+		rc = MQTTPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	header.bits.type = packettype;
+	header.bits.dup = dup;
+	header.bits.qos = (packettype == PUBREL) ? 1 : 0;
+	writeChar(&ptr, header.byte); /* write header */
+
+	ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
+	writeInt(&ptr, packetid);
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a puback packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param packetid integer - the MQTT packet identifier
+  * @return serialized length, or error if 0
+  */
+int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid)
+{
+	return MQTTSerialize_ack(buf, buflen, PUBACK, 0, packetid);
+}
+
+
+/**
+  * Serializes a pubrel packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param dup integer - the MQTT dup flag
+  * @param packetid integer - the MQTT packet identifier
+  * @return serialized length, or error if 0
+  */
+int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid)
+{
+	return MQTTSerialize_ack(buf, buflen, PUBREL, dup, packetid);
+}
+
+
+/**
+  * Serializes a pubrel packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param packetid integer - the MQTT packet identifier
+  * @return serialized length, or error if 0
+  */
+int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid)
+{
+	return MQTTSerialize_ack(buf, buflen, PUBCOMP, 0, packetid);
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTSubscribe.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTSubscribe.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTSUBSCRIBE_H_
+#define MQTTSUBSCRIBE_H_
+
+#if !defined(DLLImport)
+  #define DLLImport 
+#endif
+#if !defined(DLLExport)
+  #define DLLExport
+#endif
+
+DLLExport int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
+		int count, MQTTString topicFilters[], int requestedQoSs[]);
+
+DLLExport int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid,
+		int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], unsigned char* buf, int len);
+
+DLLExport int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs);
+
+DLLExport int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int len);
+
+
+#endif /* MQTTSUBSCRIBE_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTSubscribeClient.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTSubscribeClient.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+  * Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters
+  * @param count the number of topic filter strings in topicFilters
+  * @param topicFilters the array of topic filter strings to be used in the publish
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[])
+{
+	int i;
+	int len = 2; /* packetid */
+
+	for (i = 0; i < count; ++i)
+		len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */
+	return len;
+}
+
+
+/**
+  * Serializes the supplied subscribe data into the supplied buffer, ready for sending
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied bufferr
+  * @param dup integer - the MQTT dup flag
+  * @param packetid integer - the MQTT packet identifier
+  * @param count - number of members in the topicFilters and reqQos arrays
+  * @param topicFilters - array of topic filter names
+  * @param requestedQoSs - array of requested QoS
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, int count,
+		MQTTString topicFilters[], int requestedQoSs[])
+{
+	unsigned char *ptr = buf;
+	MQTTHeader header = {0};
+	int rem_len = 0;
+	int rc = 0;
+	int i = 0;
+
+	FUNC_ENTRY;
+	if (MQTTPacket_len(rem_len = MQTTSerialize_subscribeLength(count, topicFilters)) > buflen)
+	{
+		rc = MQTTPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	header.byte = 0;
+	header.bits.type = SUBSCRIBE;
+	header.bits.dup = dup;
+	header.bits.qos = 1;
+	writeChar(&ptr, header.byte); /* write header */
+
+	ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
+
+	writeInt(&ptr, packetid);
+
+	for (i = 0; i < count; ++i)
+	{
+		writeMQTTString(&ptr, topicFilters[i]);
+		writeChar(&ptr, requestedQoSs[i]);
+	}
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+
+/**
+  * Deserializes the supplied (wire) buffer into suback data
+  * @param packetid returned integer - the MQTT packet identifier
+  * @param maxcount - the maximum number of members allowed in the grantedQoSs array
+  * @param count returned integer - number of members in the grantedQoSs array
+  * @param grantedQoSs returned array of integers - the granted qualities of service
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int buflen)
+{
+	MQTTHeader header = {0};
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen;
+
+	FUNC_ENTRY;
+	header.byte = readChar(&curdata);
+	if (header.bits.type != SUBACK)
+		goto exit;
+
+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+	enddata = curdata + mylen;
+	if (enddata - curdata < 2)
+		goto exit;
+
+	*packetid = readInt(&curdata);
+
+	*count = 0;
+	while (curdata < enddata)
+	{
+		if (*count > maxcount)
+		{
+			rc = -1;
+			goto exit;
+		}
+		grantedQoSs[(*count)++] = readChar(&curdata);
+	}
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTSubscribeServer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTSubscribeServer.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+
+/**
+  * Deserializes the supplied (wire) buffer into subscribe data
+  * @param dup integer returned - the MQTT dup flag
+  * @param packetid integer returned - the MQTT packet identifier
+  * @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
+  * @param count - number of members in the topicFilters and requestedQoSs arrays
+  * @param topicFilters - array of topic filter names
+  * @param requestedQoSs - array of requested QoS
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
+	int requestedQoSs[], unsigned char* buf, int buflen)
+{
+	MQTTHeader header = {0};
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = -1;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	header.byte = readChar(&curdata);
+	if (header.bits.type != SUBSCRIBE)
+		goto exit;
+	*dup = header.bits.dup;
+
+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+	enddata = curdata + mylen;
+
+	*packetid = readInt(&curdata);
+
+	*count = 0;
+	while (curdata < enddata)
+	{
+		if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
+			goto exit;
+		if (curdata >= enddata) /* do we have enough data to read the req_qos version byte? */
+			goto exit;
+		requestedQoSs[*count] = readChar(&curdata);
+		(*count)++;
+	}
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes the supplied suback data into the supplied buffer, ready for sending
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param packetid integer - the MQTT packet identifier
+  * @param count - number of members in the grantedQoSs array
+  * @param grantedQoSs - array of granted QoS
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs)
+{
+	MQTTHeader header = {0};
+	int rc = -1;
+	unsigned char *ptr = buf;
+	int i;
+
+	FUNC_ENTRY;
+	if (buflen < 2 + count)
+	{
+		rc = MQTTPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	header.byte = 0;
+	header.bits.type = SUBACK;
+	writeChar(&ptr, header.byte); /* write header */
+
+	ptr += MQTTPacket_encode(ptr, 2 + count); /* write remaining length */
+
+	writeInt(&ptr, packetid);
+
+	for (i = 0; i < count; ++i)
+		writeChar(&ptr, grantedQoSs[i]);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTUnsubscribe.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTUnsubscribe.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTUNSUBSCRIBE_H_
+#define MQTTUNSUBSCRIBE_H_
+
+#if !defined(DLLImport)
+  #define DLLImport 
+#endif
+#if !defined(DLLExport)
+  #define DLLExport
+#endif
+
+DLLExport int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
+		int count, MQTTString topicFilters[]);
+
+DLLExport int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int max_count, int* count, MQTTString topicFilters[],
+		unsigned char* buf, int len);
+
+DLLExport int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid);
+
+DLLExport int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int len);
+
+#endif /* MQTTUNSUBSCRIBE_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTUnsubscribeClient.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTUnsubscribeClient.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+  * Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters
+  * @param count the number of topic filter strings in topicFilters
+  * @param topicFilters the array of topic filter strings to be used in the publish
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[])
+{
+	int i;
+	int len = 2; /* packetid */
+
+	for (i = 0; i < count; ++i)
+		len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/
+	return len;
+}
+
+
+/**
+  * Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @param dup integer - the MQTT dup flag
+  * @param packetid integer - the MQTT packet identifier
+  * @param count - number of members in the topicFilters array
+  * @param topicFilters - array of topic filter names
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
+		int count, MQTTString topicFilters[])
+{
+	unsigned char *ptr = buf;
+	MQTTHeader header = {0};
+	int rem_len = 0;
+	int rc = -1;
+	int i = 0;
+
+	FUNC_ENTRY;
+	if (MQTTPacket_len(rem_len = MQTTSerialize_unsubscribeLength(count, topicFilters)) > buflen)
+	{
+		rc = MQTTPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	header.byte = 0;
+	header.bits.type = UNSUBSCRIBE;
+	header.bits.dup = dup;
+	header.bits.qos = 1;
+	writeChar(&ptr, header.byte); /* write header */
+
+	ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
+
+	writeInt(&ptr, packetid);
+
+	for (i = 0; i < count; ++i)
+		writeMQTTString(&ptr, topicFilters[i]);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into unsuback data
+  * @param packetid returned integer - the MQTT packet identifier
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int buflen)
+{
+	unsigned char type = 0;
+	unsigned char dup = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	rc = MQTTDeserialize_ack(&type, &dup, packetid, buf, buflen);
+	if (type == UNSUBACK)
+		rc = 1;
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTUnsubscribeServer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/MQTTUnsubscribeServer.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+
+/**
+  * Deserializes the supplied (wire) buffer into unsubscribe data
+  * @param dup integer returned - the MQTT dup flag
+  * @param packetid integer returned - the MQTT packet identifier
+  * @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
+  * @param count - number of members in the topicFilters and requestedQoSs arrays
+  * @param topicFilters - array of topic filter names
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
+		unsigned char* buf, int len)
+{
+	MQTTHeader header = {0};
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	header.byte = readChar(&curdata);
+	if (header.bits.type != UNSUBSCRIBE)
+		goto exit;
+	*dup = header.bits.dup;
+
+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+	enddata = curdata + mylen;
+
+	*packetid = readInt(&curdata);
+
+	*count = 0;
+	while (curdata < enddata)
+	{
+		if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
+			goto exit;
+		(*count)++;
+	}
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes the supplied unsuback data into the supplied buffer, ready for sending
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param packetid integer - the MQTT packet identifier
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid)
+{
+	MQTTHeader header = {0};
+	int rc = 0;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 2)
+	{
+		rc = MQTTPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	header.byte = 0;
+	header.bits.type = UNSUBACK;
+	writeChar(&ptr, header.byte); /* write header */
+
+	ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
+
+	writeInt(&ptr, packetid);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/StackTrace.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/src/StackTrace.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Ian Craggs - fix for bug #434081
+ *******************************************************************************/
+
+#ifndef STACKTRACE_H_
+#define STACKTRACE_H_
+
+#include <stdio.h>
+#define NOSTACKTRACE 1
+
+#if defined(NOSTACKTRACE)
+#define FUNC_ENTRY
+#define FUNC_ENTRY_NOLOG
+#define FUNC_ENTRY_MED
+#define FUNC_ENTRY_MAX
+#define FUNC_EXIT
+#define FUNC_EXIT_NOLOG
+#define FUNC_EXIT_MED
+#define FUNC_EXIT_MAX
+#define FUNC_EXIT_RC(x)
+#define FUNC_EXIT_MED_RC(x)
+#define FUNC_EXIT_MAX_RC(x)
+
+#else
+
+#if defined(WIN32)
+#define inline __inline
+#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM)
+#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1)
+#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM)
+#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM)
+#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM)
+#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1)
+#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM)
+#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM)
+#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM)
+#else
+#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM)
+#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1)
+#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM)
+#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM)
+#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM)
+#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1)
+#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM)
+#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM)
+#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM)
+
+void StackTrace_entry(const char* name, int line, int trace);
+void StackTrace_exit(const char* name, int line, void* return_value, int trace);
+
+void StackTrace_printStack(FILE* dest);
+char* StackTrace_get(unsigned long);
+
+#endif
+
+#endif
+
+
+
+
+#endif /* STACKTRACE_H_ */
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/test/CMakeLists.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/test/CMakeLists.txt	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,35 @@
+PROJECT(mqttpacket-tests)
+
+IF (WIN32)
+  SET(MQTT_TEST_BROKER "tcp://mqtt.iotree.co.uk:1883" CACHE STRING "Hostname of a test MQTT broker to use")
+  SET(MQTT_TEST_PROXY "tcp://localhost:1883" CACHE STRING "Hostname of the test proxy to use")
+  SET(MQTT_SSL_HOSTNAME "mqtt.iotree.co.uk" CACHE STRING "Hostname of a test SSL MQTT broker to use")
+  SET(CERTDIR $ENV{APPVEYOR_BUILD_FOLDER}/test/ssl)
+ELSE ()
+  SET(MQTT_TEST_BROKER "tcp://localhost:1883" CACHE STRING "Hostname of a test MQTT broker to use")
+  SET(MQTT_TEST_PROXY "tcp://localhost:1884" CACHE STRING "Hostname of the test proxy to use")
+  SET(MQTT_SSL_HOSTNAME "localhost" CACHE STRING "Hostname of a test SSL MQTT broker to use")
+  SET(CERTDIR $ENV{TRAVIS_BUILD_DIR}/test/ssl)
+ENDIF ()
+
+include_directories(../src)
+
+ADD_EXECUTABLE(
+	test1
+	test1.c
+)
+
+TARGET_LINK_LIBRARIES(
+	test1
+	paho-embed-mqtt3c
+)
+
+ADD_TEST(
+	NAME test1
+	COMMAND "test1" "--connection" ${MQTT_TEST_BROKER}
+)
+
+SET_TESTS_PROPERTIES(
+	test1
+	PROPERTIES TIMEOUT 540
+)
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/test/build_test
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/test/build_test	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,1 @@
+gcc -Wall test1.c -o test1 -I../src ../src/MQTTConnectClient.c ../src/MQTTConnectServer.c ../src/MQTTPacket.c ../src/MQTTSerializePublish.c  ../src/MQTTDeserializePublish.c ../src/MQTTSubscribeServer.c ../src/MQTTSubscribeClient.c ../src/MQTTUnsubscribeServer.c ../src/MQTTUnsubscribeClient.c
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/test/test1.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/MQTTPacket/test/test1.c	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,635 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+
+#include "MQTTPacket.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#if !defined(_WINDOWS)
+	#include <sys/time.h>
+  	#include <sys/socket.h>
+	#include <unistd.h>
+  	#include <errno.h>
+#else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define MAXHOSTNAMELEN 256
+#define EAGAIN WSAEWOULDBLOCK
+#define EINTR WSAEINTR
+#define EINPROGRESS WSAEINPROGRESS
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define ENOTCONN WSAENOTCONN
+#define ECONNRESET WSAECONNRESET
+#endif
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+struct Options
+{
+	char* connection;         /**< connection to system under test. */
+	char** haconnections;
+	int hacount;
+	int verbose;
+	int test_no;
+} options =
+{
+	"tcp://m2m.eclipse.org:1883",
+	NULL,
+	0,
+	0,
+	0,
+};
+
+void usage()
+{
+
+}
+
+void getopts(int argc, char** argv)
+{
+	int count = 1;
+
+	while (count < argc)
+	{
+		if (strcmp(argv[count], "--test_no") == 0)
+		{
+			if (++count < argc)
+				options.test_no = atoi(argv[count]);
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--connection") == 0)
+		{
+			if (++count < argc)
+			{
+				options.connection = argv[count];
+				printf("\nSetting connection to %s\n", options.connection);
+			}
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--haconnections") == 0)
+		{
+			if (++count < argc)
+			{
+				char* tok = strtok(argv[count], " ");
+				options.hacount = 0;
+				options.haconnections = malloc(sizeof(char*) * 5);
+				while (tok)
+				{
+					options.haconnections[options.hacount] = malloc(strlen(tok) + 1);
+					strcpy(options.haconnections[options.hacount], tok);
+					options.hacount++;
+					tok = strtok(NULL, " ");
+				}
+			}
+			else
+				usage();
+		}
+		else if (strcmp(argv[count], "--verbose") == 0)
+		{
+			options.verbose = 1;
+			printf("\nSetting verbose on\n");
+		}
+		count++;
+	}
+}
+
+
+#define LOGA_DEBUG 0
+#define LOGA_INFO 1
+#include <stdarg.h>
+#include <time.h>
+#include <sys/timeb.h>
+void MyLog(int LOGA_level, char* format, ...)
+{
+	static char msg_buf[256];
+	va_list args;
+	struct timeb ts;
+
+	struct tm *timeinfo;
+
+	if (LOGA_level == LOGA_DEBUG && options.verbose == 0)
+	  return;
+
+	ftime(&ts);
+	timeinfo = localtime(&ts.time);
+	strftime(msg_buf, 80, "%Y%m%d %H%M%S", timeinfo);
+
+	sprintf(&msg_buf[strlen(msg_buf)], ".%.3hu ", ts.millitm);
+
+	va_start(args, format);
+	vsnprintf(&msg_buf[strlen(msg_buf)], sizeof(msg_buf) - strlen(msg_buf), format, args);
+	va_end(args);
+
+	printf("%s\n", msg_buf);
+	fflush(stdout);
+}
+
+
+#if defined(WIN32) || defined(_WINDOWS)
+#define mqsleep(A) Sleep(1000*A)
+#define START_TIME_TYPE DWORD
+static DWORD start_time = 0;
+START_TIME_TYPE start_clock(void)
+{
+	return GetTickCount();
+}
+#elif defined(AIX)
+#define mqsleep sleep
+#define START_TIME_TYPE struct timespec
+START_TIME_TYPE start_clock(void)
+{
+	static struct timespec start;
+	clock_gettime(CLOCK_REALTIME, &start);
+	return start;
+}
+#else
+#define mqsleep sleep
+#define START_TIME_TYPE struct timeval
+/* TODO - unused - remove? static struct timeval start_time; */
+START_TIME_TYPE start_clock(void)
+{
+	struct timeval start_time;
+	gettimeofday(&start_time, NULL);
+	return start_time;
+}
+#endif
+
+
+#if defined(WIN32)
+long elapsed(START_TIME_TYPE start_time)
+{
+	return GetTickCount() - start_time;
+}
+#elif defined(AIX)
+#define assert(a)
+long elapsed(struct timespec start)
+{
+	struct timespec now, res;
+
+	clock_gettime(CLOCK_REALTIME, &now);
+	ntimersub(now, start, res);
+	return (res.tv_sec)*1000L + (res.tv_nsec)/1000000L;
+}
+#else
+long elapsed(START_TIME_TYPE start_time)
+{
+	struct timeval now, res;
+
+	gettimeofday(&now, NULL);
+	timersub(&now, &start_time, &res);
+	return (res.tv_sec)*1000 + (res.tv_usec)/1000;
+}
+#endif
+
+
+#define assert(a, b, c, d) myassert(__FILE__, __LINE__, a, b, c, d)
+#define assert1(a, b, c, d, e) myassert(__FILE__, __LINE__, a, b, c, d, e)
+
+int tests = 0;
+int failures = 0;
+FILE* xml;
+START_TIME_TYPE global_start_time;
+char output[3000];
+char* cur_output = output;
+
+
+void write_test_result()
+{
+	long duration = elapsed(global_start_time);
+
+	fprintf(xml, " time=\"%ld.%.3ld\" >\n", duration / 1000, duration % 1000);
+	if (cur_output != output)
+	{
+		fprintf(xml, "%s", output);
+		cur_output = output;
+	}
+	fprintf(xml, "</testcase>\n");
+}
+
+
+void myassert(char* filename, int lineno, char* description, int value, char* format, ...)
+{
+	++tests;
+	if (!value)
+	{
+		va_list args;
+
+		++failures;
+		printf("Assertion failed, file %s, line %d, description: %s\n", filename, lineno, description);
+
+		va_start(args, format);
+		vprintf(format, args);
+		va_end(args);
+
+		cur_output += sprintf(cur_output, "<failure type=\"%s\">file %s, line %d </failure>\n",
+                        description, filename, lineno);
+	}
+    else
+    	MyLog(LOGA_DEBUG, "Assertion succeeded, file %s, line %d, description: %s", filename, lineno, description);
+}
+
+#define min(a, b) ((a < b) ? a : b)
+
+int checkMQTTStrings(MQTTString a, MQTTString b)
+{
+	if (!a.lenstring.data)
+	{
+		a.lenstring.data = a.cstring;
+		if (a.cstring)
+			a.lenstring.len = strlen(a.cstring);
+	}
+	if (!b.lenstring.data)
+	{
+		b.lenstring.data = b.cstring;
+		if (b.cstring)
+			b.lenstring.len = strlen(b.cstring);
+	}
+	return memcmp(a.lenstring.data, b.lenstring.data, min(a.lenstring.len, b.lenstring.len)) == 0;
+}
+
+
+int checkConnectPackets(MQTTPacket_connectData* before, MQTTPacket_connectData* after)
+{
+	int rc = 0;
+	int start_failures = failures;
+
+	assert("struct_ids should be the same",
+			memcmp(before->struct_id, after->struct_id, 4) == 0, "struct_ids were different %.4s\n", after->struct_id);
+
+	assert("struct_versions should be the same",
+			before->struct_version == after->struct_version, "struct_versions were different\n", rc);
+
+	assert("MQTT versions should be the same",
+			before->MQTTVersion == after->MQTTVersion, "MQTT versions were different\n", rc);
+
+	assert("ClientIDs should be the same",
+			checkMQTTStrings(before->clientID, after->clientID), "ClientIDs were different\n", rc);
+
+	assert("keepAliveIntervals should be the same",
+			before->keepAliveInterval == after->keepAliveInterval, "keepAliveIntervals were different %d\n", after->keepAliveInterval);
+
+	assert("cleansessions should be the same",
+			before->cleansession == after->cleansession, "cleansessions were different\n", rc);
+
+	assert("willFlags should be the same",
+				before->willFlag == after->willFlag, "willFlags were different\n", rc);
+
+	if (before->willFlag)
+	{
+		assert("will struct_ids should be the same",
+				memcmp(before->will.struct_id, after->will.struct_id, 4) == 0, "will struct_ids were different %.4s\n", after->struct_id);
+
+		assert("will struct_versions should be the same",
+				before->will.struct_version == after->will.struct_version, "will struct_versions were different\n", rc);
+
+		assert("topic names should be the same",
+				checkMQTTStrings(before->will.topicName, after->will.topicName), "topic names were different\n", rc);
+
+		assert("messages should be the same",
+				checkMQTTStrings(before->will.message, after->will.message), "messages were different\n", rc);
+
+		assert("retained flags should be the same",
+					before->will.retained == after->will.retained, "retained flags were different\n", rc);
+
+		assert("will qos should be the same",
+					before->will.qos == after->will.qos, "will qos were different\n", rc);
+	}
+
+	assert("usernames should be the same",
+			checkMQTTStrings(before->clientID, after->clientID), "usernames were different\n", rc);
+	assert("passwords should be the same",
+			checkMQTTStrings(before->password, after->password), "passwords were different\n", rc);
+	return failures == start_failures;
+}
+
+int test1(struct Options options)
+{
+	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+	MQTTPacket_connectData data_after = MQTTPacket_connectData_initializer;
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+
+	fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 1 - serialization of connect and back");
+
+	data.clientID.cstring = "me";
+
+	data.keepAliveInterval = 20;
+	data.cleansession = 1;
+	data.username.cstring = "testuser";
+	data.password.cstring = "testpassword";
+
+	data.willFlag = 1;
+	data.will.message.cstring = "will message";
+	data.will.qos = 1;
+	data.will.retained = 0;
+	data.will.topicName.cstring = "will topic";
+
+	rc = MQTTSerialize_connect(buf, buflen, &data);
+	assert("good rc from serialize connect", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTDeserialize_connect(&data_after, buf, buflen);
+	assert("good rc from deserialize connect", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	rc = checkConnectPackets(&data, &data_after);
+	assert("packets should be the same",  rc == 1, "packets were different\n", rc);
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST1: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test2(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+
+	unsigned char dup = 0;
+	int qos = 2;
+	unsigned char retained = 0;
+	unsigned short msgid = 23;
+	MQTTString topicString = MQTTString_initializer;
+	unsigned char *payload = (unsigned char*)"kkhkhkjkj jkjjk jk jk ";
+	int payloadlen = strlen((char*)payload);
+
+	unsigned char dup2 = 1;
+	int qos2 = 1;
+	unsigned char retained2 = 1;
+	unsigned short msgid2 = 3243;
+	MQTTString topicString2 = MQTTString_initializer;
+	unsigned char *payload2 = NULL;
+	int payloadlen2 = 0;
+
+	fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 2 - serialization of publish and back");
+
+	topicString.cstring = "mytopic";
+	rc = MQTTSerialize_publish(buf, buflen, dup, qos, retained, msgid, topicString,
+			payload, payloadlen);
+	assert("good rc from serialize publish", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTDeserialize_publish(&dup2, &qos2, &retained2, &msgid2, &topicString2,
+			&payload2, &payloadlen2, buf, buflen);
+	assert("good rc from deserialize publish", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2);
+	assert("qoss should be the same", qos == qos2, "qoss were different %d\n", qos2);
+	assert("retaineds should be the same", retained == retained2, "retaineds were different %d\n", retained2);
+	assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
+
+	assert("topics should be the same",
+					checkMQTTStrings(topicString, topicString2), "topics were different %s\n", ""); //topicString2);
+
+	assert("payload lengths should be the same",
+				payloadlen == payloadlen2, "payload lengths were different %d\n", payloadlen2);
+
+	assert("payloads should be the same",
+						memcmp(payload, payload2, payloadlen) == 0, "payloads were different %s\n", "");
+
+/*exit:*/
+	MyLog(LOGA_INFO, "TEST2: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+
+int test3(struct Options options)
+{
+	int i = 0;
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+#define TOPIC_COUNT 2
+
+	unsigned char dup = 0;
+	unsigned short msgid = 23;
+	int count = TOPIC_COUNT;
+	MQTTString topicStrings[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
+	int req_qoss[TOPIC_COUNT] = {2, 1};
+
+	unsigned char dup2 = 1;
+	unsigned short msgid2 = 2223;
+	int count2 = 0;
+	MQTTString topicStrings2[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
+	int req_qoss2[TOPIC_COUNT] = {0, 0};
+
+	fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 2 - serialization of subscribe and back");
+
+	topicStrings[0].cstring = "mytopic";
+	topicStrings[1].cstring = "mytopic2";
+	rc = MQTTSerialize_subscribe(buf, buflen, dup, msgid, count, topicStrings, req_qoss);
+	assert("good rc from serialize subscribe", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTDeserialize_subscribe(&dup2, &msgid2, 2, &count2, topicStrings2, req_qoss2, buf, buflen);
+	assert("good rc from deserialize subscribe", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2);
+	assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
+
+	assert("count should be the same", count == count2, "counts were different %d\n", count2);
+
+	for (i = 0; i < count2; ++i)
+	{
+		assert("topics should be the same",
+					checkMQTTStrings(topicStrings[i], topicStrings2[i]), "topics were different %s\n", "");
+
+		assert("qoss should be the same", req_qoss[i] == req_qoss2[i], "qoss were different %d\n", req_qoss2[i]);
+	}
+
+/*exit:*/
+	MyLog(LOGA_INFO, "TEST3: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test4(struct Options options)
+{
+	int i = 0;
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+#define TOPIC_COUNT 2
+
+	int msgid = 23;
+	int count = TOPIC_COUNT;
+	int granted_qoss[TOPIC_COUNT] = {2, 1};
+
+	unsigned short msgid2 = 2223;
+	int count2 = 0;
+	int granted_qoss2[TOPIC_COUNT] = {0, 0};
+
+	fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 4 - serialization of suback and back");
+
+	rc = MQTTSerialize_suback(buf, buflen, msgid, count, granted_qoss);
+	assert("good rc from serialize suback", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTDeserialize_suback(&msgid2, 2, &count2, granted_qoss2, buf, buflen);
+	assert("good rc from deserialize suback", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
+
+	assert("count should be the same", count == count2, "counts were different %d\n", count2);
+
+	for (i = 0; i < count2; ++i)
+		assert("qoss should be the same", granted_qoss[i] == granted_qoss2[i], "qoss were different %d\n", granted_qoss2[i]);
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST4: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test5(struct Options options)
+{
+	int i = 0;
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+#define TOPIC_COUNT 2
+
+	unsigned char dup = 0;
+	unsigned short msgid = 23;
+	int count = TOPIC_COUNT;
+	MQTTString topicStrings[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
+
+	unsigned char dup2 = 1;
+	unsigned short msgid2 = 2223;
+	int count2 = 0;
+	MQTTString topicStrings2[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer };
+
+	fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 2 - serialization of unsubscribe and back");
+
+	topicStrings[0].cstring = "mytopic";
+	topicStrings[1].cstring = "mytopic2";
+	rc = MQTTSerialize_unsubscribe(buf, buflen, dup, msgid, count, topicStrings);
+	assert("good rc from serialize unsubscribe", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTDeserialize_unsubscribe(&dup2, &msgid2, 2, &count2, topicStrings2, buf, buflen);
+	assert("good rc from deserialize unsubscribe", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2);
+	assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2);
+
+	assert("count should be the same", count == count2, "counts were different %d\n", count2);
+
+	for (i = 0; i < count2; ++i)
+		assert("topics should be the same",
+					checkMQTTStrings(topicStrings[i], topicStrings2[i]), "topics were different %s\n", "");
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST5: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int test6(struct Options options)
+{
+	int rc = 0;
+	unsigned char buf[100];
+	int buflen = sizeof(buf);
+
+	unsigned char sessionPresent = 1;
+	unsigned char connack_rc = 77;
+
+	unsigned char sessionPresent2 = 0;
+	unsigned char connack_rc2 = 0;
+
+	fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\"");
+	global_start_time = start_clock();
+	failures = 0;
+	MyLog(LOGA_INFO, "Starting test 2 - serialization of connack and back");
+
+	rc = MQTTSerialize_connack(buf, buflen, connack_rc, sessionPresent);
+	assert("good rc from serialize connack", rc > 0, "rc was %d\n", rc);
+
+	rc = MQTTDeserialize_connack(&sessionPresent2, &connack_rc2, buf, buflen);
+	assert("good rc from deserialize connack", rc == 1, "rc was %d\n", rc);
+
+	/* data after should be the same as data before */
+	assert("connack rcs should be the same", connack_rc == connack_rc2, "connack rcs were different %d\n", connack_rc2);
+	assert("session present flags should be the same", sessionPresent == sessionPresent2,
+			"session present flags were different %d\n", sessionPresent2);
+
+/* exit: */
+	MyLog(LOGA_INFO, "TEST6: test %s. %d tests run, %d failures.",
+			(failures == 0) ? "passed" : "failed", tests, failures);
+	write_test_result();
+	return failures;
+}
+
+
+int main(int argc, char** argv)
+{
+	int rc = 0;
+ 	int (*tests[])() = {NULL, test1, test2, test3, test4, test5, test6};
+
+	xml = fopen("TEST-test1.xml", "w");
+	fprintf(xml, "<testsuite name=\"test1\" tests=\"%d\">\n", (int)(ARRAY_SIZE(tests) - 1));
+
+	getopts(argc, argv);
+
+ 	if (options.test_no == 0)
+	{ /* run all the tests */
+ 	   	for (options.test_no = 1; options.test_no < ARRAY_SIZE(tests); ++options.test_no)
+			rc += tests[options.test_no](options); /* return number of failures.  0 = test succeeded */
+	}
+	else
+ 	   	rc = tests[options.test_no](options); /* run just the selected test */
+
+ 	if (rc == 0)
+		MyLog(LOGA_INFO, "verdict pass");
+	else
+		MyLog(LOGA_INFO, "verdict fail");
+
+	fprintf(xml, "</testsuite>\n");
+	fclose(xml);
+	return rc;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/README.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/README.md	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,58 @@
+# Eclipse Paho MQTT C/C++ client for Embedded platforms
+
+This repository contains the source code for the [Eclipse Paho](http://eclipse.org/paho) MQTT C/C++ client library for Embedded platorms.
+
+It is dual licensed under the EPL and EDL (see about.html and notice.html for more details).  You can choose which of these licenses you want to use the code under.  The EDL allows you to embed the code into your application, and distribute your application in binary or source form without contributing any of your code, or any changes you make back to Paho.  See the EDL for the exact conditions.
+
+There are three sub-projects:
+
+1. MQTTPacket - simple de/serialization of MQTT packets, plus helper functions
+2. MQTTClient - high(er) level C++ client, plus
+3. MQTTClient-C - high(er) level C client (pretty much a clone of the C++ client)
+
+The *MQTTPacket* directory contains the lowest level C library with the smallest requirements.  This supplies simple serialization
+and deserialization routines.  They serve as a base for the higher level libraries, but can also be used on their own
+It is mainly up to you to write and read to and from the network.
+
+The *MQTTClient* directory contains the next level C++ library.  This networking code is contained in separate classes so that you can plugin the
+network of your choice.  Currently there are implementations for Linux, Arduino and mbed.  ARM mbed was the first platform for which this was written,
+where the conventional language choice is C++, which explains the language choice.  I have written a starter [Porting Guide](http://modelbasedtesting.co.uk/2014/08/25/porting-a-paho-embedded-c-client/).
+
+The *MQTTClient-C* directory contains a C equivalent of MQTTClient, for those platforms where C++ is not supported or the convention.  As far
+as possible it is a direct translation from *MQTTClient*.
+
+## Build requirements / compilation
+
+CMake builds for the various packages have been introduced, along with Travis-CI configuration for automated build & testing.  The basic
+method of building on Linux is:
+
+```
+mkdir build.paho
+cd build.paho
+cmake ..
+make
+```
+
+The travis-build.sh file has the full build and test sequence for Linux.
+
+
+## Usage and API
+
+See the samples directories for examples of intended use.  Doxygen config files for each package are available in the doc directory.
+
+## Runtime tracing
+
+The *MQTTClient* API has debug tracing for MQTT packets sent and received - turn this on by setting the MQTT_DEBUG preprocessor definition.
+
+
+## Reporting bugs
+
+This project uses GitHub Issues here: [github.com/eclipse/paho.mqtt.embedded-c/issues](https://github.com/eclipse/paho.mqtt.embedded-c/issues) to track ongoing development and issues.
+
+## More information
+
+Discussion of the Paho clients takes place on the [Eclipse Mattermost Paho channel](https://mattermost.eclipse.org/eclipse/channels/paho) and the [Eclipse paho-dev mailing list](https://dev.eclipse.org/mailman/listinfo/paho-dev).
+
+General questions about the MQTT protocol are discussed in the [MQTT Google Group](https://groups.google.com/forum/?hl=en-US&fromgroups#!forum/mqtt).
+
+More information is available via the [MQTT community](http://mqtt.org).
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/about.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/about.html	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+ 
+<p><em>December 9, 2013</em></p>	
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content").  Unless otherwise 
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL") and Eclipse Distribution License Version 1.0 ("EDL").
+A copy of the EPL is available at 
+<a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> 
+and a copy of the EDL is available at 
+<a href="http://www.eclipse.org/org/documents/edl-v10.php">http://www.eclipse.org/org/documents/edl-v10.php</a>. 
+For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is 
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content.  Check the Redistributor's license that was 
+provided with the Content.  If no such license exists, contact the Redistributor.  Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body></html>
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/doc/DoxyfileMQTTClient-C.in
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/doc/DoxyfileMQTTClient-C.in	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,2430 @@
+# Doxyfile 1.8.13
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "Eclipse Paho Embedded MQTTClient-C Client Library"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           = "doc/pahologo.png"
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = "doc/MQTTClient-C/"
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        = MQTTClient-C/src MQTTClient-C/src/linux
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 0
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = YES
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = MQTTClient-C/src MQTTClient-C/src/linux
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NONE
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             = __attribute__(x)=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           =
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/doc/DoxyfileMQTTClient.in
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/doc/DoxyfileMQTTClient.in	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,2430 @@
+# Doxyfile 1.8.13
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "Eclipse Paho Embedded C++ Client Library"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           = "doc/pahologo.png"
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = "doc/MQTTClient/"
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        = MQTTClient/src MQTTClient/src/linux
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 0
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = YES
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = MQTTClient/src MQTTClient/src/linux
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NONE
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             = __attribute__(x)=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           =
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/doc/DoxyfileMQTTPacket.in
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/doc/DoxyfileMQTTPacket.in	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,2430 @@
+# Doxyfile 1.8.13
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "Eclipse Paho Embedded MQTTPacket C Client Library"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           = "doc/pahologo.png"
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = "doc/MQTTPacket/"
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        = MQTTPacket/src
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 0
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = YES
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = MQTTPacket/src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NONE
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             = __attribute__(x)=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           =
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/doc/pahologo.png
Binary file mbed-mqtt-master/paho_mqtt_embedded_c/doc/pahologo.png has changed
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/edl-v10
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/edl-v10	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,15 @@
+
+Eclipse Distribution License - v 1.0
+
+Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    Neither the name of the Eclipse Foundation, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/epl-v10
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/epl-v10	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,70 @@
+Eclipse Public License - v 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
+b) in the case of each subsequent Contributor:
+i) changes to the Program, and
+ii) additions to the Program;
+where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
+b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
+c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
+d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
+
+a) it complies with the terms and conditions of this Agreement; and
+b) its license agreement:
+i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
+ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
+iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
+iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
+When the Program is made available in source code form:
+
+a) it must be made available under this Agreement; and
+b) a copy of this Agreement must be included with each copy of the Program.
+Contributors may not remove or alter any copyright notices contained within the Program.
+
+Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/library.properties
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/library.properties	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,9 @@
+name=MQTTClient
+version=1.0.0
+author=Ian Craggs
+maintainer=Ian Craggs https://github.com/icraggs
+sentence=This is the lowest level library, the simplest and smallest, but hardest to use. It simply deals with serialization and deserialization of MQTT packets.
+paragraph=...
+category=Communication
+url=https://github.com/eclipse/paho.mqtt.embedded-c
+architectures=*
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/notice.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/notice.html	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Eclipse Foundation Software User Agreement</title>
+</head>
+
+<body lang="EN-US">
+<h2>Eclipse Foundation Software User Agreement</h2>
+<p>February 1, 2011</p>
+
+<h3>Usage Of Content</h3>
+
+<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+   (COLLECTIVELY &quot;CONTENT&quot;).  USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+   CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU AGREE THAT YOUR USE
+   OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
+   NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
+   CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+
+<h3>Applicable Licenses</h3>
+
+<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
+   (&quot;EPL&quot;).  A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+   For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
+   repository (&quot;Repository&quot;) in software modules (&quot;Modules&quot;) and made available as downloadable archives (&quot;Downloads&quot;).</p>
+
+<ul>
+       <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content.  Typical modules may include plug-ins (&quot;Plug-ins&quot;), plug-in fragments (&quot;Fragments&quot;), and features (&quot;Features&quot;).</li>
+       <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java&trade; ARchive) in a directory named &quot;plugins&quot;.</li>
+       <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.  Each Feature may be packaged as a sub-directory in a directory named &quot;features&quot;.  Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of the Plug-ins
+      and/or Fragments associated with that Feature.</li>
+       <li>Features may also include other Features (&quot;Included Features&quot;). Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of Included Features.</li>
+</ul>
+
+<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named &quot;about.html&quot; (&quot;Abouts&quot;). The terms and conditions governing Features and
+Included Features should be contained in files named &quot;license.html&quot; (&quot;Feature Licenses&quot;).  Abouts and Feature Licenses may be located in any directory of a Download or Module
+including, but not limited to the following locations:</p>
+
+<ul>
+       <li>The top-level (root) directory</li>
+       <li>Plug-in and Fragment directories</li>
+       <li>Inside Plug-ins and Fragments packaged as JARs</li>
+       <li>Sub-directories of the directory named &quot;src&quot; of certain Plug-ins</li>
+       <li>Feature directories</li>
+</ul>
+
+<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license (&quot;Feature Update License&quot;) during the
+installation process.  If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
+inform you where you can locate them.  Feature Update Licenses may be found in the &quot;license&quot; property of files named &quot;feature.properties&quot; found within a Feature.
+Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
+that directory.</p>
+
+<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.  SOME OF THESE
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+
+<ul>
+       <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
+       <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
+       <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
+       <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
+       <li>Metro Link Public License 1.00 (available at <a href="http://www.opengroup.org/openmotif/supporters/metrolink/license.html">http://www.opengroup.org/openmotif/supporters/metrolink/license.html</a>)</li>
+       <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
+</ul>
+
+<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT.  If no About, Feature License, or Feature Update License is provided, please
+contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
+
+
+<h3>Use of Provisioning Technology</h3>
+
+<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
+   Update Manager (&quot;Provisioning Technology&quot;) for the purpose of allowing users to install software, documentation, information and/or
+   other materials (collectively &quot;Installable Software&quot;). This capability is provided with the intent of allowing such users to
+   install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a
+       href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+   (&quot;Specification&quot;).</p>
+
+<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
+   applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
+   in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
+   Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
+
+<ol>
+       <li>A series of actions may occur (&quot;Provisioning Process&quot;) in which a user may execute the Provisioning Technology
+       on a machine (&quot;Target Machine&quot;) with the intent of installing, extending or updating the functionality of an Eclipse-based
+       product.</li>
+       <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
+       accessed and copied to the Target Machine.</li>
+       <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
+       Software (&quot;Installable Software Agreement&quot;) and such Installable Software Agreement shall be accessed from the Target
+       Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
+       the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
+       indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
+</ol>
+
+<h3>Cryptography</h3>
+
+<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
+   another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
+   possession, or use, and re-export of encryption software, to see if this is permitted.</p>
+
+<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
+</body>
+</html>
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/test/MQTTV3112.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/test/MQTTV3112.py	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,923 @@
+"""
+*******************************************************************
+  Copyright (c) 2013, 2014 IBM Corp.
+ 
+  All rights reserved. This program and the accompanying materials
+  are made available under the terms of the Eclipse Public License v1.0
+  and Eclipse Distribution License v1.0 which accompany this distribution. 
+ 
+  The Eclipse Public License is available at 
+     http://www.eclipse.org/legal/epl-v10.html
+  and the Eclipse Distribution License is available at 
+    http://www.eclipse.org/org/documents/edl-v10.php.
+ 
+  Contributors:
+     Ian Craggs - initial implementation and/or documentation
+*******************************************************************
+"""
+from __future__ import print_function
+
+"""
+
+Assertions are used to validate incoming data, but are omitted from outgoing packets.  This is
+so that the tests that use this package can send invalid data for error testing.
+
+"""
+
+
+import logging
+
+logger = logging.getLogger("mqttsas")
+
+# Low-level protocol interface
+
+class MQTTException(Exception):
+  pass
+   
+
+# Message types
+CONNECT, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, \
+PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, \
+PINGREQ, PINGRESP, DISCONNECT = range(1, 15)
+
+packetNames = [ "reserved", \
+"Connect", "Connack", "Publish", "Puback", "Pubrec", "Pubrel", \
+"Pubcomp", "Subscribe", "Suback", "Unsubscribe", "Unsuback", \
+"Pingreq", "Pingresp", "Disconnect"]
+
+classNames = [ "reserved", \
+"Connects", "Connacks", "Publishes", "Pubacks", "Pubrecs", "Pubrels", \
+"Pubcomps", "Subscribes", "Subacks", "Unsubscribes", "Unsubacks", \
+"Pingreqs", "Pingresps", "Disconnects"]
+
+
+def MessageType(byte):
+  if byte != None:
+    rc = ord(byte[0]) >> 4
+  else:
+    rc = None
+  return rc
+
+
+def getPacket(aSocket):
+  "receive the next packet"
+  buf = aSocket.recv(1) # get the first byte fixed header
+  if buf == b"":
+    return None
+  if str(aSocket).find("[closed]") != -1:
+    closed = True
+  else:
+    closed = False
+  if closed:
+    return None
+  # now get the remaining length
+  multiplier = 1
+  remlength = 0
+  while 1:
+    next = aSocket.recv(1)
+    while len(next) == 0:
+      next = aSocket.recv(1)
+    buf += next
+    digit = ord(buf[-1])
+    remlength += (digit & 127) * multiplier
+    if digit & 128 == 0:
+      break
+    multiplier *= 128
+  # receive the remaining length if there is any
+  rest = ''
+  if remlength > 0:
+    while len(rest) < remlength:
+      rest += aSocket.recv(remlength-len(rest))
+  assert len(rest) == remlength
+  return buf + rest
+
+
+class FixedHeaders:
+
+  def __init__(self, aMessageType):
+    self.MessageType = aMessageType
+    self.DUP = False
+    self.QoS = 0
+    self.RETAIN = False
+    self.remainingLength = 0
+
+  def __eq__(self, fh):
+    return self.MessageType == fh.MessageType and \
+           self.DUP == fh.DUP and \
+           self.QoS == fh.QoS and \
+           self.RETAIN == fh.RETAIN # and \
+           # self.remainingLength == fh.remainingLength
+
+  def __repr__(self):
+    "return printable representation of our data"
+    return classNames[self.MessageType]+'(DUP='+repr(self.DUP)+ \
+           ", QoS="+repr(self.QoS)+", Retain="+repr(self.RETAIN)
+
+  def pack(self, length):
+    "pack data into string buffer ready for transmission down socket"
+    buffer = bytes([(self.MessageType << 4) | (self.DUP << 3) |\
+                         (self.QoS << 1) | self.RETAIN])
+    self.remainingLength = length
+    buffer += self.encode(length)
+    return buffer
+
+  def encode(self, x):
+    assert 0 <= x <= 268435455
+    buffer = b''
+    while 1:
+      digit = x % 128
+      x //= 128
+      if x > 0:
+        digit |= 0x80
+      buffer += bytes([digit])
+      if x == 0:
+        break
+    return buffer
+
+  def unpack(self, buffer):
+    "unpack data from string buffer into separate fields"
+    b0 = ord(buffer[0])
+    self.MessageType = b0 >> 4
+    self.DUP = ((b0 >> 3) & 0x01) == 1
+    self.QoS = (b0 >> 1) & 0x03
+    self.RETAIN = (b0 & 0x01) == 1
+    (self.remainingLength, bytes) = self.decode(buffer[1:])
+    return bytes + 1 # length of fixed header
+
+  def decode(self, buffer):
+    multiplier = 1
+    value = 0
+    bytes = 0
+    while 1:
+      bytes += 1
+      digit = ord(buffer[0])
+      buffer = buffer[1:]
+      value += (digit & 127) * multiplier
+      if digit & 128 == 0:
+        break
+      multiplier *= 128
+    return (value, bytes)
+
+
+def writeInt16(length):
+  return bytes([length // 256, length % 256])
+
+def readInt16(buf):
+  return ord(buf[0])*256 + ord(buf[1])
+
+def writeUTF(data):
+  # data could be a string, or bytes.  If string, encode into bytes with utf-8
+  return writeInt16(len(data)) + (data if type(data) == type(b"") else bytes(data, "utf-8"))
+
+def readUTF(buffer, maxlen):
+  if maxlen >= 2:
+    length = readInt16(buffer)
+  else:
+    raise MQTTException("Not enough data to read string length")
+  maxlen -= 2
+  if length > maxlen:
+    raise MQTTException("Length delimited string too long")
+  buf = buffer[2:2+length].decode("utf-8")
+  logger.info("[MQTT-4.7.3-2] topic names and filters not include null")
+  zz = buf.find("\x00") # look for null in the UTF string
+  if zz != -1:
+    raise MQTTException("[MQTT-1.5.3-2] Null found in UTF data "+buf)
+  """for c in range (0xD800, 0xDFFF):
+    zz = buf.find(chr(c)) # look for D800-DFFF in the UTF string
+    if zz != -1:
+      raise MQTTException("[MQTT-1.5.3-1] D800-DFFF found in UTF data "+buf)
+  """
+  if buf.find("\uFEFF") != -1:
+    logger.info("[MQTT-1.5.3-3] U+FEFF in UTF string") 
+  return buf
+
+def writeBytes(buffer):
+  return writeInt16(len(buffer)) + buffer
+
+def readBytes(buffer):
+  length = readInt16(buffer)
+  return buffer[2:2+length]
+
+
+class Packets:
+
+  def pack(self):
+    buffer = self.fh.pack(0)
+    return buffer
+
+  def __repr__(self):
+    return repr(self.fh)
+
+  def __eq__(self, packet):
+    return self.fh == packet.fh if packet else False
+
+
+class Connects(Packets):
+
+  def __init__(self, buffer = None):
+    self.fh = FixedHeaders(CONNECT)
+
+    # variable header
+    self.ProtocolName = "MQTT"
+    self.ProtocolVersion = 4
+    self.CleanSession = True
+    self.WillFlag = False
+    self.WillQoS = 0
+    self.WillRETAIN = 0
+    self.KeepAliveTimer = 30
+    self.usernameFlag = False
+    self.passwordFlag = False
+
+    # Payload
+    self.ClientIdentifier = ""   # UTF-8
+    self.WillTopic = None        # UTF-8
+    self.WillMessage = None      # binary
+    self.username = None         # UTF-8
+    self.password = None         # binary
+
+    if buffer != None:
+      self.unpack(buffer)
+
+  def pack(self):    
+    connectFlags = bytes([(self.CleanSession << 1) | (self.WillFlag << 2) | \
+                       (self.WillQoS << 3) | (self.WillRETAIN << 5) | \
+                       (self.usernameFlag << 6) | (self.passwordFlag << 7)])
+    buffer = writeUTF(self.ProtocolName) + bytes([self.ProtocolVersion]) + \
+              connectFlags + writeInt16(self.KeepAliveTimer)
+    buffer += writeUTF(self.ClientIdentifier) 
+    if self.WillFlag:
+      buffer += writeUTF(self.WillTopic) 
+      buffer += writeBytes(self.WillMessage) 
+    if self.usernameFlag:
+      buffer += writeUTF(self.username) 
+    if self.passwordFlag:
+      buffer += writeBytes(self.password) 
+    buffer = self.fh.pack(len(buffer)) + buffer
+    return buffer
+
+  def unpack(self, buffer):
+    assert len(buffer) >= 2
+    assert MessageType(buffer) == CONNECT
+
+    try:
+      fhlen = self.fh.unpack(buffer)
+      packlen = fhlen + self.fh.remainingLength
+      assert len(buffer) >= packlen, "buffer length %d packet length %d" % (len(buffer), packlen)
+      curlen = fhlen # points to after header + remaining length
+      assert self.fh.DUP == False, "[MQTT-2.1.2-1]"
+      assert self.fh.QoS == 0, "[MQTT-2.1.2-1] QoS was not 0, was %d" % self.fh.QoS
+      assert self.fh.RETAIN == False, "[MQTT-2.1.2-1]"
+
+      self.ProtocolName = readUTF(buffer[curlen:], packlen - curlen)
+      curlen += len(self.ProtocolName) + 2
+      assert self.ProtocolName == "MQTT", "Wrong protocol name %s" % self.ProtocolName
+
+      self.ProtocolVersion = ord(buffer[curlen])
+      curlen += 1
+
+      connectFlags = ord(buffer[curlen])
+      assert (connectFlags & 0x01) == 0, "[MQTT-3.1.2-3] reserved connect flag must be 0"
+      self.CleanSession = ((connectFlags >> 1) & 0x01) == 1
+      self.WillFlag = ((connectFlags >> 2) & 0x01) == 1
+      self.WillQoS = (connectFlags >> 3) & 0x03
+      self.WillRETAIN = (connectFlags >> 5) & 0x01
+      self.passwordFlag = ((connectFlags >> 6) & 0x01) == 1
+      self.usernameFlag = ((connectFlags >> 7) & 0x01) == 1
+      curlen +=1
+
+      if self.WillFlag:
+        assert self.WillQoS in [0, 1, 2], "[MQTT-3.1.2-14] will qos must not be 3"
+      else:
+        assert self.WillQoS == 0, "[MQTT-3.1.2-13] will qos must be 0, if will flag is false"
+        assert self.WillRETAIN == False, "[MQTT-3.1.2-14] will retain must be false, if will flag is false"
+
+      self.KeepAliveTimer = readInt16(buffer[curlen:])
+      curlen += 2
+      logger.info("[MQTT-3.1.3-3] Clientid must be present, and first field")
+      logger.info("[MQTT-3.1.3-4] Clientid must be Unicode, and between 0 and 65535 bytes long")
+      self.ClientIdentifier = readUTF(buffer[curlen:], packlen - curlen)
+      curlen += len(self.ClientIdentifier) + 2
+
+      if self.WillFlag:
+        self.WillTopic = readUTF(buffer[curlen:], packlen - curlen)
+        curlen += len(self.WillTopic) + 2
+        self.WillMessage = readBytes(buffer[curlen:])
+        curlen += len(self.WillMessage) + 2
+        logger.info("[[MQTT-3.1.2-9] will topic and will message fields must be present")
+      else:
+        self.WillTopic = self.WillMessage = None
+
+      if self.usernameFlag:
+        assert len(buffer) > curlen+2, "Buffer too short to read username length"
+        self.username = readUTF(buffer[curlen:], packlen - curlen)
+        curlen += len(self.username) + 2
+        logger.info("[MQTT-3.1.2-19] username must be in payload if user name flag is 1")
+      else:
+        logger.info("[MQTT-3.1.2-18] username must not be in payload if user name flag is 0")
+        assert self.passwordFlag == False, "[MQTT-3.1.2-22] password flag must be 0 if username flag is 0"
+
+      if self.passwordFlag:
+        assert len(buffer) > curlen+2, "Buffer too short to read password length"
+        self.password = readBytes(buffer[curlen:])
+        curlen += len(self.password) + 2
+        logger.info("[MQTT-3.1.2-21] password must be in payload if password flag is 0")
+      else:
+        logger.info("[MQTT-3.1.2-20] password must not be in payload if password flag is 0")
+
+      if self.WillFlag and self.usernameFlag and self.passwordFlag:
+        logger.info("[MQTT-3.1.3-1] clientid, will topic, will message, username and password all present")
+
+      assert curlen == packlen, "Packet is wrong length curlen %d != packlen %d"
+    except:
+      logger.exception("[MQTT-3.1.4-1] server must validate connect packet and close connection without connack if it does not conform")
+      raise
+
+
+
+  def __repr__(self):
+    buf = repr(self.fh)+", ProtocolName="+str(self.ProtocolName)+", ProtocolVersion=" +\
+          repr(self.ProtocolVersion)+", CleanSession="+repr(self.CleanSession) +\
+          ", WillFlag="+repr(self.WillFlag)+", KeepAliveTimer=" +\
+          repr(self.KeepAliveTimer)+", ClientId="+str(self.ClientIdentifier) +\
+          ", usernameFlag="+repr(self.usernameFlag)+", passwordFlag="+repr(self.passwordFlag)
+    if self.WillFlag:
+      buf += ", WillQoS=" + repr(self.WillQoS) +\
+             ", WillRETAIN=" + repr(self.WillRETAIN) +\
+             ", WillTopic='"+ self.WillTopic +\
+             "', WillMessage='"+str(self.WillMessage)+"'"
+    if self.username:
+      buf += ", username="+self.username
+    if self.password:
+      buf += ", password="+str(self.password)
+    return buf+")"
+
+  def __eq__(self, packet):
+    rc = Packets.__eq__(self, packet) and \
+           self.ProtocolName == packet.ProtocolName and \
+           self.ProtocolVersion == packet.ProtocolVersion and \
+           self.CleanSession == packet.CleanSession and \
+           self.WillFlag == packet.WillFlag and \
+           self.KeepAliveTimer == packet.KeepAliveTimer and \
+           self.ClientIdentifier == packet.ClientIdentifier and \
+           self.WillFlag == packet.WillFlag
+    if rc and self.WillFlag:
+      rc = self.WillQoS == packet.WillQoS and \
+           self.WillRETAIN == packet.WillRETAIN and \
+           self.WillTopic == packet.WillTopic and \
+           self.WillMessage == packet.WillMessage
+    return rc
+
+
+class Connacks(Packets):
+
+  def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, ReturnCode=0):
+    self.fh = FixedHeaders(CONNACK)
+    self.fh.DUP = DUP
+    self.fh.QoS = QoS
+    self.fh.Retain = Retain
+    self.flags = 0
+    self.returnCode = ReturnCode
+    if buffer != None:
+      self.unpack(buffer)
+
+  def pack(self):
+    buffer = bytes([self.flags, self.returnCode])
+    buffer = self.fh.pack(len(buffer)) + buffer
+    return buffer
+
+  def unpack(self, buffer):
+    assert len(buffer) >= 4
+    assert MessageType(buffer) == CONNACK
+    self.fh.unpack(buffer)
+    assert self.fh.remainingLength == 2, "Connack packet is wrong length %d" % self.fh.remainingLength
+    assert ord(buffer[2]) in  [0, 1], "Connect Acknowledge Flags"
+    self.returnCode = ord(buffer[3])
+    assert self.fh.DUP == False, "[MQTT-2.1.2-1]"
+    assert self.fh.QoS == 0, "[MQTT-2.1.2-1]"
+    assert self.fh.RETAIN == False, "[MQTT-2.1.2-1]"
+
+  def __repr__(self):
+    return repr(self.fh)+", Session present="+str((self.flags & 0x01) == 1)+", ReturnCode="+repr(self.returnCode)+")"
+
+  def __eq__(self, packet):
+    return Packets.__eq__(self, packet) and \
+           self.returnCode == packet.returnCode
+
+
+class Disconnects(Packets):
+
+  def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False):
+    self.fh = FixedHeaders(DISCONNECT)
+    self.fh.DUP = DUP
+    self.fh.QoS = QoS
+    self.fh.Retain = Retain
+    if buffer != None:
+      self.unpack(buffer)
+
+  def unpack(self, buffer):
+    assert len(buffer) >= 2
+    assert MessageType(buffer) == DISCONNECT
+    self.fh.unpack(buffer)
+    assert self.fh.remainingLength == 0, "Disconnect packet is wrong length %d" % self.fh.remainingLength
+    logger.info("[MQTT-3.14.1-1] disconnect reserved bits must be 0")
+    assert self.fh.DUP == False, "[MQTT-2.1.2-1]"
+    assert self.fh.QoS == 0, "[MQTT-2.1.2-1]"
+    assert self.fh.RETAIN == False, "[MQTT-2.1.2-1]"
+
+  def __repr__(self):
+    return repr(self.fh)+")"
+
+
+class Publishes(Packets):
+
+  def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0, TopicName="", Payload=b""):
+    self.fh = FixedHeaders(PUBLISH)
+    self.fh.DUP = DUP
+    self.fh.QoS = QoS
+    self.fh.Retain = Retain
+    # variable header
+    self.topicName = TopicName
+    self.messageIdentifier = MsgId
+    # payload
+    self.data = Payload
+    if buffer != None:
+      self.unpack(buffer)
+
+  def pack(self):
+    buffer = writeUTF(self.topicName)
+    if self.fh.QoS != 0:
+      buffer +=  writeInt16(self.messageIdentifier)
+    buffer += self.data
+    buffer = self.fh.pack(len(buffer)) + buffer
+    return buffer
+
+  def unpack(self, buffer):
+    assert len(buffer) >= 2
+    assert MessageType(buffer) == PUBLISH
+    fhlen = self.fh.unpack(buffer)
+    assert self.fh.QoS in [0, 1, 2], "QoS in Publish must be 0, 1, or 2"
+    packlen = fhlen + self.fh.remainingLength
+    assert len(buffer) >= packlen
+    curlen = fhlen
+    try:
+      self.topicName = readUTF(buffer[fhlen:], packlen - curlen)
+    except UnicodeDecodeError:
+      logger.info("[MQTT-3.3.2-1] topic name in publish must be utf-8")
+      raise
+    curlen += len(self.topicName) + 2
+    if self.fh.QoS != 0:
+      self.messageIdentifier = readInt16(buffer[curlen:])
+      logger.info("[MQTT-2.3.1-1] packet indentifier must be in publish if QoS is 1 or 2")
+      curlen += 2
+      assert self.messageIdentifier > 0, "[MQTT-2.3.1-1] packet indentifier must be > 0"
+    else:
+      logger.info("[MQTT-2.3.1-5] no packet indentifier in publish if QoS is 0")
+      self.messageIdentifier = 0
+    self.data = buffer[curlen:fhlen + self.fh.remainingLength]
+    if self.fh.QoS == 0:
+      assert self.fh.DUP == False, "[MQTT-2.1.2-4]"
+    return fhlen + self.fh.remainingLength
+
+  def __repr__(self):
+    rc = repr(self.fh)
+    if self.fh.QoS != 0:
+      rc += ", MsgId="+repr(self.messageIdentifier)
+    rc += ", TopicName="+repr(self.topicName)+", Payload="+repr(self.data)+")"
+    return rc
+
+  def __eq__(self, packet):
+    rc = Packets.__eq__(self, packet) and \
+         self.topicName == packet.topicName and \
+         self.data == packet.data
+    if rc and self.fh.QoS != 0:
+      rc = self.messageIdentifier == packet.messageIdentifier
+    return rc
+
+
+class Pubacks(Packets):
+
+  def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0):
+    self.fh = FixedHeaders(PUBACK)
+    self.fh.DUP = DUP
+    self.fh.QoS = QoS
+    self.fh.Retain = Retain
+    # variable header
+    self.messageIdentifier = MsgId
+    if buffer != None:
+      self.unpack(buffer)
+
+  def pack(self):
+    buffer = writeInt16(self.messageIdentifier)
+    buffer = self.fh.pack(len(buffer)) + buffer
+    return buffer
+
+  def unpack(self, buffer):
+    assert len(buffer) >= 2
+    assert MessageType(buffer) == PUBACK
+    fhlen = self.fh.unpack(buffer)
+    assert self.fh.remainingLength == 2, "Puback packet is wrong length %d" % self.fh.remainingLength
+    assert len(buffer) >= fhlen + self.fh.remainingLength
+    self.messageIdentifier = readInt16(buffer[fhlen:])
+    assert self.fh.DUP == False, "[MQTT-2.1.2-1] Puback reserved bits must be 0"
+    assert self.fh.QoS == 0, "[MQTT-2.1.2-1] Puback reserved bits must be 0"
+    assert self.fh.RETAIN == False, "[MQTT-2.1.2-1] Puback reserved bits must be 0"
+    return fhlen + 2
+
+  def __repr__(self):
+    return repr(self.fh)+", MsgId "+repr(self.messageIdentifier)
+
+  def __eq__(self, packet):
+    return Packets.__eq__(self, packet) and \
+           self.messageIdentifier == packet.messageIdentifier
+
+
+class Pubrecs(Packets):
+
+  def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0):
+    self.fh = FixedHeaders(PUBREC)
+    self.fh.DUP = DUP
+    self.fh.QoS = QoS
+    self.fh.Retain = Retain
+    # variable header
+    self.messageIdentifier = MsgId
+    if buffer != None:
+      self.unpack(buffer)
+
+  def pack(self):
+    buffer = writeInt16(self.messageIdentifier)
+    buffer = self.fh.pack(len(buffer)) + buffer
+    return buffer
+
+  def unpack(self, buffer):
+    assert len(buffer) >= 2
+    assert MessageType(buffer) == PUBREC
+    fhlen = self.fh.unpack(buffer)
+    assert self.fh.remainingLength == 2, "Pubrec packet is wrong length %d" % self.fh.remainingLength
+    assert len(buffer) >= fhlen + self.fh.remainingLength
+    self.messageIdentifier = readInt16(buffer[fhlen:])
+    assert self.fh.DUP == False, "[MQTT-2.1.2-1] Pubrec reserved bits must be 0"
+    assert self.fh.QoS == 0, "[MQTT-2.1.2-1] Pubrec reserved bits must be 0"
+    assert self.fh.RETAIN == False, "[MQTT-2.1.2-1] Pubrec reserved bits must be 0"
+    return fhlen + 2
+
+  def __repr__(self):
+    return repr(self.fh)+", MsgId="+repr(self.messageIdentifier)+")"
+
+  def __eq__(self, packet):
+    return Packets.__eq__(self, packet) and \
+           self.messageIdentifier == packet.messageIdentifier
+
+
+class Pubrels(Packets):
+
+  def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0):
+    self.fh = FixedHeaders(PUBREL)
+    self.fh.DUP = DUP
+    self.fh.QoS = QoS
+    self.fh.Retain = Retain
+    # variable header
+    self.messageIdentifier = MsgId
+    if buffer != None:
+      self.unpack(buffer)
+
+  def pack(self):
+    buffer = writeInt16(self.messageIdentifier)
+    buffer = self.fh.pack(len(buffer)) + buffer
+    return buffer
+
+  def unpack(self, buffer):
+    assert len(buffer) >= 2
+    assert MessageType(buffer) == PUBREL
+    fhlen = self.fh.unpack(buffer)
+    assert self.fh.remainingLength == 2, "Pubrel packet is wrong length %d" % self.fh.remainingLength
+    assert len(buffer) >= fhlen + self.fh.remainingLength
+    self.messageIdentifier = readInt16(buffer[fhlen:])
+    assert self.fh.DUP == False, "[MQTT-2.1.2-1] DUP should be False in PUBREL"
+    assert self.fh.QoS == 1, "[MQTT-2.1.2-1] QoS should be 1 in PUBREL"
+    assert self.fh.RETAIN == False, "[MQTT-2.1.2-1] RETAIN should be False in PUBREL"
+    logger.info("[MQTT-3.6.1-1] bits in fixed header for pubrel are ok")
+    return fhlen + 2
+
+  def __repr__(self):
+    return repr(self.fh)+", MsgId="+repr(self.messageIdentifier)+")"
+
+  def __eq__(self, packet):
+    return Packets.__eq__(self, packet) and \
+           self.messageIdentifier == packet.messageIdentifier
+
+
+class Pubcomps(Packets):
+
+  def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0):
+    self.fh = FixedHeaders(PUBCOMP)
+    self.fh.DUP = DUP
+    self.fh.QoS = QoS
+    self.fh.Retain = Retain
+    # variable header
+    self.messageIdentifier = MsgId
+    if buffer != None:
+      self.unpack(buffer)
+
+  def pack(self):
+    buffer = writeInt16(self.messageIdentifier)
+    buffer = self.fh.pack(len(buffer)) + buffer
+    return buffer
+
+  def unpack(self, buffer):
+    assert len(buffer) >= 2
+    assert MessageType(buffer) == PUBCOMP
+    fhlen = self.fh.unpack(buffer)
+    assert len(buffer) >= fhlen + self.fh.remainingLength
+    assert self.fh.remainingLength == 2, "Pubcomp packet is wrong length %d" % self.fh.remainingLength
+    self.messageIdentifier = readInt16(buffer[fhlen:])
+    assert self.fh.DUP == False, "[MQTT-2.1.2-1] DUP should be False in Pubcomp"
+    assert self.fh.QoS == 0, "[MQTT-2.1.2-1] QoS should be 0 in Pubcomp"
+    assert self.fh.RETAIN == False, "[MQTT-2.1.2-1] Retain should be false in Pubcomp"
+    return fhlen + 2
+
+  def __repr__(self):
+    return repr(self.fh)+", MsgId="+repr(self.messageIdentifier)+")"
+
+  def __eq__(self, packet):
+    return Packets.__eq__(self, packet) and \
+           self.messageIdentifier == packet.messageIdentifier
+
+
+class Subscribes(Packets):
+
+  def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0, Data=[]):
+    self.fh = FixedHeaders(SUBSCRIBE)
+    self.fh.DUP = DUP
+    self.fh.QoS = QoS
+    self.fh.Retain = Retain
+    # variable header
+    self.messageIdentifier = MsgId
+    # payload - list of topic, qos pairs
+    self.data = Data[:]
+    if buffer != None:
+      self.unpack(buffer)
+
+  def pack(self):
+    buffer = writeInt16(self.messageIdentifier)
+    for d in self.data:
+      buffer += writeUTF(d[0]) + bytes([d[1]])
+    buffer = self.fh.pack(len(buffer)) + buffer
+    return buffer
+
+  def unpack(self, buffer):
+    assert len(buffer) >= 2
+    assert MessageType(buffer) == SUBSCRIBE
+    fhlen = self.fh.unpack(buffer)
+    assert len(buffer) >= fhlen + self.fh.remainingLength
+    logger.info("[MQTT-2.3.1-1] packet indentifier must be in subscribe")
+    self.messageIdentifier = readInt16(buffer[fhlen:])
+    assert self.messageIdentifier > 0, "[MQTT-2.3.1-1] packet indentifier must be > 0"
+    leftlen = self.fh.remainingLength - 2
+    self.data = []
+    while leftlen > 0:
+      topic = readUTF(buffer[-leftlen:], leftlen)
+      leftlen -= len(topic) + 2
+      qos = ord(buffer[-leftlen])
+      assert qos in [0, 1, 2], "[MQTT-3-8.3-2] reserved bits must be zero"
+      leftlen -= 1
+      self.data.append((topic, qos))
+    assert len(self.data) > 0, "[MQTT-3.8.3-1] at least one topic, qos pair must be in subscribe"
+    assert leftlen == 0
+    assert self.fh.DUP == False, "[MQTT-2.1.2-1] DUP must be false in subscribe"
+    assert self.fh.QoS == 1, "[MQTT-2.1.2-1] QoS must be 1 in subscribe"
+    assert self.fh.RETAIN == False, "[MQTT-2.1.2-1] RETAIN must be false in subscribe"
+    return fhlen + self.fh.remainingLength
+
+  def __repr__(self):
+    return repr(self.fh)+", MsgId="+repr(self.messageIdentifier)+\
+           ", Data="+repr(self.data)+")"
+
+  def __eq__(self, packet):
+    return Packets.__eq__(self, packet) and \
+           self.messageIdentifier == packet.messageIdentifier and \
+           self.data == packet.data
+
+
+class Subacks(Packets):
+
+  def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0, Data=[]):
+    self.fh = FixedHeaders(SUBACK)
+    self.fh.DUP = DUP
+    self.fh.QoS = QoS
+    self.fh.Retain = Retain
+    # variable header
+    self.messageIdentifier = MsgId
+    # payload - list of qos
+    self.data = Data[:]
+    if buffer != None:
+      self.unpack(buffer)
+
+  def pack(self):
+    buffer = writeInt16(self.messageIdentifier)
+    for d in self.data:
+      buffer += bytes([d])
+    buffer = self.fh.pack(len(buffer)) + buffer
+    return buffer
+
+  def unpack(self, buffer):
+    assert len(buffer) >= 2
+    assert MessageType(buffer) == SUBACK
+    fhlen = self.fh.unpack(buffer)
+    assert len(buffer) >= fhlen + self.fh.remainingLength
+    self.messageIdentifier = readInt16(buffer[fhlen:])
+    leftlen = self.fh.remainingLength - 2
+    self.data = []
+    while leftlen > 0:
+      qos = buffer[-leftlen]
+      assert ord(qos) in [0, 1, 2, 0x80], "[MQTT-3.9.3-2] return code in QoS must be 0, 1, 2 or 0x80, was "+ord(qos)
+      leftlen -= 1
+      self.data.append(qos)
+    assert leftlen == 0
+    assert self.fh.DUP == False, "[MQTT-2.1.2-1] DUP should be false in suback"
+    assert self.fh.QoS == 0, "[MQTT-2.1.2-1] QoS should be 0 in suback"
+    assert self.fh.RETAIN == False, "[MQTT-2.1.2-1] Retain should be false in suback"
+    return fhlen + self.fh.remainingLength
+
+  def __repr__(self):
+    return repr(self.fh)+", MsgId="+repr(self.messageIdentifier)+\
+           ", Data="+repr(self.data)+")"
+
+  def __eq__(self, packet):
+    return Packets.__eq__(self, packet) and \
+           self.messageIdentifier == packet.messageIdentifier and \
+           self.data == packet.data
+
+
+class Unsubscribes(Packets):
+
+  def __init__(self, buffer=None, DUP=False, QoS=1, Retain=False, MsgId=0, Data=[]):
+    self.fh = FixedHeaders(UNSUBSCRIBE)
+    self.fh.DUP = DUP
+    self.fh.QoS = QoS
+    self.fh.Retain = Retain
+    # variable header
+    self.messageIdentifier = MsgId
+    # payload - list of topics
+    self.data = Data[:]
+    if buffer != None:
+      self.unpack(buffer)
+
+  def pack(self):
+    buffer = writeInt16(self.messageIdentifier)
+    for d in self.data:
+      buffer += writeUTF(d)
+    buffer = self.fh.pack(len(buffer)) + buffer
+    return buffer
+
+  def unpack(self, buffer):
+    assert len(buffer) >= 2
+    assert MessageType(buffer) == UNSUBSCRIBE
+    fhlen = self.fh.unpack(buffer)
+    assert len(buffer) >= fhlen + self.fh.remainingLength
+    logger.info("[MQTT-2.3.1-1] packet indentifier must be in unsubscribe")
+    self.messageIdentifier = readInt16(buffer[fhlen:])
+    assert self.messageIdentifier > 0, "[MQTT-2.3.1-1] packet indentifier must be > 0"
+    leftlen = self.fh.remainingLength - 2
+    self.data = []
+    while leftlen > 0:
+      topic = readUTF(buffer[-leftlen:], leftlen)
+      leftlen -= len(topic) + 2
+      self.data.append(topic)
+    assert leftlen == 0
+    assert self.fh.DUP == False, "[MQTT-2.1.2-1]"
+    assert self.fh.QoS == 1, "[MQTT-2.1.2-1]"
+    assert self.fh.RETAIN == False, "[MQTT-2.1.2-1]"
+    logger.info("[MQTT-3-10.1-1] fixed header bits are 0,0,1,0")
+    return fhlen + self.fh.remainingLength
+
+  def __repr__(self):
+    return repr(self.fh)+", MsgId="+repr(self.messageIdentifier)+\
+           ", Data="+repr(self.data)+")"
+
+  def __eq__(self, packet):
+    return Packets.__eq__(self, packet) and \
+           self.messageIdentifier == packet.messageIdentifier and \
+           self.data == packet.data
+
+
+class Unsubacks(Packets):
+
+  def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False, MsgId=0):
+    self.fh = FixedHeaders(UNSUBACK)
+    self.fh.DUP = DUP
+    self.fh.QoS = QoS
+    self.fh.Retain = Retain
+    # variable header
+    self.messageIdentifier = MsgId
+    if buffer != None:
+      self.unpack(buffer)
+
+  def pack(self):
+    buffer = writeInt16(self.messageIdentifier)
+    buffer = self.fh.pack(len(buffer)) + buffer
+    return buffer
+
+  def unpack(self, buffer):
+    assert len(buffer) >= 2
+    assert MessageType(buffer) == UNSUBACK
+    fhlen = self.fh.unpack(buffer)
+    assert len(buffer) >= fhlen + self.fh.remainingLength
+    self.messageIdentifier = readInt16(buffer[fhlen:])
+    assert self.messageIdentifier > 0, "[MQTT-2.3.1-1] packet indentifier must be > 0"
+    self.messageIdentifier = readInt16(buffer[fhlen:])
+    assert self.fh.DUP == False, "[MQTT-2.1.2-1]"
+    assert self.fh.QoS == 0, "[MQTT-2.1.2-1]"
+    assert self.fh.RETAIN == False, "[MQTT-2.1.2-1]"
+    return fhlen + self.fh.remainingLength
+
+  def __repr__(self):
+    return repr(self.fh)+", MsgId="+repr(self.messageIdentifier)+")"
+
+  def __eq__(self, packet):
+    return Packets.__eq__(self, packet) and \
+           self.messageIdentifier == packet.messageIdentifier
+
+
+class Pingreqs(Packets):
+
+  def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False):
+    self.fh = FixedHeaders(PINGREQ)
+    self.fh.DUP = DUP
+    self.fh.QoS = QoS
+    self.fh.Retain = Retain
+    if buffer != None:
+      self.unpack(buffer)
+
+  def unpack(self, buffer):
+    assert len(buffer) >= 2
+    assert MessageType(buffer) == PINGREQ
+    fhlen = self.fh.unpack(buffer)
+    assert self.fh.remainingLength == 0
+    assert self.fh.DUP == False, "[MQTT-2.1.2-1]"
+    assert self.fh.QoS == 0, "[MQTT-2.1.2-1]"
+    assert self.fh.RETAIN == False, "[MQTT-2.1.2-1]"
+    return fhlen
+
+  def __repr__(self):
+    return repr(self.fh)+")"
+
+
+class Pingresps(Packets):
+
+  def __init__(self, buffer=None, DUP=False, QoS=0, Retain=False):
+    self.fh = FixedHeaders(PINGRESP)
+    self.fh.DUP = DUP
+    self.fh.QoS = QoS
+    self.fh.Retain = Retain
+    if buffer != None:
+      self.unpack(buffer)
+
+  def unpack(self, buffer):
+    assert len(buffer) >= 2
+    assert MessageType(buffer) == PINGRESP
+    fhlen = self.fh.unpack(buffer)
+    assert self.fh.remainingLength == 0
+    assert self.fh.DUP == False, "[MQTT-2.1.2-1]"
+    assert self.fh.QoS == 0, "[MQTT-2.1.2-1]"
+    assert self.fh.RETAIN == False, "[MQTT-2.1.2-1]"
+    return fhlen
+
+  def __repr__(self):
+    return repr(self.fh)+")"
+
+classes = [None, Connects, Connacks, Publishes, Pubacks, Pubrecs,
+           Pubrels, Pubcomps, Subscribes, Subacks, Unsubscribes,
+           Unsubacks, Pingreqs, Pingresps, Disconnects]
+
+def unpackPacket(buffer):
+  if MessageType(buffer) != None:
+    packet = classes[MessageType(buffer)]()
+    packet.unpack(buffer)
+  else:
+    packet = None
+  return packet
+
+if __name__ == "__main__":
+  fh = FixedHeaders(CONNECT)
+  tests = [0, 56, 127, 128, 8888, 16383, 16384, 65535, 2097151, 2097152,
+           20555666, 268435454, 268435455]
+  for x in tests:
+    try:
+      assert x == fh.decode(fh.encode(x))[0]
+    except AssertionError:
+      print("Test failed for x =", x, fh.decode(fh.encode(x)))
+  try:
+    fh.decode(fh.encode(268435456))
+    print("Error")
+  except AssertionError:
+    pass
+
+  for packet in classes[1:]:
+    before = str(packet())   
+    after = str(unpackPacket(packet().pack()))
+    try:
+      assert before == after
+    except:
+      print("before:", before, "\nafter:", after)
+  print("End")
+
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/test/mqttsas2.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/test/mqttsas2.py	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,122 @@
+"""
+*******************************************************************
+  Copyright (c) 2013, 2017 IBM Corp.
+
+  All rights reserved. This program and the accompanying materials
+  are made available under the terms of the Eclipse Public License v1.0
+  and Eclipse Distribution License v1.0 which accompany this distribution.
+
+  The Eclipse Public License is available at
+     http://www.eclipse.org/legal/epl-v10.html
+  and the Eclipse Distribution License is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+  Contributors:
+     Ian Craggs - initial implementation and/or documentation
+*******************************************************************
+"""
+from __future__ import print_function
+
+# Trace MQTT traffic
+import MQTTV3112 as MQTTV3
+
+import socket, sys, select, traceback, datetime, os
+import SocketServer as socketserver
+
+logging = True
+myWindow = None
+
+
+def timestamp():
+  now = datetime.datetime.now()
+  return now.strftime('%Y%m%d %H%M%S')+str(float("."+str(now.microsecond)))[1:]
+
+
+class MyHandler(socketserver.StreamRequestHandler):
+
+  def handle(self):
+    if not hasattr(self, "ids"):
+      self.ids = {}
+    if not hasattr(self, "versions"):
+      self.versions = {}
+    inbuf = True
+    i = o = e = None
+    try:
+      clients = self.request
+      brokers = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+      brokers.connect((brokerhost, brokerport))
+      terminated = False
+      while inbuf != None and not terminated:
+        (i, o, e) = select.select([clients, brokers], [], [])
+        for s in i:
+          if s == clients:
+            inbuf = MQTTV3.getPacket(clients) # get one packet
+            if inbuf == None:
+              break
+            try:
+              packet = MQTTV3.unpackPacket(inbuf)
+              if packet.fh.MessageType == MQTTV3.PUBLISH and \
+                  packet.topicName == "MQTTSAS topic" and \
+                  packet.data == b"TERMINATE":
+                print("Terminating client", self.ids[id(clients)])
+                brokers.close()
+                clients.close()
+                terminated = True
+                break
+              elif packet.fh.MessageType == MQTTV3.CONNECT:
+                self.ids[id(clients)] = packet.ClientIdentifier
+                self.versions[id(clients)] = 3
+              print(timestamp() , "C to S", self.ids[id(clients)], repr(packet))
+              #print([hex(b) for b in inbuf])
+              #print(inbuf)
+            except:
+              traceback.print_exc()
+            brokers.send(inbuf)       # pass it on
+          elif s == brokers:
+            inbuf = MQTTV3.getPacket(brokers) # get one packet
+            if inbuf == None:
+              break
+            try:
+              print(timestamp(), "S to C", self.ids[id(clients)], repr(MQTTV3.unpackPacket(inbuf)))
+            except:
+              traceback.print_exc()
+            clients.send(inbuf)
+      print(timestamp()+" client "+self.ids[id(clients)]+" connection closing")
+    except:
+      print(repr((i, o, e)), repr(inbuf))
+      traceback.print_exc()
+    if id(clients) in self.ids.keys():
+      del self.ids[id(clients)]
+    elif id(clients) in self.versions.keys():
+      del self.versions[id(clients)]
+
+class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
+  pass
+
+def run():
+  global brokerhost, brokerport
+  myhost = '127.0.0.1'
+  if len(sys.argv) > 1:
+    brokerhost = sys.argv[1]
+  else:
+    brokerhost = '127.0.0.1'
+
+  if len(sys.argv) > 2:
+    brokerport = int(sys.argv[2])
+  else:
+    brokerport = 1883
+
+  if len(sys.argv) > 3:
+    myport = int(sys.argv[3])
+  else:
+    if brokerhost == myhost:
+      myport = brokerport + 1
+    else:
+      myport = 1883
+
+  print("Listening on port", str(myport)+", broker on port", brokerport)
+  s = ThreadingTCPServer(("127.0.0.1", myport), MyHandler)
+  s.serve_forever()
+
+if __name__ == "__main__":
+  run()
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/travis-build.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/travis-build.sh	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+rm -rf build.paho
+mkdir build.paho
+cd build.paho
+echo "travis build dir $TRAVIS_BUILD_DIR pwd $PWD"
+cmake ..
+make
+python ../test/mqttsas2.py localhost 1883 1885 &
+ctest -VV --timeout 600
+kill %1
+killall mosquitto
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/travis-env-vars
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/travis-env-vars	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,2 @@
+export TRAVIS_OS_NAME=linux
+export TRAVIS_BUILD_DIR=/home/icraggs/git/paho.mqtt.embedded-c
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/paho_mqtt_embedded_c/travis-install.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/paho_mqtt_embedded_c/travis-install.sh	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+if [ "$TRAVIS_OS_NAME" == "linux" ]; then
+	pwd
+	sudo service mosquitto stop
+	# Stop any mosquitto instance which may be still running from previous runs
+	killall mosquitto
+	mosquitto -h
+	mosquitto &
+fi
+
+if [ "$TRAVIS_OS_NAME" == "osx" ]; then
+	pwd
+	brew update
+	brew install openssl mosquitto
+	brew services stop mosquitto
+	/usr/local/sbin/mosquitto -h
+	/usr/local/sbin/mosquitto &
+fi
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/src/MQTTClientMbedOs.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/src/MQTTClientMbedOs.cpp	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2019, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MQTTClientMbedOs.h"
+#include "MQTTNetworkUtil.h"
+
+int MQTTNetworkMbedOs::read(unsigned char *buffer, int len, int timeout)
+{
+    return accumulate_mqtt_read(socket, buffer, len, timeout);
+}
+
+int MQTTNetworkMbedOs::write(unsigned char *buffer, int len, int timeout)
+{
+    return mqtt_write(socket, buffer, len, timeout);
+}
+
+int MQTTNetworkMbedOs::connect(const char *hostname, int port)
+{
+    SocketAddress sockAddr(hostname, port);
+    return socket->connect(sockAddr);
+}
+
+int MQTTNetworkMbedOs::disconnect()
+{
+    return socket->close();
+}
+
+MQTTClient::MQTTClient(TCPSocket *_socket)
+{
+    init(_socket);
+    mqttNet = new MQTTNetworkMbedOs(socket);
+    client = new MQTT::Client<MQTTNetworkMbedOs, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE, MBED_CONF_MBED_MQTT_MAX_CONNECTIONS>(*mqttNet);
+};
+
+#if defined(MBEDTLS_SSL_CLI_C) || defined(DOXYGEN_ONLY)
+MQTTClient::MQTTClient(TLSSocket *_socket)
+{
+    init(_socket);
+    mqttNet = new MQTTNetworkMbedOs(socket);
+    client = new MQTT::Client<MQTTNetworkMbedOs, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE, MBED_CONF_MBED_MQTT_MAX_CONNECTIONS>(*mqttNet);
+};
+#endif
+
+MQTTClient::MQTTClient(UDPSocket *_socket)
+{
+    init(_socket);
+    mqttNet = new MQTTNetworkMbedOs(socket);
+    clientSN = new MQTTSN::Client<MQTTNetworkMbedOs, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE, MBED_CONF_MBED_MQTT_MAX_CONNECTIONS>(*mqttNet);
+};
+
+#if defined(MBEDTLS_SSL_CLI_C) || defined(DOXYGEN_ONLY)
+MQTTClient::MQTTClient(DTLSSocket *_socket)
+{
+    init(_socket);
+    mqttNet = new MQTTNetworkMbedOs(socket);
+    clientSN = new MQTTSN::Client<MQTTNetworkMbedOs, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE, MBED_CONF_MBED_MQTT_MAX_CONNECTIONS>(*mqttNet);
+};
+#endif
+
+MQTTClient::~MQTTClient()
+{
+    delete mqttNet;
+    if (client != NULL) delete client;
+    if (clientSN != NULL) delete clientSN;
+}
+
+nsapi_error_t MQTTClient::connect(MQTTPacket_connectData &options)
+{
+    if (client == NULL) {
+        return NSAPI_ERROR_NO_CONNECTION;
+    }
+    nsapi_error_t ret = client->connect(options);
+    return ret < 0 ? NSAPI_ERROR_NO_CONNECTION : ret;
+}
+
+nsapi_error_t MQTTClient::connect(MQTTSNPacket_connectData &options)
+{
+    if (clientSN == NULL) {
+        return NSAPI_ERROR_NO_CONNECTION;
+    }
+    nsapi_error_t ret = clientSN->connect(options);
+    return ret < 0 ? NSAPI_ERROR_NO_CONNECTION : ret;
+}
+
+nsapi_error_t MQTTClient::publish(const char *topicName, MQTT::Message &message)
+{
+    if (client == NULL) {
+        return NSAPI_ERROR_NO_CONNECTION;
+    }
+    nsapi_error_t ret = client->publish(topicName, message);
+    return ret < 0 ? NSAPI_ERROR_NO_CONNECTION : ret;
+}
+
+nsapi_error_t MQTTClient::publish(MQTTSN_topicid &topicName, MQTTSN::Message &message)
+{
+    if (clientSN == NULL) {
+        return NSAPI_ERROR_NO_CONNECTION;
+    }
+    nsapi_error_t ret = clientSN->publish(topicName, message);
+    return ret < 0 ? NSAPI_ERROR_NO_CONNECTION : ret;
+}
+
+nsapi_error_t MQTTClient::subscribe(const char *topicFilter, enum MQTT::QoS qos, messageHandler mh)
+{
+    if (client == NULL) {
+        return NSAPI_ERROR_NO_CONNECTION;
+    }
+    nsapi_error_t ret = client->subscribe(topicFilter, qos, mh);
+    return ret < 0 ? NSAPI_ERROR_NO_CONNECTION : ret;
+}
+
+nsapi_error_t MQTTClient::subscribe(MQTTSN_topicid &topicFilter, enum MQTTSN::QoS qos, messageHandlerSN mh)
+{
+    if (clientSN == NULL) {
+        return NSAPI_ERROR_NO_CONNECTION;
+    }
+    nsapi_error_t ret = clientSN->subscribe(topicFilter, qos, mh);
+    return ret < 0 ? NSAPI_ERROR_NO_CONNECTION : ret;
+}
+
+nsapi_error_t MQTTClient::unsubscribe(const char *topicFilter)
+{
+    if (client == NULL) {
+        return NSAPI_ERROR_NO_CONNECTION;
+    }
+    nsapi_error_t ret = client->unsubscribe(topicFilter);
+    return ret < 0 ? NSAPI_ERROR_NO_CONNECTION : ret;
+}
+
+nsapi_error_t MQTTClient::unsubscribe(MQTTSN_topicid &topicFilter)
+{
+    if (clientSN == NULL) {
+        return NSAPI_ERROR_NO_CONNECTION;
+    }
+    nsapi_error_t ret = clientSN->unsubscribe(topicFilter);
+    return ret < 0 ? NSAPI_ERROR_NO_CONNECTION : ret;
+}
+
+nsapi_error_t MQTTClient::yield(unsigned long timeout_ms)
+{
+    nsapi_error_t ret = NSAPI_ERROR_OK;
+    if (client != NULL) {
+        ret = client->yield(timeout_ms);
+    } else if (clientSN != NULL) {
+        ret = clientSN->yield(timeout_ms);
+    } else {
+        return NSAPI_ERROR_NO_CONNECTION;
+    }
+    return ret < 0 ? NSAPI_ERROR_NO_CONNECTION : ret;
+}
+
+nsapi_error_t MQTTClient::disconnect()
+{
+    nsapi_error_t ret = NSAPI_ERROR_OK;
+    if (client != NULL) {
+        ret = client->disconnect();
+    } else if (clientSN != NULL) {
+        ret = clientSN->disconnect(0);
+    } else {
+        return NSAPI_ERROR_NO_CONNECTION;
+    }
+    return ret < 0 ? NSAPI_ERROR_NO_CONNECTION : ret;
+}
+
+bool MQTTClient::isConnected()
+{
+    if ((client == NULL && clientSN == NULL) || 
+            (client != NULL && clientSN != NULL)){
+        return false;
+    } else if( client != NULL) {
+        return client->isConnected();
+    } else {
+        return clientSN->isConnected();
+    }
+}
+
+void MQTTClient::setDefaultMessageHandler(messageHandler mh)
+{
+    if (client != NULL) {
+        client->setDefaultMessageHandler(mh);
+    } else if (clientSN != NULL) {
+        client->setDefaultMessageHandler(mh);
+    }
+}
+
+nsapi_error_t MQTTClient::setMessageHandler(const char *topicFilter, messageHandler mh)
+{
+    if (clientSN != NULL) {
+        return NSAPI_ERROR_UNSUPPORTED;
+    } else if (client == NULL) {
+        return NSAPI_ERROR_NO_CONNECTION;
+    } else {
+        return client->setMessageHandler(topicFilter, mh);
+    }
+}
+
+void MQTTClient::init(Socket *sock)
+{
+    socket = sock;
+    client = NULL;
+    clientSN = NULL;
+}
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/src/MQTTClientMbedOs.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/src/MQTTClientMbedOs.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2019, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MQTT_CLIENT_MBED_OS_H
+#define MQTT_CLIENT_MBED_OS_H
+
+#include <TCPSocket.h>
+#include <TLSSocket.h>
+#include <DTLSSocket.h>
+#include <UDPSocket.h>
+#include "unity/unity.h"
+
+#include "FP.h"
+#include <MQTTPacket.h>
+#include <MQTTClient.h>
+#include <MQTTSNPacket.h>
+#include <MQTTSNClient.h>
+#include <MQTTmbed.h> // Countdown
+
+/**
+ * @brief Implementation of the Network class template parameter of MQTTClient.
+ */
+class MQTTNetworkMbedOs {
+public:
+    /**
+     * @brief Construct the network implementation.
+     *
+     * If TCPSocket or TLSSocket are provided, the MQTT protocol will be used.
+     * If UDPSocket or DTLSSocket are provided, the MQTT-SN protocol will be used.
+     *
+     * @param _socket socket to be used for MQTT communication.
+     */
+    MQTTNetworkMbedOs(Socket *_socket) : socket(_socket) {}
+
+    /**
+     * @brief Read data from the socket.
+     *
+     * @param buffer buffer to store the data
+     * @param len expected amount of bytes
+     * @param timeout timeout for the operation
+     */
+    int read(unsigned char *buffer, int len, int timeout);
+
+    /**
+     * @brief Write data to the socket.
+     *
+     * @param buffer buffer that contains data to be written
+     * @param len amount of bytes to write
+     * @param timeout timeout for the operation
+     */
+    int write(unsigned char *buffer, int len, int timeout);
+
+    /**
+     * @brief Connect the socket to the hostname at a given port.
+     *
+     * The socket must have the network interface set up and connected before.
+     * This connect() is different from MQTTClient::connect, which performs the
+     * connection to a broker, over the connected socket.
+     *
+     * @param hostname Hostname to connect to. This can be a string containing
+     * IP address like "192.168.52.10" or domain address, like "mqtt.flespi.io"
+     * @param port port number to be used for connection
+     */
+    int connect(const char *hostname, int port);
+
+    /**
+     * @brief Disconnect from the hostname.
+     */
+    int disconnect();
+
+private:
+    Socket *socket;
+};
+
+/**
+ * @brief MQTT client mbed-os wrapper class
+ *
+ * This class wraps around the paho library templated MQTT(-SN)Client.
+ * It depends on the type of socket provided whether MQTT or MQTT-SN will be used.
+ * MQTTNetworkMbedOs will be used as a Network for the paho MQTTClient.
+ */
+class MQTTClient {
+public:
+    /** MQTT message handler */
+    typedef void (*messageHandler)(MQTT::MessageData &);
+    /** MQTT-SN message handler */
+    typedef void (*messageHandlerSN)(MQTTSN::MessageData &);
+
+    /**
+     * @brief Constructor for the TCPSocket-based communication.
+     * MQTT protocol will be used.
+     *
+     * @param _socket socket to be used for communication
+     */
+    MQTTClient(TCPSocket *_socket);
+#if defined(MBEDTLS_SSL_CLI_C) || defined(DOXYGEN_ONLY)
+    /**
+     * @brief Constructor for the TLSSocket-based communication.
+     * MQTT protocol will be used over a secure socket.
+     *
+     * @param _socket socket to be used for communication
+     */
+    MQTTClient(TLSSocket *_socket);
+#endif
+    /**
+     * @brief Constructor for the UDPSocket-based communication.
+     * MQTT-SN protocol will be used.
+     *
+     * @param _socket socket to be used for communication
+     */
+    MQTTClient(UDPSocket *_socket);
+#if defined(MBEDTLS_SSL_CLI_C) || defined(DOXYGEN_ONLY)
+    /**
+     * @brief Constructor for the DTLSSocket-based communication.
+     * MQTT-SN protocol will be used over a secure socket.
+     *
+     * @param _socket socket to be used for communication
+     */
+    MQTTClient(DTLSSocket *_socket);
+#endif
+
+    /**
+     * @brief Destructor for the TCPSocket-based communication.
+     */
+    ~MQTTClient();
+
+    /**
+     * @brief Connect to the MQTT broker
+     *
+     * This is different from connecting to the server, done in MQTTNetworkMbedOs::connect()
+     * and also different from connecting the network interface, that the socket is using.
+     *
+     * @param options options to be used for the connection.
+     * @retval NSAPI_ERROR_OK on success, error code on failure
+     */
+    nsapi_error_t connect(MQTTPacket_connectData &options);
+    /**
+     * @brief Connect to the MQTT broker via an MQTT-SN gateway
+     *
+     * This is different from connecting to the server, done in MQTTNetworkMbedOs::connect()
+     * and also different from connecting the network interface, that the socket is using.
+     *
+     * @param options options to be used for the connection.
+     * @retval NSAPI_ERROR_OK on success, error code on failure
+     */
+    nsapi_error_t connect(MQTTSNPacket_connectData &options);
+
+    /**
+     * @brief Publish message to a topic.
+     * @param topicName string with a topic name
+     * @param message message to be published
+     * @retval NSAPI_ERROR_OK on success, error code on failure
+     */
+    nsapi_error_t publish(const char *topicName, MQTT::Message &message);
+    /**
+     * @brief Publish message to an MQTT-SN topic.
+     * @param topicName MQTTSN_topicid structure specifying the topic.
+     * @param message message to be published
+     * @retval NSAPI_ERROR_OK on success, error code on failure
+     */
+    nsapi_error_t publish(MQTTSN_topicid &topicName, MQTTSN::Message &message);
+
+    /**
+     * @brief Subscribe to a topic.
+     * @param topicFilter string with a topic filter
+     * @param qos level of qos to be received
+     * @param mh message handler to be called upon message reception
+     * @retval NSAPI_ERROR_OK on success, error code on failure
+     */
+    nsapi_error_t subscribe(const char *topicFilter, enum MQTT::QoS qos, messageHandler mh);
+    /**
+     * @brief Subscribe to an MQTT-SN topic.
+     * @param topicFilter string with a topic filter
+     * @param qos level of qos to be received
+     * @param mh message handler to be called upon message reception
+     * @retval NSAPI_ERROR_OK on success, error code on failure
+     */
+    nsapi_error_t subscribe(MQTTSN_topicid &topicFilter, enum MQTTSN::QoS qos, messageHandlerSN mh);
+
+    /**
+     * @brief Unsubscribe from a topic.
+     * @param topicFilter string with a topic filter
+     * @retval NSAPI_ERROR_OK on success, error code on failure
+     */
+    nsapi_error_t unsubscribe(const char *topicFilter);
+    /**
+     * @brief Unsubscribe from an MQTT-SN topic.
+     * @param topicFilter string with a topic filter
+     * @retval NSAPI_ERROR_OK on success, error code on failure
+     */
+    nsapi_error_t unsubscribe(MQTTSN_topicid &topicFilter);
+
+    /**
+     * @brief Yield current thread execution and handle other events
+     * @param timeout_ms ms to yield for
+     * @retval NSAPI_ERROR_OK on success, error code on failure
+     */
+    nsapi_error_t yield(unsigned long timeout_ms = 1000L) ;
+
+    /**
+     * @brief Disconnect from a broker, that the client has been connected to.
+     * @retval NSAPI_ERROR_OK on success, error code on failure
+     */
+    nsapi_error_t disconnect();
+
+    /**
+     * @brief Check whether client is connected to a broker.
+     * @retval true if the client is connected, false otherwise
+     */
+    bool isConnected();
+
+    /** Set the default message handling callback - used for any message which does not match a subscription message handler
+     *  @param mh - pointer to the callback function.  Set to 0 to remove.
+     */
+    void setDefaultMessageHandler(messageHandler mh);
+
+    /** Set a message handling callback.  This can be used outside of the the subscribe method.
+     *  @param topicFilter - a topic pattern which can include wildcards
+     *  @param mh - pointer to the callback function. If 0, removes the callback if any
+     */
+    nsapi_error_t setMessageHandler(const char *topicFilter, messageHandler mh);
+
+private:
+    /**
+     * @brief Helper function to initialize member variables.
+     */
+    void init(Socket *sock);
+
+    Socket *socket;
+    MQTTNetworkMbedOs *mqttNet;
+    NetworkInterface *net;
+
+    MQTT::Client<MQTTNetworkMbedOs, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE, MBED_CONF_MBED_MQTT_MAX_CONNECTIONS> *client;
+    MQTTSN::Client<MQTTNetworkMbedOs, Countdown, MBED_CONF_MBED_MQTT_MAX_PACKET_SIZE, MBED_CONF_MBED_MQTT_MAX_CONNECTIONS> *clientSN;
+};
+
+#endif // MQTT_CLIENT_MBED_OS_H
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/src/MQTTNetwork.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/src/MQTTNetwork.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _MQTTNETWORK_H_
+#define _MQTTNETWORK_H_
+
+#include "NetworkInterface.h"
+#include "TCPSocket.h"
+#include "MQTTNetworkUtil.h"
+
+class MQTTNetwork {
+public:
+    MQTTNetwork(NetworkInterface *aNetwork) : network(aNetwork)
+    {
+        socket = new TCPSocket();
+    }
+
+    ~MQTTNetwork()
+    {
+        delete socket;
+    }
+
+    int read(unsigned char *buffer, int len, int timeout)
+    {
+        return accumulate_mqtt_read(socket, buffer, len, timeout);
+    }
+
+    int write(unsigned char *buffer, int len, int timeout)
+    {
+        return mqtt_write(socket, buffer, len, timeout);
+    }
+
+    int connect(const char *hostname, int port)
+    {
+        int ret = NSAPI_ERROR_OK;
+        if ((ret = socket->open(network)) != NSAPI_ERROR_OK) {
+            return ret;
+        }
+        SocketAddress addr;
+        if (network->gethostbyname(hostname, &addr) != NSAPI_ERROR_OK) {
+            return NSAPI_ERROR_DNS_FAILURE;
+        }
+        addr.set_port(port);
+        return socket->connect(addr);
+    }
+
+    int disconnect()
+    {
+        return socket->close();
+    }
+
+private:
+    NetworkInterface *network;
+    TCPSocket *socket;
+};
+
+#endif // _MQTTNETWORK_H_
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/src/MQTTNetworkTLS.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/src/MQTTNetworkTLS.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _MQTTNETWORKTLS_H_
+#define _MQTTNETWORKTLS_H_
+
+#include "NetworkInterface.h"
+#include "TLSSocket.h"
+#include "MQTTNetworkUtil.h"
+
+#if defined(MBEDTLS_SSL_CLI_C) || defined(DOXYGEN_ONLY)
+
+class MQTTNetworkTLS {
+public:
+    MQTTNetworkTLS(NetworkInterface *aNetwork) : network(aNetwork)
+    {
+        socket = new TLSSocket();
+    }
+
+    ~MQTTNetworkTLS()
+    {
+        delete socket;
+    }
+
+    int read(unsigned char *buffer, int len, int timeout)
+    {
+        return accumulate_mqtt_read(socket, buffer, len, timeout);
+    }
+
+    int write(unsigned char *buffer, int len, int timeout)
+    {
+        return mqtt_write(socket, buffer, len, timeout);
+    }
+
+    int connect(const char *hostname, int port, const char *ssl_ca_pem = NULL,
+                const char *ssl_cli_pem = NULL, const char *ssl_pk_pem = NULL)
+    {
+        int ret = socket->open(network);
+        if (ret < 0) {
+            return ret;
+        }
+        SocketAddress addr;
+        ret = network->gethostbyname(hostname, &addr);
+        if (ret < 0) {
+            return ret;
+        }
+        addr.set_port(port);
+        ret = socket->set_root_ca_cert(ssl_ca_pem);
+        if (ret < 0) {
+            return ret;
+        }
+        if (ssl_cli_pem != NULL && ssl_pk_pem != NULL) {
+            ret = socket->set_client_cert_key(ssl_cli_pem, ssl_pk_pem);
+            if (ret < 0) {
+                return ret;
+            }
+        }
+        return socket->connect(addr);
+    }
+
+    int disconnect()
+    {
+        return socket->close();
+    }
+
+    int set_root_ca_cert(const char *root_ca_pem)
+    {
+        return socket->set_root_ca_cert(root_ca_pem);
+    }
+
+private:
+    NetworkInterface *network;
+    TLSSocket *socket;
+};
+
+#endif // defined(MBEDTLS_SSL_CLI_C) || defined(DOXYGEN_ONLY)
+#endif // _MQTTNETWORKTLS_H_
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/src/MQTTNetworkUtil.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/src/MQTTNetworkUtil.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _MQTTNETWORK_UTIL_H_
+#define _MQTTNETWORK_UTIL_H_
+
+/* MQTT doesn't expect nsapi error values so we translate them */
+static int convert_nsapi_error_to_mqtt_error(int nsapi_error)
+{
+    if (nsapi_error == NSAPI_ERROR_WOULD_BLOCK) {
+        /* MQTT expects 0 on timeout */
+        return 0;
+    } else if (nsapi_error == 0) {
+        /* MQTT expect -1 on closed sockets */
+        return -1;
+    }
+    return nsapi_error;
+}
+
+/** Reads data and returns number of bytes read or a translated error that MQTT expects. This will call
+ * read on the socket multiple times until all data is retrieved.
+ *
+ * @tparam SocketType Socket type like TCPSocket.
+ * @param socket Socket to read data from.
+ * @param buffer Buffer to store data.
+ * @param len Length of expected data.
+ * @param timeout Timeout for the operation.
+ * @return Always returns the full length if successful or an error.
+ */
+template<typename SocketType>
+static int accumulate_mqtt_read(SocketType socket, unsigned char *buffer, int len, int timeout)
+{
+    /* TODO: Timout should be applied to whole operation not partial recv */
+    socket->set_timeout(timeout);
+
+    /* MQTT Client expects the full packet so we accumulate until we get all bytes */
+    int remaining = len;
+    while (remaining) {
+        int ret = socket->recv(buffer, remaining);
+        if (ret > 0) {
+            remaining -= ret;
+            buffer += ret;
+        } else {
+            return convert_nsapi_error_to_mqtt_error(ret);
+        }
+    }
+    return len;
+}
+
+/** Sends data and returns number of bytes sent or a translated error that MQTT expects.
+ *
+ * @tparam SocketType Socket type like TCPSocket.
+ * @param socket Socket to send data on.
+ * @param buffer Data to send.
+ * @param len Length of data.
+ * @param timeout Timeout for the operation.
+ * @return Always returns the full length if successful or an error.
+ */
+template<typename SocketType>
+static int mqtt_write(SocketType socket, unsigned char *buffer, int len, int timeout)
+{
+    socket->set_timeout(timeout);
+    int ret = socket->send(buffer, len);
+    if (ret > 0) {
+        return ret;
+    } else {
+        return convert_nsapi_error_to_mqtt_error(ret);
+    }
+}
+
+#endif // _MQTTNETWORK_UTIL_H_
diff -r 000000000000 -r ba7e439238ab mbed-mqtt-master/src/MQTTSNNetworkUDP.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-mqtt-master/src/MQTTSNNetworkUDP.h	Mon Jun 20 16:24:43 2022 +0000
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _MQTTNETWORKUDP_H_
+#define _MQTTNETWORKUDP_H_
+
+#include "UDPSocket.h"
+#include "MQTTNetworkUtil.h"
+
+class MQTTSNNetworkUDP {
+public:
+    MQTTSNNetworkUDP(NetworkInterface *net) :
+        network(net)
+    {
+        socket = new UDPSocket();
+    }
+
+    ~MQTTSNNetworkUDP()
+    {
+        delete socket;
+    }
+
+    int read(unsigned char *buffer, int len, int timeout)
+    {
+        return accumulate_mqtt_read(socket, buffer, len, timeout);
+    }
+
+    int write(unsigned char *buffer, int len, int timeout)
+    {
+        return mqtt_write(socket, buffer, len, timeout);
+    }
+
+    int connect(const char *hostname, int port)
+    {
+        socket->open(network);
+        SocketAddress addr(hostname, port);
+        return socket->connect(addr);
+    }
+
+    int disconnect(void)
+    {
+        return 0;
+    }
+
+private:
+    NetworkInterface *network;
+    UDPSocket *socket;
+};
+
+#endif // _MQTTNETWORKUDP_H_