├── .gitignore ├── LICENSE ├── global_defines.h ├── System.cpp ├── examples ├── sx1276 │ └── LoRaMqttsnClient │ │ └── LoRaMqttsnClient.ino ├── esp8266 │ ├── WiFiUdpUartBridge │ │ └── WiFiUdpUartBridge.ino │ ├── WiFiUdpMqttSnClient │ │ └── WiFiUdpMqttSnClient.ino │ ├── UdpMqttSnClient │ │ └── UdpMqttSnClient.ino │ └── TcpMqttSnClient │ │ └── TcpMqttSnClient.ino ├── rf95 │ ├── RF95GenericDriverSocketSerialBridge │ │ └── RF95GenericDriverSocketSerialBridge.ino │ ├── RF95DatagramSerialBridge │ │ └── RF95DatagramSerialBridge.ino │ ├── RF95DatagramConsoleBridge │ │ └── RF95DatagramConsoleBridge.ino │ ├── RF95GenericDriverSocketConsoleBridge │ │ └── RF95GenericDriverSocketConsoleBridge.ino │ ├── RF95SerialSniffer │ │ └── RF95SerialSniffer.ino │ ├── RF95DatagramMqttSnClient │ │ └── RF95DatagramMqttSnClient.ino │ ├── RF95SerialTransmitter │ │ └── RF95SerialTransmitter.ino │ ├── RF95ConsoleTransmitter │ │ └── RF95ConsoleTransmitter.ino │ └── RF95ConsoleSniffer │ │ └── RF95ConsoleSniffer.ino └── arduino_uno │ ├── TcpMqttSnClient │ └── TcpMqttSnClient.ino │ └── UdpMqttSnClient │ └── UdpMqttSnClient.ino ├── System.h ├── SX1276Socket.h ├── RHDatagramSocket.h ├── RHGenericDriverSocket.h ├── README.md ├── SocketInterface.h ├── WiFiUdpSocket.h ├── ClientSocket.h ├── UdpSocket.h ├── MqttSnMessageHandler.h ├── MqttSnClient.h ├── mqttsn_messages.h └── TransmissionProtocolUartBridge.h /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Gabriel Nikol 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /global_defines.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #ifndef ARDUINO_MQTTSN_CLIENT_GLOBAL_DEFINES_H 8 | #define ARDUINO_MQTTSN_CLIENT_GLOBAL_DEFINES_H 9 | 10 | #include 11 | 12 | struct device_address { 13 | uint8_t bytes[6]; // mac 14 | device_address() { 15 | bytes[0] = 0x0; 16 | bytes[1] = 0x0; 17 | bytes[2] = 0x0; 18 | bytes[3] = 0x0; 19 | bytes[4] = 0x0; 20 | bytes[5] = 0x0; 21 | } 22 | device_address(uint8_t one, uint8_t two, 23 | uint8_t three, uint8_t four, 24 | uint8_t five, uint8_t six) { 25 | bytes[0] = one; 26 | bytes[1] = two; 27 | bytes[2] = three; 28 | bytes[3] = four; 29 | bytes[4] = five; 30 | bytes[5] = six; 31 | } 32 | }; 33 | 34 | void printDeviceAddress(device_address *address) { 35 | for (uint8_t i = 0; i < sizeof(device_address); i++) { 36 | if (i == sizeof(device_address) - 1) { 37 | Serial.print(address->bytes[i]); 38 | } else { 39 | Serial.print(address->bytes[i]); 40 | Serial.print(", "); 41 | } 42 | } 43 | } 44 | 45 | #endif //ARDUINO_MQTTSN_CLIENT_GLOBAL_DEFINES_H 46 | -------------------------------------------------------------------------------- /System.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #include "System.h" 8 | 9 | void System::set_heartbeat(uint32_t period) { 10 | this->heartbeat_period = period; 11 | this->heartbeat_current = millis(); 12 | } 13 | 14 | uint32_t System::get_heartbeat() { 15 | return this->heartbeat_period; 16 | } 17 | 18 | bool System::has_beaten() { 19 | uint32_t current = millis(); 20 | if (current - heartbeat_current > heartbeat_period) { 21 | this->heartbeat_current = current; 22 | return true; 23 | } 24 | return false; 25 | } 26 | 27 | uint32_t System::get_elapsed_time() { 28 | uint32_t current = millis(); 29 | uint32_t elapsed_time = current - elapsed_current; 30 | elapsed_current = current; 31 | return elapsed_time; 32 | } 33 | 34 | void System::sleep(uint32_t duration) { 35 | delay(duration); 36 | } 37 | 38 | void System::exit() { 39 | #if defined(ESP8266) 40 | ESP.restart(); 41 | #elif defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_YUN) || defined(ARDUINO_AVR_MEGA2560) 42 | asm volatile (" jmp 0"); 43 | #else 44 | #error "System::exit() not properly implemented. This means we cannot reset the hardware. Change #error to #warning if you want to build anyway." 45 | #endif 46 | } 47 | -------------------------------------------------------------------------------- /examples/sx1276/LoRaMqttsnClient/LoRaMqttsnClient.ino: -------------------------------------------------------------------------------- 1 | #include "SX1276Socket.h" 2 | #include "MqttSnClient.h" 3 | 4 | SX1276Socket loRaSocket(sx1276); 5 | 6 | MqttSnClient mqttSnClient(loRaSocket); 7 | char* subscribeTopicName = "LoRa/SX1276/subscribe"; 8 | int8_t qos = 0; 9 | 10 | void mqttsn_callback(char *topic, uint8_t *payload, uint16_t length, bool retain) { 11 | Serial.print("Received - Topic: "); 12 | Serial.print(topic); 13 | Serial.print(" Payload: "); 14 | for (uint16_t i = 0; i < length; i++) { 15 | char c = (char) * (payload + i); 16 | Serial.print(c); 17 | } 18 | Serial.print(" Lenght: "); 19 | Serial.println(length); 20 | } 21 | 22 | void setup() { 23 | Serial.begin(115200); 24 | loRaSocket.begin(); 25 | Serial.print("Starting MqttSnClient - "); 26 | mqttSnClient.setCallback(mqttsn_callback); 27 | if (!mqttSnClient.begin()) { 28 | Serial.print("Could not initialize MQTT-SN Client "); 29 | while (true) { 30 | Serial.println("."); 31 | delay(1000); 32 | } 33 | } 34 | Serial.println(" ready!"); 35 | 36 | } 37 | 38 | void loop() { 39 | if (mqttSnClient.is_mqttsn_connected()) { 40 | Serial.println("Connected to gateway"); 41 | } 42 | Serial.println("MQTT-SN Client connected."); 43 | mqttSnClient.subscribe(subscribeTopicName, qos); 44 | mqttSnClient.loop(); 45 | 46 | } 47 | -------------------------------------------------------------------------------- /System.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Copyright (c) 2018 Gabriel Nikol 5 | */ 6 | 7 | #ifndef ARDUINO_MQTTSN_CLIENT_SYSTEM_H 8 | #define ARDUINO_MQTTSN_CLIENT_SYSTEM_H 9 | 10 | #include 11 | 12 | #if ARDUINO >= 100 13 | #include "Arduino.h" 14 | #endif 15 | 16 | /** 17 | * Defines basic functionality provided by an underlying OS or must be implemented otherwise. 18 | */ 19 | class System { 20 | private: 21 | uint32_t heartbeat_period = 10000; 22 | uint32_t heartbeat_current = 0; 23 | uint32_t elapsed_current = 0; 24 | 25 | public: 26 | /** 27 | * Sets the heartbeat value where the System perform regular checks. 28 | * Default value is a period of 30 000 ms 29 | * @param period 30 | */ 31 | virtual void set_heartbeat(uint32_t period); 32 | 33 | /** 34 | * Gets the heartbeat value where the System perform regular checks. 35 | * Default value is a period of 30 000 ms 36 | */ 37 | virtual uint32_t get_heartbeat(); 38 | 39 | /** 40 | * Checks if the heartbeat is timed out. 41 | * @return true if the heartbeat value was reached, false otherwise. 42 | */ 43 | virtual bool has_beaten(); 44 | 45 | /** 46 | * Get the elapsed time between two calls of this function. 47 | * @return the elapsed time between two calls 48 | */ 49 | virtual uint32_t get_elapsed_time(); 50 | 51 | /** 52 | * Lets the execution sleep for some seconds. 53 | */ 54 | virtual void sleep(uint32_t duration); 55 | 56 | /** 57 | * Stop/exit the whole program or restart it if you want to. 58 | */ 59 | virtual void exit(); 60 | }; 61 | 62 | #endif //ARDUINO_MQTTSN_CLIENT_SYSTEM_H 63 | -------------------------------------------------------------------------------- /examples/esp8266/WiFiUdpUartBridge/WiFiUdpUartBridge.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 2018 Gabriel Nikol 5 | */ 6 | 7 | #include 8 | #include 9 | #include "WiFiUdpSocket.h" 10 | #include "TransmissionProtocolUartBridge.h" 11 | 12 | const char* ssid = "your-ssid"; 13 | const char* password = "your-password"; 14 | 15 | WiFiUDP udp; 16 | uint16_t localUdpPort = 8888; 17 | WiFiUdpSocket wiFiUdpSocket(udp, localUdpPort); 18 | 19 | TransmissionProtocolUartBridge transmissionProtocolUartBridge(&Serial, wiFiUdpSocket); 20 | 21 | void setup(){ 22 | Serial.begin(115200); 23 | while (!Serial) { } 24 | 25 | Serial.println(); 26 | Serial.print("Connecting to "); 27 | Serial.println(ssid); 28 | 29 | /* Explicitly set the ESP8266 to be a WiFi-client, otherwise, it by default, 30 | would try to act as both a client and an access-point and could cause 31 | network-issues with your other WiFi-devices on your WiFi-network. */ 32 | WiFi.mode(WIFI_STA); 33 | WiFi.begin(ssid, password); 34 | 35 | while (WiFi.status() != WL_CONNECTED) { 36 | delay(500); 37 | Serial.print("."); 38 | } 39 | 40 | Serial.println(""); 41 | Serial.println("WiFi connected"); 42 | Serial.println("IP address: "); 43 | Serial.println(WiFi.localIP()); 44 | 45 | Serial.print("Starting TransmissionProtocolUartBridge - "); 46 | //mqttSnClient.setCallback(mqttsn_callback); 47 | if (!transmissionProtocolUartBridge.begin()) { 48 | Serial.print("Could not initialize TransmissionProtocolUartBridge "); 49 | while (true) { 50 | Serial.println("."); 51 | delay(1000); 52 | } 53 | } 54 | Serial.println(" ready!"); 55 | } 56 | 57 | void loop(){ 58 | if (Serial.available() > 0) { 59 | char c = Serial.read(); 60 | transmissionProtocolUartBridge.putChar(c); 61 | } 62 | transmissionProtocolUartBridge.loop(); 63 | } 64 | -------------------------------------------------------------------------------- /examples/rf95/RF95GenericDriverSocketSerialBridge/RF95GenericDriverSocketSerialBridge.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #include "RHGenericDriverSocket.h" 8 | #include "MqttSnClient.h" 9 | #include 10 | 11 | 12 | #define RFM95_CS 10 13 | #define RFM95_RST 9 14 | //#define RFM95_INT 7 15 | #define RFM95_INT 2 16 | 17 | #define FREQUENCY 434.0 18 | #define TX_POWER 13 19 | #define MODEM_CONFIG_CHOICE RH_RF95::Bw125Cr48Sf4096 20 | 21 | #define OWN_ADDRESS 3 22 | 23 | RH_RF95 rf95(RFM95_CS, RFM95_INT); 24 | RHGenericDriverSocket rhGenericDriverSocket(&rf95, OWN_ADDRESS); 25 | TransmissionProtocolUartBridge transmissionProtocolUartBridge(&Serial, rhGenericDriverSocket); 26 | 27 | #define BAUDRATE 115200 28 | 29 | void setup() { 30 | // Initialize Console and wait for port to open: 31 | Serial.begin(BAUDRATE); 32 | 33 | // Wait for Console por t to connect 34 | while (!Serial) {} 35 | 36 | if (!transmissionProtocolUartBridge.begin()) { 37 | Serial.print("Could not initialize RHRF95DatagramUartBridge "); 38 | while (true) { 39 | Serial.println("."); 40 | delay(1000); 41 | } 42 | } 43 | 44 | // Configure RH_RF95 driver after init 45 | // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 46 | 47 | if (!rf95.setFrequency(FREQUENCY)) { 48 | Serial.print(F("setFrequency failed\n")); 49 | while (true) { 50 | Serial.println("."); 51 | delay(1000); 52 | } 53 | } 54 | Serial.print("Set Freq to: "); Serial.println(FREQUENCY); 55 | 56 | if (!rf95.setModemConfig(RH_RF95::MODEM_CONFIG_CHOICE)) { 57 | Serial.print(F("setModemConfig failed\n")); 58 | while (true) { 59 | Serial.println("."); 60 | delay(1000); 61 | } 62 | } 63 | Serial.print("Set Modem Config to: "); Serial.println(RH_RF95::MODEM_CONFIG_CHOICE); 64 | 65 | rf95.setTxPower(TX_POWER); 66 | Serial.print("Set TX Power to: "); Serial.println(TX_POWER); 67 | 68 | Serial.println("RF95GenericDriverSocketSerialBridge v0.1 ready!"); 69 | } 70 | 71 | void loop() { 72 | if (Serial.available() > 0) { 73 | char c = Serial.read(); 74 | transmissionProtocolUartBridge.putChar(c); 75 | } 76 | transmissionProtocolUartBridge.loop(); 77 | } 78 | -------------------------------------------------------------------------------- /examples/rf95/RF95DatagramSerialBridge/RF95DatagramSerialBridge.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | 8 | #include 9 | #include "RHDatagramSocket.h" 10 | #include "MqttSnClient.h" 11 | #include 12 | 13 | #define RFM95_CS 10 14 | #define RFM95_RST 9 15 | //#define RFM95_INT 7 16 | #define RFM95_INT 2 17 | 18 | #define FREQUENCY 434.0 19 | #define TX_POWER 13 20 | #define MODEM_CONFIG_CHOICE RH_RF95::Bw125Cr48Sf4096 21 | 22 | #define OWN_ADDRESS 3 23 | 24 | RH_RF95 rf95(RFM95_CS, RFM95_INT); 25 | RHDatagram rhDatagram(rf95, OWN_ADDRESS); 26 | RHDatagramSocket rhDatagramSocket(rhDatagram); 27 | 28 | TransmissionProtocolUartBridge transmissionProtocolUartBridge(&Serial, rhDatagramSocket); 29 | 30 | #define BAUDRATE 115200 31 | 32 | void setup() { 33 | // Initialize Console and wait for port to open: 34 | Serial.begin(BAUDRATE); 35 | 36 | // Wait for Console port to connect 37 | while (!Serial) {} 38 | 39 | if (!transmissionProtocolUartBridge.begin()) { 40 | Serial.print("Could not initialize RHRF95DatagramUartBridge "); 41 | while (true) { 42 | Serial.println("."); 43 | delay(1000); 44 | } 45 | } 46 | 47 | // Configure RH_RF95 driver after init 48 | // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 49 | 50 | if (!rf95.setFrequency(FREQUENCY)) { 51 | Serial.print(F("setFrequency failed\n")); 52 | while (true) { 53 | Serial.println("."); 54 | delay(1000); 55 | } 56 | } 57 | Serial.print("Set Freq to: "); Serial.println(FREQUENCY); 58 | 59 | if (!rf95.setModemConfig(RH_RF95::MODEM_CONFIG_CHOICE)) { 60 | Serial.print(F("setModemConfig failed\n")); 61 | while (true) { 62 | Serial.println("."); 63 | delay(1000); 64 | } 65 | } 66 | Serial.print("Set Modem Config to: "); Serial.println(RH_RF95::MODEM_CONFIG_CHOICE); 67 | 68 | rf95.setTxPower(TX_POWER); 69 | Serial.print("Set TX Power to: "); Serial.println(TX_POWER); 70 | 71 | Serial.println("RHRF95DatagramSerialBridge v0.1 ready!"); 72 | } 73 | 74 | void loop() { 75 | if (Serial.available() > 0) { 76 | char c = Serial.read(); 77 | transmissionProtocolUartBridge.putChar(c); 78 | } 79 | transmissionProtocolUartBridge.loop(); 80 | } 81 | -------------------------------------------------------------------------------- /examples/rf95/RF95DatagramConsoleBridge/RF95DatagramConsoleBridge.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #include 8 | #include "RHDatagramSocket.h" 9 | #include "TransmissionProtocolUartBridge.h" 10 | #include 11 | #include 12 | 13 | RH_RF95 rf95; 14 | #define FREQUENCY 434.0 15 | #define TX_POWER 13 16 | #define MODEM_CONFIG_CHOICE Bw125Cr48Sf4096 17 | 18 | #define OWN_ADDRESS 2 19 | 20 | RHDatagram rhDatagram(rf95, OWN_ADDRESS); 21 | RHDatagramSocket rhDatagramSocket(rhDatagram); 22 | 23 | TransmissionProtocolUartBridge transmissionProtocolUartBridge(&Console, rhDatagramSocket); 24 | 25 | 26 | //If you use Dragino IoT Mesh Firmware, uncomment below lines. 27 | //For product: LG01. 28 | #define BAUDRATE 115200 29 | 30 | //If you use Dragino Yun Mesh Firmware , uncomment below lines. 31 | //#define BAUDRATE 250000 32 | 33 | void setup() { 34 | // Initialize Console and wait for port to open: 35 | Bridge.begin(BAUDRATE); 36 | Console.begin(); 37 | 38 | // Wait for Console port to connect 39 | while (!Console); 40 | 41 | if (!transmissionProtocolUartBridge.begin()) { 42 | Console.print("Could not initialize RHRF95DatagramUartBridge "); 43 | while (true) { 44 | Console.println("."); 45 | delay(1000); 46 | } 47 | } 48 | 49 | // Configure RH_RF95 driver after init 50 | // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 51 | 52 | if (!rf95.setFrequency(FREQUENCY)) { 53 | Console.print(F("setFrequency failed\n")); 54 | while (true) { 55 | Console.println("."); 56 | delay(1000); 57 | } 58 | } 59 | Console.print("Set Freq to: "); Console.println(FREQUENCY); 60 | 61 | if (!rf95.setModemConfig(RH_RF95::MODEM_CONFIG_CHOICE)) { 62 | Console.print(F("setModemConfig failed\n")); 63 | while (true) { 64 | Console.println("."); 65 | delay(1000); 66 | } 67 | } 68 | Console.print("Set Modem Config to: "); Console.println(RH_RF95::MODEM_CONFIG_CHOICE); 69 | 70 | rf95.setTxPower(TX_POWER); 71 | Console.print("Set TX Power to: "); Console.println(TX_POWER); 72 | 73 | Console.println("RHRF95DatagramConsoleBridge v0.1 ready!"); 74 | } 75 | 76 | void loop() { 77 | if (Console.available() > 0) { 78 | char c = Console.read(); 79 | transmissionProtocolUartBridge.putChar(c); 80 | } 81 | transmissionProtocolUartBridge.loop(); 82 | } 83 | -------------------------------------------------------------------------------- /examples/rf95/RF95GenericDriverSocketConsoleBridge/RF95GenericDriverSocketConsoleBridge.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #include "RHGenericDriverSocket.h" 8 | #include "MqttSnClient.h" 9 | #include 10 | #include 11 | 12 | #define RFM95_CS 10 13 | #define RFM95_RST 9 14 | //#define RFM95_INT 7 15 | #define RFM95_INT 2 16 | 17 | #define FREQUENCY 434.0 18 | #define TX_POWER 13 19 | #define MODEM_CONFIG_CHOICE Bw125Cr48Sf4096 20 | 21 | #define OWN_ADDRESS 2 22 | 23 | RH_RF95 rf95(RFM95_CS, RFM95_INT); 24 | RHGenericDriverSocket rhGenericDriverSocket(&rf95, OWN_ADDRESS); 25 | TransmissionProtocolUartBridge transmissionProtocolUartBridge(&Console, rhGenericDriverSocket); 26 | 27 | //If you use Dragino IoT Mesh Firmware, uncomment below lines. 28 | //For product: LG01. 29 | #define BAUDRATE 115200 30 | 31 | //If you use Dragino Yun Mesh Firmware , uncomment below lines. 32 | //#define BAUDRATE 250000 33 | 34 | void setup() { 35 | // Initialize Console and wait for port to open: 36 | Bridge.begin(BAUDRATE); 37 | Console.begin(); 38 | 39 | // Wait for Console port to connect 40 | while (!Console); 41 | 42 | if (!transmissionProtocolUartBridge.begin()) { 43 | Console.print("Could not initialize RHRF95DatagramUartBridge "); 44 | while (true) { 45 | Console.println("."); 46 | delay(1000); 47 | } 48 | } 49 | 50 | // Configure RH_RF95 driver after init 51 | // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 52 | 53 | if (!rf95.setFrequency(FREQUENCY)) { 54 | Console.print(F("setFrequency failed\n")); 55 | while (true) { 56 | Console.println("."); 57 | delay(1000); 58 | } 59 | } 60 | Console.print("Set Freq to: "); Console.println(FREQUENCY); 61 | 62 | if (!rf95.setModemConfig(RH_RF95::MODEM_CONFIG_CHOICE)) { 63 | Console.print(F("setModemConfig failed\n")); 64 | while (true) { 65 | Console.println("."); 66 | delay(1000); 67 | } 68 | } 69 | Console.print("Set Modem Config to: "); Console.println(RH_RF95::MODEM_CONFIG_CHOICE); 70 | 71 | rf95.setTxPower(TX_POWER); 72 | Console.print("Set TX Power to: "); Console.println(TX_POWER); 73 | 74 | Console.println("RF95GenericDriverSocketConsoleBridge v0.1 ready!"); 75 | } 76 | 77 | void loop() { 78 | if (Console.available() > 0) { 79 | char c = Console.read(); 80 | transmissionProtocolUartBridge.putChar(c); 81 | } 82 | transmissionProtocolUartBridge.loop(); 83 | } -------------------------------------------------------------------------------- /SX1276Socket.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Bassirou on 09.09.2018. 3 | // 4 | 5 | #ifndef ARDUINO_MQTTSN_CLIENT_LORASOCKET_H 6 | #define ARDUINO_MQTTSN_CLIENT_LORASOCKET_H 7 | 8 | 9 | #include "MqttSnMessageHandler.h" 10 | #include "SocketInterface.h" 11 | #include 12 | 13 | #define LORA_MODE 4 14 | #define LORA_CHANNEL CH_10_868 15 | #define LORA_POWER 'H' 16 | #define LORA_ADDR 3 17 | 18 | 19 | class SX1276Socket : SocketInterface { 20 | private: 21 | SX1276 &loraConnection; 22 | uint16_t port; 23 | device_address own_address; 24 | device_address receive_address; 25 | uint8_t receive_buffer[MAX_PAYLOAD]; 26 | public: 27 | 28 | SX1276Socket(SX1276 &loraConnection) : loraConnection(loraConnection){}; 29 | 30 | 31 | bool begin() override { 32 | loraConnection.ON(); 33 | loraConnection.setMode(LORA_MODE); 34 | loraConnection.setChannel(CH_10_868); 35 | loraConnection.setPower(LORA_POWER); 36 | loraConnection.setNodeAddress(LORA_ADDR); 37 | return 1; 38 | } 39 | device_address *getBroadcastAddress() override { 40 | // TODO return multicast address 41 | return nullptr; 42 | } 43 | 44 | device_address *getAddress() override { 45 | own_address.bytes[0] = LORA_ADDR; 46 | return &own_address; 47 | } 48 | 49 | uint8_t getMaximumMessageLength() override { 50 | return MAX_PAYLOAD; 51 | } 52 | 53 | bool send(device_address *destination, uint8_t *bytes, uint16_t bytes_len) override { 54 | return send(destination, bytes, bytes_len, UINT8_MAX); 55 | } 56 | 57 | bool send(device_address *destination, uint8_t *bytes, uint16_t bytes_len, uint8_t signal_strength) override { 58 | loraConnection.sendPacketTimeout(destination->bytes[1], bytes, bytes_len); 59 | 60 | return false; 61 | } 62 | 63 | bool loop() override { 64 | if (loraConnection.availableData()) { 65 | device_address from; 66 | memset(&from.bytes[0], 0x0, sizeof(device_address)); 67 | int available = loraConnection.receive(); 68 | if (available == 0) { 69 | memcpy(receive_buffer,loraConnection.packet_received.data, loraConnection.packet_received.length); 70 | from.bytes[0] = loraConnection.packet_received.dst; 71 | mqttSnMessageHandler->receiveData(&from, receive_buffer); 72 | } 73 | } 74 | return true; 75 | } 76 | 77 | template 78 | void setMqttSnMessageHandler( 79 | MqttSnMessageHandler *mqttSnMessageHandler) { 80 | this->mqttSnMessageHandler = mqttSnMessageHandler; 81 | }; 82 | private: 83 | MqttSnMessageHandler *mqttSnMessageHandler; 84 | }; 85 | 86 | 87 | #endif //ARDUINO_MQTTSN_CLIENT_LORASOCKET_H 88 | -------------------------------------------------------------------------------- /RHDatagramSocket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #ifndef ARDUINO_MQTT_SN_CLIENT_RHDATAGRAMSOCKET_H 8 | #define ARDUINO_MQTT_SN_CLIENT_RHDATAGRAMSOCKET_H 9 | 10 | #include "MqttSnMessageHandler.h" 11 | #include "SocketInterface.h" 12 | 13 | class RHDatagramSocket : SocketInterface { 14 | private: 15 | RHDatagram &rhDatagram; 16 | 17 | device_address own_address; 18 | device_address broadcast_address; 19 | 20 | public: 21 | RHDatagramSocket(RHDatagram &rhDatagram) : rhDatagram(rhDatagram) {}; 22 | 23 | bool begin() override { 24 | own_address = device_address(rhDatagram.thisAddress(), 0, 0, 0, 0, 0); 25 | broadcast_address = device_address(RH_BROADCAST_ADDRESS, 0, 0, 0, 0, 0); 26 | return rhDatagram.init(); 27 | } 28 | 29 | device_address *getBroadcastAddress() override { 30 | return &broadcast_address; 31 | } 32 | 33 | device_address *getAddress() override { 34 | return &own_address; 35 | } 36 | 37 | uint8_t getMaximumMessageLength() override { 38 | return RH_MAX_MESSAGE_LEN; 39 | } 40 | 41 | bool send(device_address *destination, uint8_t *bytes, uint16_t bytes_len) override { 42 | return send(destination, bytes, bytes_len, UINT8_MAX); 43 | } 44 | 45 | bool send(device_address *destination, uint8_t *bytes, uint16_t bytes_len, uint8_t signal_strength) override { 46 | if (!rhDatagram.sendto(bytes, bytes_len, destination->bytes[0])) { 47 | rhDatagram.waitPacketSent(); 48 | rhDatagram.available(); // put it back to receive mode 49 | return false; 50 | } 51 | rhDatagram.waitPacketSent(); 52 | rhDatagram.available(); // put it back to receive mode 53 | return true; 54 | } 55 | 56 | bool loop() override { 57 | if (rhDatagram.available()) { 58 | 59 | device_address receive_address; 60 | memset(&receive_address, 0x0, sizeof(device_address)); 61 | 62 | uint8_t receive_buffer[RH_MAX_MESSAGE_LEN]; 63 | memset(&receive_buffer, 0x0, RH_MAX_MESSAGE_LEN); 64 | 65 | uint8_t receive_buffer_len = sizeof(receive_buffer); 66 | 67 | if (rhDatagram.recvfrom(receive_buffer, &receive_buffer_len, &receive_address.bytes[0])) { 68 | 69 | if (mqttSnMessageHandler != nullptr) { 70 | mqttSnMessageHandler->receiveData(&receive_address, receive_buffer); 71 | } 72 | 73 | if (transmissionProtocolUartBridge != nullptr) { 74 | transmissionProtocolUartBridge->receiveData(&receive_address, receive_buffer, receive_buffer_len); 75 | } 76 | 77 | } 78 | } 79 | 80 | return true; 81 | } 82 | 83 | template 84 | void setMqttSnMessageHandler( 85 | MqttSnMessageHandler *mqttSnMessageHandler) { 86 | this->mqttSnMessageHandler = mqttSnMessageHandler; 87 | }; 88 | 89 | template 90 | void setTransmissionProtocolUartBridge( 91 | TransmissionProtocolUartBridge *transmissionProtocolUartBridge) { 92 | this->transmissionProtocolUartBridge = transmissionProtocolUartBridge; 93 | }; 94 | private: 95 | MqttSnMessageHandler *mqttSnMessageHandler = nullptr; 96 | TransmissionProtocolUartBridge *transmissionProtocolUartBridge = nullptr; 97 | }; 98 | 99 | #endif //ARDUINO_MQTT_SN_CLIENT_RHDATAGRAMSOCKET_H 100 | -------------------------------------------------------------------------------- /examples/rf95/RF95SerialSniffer/RF95SerialSniffer.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | /* for feather32u4 */ 11 | #if defined(ARDUINO_AVR_FEATHER32U4) 12 | #define RFM95_CS 8 13 | #define RFM95_RST 4 14 | #define RFM95_INT 7 15 | #elif (ESP8266) 16 | #define RFM95_CS 2 17 | #define RFM95_INT 15 18 | #elif (ARDUINO_AVR_UNO) 19 | #define RFM95_CS 10 20 | #define RFM95_RST 9 21 | //#define RFM95_INT 7 22 | #define RFM95_INT 2 23 | #elif (ARDUINO_AVR_YUN) 24 | #define RFM95_CS 10 25 | #define RFM95_RST 9 26 | //#define RFM95_INT 7 27 | #define RFM95_INT 2 28 | #else 29 | 30 | #endif 31 | 32 | 33 | /* for feather m0 34 | #define RFM95_CS 8 35 | #define RFM95_RST 4 36 | #define RFM95_INT 3 37 | */ 38 | 39 | /* for shield 40 | #define RFM95_CS 10 41 | #define RFM95_RST 9 42 | #define RFM95_INT 7 43 | */ 44 | 45 | 46 | /* for ESP w/featherwing 47 | #define RFM95_CS 2 // "E" 48 | #define RFM95_RST 16 // "D" 49 | #define RFM95_INT 15 // "B" 50 | */ 51 | 52 | /* Feather 32u4 w/wing 53 | #define RFM95_RST 11 // "A" 54 | #define RFM95_CS 10 // "B" 55 | #define RFM95_INT 2 // "SDA" (only SDA/SCL/RX/TX have IRQ!) 56 | */ 57 | 58 | /* Feather m0 w/wing 59 | #define RFM95_RST 11 // "A" 60 | #define RFM95_CS 10 // "B" 61 | #define RFM95_INT 6 // "D" 62 | */ 63 | 64 | /* Teensy 3.x w/wing 65 | #define RFM95_RST 9 // "A" 66 | #define RFM95_CS 10 // "B" 67 | #define RFM95_INT 4 // "C" 68 | */ 69 | 70 | // Change to 434.0 or other frequency, must match RX's freq! 71 | //#define FREQUENCY 868.0 72 | #define FREQUENCY 434.0 73 | #define TX_POWER 13 74 | #define MODEM_CONFIG_CHOICE RH_RF95::Bw125Cr48Sf4096 75 | 76 | // Singleton instance of the radio driver 77 | RH_RF95 rf95(RFM95_CS, RFM95_INT); 78 | 79 | // Blinky on receipt 80 | #define LED 13 81 | 82 | void setup() 83 | { 84 | pinMode(LED, OUTPUT); 85 | 86 | Serial.begin(115200); 87 | //while (!Serial); 88 | delay(100); 89 | 90 | Serial.println("RX Test!"); 91 | 92 | 93 | while (!rf95.init()) { 94 | Serial.println("LoRa radio init failed"); 95 | while (1); 96 | } 97 | Serial.println("LoRa radio init OK!"); 98 | 99 | // Configure RH_RF95 driver after init 100 | // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 101 | 102 | if (!rf95.setFrequency(FREQUENCY)) { 103 | Serial.print(F("setFrequency failed\n")); 104 | while (true) { 105 | Serial.println("."); 106 | delay(1000); 107 | } 108 | } 109 | Serial.print("Set Freq to: "); Serial.println(FREQUENCY); 110 | 111 | if (!rf95.setModemConfig(RH_RF95::MODEM_CONFIG_CHOICE)) { 112 | Serial.print(F("setModemConfig failed\n")); 113 | while (true) { 114 | Serial.println("."); 115 | delay(1000); 116 | } 117 | } 118 | Serial.print("Set Modem Config to: "); Serial.println(RH_RF95::MODEM_CONFIG_CHOICE); 119 | 120 | rf95.setTxPower(TX_POWER); 121 | Serial.print("Set TX Power to: "); Serial.println(TX_POWER); 122 | 123 | } 124 | 125 | void loop() 126 | { 127 | if (rf95.waitAvailableTimeout(10000)) 128 | { 129 | // Should be a message for us now 130 | uint8_t buf[RH_RF95_MAX_MESSAGE_LEN]; 131 | uint8_t len = sizeof(buf); 132 | 133 | if (rf95.recv(buf, &len)) 134 | { 135 | digitalWrite(LED, HIGH); 136 | RH_RF95::printBuffer("Received: ", buf, len); 137 | Serial.print("Got: "); 138 | Serial.println((char*)buf); 139 | Serial.print("RSSI: "); 140 | Serial.println(rf95.lastRssi(), DEC); 141 | digitalWrite(LED, LOW); 142 | } 143 | else 144 | { 145 | Serial.println("Receive failed"); 146 | } 147 | }else{ 148 | Serial.println("Nothing"); 149 | } 150 | } 151 | 152 | -------------------------------------------------------------------------------- /examples/rf95/RF95DatagramMqttSnClient/RF95DatagramMqttSnClient.ino: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #include 8 | #include "RHDatagramSocket.h" 9 | #include "MqttSnClient.h" 10 | #include 11 | 12 | #define buffer_length 10 13 | char buffer[buffer_length + 1]; 14 | uint16_t buffer_pos = 0; 15 | 16 | RH_RF95 rf95; 17 | 18 | // Change to 434.0 or other frequency, must match RX's freq! 19 | //#define FREQUENCY 868.0 20 | #define FREQUENCY 434.0 21 | #define TX_POWER 13 22 | #define MODEM_CONFIG_CHOICE RH_RF95::Bw125Cr48Sf4096 23 | 24 | #define OWN_ADDRESS 4 25 | RHDatagram rhDatagram(rf95, OWN_ADDRESS); 26 | RHDatagramSocket rhDatagramSocket(rhDatagram); 27 | MqttSnClient mqttSnClient(rhDatagramSocket); 28 | 29 | #define MqttSnGateway_Address 2 30 | 31 | const char* clientId = "RHDSMqttSnClient"; 32 | char* subscribeTopicName = "RHDatagram/subscribe"; 33 | char* publishTopicName = "RHDatagram/publish"; 34 | int8_t qos = 0; 35 | 36 | 37 | void mqttsn_callback(char *topic, uint8_t *payload, uint16_t length, bool retain) { 38 | Serial.print(F("Received - Topic: ")); 39 | Serial.print(topic); 40 | Serial.print(F(" Payload: ")); 41 | for (uint16_t i = 0; i < length; i++) { 42 | char c = (char) * (payload + i); 43 | Serial.print(c); 44 | } 45 | Serial.print(F(" Length: ")); 46 | Serial.println(length); 47 | } 48 | 49 | void setup() { 50 | 51 | Serial.begin(115200); 52 | delay(10); 53 | Serial.println(); 54 | 55 | Serial.print(F("Starting MqttSnClient - ")); 56 | mqttSnClient.setCallback(mqttsn_callback); 57 | if (!mqttSnClient.begin()) { 58 | Serial.print(F("Could not initialize MQTT-SN Client ")); 59 | while (true) { 60 | Serial.println(F(".")); 61 | delay(1000); 62 | } 63 | } 64 | 65 | // Configure RH_RF95 driver after init from RHDatagram 66 | // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 67 | 68 | if (!rf95.setFrequency(FREQUENCY)) { 69 | Serial.print(F("setFrequency failed\n")); 70 | while (true) { 71 | Serial.println("."); 72 | delay(1000); 73 | } 74 | } 75 | Serial.print("Set Freq to: "); Serial.println(FREQUENCY); 76 | 77 | if (!rf95.setModemConfig(RH_RF95::MODEM_CONFIG_CHOICE)) { 78 | Serial.print(F("setModemConfig failed\n")); 79 | while (true) { 80 | Serial.println("."); 81 | delay(1000); 82 | } 83 | } 84 | Serial.print("Set Modem Config to: "); Serial.println(RH_RF95::MODEM_CONFIG_CHOICE); 85 | 86 | rf95.setTxPower(TX_POWER); 87 | Serial.print("Set TX Power to: "); Serial.println(TX_POWER); 88 | 89 | Serial.println(F("ready!")); 90 | } 91 | 92 | void loop() { 93 | if (!mqttSnClient.is_mqttsn_connected()) { 94 | device_address gateway_device_address; 95 | memset(&gateway_device_address, 0x0, sizeof(device_address)); 96 | gateway_device_address.bytes[0] = MqttSnGateway_Address; 97 | Serial.print(F("MQTT-SN Gateway device_address: ")); 98 | printDeviceAddress(&gateway_device_address); 99 | Serial.println(); 100 | 101 | if (!mqttSnClient.connect(&gateway_device_address, clientId, 180) ) { 102 | Serial.println(F("Could not connect MQTT-SN Client.")); 103 | delay(1000); 104 | return; 105 | } 106 | if (!mqttSnClient.subscribe(subscribeTopicName, qos)) { 107 | Serial.println("subscription failed."); 108 | delay(1000); 109 | return; 110 | } 111 | Serial.println("subscribed."); 112 | 113 | } 114 | 115 | if (Serial.available() > 0) { 116 | buffer[buffer_pos++] = Serial.read(); 117 | if (buffer[buffer_pos - 1] == '\n') { 118 | // only qos -1, 0, 1 are supported 119 | if (!mqttSnClient.publish(buffer, publishTopicName , qos)) { 120 | Serial.println(F("Could not publish")); 121 | } 122 | Serial.println(F("Published")); 123 | memset(buffer, 0x0, buffer_length); 124 | buffer_pos = 0; 125 | } 126 | } 127 | 128 | mqttSnClient.loop(); 129 | 130 | } 131 | -------------------------------------------------------------------------------- /examples/rf95/RF95SerialTransmitter/RF95SerialTransmitter.ino: -------------------------------------------------------------------------------- 1 | // RF95Transmitter TX 2 | // -*- mode: C++ -*- 3 | // Example sketch showing how to create a simple messaging client (transmitter) 4 | // with the RH_RF95 class. RH_RF95 class does not provide for addressing or 5 | // reliability, so you should only use RH_RF95 if you do not need the higher 6 | // level messaging abilities. 7 | // It is designed to work with the other example RF95Sniffer 8 | 9 | #include 10 | #include 11 | 12 | /* for feather32u4 */ 13 | #if defined(ARDUINO_AVR_FEATHER32U4) 14 | #define RFM95_CS 8 15 | #define RFM95_RST 4 16 | #define RFM95_INT 7 17 | #elif (ESP8266) 18 | #define RFM95_CS 2 19 | #define RFM95_INT 15 20 | #elif (ARDUINO_AVR_UNO) 21 | #define RFM95_CS 10 22 | #define RFM95_RST 9 23 | //#define RFM95_INT 7 24 | #define RFM95_INT 2 25 | #elif (ARDUINO_AVR_YUN) 26 | #define RFM95_CS 10 27 | #define RFM95_RST 9 28 | //#define RFM95_INT 7 29 | #define RFM95_INT 2 30 | #else 31 | 32 | #endif 33 | 34 | /* for feather m0 35 | #define RFM95_CS 8 36 | #define RFM95_RST 4 37 | #define RFM95_INT 3 38 | */ 39 | 40 | /* for shield 41 | #define RFM95_CS 10 42 | #define RFM95_RST 9 43 | #define RFM95_INT 7 44 | */ 45 | 46 | 47 | /* for ESP w/featherwing 48 | #define RFM95_CS 2 // "E" 49 | #define RFM95_RST 16 // "D" 50 | #define RFM95_INT 15 // "B" 51 | */ 52 | 53 | /* Feather 32u4 w/wing 54 | #define RFM95_RST 11 // "A" 55 | #define RFM95_CS 10 // "B" 56 | #define RFM95_INT 2 // "SDA" (only SDA/SCL/RX/TX have IRQ!) 57 | */ 58 | 59 | /* Feather m0 w/wing 60 | #define RFM95_RST 11 // "A" 61 | #define RFM95_CS 10 // "B" 62 | #define RFM95_INT 6 // "D" 63 | */ 64 | 65 | /* Teensy 3.x w/wing 66 | #define RFM95_RST 9 // "A" 67 | #define RFM95_CS 10 // "B" 68 | #define RFM95_INT 4 // "C" 69 | */ 70 | 71 | // Change to 434.0 or other frequency, must match RX's freq! 72 | //#define FREQUENCY 868.0 73 | #define FREQUENCY 434.0 74 | #define TX_POWER 13 75 | #define MODEM_CONFIG_CHOICE RH_RF95::Bw125Cr48Sf4096 76 | 77 | // Singleton instance of the radio driver 78 | RH_RF95 rf95(RFM95_CS, RFM95_INT); 79 | 80 | #define MODEM_CONFIG_CHOICE Bw31_25Cr48Sf512 81 | 82 | void setup() 83 | { 84 | 85 | pinMode(RFM95_INT, INPUT); 86 | 87 | Serial.begin(115200); 88 | while (!Serial); 89 | 90 | delay(100); 91 | 92 | Serial.println("TX Test!"); 93 | 94 | while (!rf95.init()) { 95 | Serial.println("LoRa radio init failed"); 96 | while (1); 97 | } 98 | Serial.println("LoRa radio init OK!"); 99 | 100 | // Configure RH_RF95 driver after init 101 | // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 102 | 103 | if (!rf95.setFrequency(FREQUENCY)) { 104 | Serial.print(F("setFrequency failed\n")); 105 | while (true) { 106 | Serial.println("."); 107 | delay(1000); 108 | } 109 | } 110 | Serial.print("Set Freq to: "); Serial.println(FREQUENCY); 111 | 112 | if (!rf95.setModemConfig(RH_RF95::MODEM_CONFIG_CHOICE)) { 113 | Serial.print(F("setModemConfig failed\n")); 114 | while (true) { 115 | Serial.println("."); 116 | delay(1000); 117 | } 118 | } 119 | Serial.print("Set Modem Config to: "); Serial.println(RH_RF95::MODEM_CONFIG_CHOICE); 120 | 121 | rf95.setTxPower(TX_POWER); 122 | Serial.print("Set TX Power to: "); Serial.println(TX_POWER); 123 | } 124 | 125 | int16_t packetnum = 0; // packet counter, we increment per xmission 126 | 127 | void loop() 128 | { 129 | Serial.println("Sending to rf95_server"); 130 | // Send a message to rf95_server 131 | 132 | char radiopacket[20] = "Hello World # "; 133 | itoa(packetnum++, radiopacket + 13, 10); 134 | Serial.print("Sending "); Serial.println(radiopacket); 135 | radiopacket[19] = 0; 136 | 137 | Serial.println("Sending..."); delay(10); 138 | rf95.send((uint8_t *)radiopacket, 20); 139 | 140 | Serial.println("Waiting for packet to complete..."); delay(10); 141 | rf95.waitPacketSent(); 142 | delay(1000); 143 | } 144 | 145 | -------------------------------------------------------------------------------- /examples/esp8266/WiFiUdpMqttSnClient/WiFiUdpMqttSnClient.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #include 8 | #include 9 | #include "WiFiUdpSocket.h" 10 | #include "MqttSnClient.h" 11 | 12 | const char* ssid = "your-ssid"; 13 | const char* password = "your-password"; 14 | 15 | 16 | #define buffer_length 10 17 | char buffer[buffer_length + 1]; 18 | uint16_t buffer_pos = 0; 19 | 20 | IPAddress gatewayIPAddress(192, 168, 178, 20); 21 | uint16_t localUdpPort = 8888; 22 | 23 | // #define gatewayHostAddress "arsmb.de" 24 | 25 | WiFiUDP udp; 26 | WiFiUdpSocket wiFiUdpSocket(udp, localUdpPort); 27 | MqttSnClient mqttSnClient(wiFiUdpSocket); 28 | 29 | const char* clientId = "WiFiUdpMqttSnClient"; 30 | char* subscribeTopicName = "ESP8266/WiFi/Udp/subscribe"; 31 | char* publishTopicName = "ESP8266/WiFi/Udp/publish"; 32 | 33 | int8_t qos = 0; 34 | 35 | void mqttsn_callback(char *topic, uint8_t *payload, uint16_t length, bool retain) { 36 | Serial.print("Received - Topic: "); 37 | Serial.print(topic); 38 | Serial.print(" Payload: "); 39 | for (uint16_t i = 0; i < length; i++) { 40 | char c = (char) * (payload + i); 41 | Serial.print(c); 42 | } 43 | Serial.print(" Lenght: "); 44 | Serial.println(length); 45 | } 46 | 47 | void setup() { 48 | 49 | Serial.begin(115200); 50 | delay(10); 51 | Serial.println(); 52 | Serial.print("Connecting to "); 53 | Serial.println(ssid); 54 | 55 | /* Explicitly set the ESP8266 to be a WiFi-client, otherwise, it by default, 56 | would try to act as both a client and an access-point and could cause 57 | network-issues with your other WiFi-devices on your WiFi-network. */ 58 | WiFi.mode(WIFI_STA); 59 | WiFi.begin(ssid, password); 60 | 61 | while (WiFi.status() != WL_CONNECTED) { 62 | delay(500); 63 | Serial.print("."); 64 | } 65 | 66 | Serial.println(""); 67 | Serial.println("WiFi connected"); 68 | Serial.println("IP address: "); 69 | Serial.println(WiFi.localIP()); 70 | 71 | Serial.print("Starting MqttSnClient - "); 72 | mqttSnClient.setCallback(mqttsn_callback); 73 | if (!mqttSnClient.begin()) { 74 | Serial.print("Could not initialize MQTT-SN Client "); 75 | while (true) { 76 | Serial.println("."); 77 | delay(1000); 78 | } 79 | } 80 | Serial.println(" ready!"); 81 | } 82 | 83 | void convertIPAddressAndPortToDeviceAddress(IPAddress& source, uint16_t port, device_address& target) { 84 | // IPAdress 0 - 3 bytes 85 | target.bytes[0] = source[0]; 86 | target.bytes[1] = source[1]; 87 | target.bytes[2] = source[2]; 88 | target.bytes[3] = source[3]; 89 | // Port 4 - 5 bytes 90 | target.bytes[4] = port >> 8; 91 | target.bytes[5] = (uint8_t) port ; 92 | } 93 | 94 | 95 | void loop() { 96 | if (!mqttSnClient.is_mqttsn_connected()) { 97 | #if defined(gatewayHostAddress) 98 | IPAddress gatewayIPAddress; 99 | if (!WiFi.hostByName(gatewayHostAddress, gatewayIPAddress, 20000)) { 100 | Serial.println("Could not lookup MQTT-SN Gateway."); 101 | return; 102 | } 103 | #endif 104 | device_address gateway_device_address; 105 | convertIPAddressAndPortToDeviceAddress(gatewayIPAddress, localUdpPort, gateway_device_address); 106 | Serial.print("MQTT-SN Gateway device_address: "); 107 | printDeviceAddress(&gateway_device_address); 108 | 109 | 110 | if (!mqttSnClient.connect(&gateway_device_address, clientId, 180) ) { 111 | Serial.println("Could not connect MQTT-SN Client."); 112 | delay(1000); 113 | return; 114 | } 115 | Serial.println("MQTT-SN Client connected."); 116 | mqttSnClient.subscribe(subscribeTopicName, qos); 117 | 118 | } 119 | if (Serial.available() > 0) { 120 | buffer[buffer_pos++] = Serial.read(); 121 | if (buffer[buffer_pos - 1] == '\n') { 122 | // only qos -1, 0, 1 are supported 123 | if (!mqttSnClient.publish(buffer, publishTopicName , qos)) { 124 | Serial.println("Could not publish"); 125 | } 126 | Serial.println("Published"); 127 | memset(buffer, 0x0, buffer_length); 128 | buffer_pos = 0; 129 | } 130 | } 131 | 132 | mqttSnClient.loop(); 133 | 134 | } -------------------------------------------------------------------------------- /examples/rf95/RF95ConsoleTransmitter/RF95ConsoleTransmitter.ino: -------------------------------------------------------------------------------- 1 | // RF95Transmitter TX 2 | // -*- mode: C++ -*- 3 | // Example sketch showing how to create a simple messaging client (transmitter) 4 | // with the RH_RF95 class. RH_RF95 class does not provide for addressing or 5 | // reliability, so you should only use RH_RF95 if you do not need the higher 6 | // level messaging abilities. 7 | // It is designed to work with the other example RF95Sniffer 8 | 9 | #include 10 | #include 11 | 12 | /* for feather32u4 */ 13 | #if defined(ARDUINO_AVR_FEATHER32U4) 14 | #define RFM95_CS 8 15 | #define RFM95_RST 4 16 | #define RFM95_INT 7 17 | #elif (ESP8266) 18 | #define RFM95_CS 2 19 | #define RFM95_INT 15 20 | #elif (ARDUINO_AVR_UNO) 21 | #define RFM95_CS 10 22 | #define RFM95_RST 9 23 | //#define RFM95_INT 7 24 | #define RFM95_INT 2 25 | #elif (ARDUINO_AVR_YUN) 26 | #define RFM95_CS 10 27 | #define RFM95_RST 9 28 | //#define RFM95_INT 7 29 | #define RFM95_INT 2 30 | #else 31 | 32 | #endif 33 | 34 | /* for feather m0 35 | #define RFM95_CS 8 36 | #define RFM95_RST 4 37 | #define RFM95_INT 3 38 | */ 39 | 40 | /* for shield 41 | #define RFM95_CS 10 42 | #define RFM95_RST 9 43 | #define RFM95_INT 7 44 | */ 45 | 46 | 47 | /* for ESP w/featherwing 48 | #define RFM95_CS 2 // "E" 49 | #define RFM95_RST 16 // "D" 50 | #define RFM95_INT 15 // "B" 51 | */ 52 | 53 | /* Feather 32u4 w/wing 54 | #define RFM95_RST 11 // "A" 55 | #define RFM95_CS 10 // "B" 56 | #define RFM95_INT 2 // "SDA" (only SDA/SCL/RX/TX have IRQ!) 57 | */ 58 | 59 | /* Feather m0 w/wing 60 | #define RFM95_RST 11 // "A" 61 | #define RFM95_CS 10 // "B" 62 | #define RFM95_INT 6 // "D" 63 | */ 64 | 65 | /* Teensy 3.x w/wing 66 | #define RFM95_RST 9 // "A" 67 | #define RFM95_CS 10 // "B" 68 | #define RFM95_INT 4 // "C" 69 | */ 70 | 71 | 72 | // Change to 434.0 or other frequency, must match RX's freq! 73 | //#define FREQUENCY 868.0 74 | #define FREQUENCY 434.0 75 | #define TX_POWER 13 76 | #define MODEM_CONFIG_CHOICE RH_RF95::Bw125Cr48Sf4096 77 | 78 | // Singleton instance of the radio driver 79 | RH_RF95 rf95(RFM95_CS, RFM95_INT); 80 | 81 | #define MODEM_CONFIG_CHOICE Bw31_25Cr48Sf512 82 | 83 | void setup() 84 | { 85 | 86 | pinMode(RFM95_INT, INPUT); 87 | 88 | // Initialize Console and wait for port to open: 89 | Bridge.begin(BAUDRATE); 90 | Console.begin(); 91 | 92 | // Wait for Console port to connect 93 | while (!Console); 94 | 95 | Console.println("TX Test!"); 96 | 97 | while (!rf95.init()) { 98 | Console.println("LoRa radio init failed"); 99 | while (1); 100 | } 101 | Console.println("LoRa radio init OK!"); 102 | 103 | // Configure RH_RF95 driver after init 104 | // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 105 | 106 | if (!rf95.setFrequency(FREQUENCY)) { 107 | Console.print(F("setFrequency failed\n")); 108 | while (true) { 109 | Console.println("."); 110 | delay(1000); 111 | } 112 | } 113 | Console.print("Set Freq to: "); Console.println(FREQUENCY); 114 | 115 | if (!rf95.setModemConfig(RH_RF95::MODEM_CONFIG_CHOICE)) { 116 | Console.print(F("setModemConfig failed\n")); 117 | while (true) { 118 | Console.println("."); 119 | delay(1000); 120 | } 121 | } 122 | Console.print("Set Modem Config to: "); Console.println(RH_RF95::MODEM_CONFIG_CHOICE); 123 | 124 | rf95.setTxPower(TX_POWER); 125 | Console.print("Set TX Power to: "); Console.println(TX_POWER); 126 | } 127 | 128 | int16_t packetnum = 0; // packet counter, we increment per xmission 129 | 130 | void loop() 131 | { 132 | Console.println("Sending to rf95_server"); 133 | // Send a message to rf95_server 134 | 135 | char radiopacket[20] = "Hello World # "; 136 | itoa(packetnum++, radiopacket + 13, 10); 137 | Console.print("Sending "); Console.println(radiopacket); 138 | radiopacket[19] = 0; 139 | 140 | Console.println("Sending..."); delay(10); 141 | rf95.send((uint8_t *)radiopacket, 20); 142 | 143 | Console.println("Waiting for packet to complete..."); delay(10); 144 | rf95.waitPacketSent(); 145 | delay(1000); 146 | } 147 | 148 | -------------------------------------------------------------------------------- /examples/arduino_uno/TcpMqttSnClient/TcpMqttSnClient.ino: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #include 8 | #include 9 | #include "ClientSocket.h" 10 | #include "MqttSnClient.h" 11 | 12 | // Enter a MAC address for your controller below. 13 | // Newer Ethernet shields have a MAC address printed on a sticker on the shield 14 | byte mac[] = { 15 | 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 16 | }; 17 | 18 | #define buffer_length 10 19 | char buffer[buffer_length + 1]; 20 | uint16_t buffer_pos = 0; 21 | 22 | IPAddress gatewayIPAddress(192, 168, 178, 88); 23 | uint16_t localTcpPort = 8888; 24 | 25 | // #define gatewayHostAddress "arsmb.de" 26 | 27 | EthernetClient client; 28 | ClientSocket clientSocket(&client); 29 | MqttSnClient mqttSnClient(clientSocket); 30 | 31 | const char* clientId = "TcpMqttSnClient"; 32 | char* subscribeTopicName = "Uno/Ethernet/Tcp/subscribe"; 33 | char* publishTopicName = "Uno/Ethernet/Tcp/publish"; 34 | 35 | int8_t qos = 0; 36 | 37 | void mqttsn_callback(char *topic, uint8_t *payload, uint16_t length, bool retain) { 38 | Serial.print("Received - Topic: "); 39 | Serial.print(topic); 40 | Serial.print(" Payload: "); 41 | for (uint16_t i = 0; i < length; i++) { 42 | char c = (char) * (payload + i); 43 | Serial.print(c); 44 | } 45 | Serial.print(" Length: "); 46 | Serial.println(length); 47 | } 48 | 49 | void setup() { 50 | 51 | Serial.begin(115200); 52 | delay(10); 53 | Serial.println(); 54 | Serial.println("Connecting to network"); 55 | Serial.print("MAC:"); 56 | for (uint8_t i = 0; i < sizeof(mac); i++) { 57 | Serial.print(" "); 58 | Serial.print(mac[i], HEX); 59 | } 60 | Serial.println(); 61 | 62 | // start the Ethernet connection: 63 | if (Ethernet.begin(mac) == 0) { 64 | Serial.println("Failed to configure Ethernet using DHCP"); 65 | // no point in carrying on, so do nothing forevermore: 66 | while (true) { 67 | Serial.println("."); 68 | delay(1000); 69 | } 70 | } 71 | Serial.print("IP: "); 72 | for (byte thisByte = 0; thisByte < 4; thisByte++) { 73 | // print the value of each byte of the IP address: 74 | Serial.print(Ethernet.localIP()[thisByte], DEC); 75 | Serial.print("."); 76 | } 77 | 78 | Serial.println(); 79 | 80 | 81 | Serial.print("Starting MqttSnClient - "); 82 | mqttSnClient.setCallback(mqttsn_callback); 83 | if (!mqttSnClient.begin()) { 84 | Serial.print("Could not initialize MQTT-SN Client "); 85 | while (true) { 86 | Serial.println("."); 87 | delay(1000); 88 | } 89 | } 90 | Serial.println(" ready!"); 91 | } 92 | 93 | void convertIPAddressAndPortToDeviceAddress(IPAddress& source, uint16_t port, device_address& target) { 94 | // IPAddress 0 - 3 bytes 95 | target.bytes[0] = source[0]; 96 | target.bytes[1] = source[1]; 97 | target.bytes[2] = source[2]; 98 | target.bytes[3] = source[3]; 99 | // Port 4 - 5 bytes 100 | target.bytes[4] = port >> 8; 101 | target.bytes[5] = (uint8_t) port ; 102 | } 103 | 104 | 105 | void loop() { 106 | if (!mqttSnClient.is_mqttsn_connected()) { 107 | device_address gateway_device_address; 108 | convertIPAddressAndPortToDeviceAddress(gatewayIPAddress, localTcpPort, gateway_device_address); 109 | Serial.print("MQTT-SN Gateway device_address: "); 110 | printDeviceAddress(&gateway_device_address); 111 | 112 | if (!mqttSnClient.connect(&gateway_device_address, clientId, 180) ) { 113 | Serial.println("Could not connect MQTT-SN Client."); 114 | delay(1000); 115 | return; 116 | } 117 | Serial.println(); 118 | 119 | Serial.println("MQTT-SN Client connected."); 120 | mqttSnClient.subscribe(subscribeTopicName, qos); 121 | 122 | } 123 | if (Serial.available() > 0) { 124 | buffer[buffer_pos++] = Serial.read(); 125 | if (buffer[buffer_pos - 1] == '\n') { 126 | // only qos -1, 0, 1 are supported 127 | if (!mqttSnClient.publish(buffer, publishTopicName , qos)) { 128 | Serial.println("Could not publish"); 129 | } 130 | Serial.println("Published"); 131 | memset(buffer, 0x0, buffer_length); 132 | buffer_pos = 0; 133 | } 134 | } 135 | 136 | mqttSnClient.loop(); 137 | 138 | } 139 | -------------------------------------------------------------------------------- /examples/esp8266/UdpMqttSnClient/UdpMqttSnClient.ino: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #include 8 | #include 9 | #include "UdpSocket.h" 10 | #include "MqttSnClient.h" 11 | 12 | 13 | const char* ssid = "..."; 14 | const char* password = "..."; 15 | 16 | 17 | #define buffer_length 10 18 | char buffer[buffer_length + 1]; 19 | uint16_t buffer_pos = 0; 20 | 21 | IPAddress gatewayIPAddress(192, 168, 178, 88); 22 | uint16_t localUdpPort = 8888; 23 | 24 | // #define gatewayHostAddress "arsmb.de" 25 | 26 | WiFiUDP udp; 27 | UDPSocket udpSocket(&udp, localUdpPort); 28 | MqttSnClient mqttSnClient(udpSocket); 29 | 30 | const char* clientId = "UdpMqttSnClient"; 31 | char* subscribeTopicName = "ESP8266/Udp/subscribe"; 32 | char* publishTopicName = "ESP8266/Udp/publish"; 33 | 34 | int8_t qos = 0; 35 | 36 | void mqttsn_callback(char *topic, uint8_t *payload, uint16_t length, bool retain) { 37 | Serial.print("Received - Topic: "); 38 | Serial.print(topic); 39 | Serial.print(" Payload: "); 40 | for (uint16_t i = 0; i < length; i++) { 41 | char c = (char) * (payload + i); 42 | Serial.print(c); 43 | } 44 | Serial.print(" Length: "); 45 | Serial.println(length); 46 | } 47 | 48 | void setup() { 49 | 50 | Serial.begin(115200); 51 | delay(10); 52 | Serial.println(); 53 | Serial.print("Connecting to "); 54 | Serial.println(ssid); 55 | 56 | /* Explicitly set the ESP8266 to be a WiFi-client, otherwise, it by default, 57 | would try to act as both a client and an access-point and could cause 58 | network-issues with your other WiFi-devices on your WiFi-network. */ 59 | WiFi.mode(WIFI_STA); 60 | WiFi.begin(ssid, password); 61 | 62 | while (WiFi.status() != WL_CONNECTED) { 63 | delay(500); 64 | Serial.print("."); 65 | } 66 | 67 | Serial.println(""); 68 | Serial.println("WiFi connected"); 69 | Serial.println("IP address: "); 70 | Serial.println(WiFi.localIP()); 71 | 72 | Serial.print("Starting MqttSnClient - "); 73 | mqttSnClient.setCallback(mqttsn_callback); 74 | if (!mqttSnClient.begin()) { 75 | Serial.print("Could not initialize MQTT-SN Client "); 76 | while (true) { 77 | Serial.println("."); 78 | delay(1000); 79 | } 80 | } 81 | Serial.println(" ready!"); 82 | } 83 | 84 | void convertIPAddressAndPortToDeviceAddress(IPAddress& source, uint16_t port, device_address& target) { 85 | // IPAdress 0 - 3 bytes 86 | target.bytes[0] = source[0]; 87 | target.bytes[1] = source[1]; 88 | target.bytes[2] = source[2]; 89 | target.bytes[3] = source[3]; 90 | // Port 4 - 5 bytes 91 | target.bytes[4] = port >> 8; 92 | target.bytes[5] = (uint8_t) port ; 93 | } 94 | 95 | 96 | void loop() { 97 | if (!mqttSnClient.is_mqttsn_connected()) { 98 | #if defined(gatewayHostAddress) 99 | IPAddress gatewayIPAddress; 100 | if (!WiFi.hostByName(gatewayHostAddress, gatewayIPAddress, 20000)) { 101 | Serial.println("Could not lookup MQTT-SN Gateway."); 102 | return; 103 | } 104 | #endif 105 | device_address gateway_device_address; 106 | convertIPAddressAndPortToDeviceAddress(gatewayIPAddress, localUdpPort, gateway_device_address); 107 | Serial.print("MQTT-SN Gateway device_address: "); 108 | printDeviceAddress(&gateway_device_address); 109 | Serial.println(); 110 | if (!mqttSnClient.connect(&gateway_device_address, clientId, 180) ) { 111 | Serial.println("Could not connect MQTT-SN Client."); 112 | delay(1000); 113 | return; 114 | } 115 | Serial.println("MQTT-SN Client connected."); 116 | if (!mqttSnClient.subscribe(subscribeTopicName, qos)) { 117 | Serial.println("subscription failed."); 118 | delay(1000); 119 | return; 120 | } 121 | Serial.println("subscribed."); 122 | } 123 | if (Serial.available() > 0) { 124 | buffer[buffer_pos++] = Serial.read(); 125 | if (buffer[buffer_pos - 1] == '\n') { 126 | // only qos -1, 0, 1 are supported 127 | if (!mqttSnClient.publish(buffer, publishTopicName , qos)) { 128 | Serial.println("Could not publish"); 129 | } 130 | Serial.println("Published"); 131 | memset(buffer, 0x0, buffer_length); 132 | buffer_pos = 0; 133 | } 134 | } 135 | 136 | mqttSnClient.loop(); 137 | 138 | } -------------------------------------------------------------------------------- /examples/esp8266/TcpMqttSnClient/TcpMqttSnClient.ino: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #include 8 | #include 9 | #include "ClientSocket.h" 10 | #include "MqttSnClient.h" 11 | 12 | const char* ssid = "..."; 13 | const char* password = "..."; 14 | 15 | 16 | #define buffer_length 10 17 | char buffer[buffer_length + 1]; 18 | uint16_t buffer_pos = 0; 19 | 20 | IPAddress gatewayIPAddress(192, 168, 178, 88); 21 | uint16_t localTcpPort = 8888; 22 | 23 | // #define gatewayHostAddress "arsmb.de" 24 | 25 | WiFiClient client; 26 | ClientSocket clientSocket(&client); 27 | MqttSnClient mqttSnClient(clientSocket); 28 | 29 | const char* clientId = "UdpMqttSnClient"; 30 | char* subscribeTopicName = "ESP8266/Tcp/subscribe"; 31 | char* publishTopicName = "ESP8266/Tcp/publish"; 32 | 33 | int8_t qos = 0; 34 | 35 | void mqttsn_callback(char *topic, uint8_t *payload, uint16_t length, bool retain) { 36 | Serial.print("Received - Topic: "); 37 | Serial.print(topic); 38 | Serial.print(" Payload: "); 39 | for (uint16_t i = 0; i < length; i++) { 40 | char c = (char) * (payload + i); 41 | Serial.print(c); 42 | } 43 | Serial.print(" Length: "); 44 | Serial.println(length); 45 | } 46 | 47 | void setup() { 48 | 49 | Serial.begin(115200); 50 | delay(10); 51 | Serial.println(); 52 | Serial.print("Connecting to "); 53 | Serial.println(ssid); 54 | 55 | /* Explicitly set the ESP8266 to be a WiFi-client, otherwise, it by default, 56 | would try to act as both a client and an access-point and could cause 57 | network-issues with your other WiFi-devices on your WiFi-network. */ 58 | WiFi.mode(WIFI_STA); 59 | WiFi.begin(ssid, password); 60 | 61 | while (WiFi.status() != WL_CONNECTED) { 62 | delay(500); 63 | Serial.print("."); 64 | } 65 | 66 | Serial.println(""); 67 | Serial.println("WiFi connected"); 68 | Serial.println("IP address: "); 69 | Serial.println(WiFi.localIP()); 70 | 71 | Serial.print("Starting MqttSnClient - "); 72 | mqttSnClient.setCallback(mqttsn_callback); 73 | if (!mqttSnClient.begin()) { 74 | Serial.print("Could not initialize MQTT-SN Client "); 75 | while (true) { 76 | Serial.println("."); 77 | delay(1000); 78 | } 79 | } 80 | Serial.println(" ready!"); 81 | } 82 | 83 | void convertIPAddressAndPortToDeviceAddress(IPAddress& source, uint16_t port, device_address& target) { 84 | // IPAdress 0 - 3 bytes 85 | target.bytes[0] = source[0]; 86 | target.bytes[1] = source[1]; 87 | target.bytes[2] = source[2]; 88 | target.bytes[3] = source[3]; 89 | // Port 4 - 5 bytes 90 | target.bytes[4] = port >> 8; 91 | target.bytes[5] = (uint8_t) port ; 92 | } 93 | 94 | 95 | void loop() { 96 | if (!mqttSnClient.is_mqttsn_connected()) { 97 | #if defined(gatewayHostAddress) 98 | IPAddress gatewayIPAddress; 99 | if (!WiFi.hostByName(gatewayHostAddress, gatewayIPAddress, 20000)) { 100 | Serial.println("Could not lookup MQTT-SN Gateway."); 101 | return; 102 | } 103 | #endif 104 | device_address gateway_device_address; 105 | convertIPAddressAndPortToDeviceAddress(gatewayIPAddress, localTcpPort, gateway_device_address); 106 | Serial.print("MQTT-SN Gateway device_address: "); 107 | printDeviceAddress(&gateway_device_address); 108 | Serial.println(); 109 | if (!mqttSnClient.connect(&gateway_device_address, clientId, 180) ) { 110 | Serial.println("Could not connect MQTT-SN Client."); 111 | delay(1000); 112 | return; 113 | } 114 | Serial.println("MQTT-SN Client connected."); 115 | if (!mqttSnClient.subscribe(subscribeTopicName, qos)) { 116 | Serial.println("subscription failed."); 117 | delay(1000); 118 | return; 119 | } 120 | Serial.println("subscribed."); 121 | } 122 | if (Serial.available() > 0) { 123 | buffer[buffer_pos++] = Serial.read(); 124 | if (buffer[buffer_pos - 1] == '\n') { 125 | // only qos -1, 0, 1 are supported 126 | if (!mqttSnClient.publish(buffer, publishTopicName , qos)) { 127 | Serial.println("Could not publish"); 128 | } 129 | Serial.println("Published"); 130 | memset(buffer, 0x0, buffer_length); 131 | buffer_pos = 0; 132 | } 133 | } 134 | 135 | mqttSnClient.loop(); 136 | 137 | } -------------------------------------------------------------------------------- /examples/arduino_uno/UdpMqttSnClient/UdpMqttSnClient.ino: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "UdpSocket.h" 11 | #include "MqttSnClient.h" 12 | 13 | // Enter a MAC address for your controller below. 14 | // Newer Ethernet shields have a MAC address printed on a sticker on the shield 15 | byte mac[] = { 16 | 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 17 | }; 18 | // Initialize the Ethernet client library 19 | EthernetClient client; 20 | 21 | #define buffer_length 10 22 | char buffer[buffer_length + 1]; 23 | uint16_t buffer_pos = 0; 24 | 25 | IPAddress gatewayIPAddress(192, 168, 178, 88); 26 | uint16_t localUdpPort = 8888; 27 | 28 | // #define gatewayHostAddress "arsmb.de" 29 | 30 | EthernetUDP udp; 31 | UDPSocket udpSocket(&udp, localUdpPort); 32 | MqttSnClient mqttSnClient(udpSocket); 33 | 34 | const char* clientId = "UdpMqttSnClient"; 35 | char* subscribeTopicName = "Uno/Ethernet/Udp/subscribe"; 36 | char* publishTopicName = "Uno/Ethernet/Udp/publish"; 37 | 38 | int8_t qos = 0; 39 | 40 | void mqttsn_callback(char *topic, uint8_t *payload, uint16_t length, bool retain) { 41 | Serial.print("Received - Topic: "); 42 | Serial.print(topic); 43 | Serial.print(" Payload: "); 44 | for (uint16_t i = 0; i < length; i++) { 45 | char c = (char) * (payload + i); 46 | Serial.print(c); 47 | } 48 | Serial.print(" Length: "); 49 | Serial.println(length); 50 | } 51 | 52 | void setup() { 53 | 54 | Serial.begin(115200); 55 | delay(10); 56 | Serial.println(); 57 | Serial.println("Connecting to network"); 58 | Serial.print("MAC:"); 59 | for (uint8_t i = 0; i < sizeof(mac); i++) { 60 | Serial.print(" "); 61 | Serial.print(mac[i], HEX); 62 | } 63 | Serial.println(); 64 | 65 | // start the Ethernet connection: 66 | if (Ethernet.begin(mac) == 0) { 67 | Serial.println("Failed to configure Ethernet using DHCP"); 68 | // no point in carrying on, so do nothing forevermore: 69 | while (true) { 70 | Serial.println("."); 71 | delay(1000); 72 | } 73 | } 74 | Serial.print("IP: "); 75 | for (byte thisByte = 0; thisByte < 4; thisByte++) { 76 | // print the value of each byte of the IP address: 77 | Serial.print(Ethernet.localIP()[thisByte], DEC); 78 | Serial.print("."); 79 | } 80 | 81 | Serial.println(); 82 | 83 | 84 | Serial.print("Starting MqttSnClient - "); 85 | mqttSnClient.setCallback(mqttsn_callback); 86 | if (!mqttSnClient.begin()) { 87 | Serial.print("Could not initialize MQTT-SN Client "); 88 | while (true) { 89 | Serial.println("."); 90 | delay(1000); 91 | } 92 | } 93 | Serial.println(" ready!"); 94 | } 95 | 96 | void convertIPAddressAndPortToDeviceAddress(IPAddress& source, uint16_t port, device_address& target) { 97 | // IPAddress 0 - 3 bytes 98 | target.bytes[0] = source[0]; 99 | target.bytes[1] = source[1]; 100 | target.bytes[2] = source[2]; 101 | target.bytes[3] = source[3]; 102 | // Port 4 - 5 bytes 103 | target.bytes[4] = port >> 8; 104 | target.bytes[5] = (uint8_t) port ; 105 | } 106 | 107 | 108 | void loop() { 109 | if (!mqttSnClient.is_mqttsn_connected()) { 110 | device_address gateway_device_address; 111 | convertIPAddressAndPortToDeviceAddress(gatewayIPAddress, localUdpPort, gateway_device_address); 112 | Serial.print("MQTT-SN Gateway device_address: "); 113 | printDeviceAddress(&gateway_device_address); 114 | 115 | if (!mqttSnClient.connect(&gateway_device_address, clientId, 180) ) { 116 | Serial.println("Could not connect MQTT-SN Client."); 117 | delay(1000); 118 | return; 119 | } 120 | Serial.println(); 121 | 122 | Serial.println("MQTT-SN Client connected."); 123 | mqttSnClient.subscribe(subscribeTopicName, qos); 124 | 125 | } 126 | if (Serial.available() > 0) { 127 | buffer[buffer_pos++] = Serial.read(); 128 | if (buffer[buffer_pos - 1] == '\n') { 129 | // only qos -1, 0, 1 are supported 130 | if (!mqttSnClient.publish(buffer, publishTopicName , qos)) { 131 | Serial.println("Could not publish"); 132 | } 133 | Serial.println("Published"); 134 | memset(buffer, 0x0, buffer_length); 135 | buffer_pos = 0; 136 | } 137 | } 138 | 139 | mqttSnClient.loop(); 140 | 141 | } 142 | -------------------------------------------------------------------------------- /RHGenericDriverSocket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #ifndef ARDUINO_MQTT_SN_CLIENT_RHDATAGRAMSOCKET_H 8 | #define ARDUINO_MQTT_SN_CLIENT_RHDATAGRAMSOCKET_H 9 | 10 | #include "MqttSnMessageHandler.h" 11 | #include "SocketInterface.h" 12 | #include 13 | 14 | #define RECEIVE_BUFFER_SIZE 255 15 | 16 | class RHGenericDriverSocket : SocketInterface { 17 | private: 18 | RHGenericDriver *rhDatagram; 19 | 20 | uint8_t ownAddress; 21 | device_address own_address; 22 | device_address broadcast_address; 23 | 24 | 25 | public: 26 | RHGenericDriverSocket(RHGenericDriver *rhDatagram, uint8_t ownAddress) : rhDatagram(rhDatagram), 27 | ownAddress(ownAddress) {}; 28 | 29 | bool begin() override { 30 | rhDatagram->setThisAddress(ownAddress); 31 | rhDatagram->setHeaderFrom(ownAddress); 32 | own_address = device_address(ownAddress, 0, 0, 0, 0, 0); 33 | broadcast_address = device_address(RH_BROADCAST_ADDRESS, 0, 0, 0, 0, 0); 34 | return rhDatagram->init(); 35 | } 36 | 37 | device_address *getBroadcastAddress() override { 38 | return &broadcast_address; 39 | } 40 | 41 | device_address *getAddress() override { 42 | return &own_address; 43 | } 44 | 45 | uint8_t getMaximumMessageLength() override { 46 | return RECEIVE_BUFFER_SIZE; 47 | } 48 | 49 | bool send(device_address *destination, uint8_t *bytes, uint16_t bytes_len) override { 50 | return send(destination, bytes, bytes_len, UINT8_MAX); 51 | } 52 | 53 | bool send(device_address *destination, uint8_t *bytes, uint16_t bytes_len, uint8_t signal_strength) override { 54 | rhDatagram->setHeaderTo(destination->bytes[0]); 55 | rhDatagram->setHeaderFrom(own_address.bytes[0]); 56 | 57 | if(!rhDatagram->send(bytes, bytes_len)){ 58 | rhDatagram->waitPacketSent(); 59 | rhDatagram->available(); // put it back to receive mode 60 | return false; 61 | } 62 | rhDatagram->waitPacketSent(); 63 | rhDatagram->available(); // put it back to receive mode 64 | return true; 65 | } 66 | 67 | bool loop() override { 68 | if (rhDatagram->available()) { 69 | 70 | device_address receive_address; 71 | memset(&receive_address, 0x0, sizeof(device_address)); 72 | 73 | uint8_t receive_buffer[RECEIVE_BUFFER_SIZE]; 74 | memset(&receive_buffer, 0x0, RECEIVE_BUFFER_SIZE); 75 | 76 | uint8_t receive_buffer_len = sizeof(receive_buffer); 77 | 78 | if (rhDatagram->recv(receive_buffer, &receive_buffer_len)) { 79 | if (rhDatagram->headerTo() == own_address.bytes[0] || 80 | rhDatagram->headerTo() == RH_BROADCAST_ADDRESS ) { 81 | 82 | receive_address.bytes[0] = rhDatagram->headerFrom(); 83 | 84 | if (mqttSnMessageHandler != nullptr) { 85 | mqttSnMessageHandler->receiveData(&receive_address, receive_buffer); 86 | } 87 | 88 | if (transmissionProtocolUartBridge != nullptr) { 89 | transmissionProtocolUartBridge->receiveData(&receive_address, receive_buffer, 90 | receive_buffer_len); 91 | } 92 | 93 | } 94 | 95 | } 96 | } 97 | 98 | return true; 99 | } 100 | 101 | template 102 | void setMqttSnMessageHandler( 103 | MqttSnMessageHandler *mqttSnMessageHandler) { 104 | this->mqttSnMessageHandler = mqttSnMessageHandler; 105 | }; 106 | 107 | template 108 | void setTransmissionProtocolUartBridge( 109 | TransmissionProtocolUartBridge *transmissionProtocolUartBridge) { 110 | this->transmissionProtocolUartBridge = transmissionProtocolUartBridge; 111 | }; 112 | private: 113 | MqttSnMessageHandler *mqttSnMessageHandler = nullptr; 114 | TransmissionProtocolUartBridge *transmissionProtocolUartBridge = nullptr; 115 | }; 116 | 117 | #endif //ARDUINO_MQTT_SN_CLIENT_RHDATAGRAMSOCKET_H 118 | -------------------------------------------------------------------------------- /examples/rf95/RF95ConsoleSniffer/RF95ConsoleSniffer.ino: -------------------------------------------------------------------------------- 1 | // RF95Sniffer RX 2 | // -*- mode: C++ -*- 3 | // Example sketch showing how to create a simple messaging client (receiver) 4 | // with the RH_RF95 class. RH_RF95 class does not provide for addressing or 5 | // reliability, so you should only use RH_RF95 if you do not need the higher 6 | // level messaging abilities. 7 | // It is designed to work with the other example RF95Transmitter 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | /* for feather32u4 */ 14 | #if defined(ARDUINO_AVR_FEATHER32U4) 15 | #define RFM95_CS 8 16 | #define RFM95_RST 4 17 | #define RFM95_INT 7 18 | #elif (ESP8266) 19 | #define RFM95_CS 2 20 | #define RFM95_INT 15 21 | #elif (ARDUINO_AVR_UNO) 22 | #define RFM95_CS 10 23 | #define RFM95_RST 9 24 | //#define RFM95_INT 7 25 | #define RFM95_INT 2 26 | #elif (ARDUINO_AVR_YUN) 27 | #define RFM95_CS 10 28 | #define RFM95_RST 9 29 | //#define RFM95_INT 7 30 | #define RFM95_INT 2 31 | #else 32 | 33 | #endif 34 | 35 | 36 | /* for feather m0 37 | #define RFM95_CS 8 38 | #define RFM95_RST 4 39 | #define RFM95_INT 3 40 | */ 41 | 42 | /* for shield 43 | #define RFM95_CS 10 44 | #define RFM95_RST 9 45 | #define RFM95_INT 7 46 | */ 47 | 48 | 49 | /* for ESP w/featherwing 50 | #define RFM95_CS 2 // "E" 51 | #define RFM95_RST 16 // "D" 52 | #define RFM95_INT 15 // "B" 53 | */ 54 | 55 | /* Feather 32u4 w/wing 56 | #define RFM95_RST 11 // "A" 57 | #define RFM95_CS 10 // "B" 58 | #define RFM95_INT 2 // "SDA" (only SDA/SCL/RX/TX have IRQ!) 59 | */ 60 | 61 | /* Feather m0 w/wing 62 | #define RFM95_RST 11 // "A" 63 | #define RFM95_CS 10 // "B" 64 | #define RFM95_INT 6 // "D" 65 | */ 66 | 67 | /* Teensy 3.x w/wing 68 | #define RFM95_RST 9 // "A" 69 | #define RFM95_CS 10 // "B" 70 | #define RFM95_INT 4 // "C" 71 | */ 72 | 73 | // Change to 434.0 or other frequency, must match RX's freq! 74 | //#define FREQUENCY 868.0 75 | #define FREQUENCY 434.0 76 | #define TX_POWER 13 77 | #define MODEM_CONFIG_CHOICE RH_RF95::Bw125Cr48Sf4096 78 | 79 | // Singleton instance of the radio driver 80 | RH_RF95 rf95; 81 | 82 | // Blinky on receipt 83 | #define LED 13 84 | 85 | //If you use Dragino IoT Mesh Firmware, uncomment below lines. 86 | //For product: LG01. 87 | #define BAUDRATE 115200 88 | 89 | //If you use Dragino Yun Mesh Firmware , uncomment below lines. 90 | //#define BAUDRATE 250000 91 | 92 | void setup() 93 | { 94 | pinMode(LED, OUTPUT); 95 | 96 | // Initialize Console and wait for port to open: 97 | Bridge.begin(BAUDRATE); 98 | Console.begin(); 99 | 100 | // Wait for Console port to connect 101 | while (!Console); 102 | 103 | Console.println("RX Test!"); 104 | 105 | 106 | while (!rf95.init()) { 107 | Console.println("LoRa radio init failed"); 108 | while (1); 109 | } 110 | Console.println("LoRa radio init OK!"); 111 | 112 | // Configure RH_RF95 driver after init 113 | // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 114 | 115 | if (!rf95.setFrequency(FREQUENCY)) { 116 | Console.print(F("setFrequency failed\n")); 117 | while (true) { 118 | Console.println("."); 119 | delay(1000); 120 | } 121 | } 122 | Console.print("Set Freq to: "); Console.println(FREQUENCY); 123 | 124 | if (!rf95.setModemConfig(RH_RF95::MODEM_CONFIG_CHOICE)) { 125 | Console.print(F("setModemConfig failed\n")); 126 | while (true) { 127 | Console.println("."); 128 | delay(1000); 129 | } 130 | } 131 | Console.print("Set Modem Config to: "); Console.println(RH_RF95::MODEM_CONFIG_CHOICE); 132 | 133 | rf95.setTxPower(TX_POWER); 134 | Console.print("Set TX Power to: "); Console.println(TX_POWER); 135 | 136 | } 137 | 138 | void loop() 139 | { 140 | if (rf95.waitAvailableTimeout(10000)) 141 | { 142 | // Should be a message for us now 143 | uint8_t buf[RH_RF95_MAX_MESSAGE_LEN]; 144 | uint8_t len = sizeof(buf); 145 | 146 | if (rf95.recv(buf, &len)) 147 | { 148 | digitalWrite(LED, HIGH); 149 | RH_RF95::printBuffer("Received: ", buf, len); 150 | Console.print("Got: "); 151 | Console.println((char*)buf); 152 | Console.print("RSSI: "); 153 | Console.println(rf95.lastRssi(), DEC); 154 | digitalWrite(LED, LOW); 155 | } 156 | else 157 | { 158 | Console.println("Receive failed"); 159 | } 160 | }else{ 161 | Console.println("Nothing"); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # arduino-mqtt-sn-client 2 | Arduino based MQTT-SN Client 3 | 4 | ### Models 5 | * ESP8266 ✅ 6 | * ESP32 ❎ 7 | * Arduino Mega ❎ 8 | * Arduino Uno ✅ 9 | 10 | ### Transmission Technology to Platform Matrix 11 | | | UDP | TCP | Ethernet | WiFi | ZigBee | LoRa | BLE | 12 | |--- |--- |--- |--- |--- |--- |--- |--- | 13 | | Arduino ESP8266 | ✅ | ✅ | | ✅ | ❎\* | ❎\* | | 14 | | Arduino ESP32 | ❎ | ❎ | | ✅ | ❎\* | ❎\* | ❎ | 15 | | Arduino Mega | ❎\* | ❎\* | ❎\* | | ❎\* | ❎\* | | 16 | | Arduino Uno | ✅\* | ✅\* | ✅\* | | ❎\* | ✅\* | | 17 | 18 | \* needs additional transmission hardware 19 | 20 | ##### Legend: 21 | * ✅ implemented and tested 22 | * ❎ not implemented yet 23 | 24 | ## Getting Started 25 | 26 | ### ESP8266 (UDP) 27 | For UDP we use the `WiFiUdpMqttSnClient` example with a `ESP8266` (e.g. NodeMCU v1.0). 28 | #### Hardware 29 | You do not need additional hardware as mentioned in [Transmission Technology to Platform Matrix](#transmission-technology-to-platform-matrix). 30 | We tested it with the following Hardware: 31 | * NodeMCU v1.0 32 | #### Libraries 33 | We only need the `arduino-mqtt-sn-client` library. 34 | Perform the following steps for the ESP8266 UDP MQTT-SN Client: 35 | * [Download this library](https://github.com/S3ler/arduino-mqtt-sn-client/archive/master.zip). 36 | * Extract the archive and rename the folder to `arduino-mqtt-sn-client` then copy it to your Arduino library directory. 37 | * Restart your Arduino IDE if open. 38 | * Select a ESP8266 board in the Arduino IDE. 39 | * Open the example in `examples -> arduin-mqtt-sn-client -> esp8266 -> WiFiUdpMqttSnClient`. 40 | * Adapt `ssid` and `password` to your WiFi network. 41 | * Change `gatewayIPAddress` and `localUdpPort` to your MQTT-SN gateway's IPAddress and UDP port 42 | * Upload and try :) 43 | 44 | ### ESP8266 (TCP) 45 | For TCP we use the `TcpMqttSnClient` example with a `ESP8266` (e.g. NodeMCU v1.0). 46 | #### Hardware 47 | You do not need additional hardware as mentioned in [Transmission Technology to Platform Matrix](#transmission-technology-to-platform-matrix). 48 | We tested it with the following Hardware: 49 | * NodeMCU v1.0 50 | #### Libraries 51 | We only need the `arduino-mqtt-sn-client` library. 52 | Perform the following steps for the ESP8266 TCP MQTT-SN Client: 53 | * [Download this library](https://github.com/S3ler/arduino-mqtt-sn-client/archive/master.zip). 54 | * Extract the archive and rename the folder to `arduino-mqtt-sn-client` then copy it to your Arduino library directory. 55 | * Restart your Arduino IDE if open. 56 | * Select a ESP8266 board in the Arduino IDE. 57 | * Open the example in `examples -> arduin-mqtt-sn-client -> esp8266 -> TcpMqttSnClient`. 58 | * Adapt `ssid` and `password` to your WiFi network. 59 | * Change `gatewayIPAddress` and `localTcpPort` to your MQTT-SN gateway's IPAddress and TCP port 60 | * Upload and try :) 61 | 62 | ### Arduino Uno (LoRa) 63 | For LoRa we use the `RF95DatagramMqttSnClient` example with a `Arduino Uno`. `LoRa` on the physical layer and the `RHDatagram` on the data link layer. 64 | #### Hardware 65 | As mentioned in the [Transmission Technology to Platform Matrix](#transmission-technology-to-platform-matrix) you need additional Hardware. We tested it with the following Hardware: 66 | * Arduino Uno + Dragino LoRa Shield 67 | * Arduino Uno + Dragino LoRa/GPS Shield 68 | #### Libraries 69 | We only need the `arduino-mqtt-sn-client` library and the [airspayce RadioHead library](https://www.airspayce.com/mikem/arduino/RadioHead/). 70 | Perform the following steps for the Arduino LoRa MQTT-SN Client: 71 | * [Download this library](https://github.com/S3ler/arduino-mqtt-sn-client/archive/master.zip). 72 | * Extract the archive and rename the folder to `arduino-mqtt-sn-client` then copy it to your Arduino library directory. 73 | * [Download the airspayce RadioHead library](https://www.airspayce.com/mikem/arduino/RadioHead/) from homepage. I tested it with [version 1.87]( http://www.airspayce.com/mikem/arduino/RadioHead/RadioHead-1.87.zip). Copy it into your Arduino Library directory. 74 | * Extract the archive, then copy `RadioHead-1.87/RadioHead` into to your Arduino library directory. 75 | * Restart your Arduino IDE if open. 76 | * Select the `Arduino/Genuino Uno` board in the Arduino IDE. 77 | * Open the example in `examples -> arduino-mqtt-sn-client -> rf95 -> RF95DatagramMqttSnClient`. 78 | * Adapt `OWN_ADDRESS` to your your MQTT-SN client's `RHDatagram` address. 79 | * Configuration LoRa by changing `FREQUENCY`, `TX_POWER` and `MODEM_CONFIG_CHOICE` 80 | * Change `MqttSnGateway_Address` to your MQTT-SN gateway's `RHDatagram` address. 81 | * Upload and try :) 82 | -------------------------------------------------------------------------------- /SocketInterface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #ifndef ARDUINO_MQTTSN_CLIENT_SOCKETINTERFACE_H 8 | #define ARDUINO_MQTTSN_CLIENT_SOCKETINTERFACE_H 9 | 10 | 11 | #include "MqttSnMessageHandler.h" 12 | #include "TransmissionProtocolUartBridge.h" 13 | #include "global_defines.h" 14 | 15 | class SocketInterface 16 | { 17 | public: 18 | SocketInterface(){} 19 | virtual ~SocketInterface(){} 20 | 21 | /** 22 | * Set the MqttSnMessageHandler the receiveData method shall be called. 23 | * @tparam T type of SocketInterface implementation 24 | * @param mqttSnMessageHandler 25 | */ 26 | template 27 | void setMqttSnMessageHandler(MqttSnMessageHandler *mqttSnMessageHandler); 28 | 29 | /** 30 | * Set the TransmissionProtocolUartBridge the receiveData method shall be called. 31 | * @tparam T type of SocketInterface implementation 32 | * @param transmissionProtocolUartBridge 33 | */ 34 | template 35 | void setTransmissionProtocolUartBridge(TransmissionProtocolUartBridge *transmissionProtocolUartBridge); 36 | 37 | /** 38 | * Initialize the network stack below, with what ever you have to do to establish the connection to the network. 39 | * @return true if the connection is successfully established, false in any other case. 40 | */ 41 | virtual bool begin() =0 ; 42 | 43 | /** 44 | * Get the abstract broadcast address to send packets to. 45 | * Implementation Note: 46 | * - If your network stack does not provide any broadcast address, map it to a address you save as not-to-send-address. 47 | * - If your network stack has a procedure to broadcast packets, map it to a address you save as to-broadcast-address. 48 | * @return the abstract broadcast address as device address from of the network stack below. 49 | */ 50 | virtual device_address* getBroadcastAddress() = 0; 51 | 52 | /** 53 | * Get your own address converted to an abstract device address. 54 | * This is used in the GWINFO messages, despite the mqtt-sn standard does not tell to. 55 | * // TODO maybe we can change this, depend on the Mqtt-Sn client implementation 56 | * @return the abstract own device address provided by the network stack below. 57 | */ 58 | virtual device_address* getAddress() = 0; 59 | 60 | /** 61 | * Get the maximum count of bytes the network stack you use can provide as payload in a single message. 62 | * The minimum value you should provide is 8 bytes and the maximum the mqtt-sn standard supports are 255 bytes. 63 | * If you support more then 255 bytes payload in a message return 255. 64 | * Implementation Note: 65 | * - The absolute minimum are 8 bytes, but can only publish 1 byte raw data. 66 | * 7 bytes are needed by the header, you have only 1 byte data left. 67 | * If this makes sense is up to you. 68 | * - The maximum are 255 bytes. because the mqtt-sn standard message length up to 255 bytes. 69 | * The Length field in each Mqtt-Sn message is only 1 byte long. 70 | * Supporting longer message are out of the standard and will break the gateway implementation. 71 | * @return the maximum count of bytes the network stack can send 72 | */ 73 | virtual uint8_t getMaximumMessageLength() = 0; 74 | 75 | /** 76 | * Abstract and simple message to send the bytes of the mqtt-sn message 77 | * @param destination is the abstract destination address to send the payload 78 | * @param bytes is the pointer to the bytes to be send 79 | * @param bytes_len is the length of the bytes send to, maximum is 255, minimum 8. See method: getMaximumMessageLength 80 | * @return true if the connection to the network still exist. 81 | */ 82 | virtual bool send(device_address* destination, uint8_t* bytes, uint16_t bytes_len) = 0; 83 | 84 | /** 85 | * Abstract and simple message to send the bytes of the mqtt-sn message with a maximum signal strength parsed out of a SEARCHGW message. 86 | * Implementation Note: 87 | * - If your network stack below does not have the ability to change the signal strength or does it automatically, ignore the parameter. 88 | * @param destination is the abstract destination address to send the payload 89 | * @param bytes is the pointer to the bytes to be send 90 | * @param bytes_len is the length of the bytes send to, maximum is 255, minimum 8. See method: getMaximumMessageLength 91 | * @param signal_strength is the strength of the signal from the radius field received from the SEARCHGW message from the client with the destination_address. 92 | * @return true if the connection to the network still exist. 93 | */ 94 | virtual bool send(device_address* destination, uint8_t* bytes, uint16_t bytes_len, uint8_t signal_strength) = 0; 95 | 96 | virtual bool loop() = 0; 97 | }; 98 | 99 | #endif //ARDUINO_MQTTSN_CLIENT_SOCKETINTERFACE_H 100 | -------------------------------------------------------------------------------- /WiFiUdpSocket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #ifndef ARDUINO_MQTTSN_CLIENT_WIFIUDPSOCKET_H 8 | #define ARDUINO_MQTTSN_CLIENT_WIFIUDPSOCKET_H 9 | 10 | 11 | #include "MqttSnMessageHandler.h" 12 | #include "SocketInterface.h" 13 | #include 14 | #include 15 | 16 | #define RECEIVE_BUFFER_SIZE 255 17 | 18 | class WiFiUdpSocket : SocketInterface { 19 | private: 20 | uint16_t port; 21 | WiFiUDP &wiFiUdp; 22 | 23 | device_address own_address; 24 | 25 | device_address receive_address; 26 | uint8_t receive_buffer[RECEIVE_BUFFER_SIZE]; 27 | public: 28 | WiFiUdpSocket(WiFiUDP &wiFiUdp, uint16_t port) : wiFiUdp(wiFiUdp), port(port) {}; 29 | 30 | bool begin() override { 31 | // TODO multicast socket receive of advertisements 32 | // uint8_t beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port); 33 | return wiFiUdp.begin(port); 34 | } 35 | 36 | device_address *getBroadcastAddress() override { 37 | // TODO return multicast address 38 | return nullptr; 39 | } 40 | 41 | device_address *getAddress() override { 42 | IPAddress localIP = WiFi.localIP(); 43 | uint16_t localPort = wiFiUdp.localPort(); 44 | convertIPAddressAndPortToDeviceAddress(localIP, localPort, own_address); 45 | return &own_address; 46 | } 47 | 48 | uint8_t getMaximumMessageLength() override { 49 | return RECEIVE_BUFFER_SIZE; 50 | } 51 | 52 | bool send(device_address *destination, uint8_t *bytes, uint16_t bytes_len) override { 53 | return send(destination, bytes, bytes_len, UINT8_MAX); 54 | } 55 | 56 | bool send(device_address *destination, uint8_t *bytes, uint16_t bytes_len, uint8_t signal_strength) override { 57 | IPAddress destination_IPAddress; 58 | uint16_t destination_port = 0; 59 | convertDeviceAddressToIPAddressAndPort(destination, destination_IPAddress, &destination_port); 60 | 61 | if (wiFiUdp.beginPacket(destination_IPAddress, destination_port) == 1) { 62 | if (wiFiUdp.write(bytes, bytes_len) == bytes_len) { 63 | if (wiFiUdp.endPacket() == 1) { 64 | return true; 65 | } 66 | } 67 | } 68 | 69 | return false; 70 | } 71 | 72 | void convertIPAddressAndPortToDeviceAddress(IPAddress &source, uint16_t port, device_address &target) { 73 | // IPAdress 0 - 3 bytes 74 | target.bytes[0] = source[0]; 75 | target.bytes[1] = source[1]; 76 | target.bytes[2] = source[2]; 77 | target.bytes[3] = source[3]; 78 | // Port 4 - 5 bytes 79 | target.bytes[4] = port >> 8; 80 | target.bytes[5] = (uint8_t) port; 81 | } 82 | 83 | 84 | void convertDeviceAddressToIPAddressAndPort(device_address *source, IPAddress &destination_IPAddress, 85 | uint16_t *destination_port) { 86 | // convert device_address to IPAddress and port 87 | // IPAdress 0 - 3 bytes 88 | destination_IPAddress[0] = source->bytes[0]; 89 | destination_IPAddress[1] = source->bytes[1]; 90 | destination_IPAddress[2] = source->bytes[2]; 91 | destination_IPAddress[3] = source->bytes[3]; 92 | // Port 4 - 5 bytes 93 | uint16_t tmp_port = 0; 94 | tmp_port = ((uint16_t) source->bytes[4]) << 8; 95 | tmp_port += (uint16_t) source->bytes[5]; 96 | *destination_port = tmp_port; 97 | } 98 | 99 | bool loop() override { 100 | if (wiFiUdp.parsePacket() > 0) { 101 | memset(&receive_address, 0x0, sizeof(device_address)); 102 | memset(receive_buffer, 0x0, RECEIVE_BUFFER_SIZE); 103 | 104 | int available = wiFiUdp.available(); 105 | if (available < RECEIVE_BUFFER_SIZE) { 106 | 107 | if (wiFiUdp.read(receive_buffer, RECEIVE_BUFFER_SIZE) == available) { 108 | 109 | IPAddress remoteIP = wiFiUdp.remoteIP(); 110 | uint16_t remotePort = wiFiUdp.remotePort(); 111 | convertIPAddressAndPortToDeviceAddress(remoteIP, remotePort, receive_address); 112 | 113 | if (mqttSnMessageHandler != nullptr) { 114 | mqttSnMessageHandler->receiveData(&receive_address, receive_buffer); 115 | } 116 | 117 | if (transmissionProtocolUartBridge != nullptr) { 118 | transmissionProtocolUartBridge->receiveData(&receive_address, receive_buffer, available); 119 | } 120 | 121 | } 122 | } 123 | // too much data => ignored 124 | wiFiUdp.flush(); 125 | } 126 | return true; 127 | } 128 | 129 | template 130 | void setMqttSnMessageHandler( 131 | MqttSnMessageHandler *mqttSnMessageHandler) { 132 | this->mqttSnMessageHandler = mqttSnMessageHandler; 133 | }; 134 | 135 | template 136 | void setTransmissionProtocolUartBridge( 137 | TransmissionProtocolUartBridge *transmissionProtocolUartBridge) { 138 | this->transmissionProtocolUartBridge = transmissionProtocolUartBridge; 139 | }; 140 | private: 141 | MqttSnMessageHandler *mqttSnMessageHandler = nullptr; 142 | TransmissionProtocolUartBridge *transmissionProtocolUartBridge = nullptr; 143 | 144 | }; 145 | 146 | 147 | #endif //ARDUINO_MQTTSN_CLIENT_WIFIUDPSOCKET_H 148 | -------------------------------------------------------------------------------- /ClientSocket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #ifndef ARDUINO_MQTTSN_CLIENT_CLIENTSOCKET_H 8 | #define ARDUINO_MQTTSN_CLIENT_CLIENTSOCKET_H 9 | 10 | 11 | #include "MqttSnMessageHandler.h" 12 | #include "SocketInterface.h" 13 | #include 14 | #include 15 | 16 | #define RECEIVE_BUFFER_SIZE 255 17 | 18 | class ClientSocket : SocketInterface { 19 | private: 20 | Client *client; 21 | uint16_t localPort = 0; 22 | 23 | device_address own_address; 24 | device_address receive_address; 25 | 26 | public: 27 | ClientSocket(Client *client) : client(client){}; 28 | 29 | bool begin() override { 30 | memset(&own_address, 0x0, sizeof(device_address)); 31 | memset(&receive_address, 0x0, sizeof(device_address)); 32 | return true; 33 | } 34 | 35 | device_address *getBroadcastAddress() override { 36 | return nullptr; 37 | } 38 | 39 | void setIpAddressAndPort(IPAddress &ipAddress, uint16_t localPort){ 40 | this->localPort = localPort; 41 | convertIPAddressAndPortToDeviceAddress(ipAddress, localPort, own_address); 42 | } 43 | 44 | device_address *getAddress() override { 45 | // returns 0, 0, 0, 0, 0, 0 if no address was set 46 | return &own_address; 47 | } 48 | 49 | uint8_t getMaximumMessageLength() override { 50 | return RECEIVE_BUFFER_SIZE; 51 | } 52 | 53 | bool send(device_address *destination, uint8_t *bytes, uint16_t bytes_len) override { 54 | return send(destination, bytes, bytes_len, UINT8_MAX); 55 | } 56 | 57 | bool send(device_address *destination, uint8_t *bytes, uint16_t bytes_len, uint8_t signal_strength) override { 58 | if(client->connected()){ 59 | if(memcmp(&receive_address, destination, sizeof(device_address))==0){ 60 | if (client->write(bytes, bytes_len) == bytes_len) { 61 | client->flush(); 62 | return true; 63 | } 64 | } 65 | } else { 66 | IPAddress ip; 67 | uint16_t port; 68 | convertDeviceAddressToIPAddressAndPort(destination, ip, &port); 69 | if(client->connect(ip, port)){ 70 | if (client->write(bytes, bytes_len) == bytes_len) { 71 | memcpy(&receive_address, destination, sizeof(device_address)); 72 | client->flush(); 73 | return true; 74 | } 75 | } 76 | } 77 | return false; 78 | } 79 | 80 | bool loop() override { 81 | if(client->connected()) { 82 | 83 | if (client->available()) { 84 | 85 | uint8_t receive_buffer[RECEIVE_BUFFER_SIZE]; 86 | memset(receive_buffer, 0x0, RECEIVE_BUFFER_SIZE); 87 | 88 | int available = client->available(); 89 | if (available < RECEIVE_BUFFER_SIZE) { 90 | 91 | if (client->read(receive_buffer, RECEIVE_BUFFER_SIZE) == available) { 92 | 93 | if (mqttSnMessageHandler != nullptr) { 94 | mqttSnMessageHandler->receiveData(&receive_address, receive_buffer); 95 | } 96 | 97 | if (transmissionProtocolUartBridge != nullptr) { 98 | transmissionProtocolUartBridge->receiveData(&receive_address, receive_buffer, available); 99 | } 100 | } 101 | 102 | } else { 103 | client->flush(); 104 | } 105 | } 106 | client->flush(); 107 | return true; 108 | } 109 | return false; 110 | } 111 | 112 | void convertIPAddressAndPortToDeviceAddress(IPAddress &source, uint16_t port, device_address &target) { 113 | // IPAddress 0 - 3 bytes 114 | target.bytes[0] = source[0]; 115 | target.bytes[1] = source[1]; 116 | target.bytes[2] = source[2]; 117 | target.bytes[3] = source[3]; 118 | // Port 4 - 5 bytes 119 | target.bytes[4] = port >> 8; 120 | target.bytes[5] = (uint8_t) port; 121 | } 122 | 123 | 124 | void convertDeviceAddressToIPAddressAndPort(device_address *source, IPAddress &destination_IPAddress, 125 | uint16_t *destination_port) { 126 | // convert device_address to IPAddress and port 127 | // IPAddress 0 - 3 bytes 128 | destination_IPAddress[0] = source->bytes[0]; 129 | destination_IPAddress[1] = source->bytes[1]; 130 | destination_IPAddress[2] = source->bytes[2]; 131 | destination_IPAddress[3] = source->bytes[3]; 132 | // Port 4 - 5 bytes 133 | uint16_t tmp_port = 0; 134 | tmp_port = ((uint16_t) source->bytes[4]) << 8; 135 | tmp_port += (uint16_t) source->bytes[5]; 136 | *destination_port = tmp_port; 137 | } 138 | 139 | template 140 | void setMqttSnMessageHandler( 141 | MqttSnMessageHandler *mqttSnMessageHandler) { 142 | this->mqttSnMessageHandler = mqttSnMessageHandler; 143 | }; 144 | 145 | template 146 | void setTransmissionProtocolUartBridge( 147 | TransmissionProtocolUartBridge *transmissionProtocolUartBridge) { 148 | this->transmissionProtocolUartBridge = transmissionProtocolUartBridge; 149 | }; 150 | private: 151 | MqttSnMessageHandler *mqttSnMessageHandler = nullptr; 152 | TransmissionProtocolUartBridge *transmissionProtocolUartBridge = nullptr; 153 | 154 | }; 155 | 156 | 157 | #endif //ARDUINO_MQTTSN_CLIENT_CLIENTSOCKET_H 158 | -------------------------------------------------------------------------------- /UdpSocket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #ifndef ARDUINO_MQTTSN_CLIENT_WIFIUDPSOCKET_H 8 | #define ARDUINO_MQTTSN_CLIENT_WIFIUDPSOCKET_H 9 | 10 | 11 | #include "MqttSnMessageHandler.h" 12 | #include "SocketInterface.h" 13 | #include 14 | 15 | #define RECEIVE_BUFFER_SIZE 255 16 | 17 | class UDPSocket : SocketInterface { 18 | private: 19 | UDP *udp; 20 | uint16_t localPort; 21 | 22 | device_address own_address; 23 | device_address broadcast_address; 24 | 25 | 26 | public: 27 | UDPSocket(UDP *udp, uint16_t localPort) : udp(udp), localPort(localPort) { 28 | memset(&own_address, 0x0, sizeof(device_address)); 29 | memset(&broadcast_address, 0x0, sizeof(device_address)); 30 | }; 31 | 32 | #ifndef ESP8266 33 | UDPSocket(UDP *udp, uint16_t localPort, IPAddress multicastIp, uint16_t multicastPort) : 34 | udp(udp), localPort(localPort) 35 | { 36 | memset(&own_address, 0x0, sizeof(device_address)); 37 | memset(&broadcast_address, 0x0, sizeof(device_address)); 38 | convertIPAddressAndPortToDeviceAddress(multicastIp, multicastPort, broadcast_address); 39 | }; 40 | #endif 41 | 42 | bool begin() override { 43 | #ifndef ESP8266 44 | device_address empty_device_address; 45 | memset(&empty_device_address, 0x0, sizeof(device_address)); 46 | if(!(memcmp(&broadcast_address, &empty_device_address, sizeof(device_address))==0)){ 47 | IPAddress ip; 48 | uint16_t port; 49 | convertDeviceAddressToIPAddressAndPort(&broadcast_address, ip, &port); 50 | if(!udp->beginMulticast(ip, port)){ 51 | return false; 52 | } 53 | } 54 | #endif 55 | return udp->begin(localPort); 56 | } 57 | 58 | device_address *getBroadcastAddress() override { 59 | return &broadcast_address; 60 | } 61 | 62 | void setIpAddress(IPAddress &ipAddress){ 63 | convertIPAddressAndPortToDeviceAddress(ipAddress, localPort, own_address); 64 | } 65 | 66 | device_address *getAddress() override { 67 | // return 0, 0, 0, 0, 0, 0 if no address was set 68 | return &own_address; 69 | } 70 | 71 | uint8_t getMaximumMessageLength() override { 72 | return RECEIVE_BUFFER_SIZE; 73 | } 74 | 75 | bool send(device_address *destination, uint8_t *bytes, uint16_t bytes_len) override { 76 | return send(destination, bytes, bytes_len, UINT8_MAX); 77 | } 78 | 79 | bool send(device_address *destination, uint8_t *bytes, uint16_t bytes_len, uint8_t signal_strength) override { 80 | IPAddress destination_IPAddress; 81 | uint16_t destination_port = 0; 82 | convertDeviceAddressToIPAddressAndPort(destination, destination_IPAddress, &destination_port); 83 | 84 | if (udp->beginPacket(destination_IPAddress, destination_port) == 1) { 85 | if (udp->write(bytes, bytes_len) == bytes_len) { 86 | if (udp->endPacket() == 1) { 87 | return true; 88 | } 89 | } 90 | } 91 | 92 | return false; 93 | } 94 | 95 | void convertIPAddressAndPortToDeviceAddress(IPAddress &source, uint16_t port, device_address &target) { 96 | // IPAddress 0 - 3 bytes 97 | target.bytes[0] = source[0]; 98 | target.bytes[1] = source[1]; 99 | target.bytes[2] = source[2]; 100 | target.bytes[3] = source[3]; 101 | // Port 4 - 5 bytes 102 | target.bytes[4] = port >> 8; 103 | target.bytes[5] = (uint8_t) port; 104 | } 105 | 106 | 107 | void convertDeviceAddressToIPAddressAndPort(device_address *source, IPAddress &destination_IPAddress, 108 | uint16_t *destination_port) { 109 | // convert device_address to IPAddress and port 110 | // IPAddress 0 - 3 bytes 111 | destination_IPAddress[0] = source->bytes[0]; 112 | destination_IPAddress[1] = source->bytes[1]; 113 | destination_IPAddress[2] = source->bytes[2]; 114 | destination_IPAddress[3] = source->bytes[3]; 115 | // Port 4 - 5 bytes 116 | uint16_t tmp_port = 0; 117 | tmp_port = ((uint16_t) source->bytes[4]) << 8; 118 | tmp_port += (uint16_t) source->bytes[5]; 119 | *destination_port = tmp_port; 120 | } 121 | 122 | bool loop() override { 123 | if (udp->parsePacket() > 0) { 124 | device_address receive_address; 125 | uint8_t receive_buffer[RECEIVE_BUFFER_SIZE]; 126 | 127 | memset(&receive_address, 0x0, sizeof(device_address)); 128 | memset(receive_buffer, 0x0, RECEIVE_BUFFER_SIZE); 129 | 130 | int available = udp->available(); 131 | if (available < RECEIVE_BUFFER_SIZE) { 132 | 133 | if (udp->read(receive_buffer, RECEIVE_BUFFER_SIZE) == available) { 134 | 135 | IPAddress remoteIP = udp->remoteIP(); 136 | uint16_t remotePort = udp->remotePort(); 137 | convertIPAddressAndPortToDeviceAddress(remoteIP, remotePort, receive_address); 138 | 139 | if (mqttSnMessageHandler != nullptr) { 140 | mqttSnMessageHandler->receiveData(&receive_address, receive_buffer); 141 | } 142 | 143 | if (transmissionProtocolUartBridge != nullptr) { 144 | transmissionProtocolUartBridge->receiveData(&receive_address, receive_buffer, available); 145 | } 146 | 147 | } 148 | }else{ 149 | // too much data => ignored 150 | udp->flush(); 151 | } 152 | 153 | } 154 | // TODO check if flush is needed 155 | udp->flush(); 156 | return true; 157 | } 158 | 159 | template 160 | void setMqttSnMessageHandler( 161 | MqttSnMessageHandler *mqttSnMessageHandler) { 162 | this->mqttSnMessageHandler = mqttSnMessageHandler; 163 | }; 164 | 165 | template 166 | void setTransmissionProtocolUartBridge( 167 | TransmissionProtocolUartBridge *transmissionProtocolUartBridge) { 168 | this->transmissionProtocolUartBridge = transmissionProtocolUartBridge; 169 | }; 170 | private: 171 | MqttSnMessageHandler *mqttSnMessageHandler = nullptr; 172 | TransmissionProtocolUartBridge *transmissionProtocolUartBridge = nullptr; 173 | 174 | }; 175 | 176 | 177 | #endif //ARDUINO_MQTTSN_CLIENT_WIFIUDPSOCKET_H 178 | -------------------------------------------------------------------------------- /MqttSnMessageHandler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #ifndef ARDUINO_MQTTSN_CLIENT_MQTTSNMESSAGEHANDLER_H 8 | #define ARDUINO_MQTTSN_CLIENT_MQTTSNMESSAGEHANDLER_H 9 | 10 | #include "MqttSnClient.h" 11 | #include "global_defines.h" 12 | #include "mqttsn_messages.h" 13 | #include 14 | 15 | template 16 | class MqttSnClient; 17 | 18 | template 19 | class MqttSnMessageHandler { 20 | private: 21 | MqttSnMessageHandler_SocketInterface &socketInterface; 22 | MqttSnClient &mqttSnClient; 23 | public: 24 | MqttSnMessageHandler(MqttSnMessageHandler_SocketInterface &socketInterface, 25 | MqttSnClient &mqttSnClient) 26 | : socketInterface(socketInterface), mqttSnClient(mqttSnClient) {} 27 | 28 | bool begin() { 29 | return socketInterface.begin(); 30 | } 31 | 32 | 33 | void receiveData(device_address *address, uint8_t *bytes) { 34 | 35 | message_header *header = (message_header *) bytes; 36 | if (header->length < 2) { 37 | return; 38 | } 39 | if (header->type == MQTTSN_ADVERTISE) { 40 | //TODO 41 | return; 42 | } 43 | if (!mqttSnClient.is_gateway_address(address)) { 44 | return; 45 | } 46 | if (!mqttSnClient.is_mqttsn_connected()) { 47 | if (header->type == MQTTSN_CONNACK) { 48 | parse_connack(address, bytes); 49 | } 50 | return; 51 | } 52 | switch (header->type) { 53 | case MQTTSN_PINGREQ: 54 | parse_pingreq(address, bytes); 55 | break; 56 | case MQTTSN_PINGRESP: 57 | parse_pingresp(address, bytes); 58 | break; 59 | case MQTTSN_CONNACK: 60 | parse_connack(address, bytes); 61 | break; 62 | case MQTTSN_SUBACK: 63 | parse_suback(address, bytes); 64 | break; 65 | case MQTTSN_REGACK: 66 | parse_regack(address, bytes); 67 | case MQTTSN_PUBLISH: 68 | Serial.println("MQTTSN_PUBLISH"); 69 | parse_publish(address, bytes); 70 | break; 71 | default: 72 | break; 73 | } 74 | } 75 | 76 | void parse_pingreq(device_address *address, uint8_t *bytes) { 77 | msg_pingreq *msg = (msg_pingreq *) bytes; 78 | if (bytes[0] == 2 && bytes[1] == MQTTSN_PINGREQ) { 79 | handle_pingreq(address); 80 | } 81 | } 82 | 83 | void handle_pingreq(device_address *address) { 84 | if (mqttSnClient.is_gateway_address(address)) { 85 | if (mqttSnClient.get_await_message() == MQTTSN_PINGREQ) { 86 | send_pingresp(address); 87 | } 88 | // TODO disconnect 89 | } 90 | } 91 | 92 | void send_pingresp(device_address *address) { 93 | message_header to_send; 94 | to_send.length = 2; 95 | to_send.type = MQTTSN_PINGRESP; 96 | if (!socketInterface.send(address, (uint8_t *) &to_send, sizeof(message_header))) { 97 | mqttSnClient.notify_socket_disconnected(); 98 | } 99 | } 100 | 101 | void send_connect(device_address *address, const char *client_id, uint16_t duration) { 102 | msg_connect to_send(false, true, PROTOCOL_ID, duration, client_id); 103 | if (!socketInterface.send(address, (uint8_t *) &to_send, to_send.length)) { 104 | mqttSnClient.notify_socket_disconnected(); 105 | } 106 | } 107 | 108 | void parse_connack(device_address *pAddress, uint8_t *bytes) { 109 | msg_connack *msg = (msg_connack *) bytes; 110 | // TODO check values 111 | if (bytes[0] == 3 && bytes[1] == MQTTSN_CONNACK) { 112 | if (msg->type == mqttSnClient.get_await_message()) { 113 | if (msg->return_code == ACCEPTED) { 114 | mqttSnClient.set_await_message(MQTTSN_PINGREQ); 115 | mqttSnClient.set_mqttsn_connected(); 116 | return; 117 | } else if (msg->return_code == REJECTED_CONGESTION) { 118 | return; 119 | } 120 | } 121 | send_disconnect(pAddress); 122 | mqttSnClient.set_await_message(MQTTSN_DISCONNECT); 123 | } 124 | } 125 | 126 | void send_disconnect(device_address *address) { 127 | message_header to_send; 128 | to_send.to_disconnect(); 129 | if (!socketInterface.send(address, (uint8_t *) &to_send, sizeof(message_header))) { 130 | mqttSnClient.notify_socket_disconnected(); 131 | } 132 | } 133 | 134 | void notify_socket_connected() { 135 | mqttSnClient.notify_socket_connected(); 136 | } 137 | 138 | void notify_socket_disconnected() { 139 | mqttSnClient.notify_socket_disconnected(); 140 | } 141 | 142 | void send_pingreq(device_address *address) { 143 | message_header to_send; 144 | to_send.to_pingreq(); 145 | if (!socketInterface.send(address, (uint8_t *) &to_send, (uint16_t) to_send.length)) { 146 | mqttSnClient.notify_socket_disconnected(); 147 | } 148 | } 149 | 150 | void parse_pingresp(device_address *pAddress, uint8_t *bytes) { 151 | msg_pingreq *msg = (msg_pingreq *) bytes; 152 | if (bytes[0] == 2 && bytes[1] == MQTTSN_PINGRESP) { 153 | if (mqttSnClient.get_await_message() == MQTTSN_PINGRESP) { 154 | mqttSnClient.notify_pingresponse_arrived(); 155 | mqttSnClient.set_await_message(MQTTSN_PINGREQ); 156 | } 157 | //TODO disconnect 158 | } 159 | } 160 | 161 | void send_subscribe(device_address *address, const char *topic_name, uint8_t qos) { 162 | msg_subscribe_topicname to_send(topic_name, mqttSnClient.increment_and_get_msg_id_counter(), qos, false); 163 | if (!socketInterface.send(address, (uint8_t *) &to_send, (uint16_t) to_send.length)) { 164 | mqttSnClient.notify_socket_disconnected(); 165 | } 166 | 167 | } 168 | 169 | void parse_suback(device_address *pAddress, uint8_t *bytes) { 170 | msg_suback *msg = (msg_suback *) bytes; 171 | if (msg->length == 8 && msg->type == MQTTSN_SUBACK && msg->message_id == mqttSnClient.get_await_message_id()) { 172 | if (msg->return_code == ACCEPTED) { 173 | int8_t granted_qos = 0; 174 | if ((msg->flags & FLAG_QOS_M1) == FLAG_QOS_M1) { 175 | granted_qos = -1; 176 | } else if ((msg->flags & FLAG_QOS_2) == FLAG_QOS_2) { 177 | granted_qos = 2; 178 | } else if ((msg->flags & FLAG_QOS_1) == FLAG_QOS_1) { 179 | granted_qos = 1; 180 | } else { 181 | granted_qos = 0; 182 | } 183 | if (granted_qos == -1) { 184 | //TODO disconnect 185 | } 186 | if (mqttSnClient.await_topic_id) { 187 | mqttSnClient.set_await_topic_id(msg->topic_id); 188 | } 189 | mqttSnClient.set_granted_qos(granted_qos); 190 | mqttSnClient.set_await_message(MQTTSN_PINGREQ); 191 | return; 192 | } else if (msg->return_code == REJECTED_CONGESTION) { 193 | // TODO try again later 194 | } else if (msg->return_code == REJECTED_INVALID_TOPIC_ID) { 195 | // TODO register topic name again! 196 | } 197 | /*else if (msg->return_code == REJECTED_NOT_SUPPORTED) { 198 | // disconnect 199 | }*/ 200 | } 201 | //TODO disconnect 202 | } 203 | 204 | void parse_regack(device_address *pAddress, uint8_t *bytes) { 205 | msg_regack* msg = (msg_regack *) bytes; 206 | if(bytes[0] == 7 & bytes[1] == MQTTSN_REGACK){ 207 | mqttSnClient.handle_regack(msg->topic_id, msg->message_id, msg->return_code); 208 | } 209 | } 210 | 211 | void parse_publish(device_address *address, uint8_t *bytes) { 212 | msg_publish *msg = (msg_publish *) bytes; 213 | if (bytes[0] > 7 && bytes[1] == MQTTSN_PUBLISH) { // 7 bytes header + at least 1 byte data 214 | bool dup = (msg->flags & FLAG_DUP) != 0; 215 | 216 | int8_t qos = 0; 217 | if ((msg->flags & FLAG_QOS_M1) == FLAG_QOS_M1) { 218 | qos = -1; 219 | } else if ((msg->flags & FLAG_QOS_2) == FLAG_QOS_2) { 220 | qos = 2; 221 | } else if ((msg->flags & FLAG_QOS_1) == FLAG_QOS_1) { 222 | qos = 1; 223 | } else { 224 | qos = 0; 225 | } 226 | 227 | bool retain = (msg->flags & FLAG_RETAIN) != 0; 228 | bool short_topic = (msg->flags & FLAG_TOPIC_SHORT_NAME) != 0; 229 | uint16_t data_len = bytes[0] - (uint8_t) 7; 230 | if (((qos == 0) || (qos == -1)) && msg->message_id != 0x0000) { 231 | // this can be too strict 232 | // we can also ignore the message_id for Qos 0 and -1 233 | return; 234 | } 235 | 236 | //if (!short_topic && !(msg->flags & FLAG_TOPIC_PREDEFINED_ID != 0)) { // TODO what does this so?! WTF?! 237 | // mqttSnClient.handle_publish(address, msg->data, data_len, msg->message_id, msg->topic_id, short_topic, retain, qos, dup); 238 | //} 239 | //msg id 240 | // short topic 241 | mqttSnClient.handle_publish(address, msg->data, data_len, msg->topic_id, retain, qos); 242 | return; 243 | } 244 | 245 | // TODO disconnect 246 | } 247 | 248 | 249 | void send_publish(device_address *address, uint8_t *data, uint8_t data_len, uint16_t msg_id, 250 | uint16_t topic_id, bool short_topic, bool retain, uint8_t qos, bool dup) { 251 | msg_publish to_send(dup, qos, retain, short_topic, topic_id, msg_id, data, data_len); 252 | if (!socketInterface.send(address, (uint8_t *) &to_send, (uint16_t) to_send.length)) { 253 | mqttSnClient.notify_socket_disconnected(); 254 | } 255 | } 256 | 257 | void send_register(device_address *address, uint16_t msg_id, const char *topic_name) { 258 | msg_register to_send(0x0, msg_id, topic_name); 259 | if (!socketInterface.send(address, (uint8_t *) &to_send, (uint16_t) to_send.length)) { 260 | mqttSnClient.notify_socket_disconnected(); 261 | } 262 | } 263 | 264 | }; 265 | 266 | 267 | #endif //ARDUINO_MQTTSN_CLIENT_MQTTSNMESSAGEHANDLER_H 268 | -------------------------------------------------------------------------------- /MqttSnClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Gabriel Nikol 5 | */ 6 | 7 | #ifndef ARDUINO_MQTTSN_CLIENT_MQTTSNCLIENT_H 8 | #define ARDUINO_MQTTSN_CLIENT_MQTTSNCLIENT_H 9 | 10 | #include "MqttSnMessageHandler.h" 11 | #include "System.h" 12 | #include 13 | #include "global_defines.h" 14 | #include "mqttsn_messages.h" 15 | 16 | template 17 | class MqttSnMessageHandler; 18 | 19 | 20 | struct topic_registration { 21 | char *topic_name; 22 | uint16_t topic_id; 23 | uint8_t granted_qos; 24 | }; 25 | 26 | #ifdef ESP8266 27 | #include 28 | #define MQTT_SN_CALLBACK_SIGNATURE std::function callback 29 | #else 30 | #define MQTT_SN_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, uint16_t, bool retain) 31 | #endif 32 | 33 | 34 | template 35 | class MqttSnClient { 36 | private: 37 | MqttSnClient_SocketInterface &socketInterface; 38 | MqttSnMessageHandler mqttSnMessageHandler; 39 | 40 | template friend 41 | class MqttSnMessageHandler; 42 | 43 | System system; 44 | 45 | device_address gw_address; 46 | bool socket_disconnected = false; 47 | bool mqttsn_connected = false; 48 | message_type await_msg_type = MQTTSN_GWINFO; 49 | bool ping_outstanding = false; 50 | 51 | MQTT_SN_CALLBACK_SIGNATURE; 52 | 53 | uint16_t msg_id_counter = 1; 54 | bool await_topic_id = false; 55 | 56 | //we supports only single subscription at the moment 57 | topic_registration registration; 58 | topic_registration publish_registration; 59 | 60 | public: 61 | explicit MqttSnClient(MqttSnClient_SocketInterface &socketInterface) : socketInterface( 62 | socketInterface), mqttSnMessageHandler(socketInterface, *this) {} 63 | 64 | bool begin() { 65 | memset(&publish_registration, 0x0, sizeof(topic_registration)); 66 | memset(®istration, 0x0, sizeof(topic_registration)); 67 | 68 | socketInterface.setMqttSnMessageHandler(&mqttSnMessageHandler); 69 | return mqttSnMessageHandler.begin(); 70 | } 71 | 72 | 73 | bool is_gateway_address(device_address *pAddress) { 74 | return memcmp(&this->gw_address, pAddress, sizeof(device_address)) == 0; 75 | } 76 | 77 | void notify_socket_disconnected() { 78 | this->socket_disconnected = true; 79 | } 80 | 81 | void set_await_message(message_type msg_type) { 82 | this->await_msg_type = msg_type; 83 | } 84 | 85 | bool loop() { 86 | if (!mqttsn_connected) { 87 | return false; 88 | } 89 | if (socket_disconnected) { 90 | set_await_message(MQTTSN_PINGREQ); 91 | return false; 92 | } 93 | socketInterface.loop(); 94 | if (system.has_beaten()) { 95 | ping_outstanding = true; 96 | } 97 | if (ping_outstanding && await_msg_type == MQTTSN_PINGREQ) { 98 | mqttSnMessageHandler.send_pingreq(&gw_address); 99 | set_await_message(MQTTSN_PINGRESP); 100 | } 101 | return true; 102 | } 103 | 104 | void setCallback(MQTT_SN_CALLBACK_SIGNATURE) { 105 | this->callback = callback; 106 | } 107 | 108 | bool connect(device_address *address, const char *client_id, uint16_t duration) { 109 | // global verwalten 110 | uint8_t retries = 2; 111 | memcpy(&this->gw_address, address, sizeof(device_address)); 112 | 113 | for (uint8_t tries = 0; tries < retries; tries++) { 114 | system.set_heartbeat(5 * 1000); 115 | mqttSnMessageHandler.send_connect(address, client_id, duration); 116 | this->set_await_message(MQTTSN_CONNACK); 117 | while (!mqttsn_connected) { 118 | socketInterface.loop(); 119 | if (mqttsn_connected) { 120 | memcpy(&this->gw_address, address, sizeof(device_address)); 121 | system.set_heartbeat(duration * 1000); 122 | return true; 123 | } 124 | if (system.has_beaten()) { 125 | // timeout 126 | break; 127 | } 128 | if (socket_disconnected) { 129 | return false; 130 | } 131 | } 132 | system.sleep((tries + 1) * 10 * 1000); 133 | } 134 | // timeout - take another gateway 135 | return false; 136 | } 137 | 138 | bool subscribe(const char *topic, uint8_t qos) { 139 | while (this->await_msg_type != MQTTSN_PINGREQ) { 140 | // wait until we have no other messages in flight 141 | if (!socketInterface.loop()) { 142 | return false; 143 | } 144 | } 145 | mqttSnMessageHandler.send_subscribe(&gw_address, topic, qos); 146 | this->set_await_message(MQTTSN_SUBACK); 147 | memset(®istration, 0, sizeof(topic_registration)); 148 | //strcpy(registration.topic_name, topic); 149 | registration.topic_name = (char *) topic; 150 | registration.granted_qos = qos; 151 | await_topic_id = true; 152 | while (this->await_msg_type != MQTTSN_PINGREQ) { 153 | // wait until we have no other messages in flight 154 | if (!socketInterface.loop()) { 155 | return false; 156 | } 157 | } 158 | return true; 159 | } 160 | 161 | bool publish(char *payload, char *topic_name, int8_t qos) { 162 | 163 | // check if payload is not too long 164 | uint16_t payload_length = 0; 165 | uint8_t msg_publish_without_payload_length = 7; 166 | if (strlen(payload) + 1 > socketInterface.getMaximumMessageLength() - msg_publish_without_payload_length) { 167 | // payload is too long 168 | return false; 169 | } 170 | payload_length = strlen(payload) + 1; 171 | if (qos == 2) { 172 | // TODO not implemented yet 173 | return false; 174 | } 175 | if (qos < -1 || qos > 2) { 176 | // invalid qos 177 | return false; 178 | } 179 | 180 | if (qos > 0) { 181 | while (this->await_msg_type != MQTTSN_PINGREQ) { 182 | // wait until we have no other messages are in flight 183 | if (!socketInterface.loop()) { 184 | return false; 185 | } 186 | } 187 | } 188 | 189 | // check if topic_name is already registered 190 | uint16_t topic_id = 0; 191 | if (this->registration.topic_name == topic_name) { 192 | topic_id = registration.topic_id; 193 | } else if (this->publish_registration.topic_name == topic_name) { 194 | topic_id = publish_registration.topic_id; 195 | } else { 196 | // it is not registered - register it now 197 | topic_id = register_topic(topic_name); 198 | } 199 | if (topic_id == 0) { 200 | // TODO check if compatible or if gateway deliveres 0 too (then change return type of register_topic) 201 | return false; 202 | } 203 | publish_registration.topic_id = topic_id; 204 | 205 | 206 | uint16_t msg_id = this->increment_and_get_msg_id_counter(); 207 | if (qos == 0) { 208 | msg_id = 0; 209 | } 210 | if (qos == 1) { 211 | this->set_await_message(MQTTSN_PUBACK); 212 | } 213 | 214 | mqttSnMessageHandler.send_publish(&gw_address, (uint8_t *) payload, payload_length, msg_id, topic_id, true, 215 | false, qos, false); 216 | if (qos > 0) { 217 | while (this->await_msg_type != MQTTSN_PINGREQ) { 218 | // wait until we have no other messages in flight 219 | if (!socketInterface.loop()) { 220 | return false; 221 | } 222 | } 223 | } 224 | return true; 225 | } 226 | 227 | uint16_t register_topic(char *topic_name) { 228 | while (this->await_msg_type != MQTTSN_PINGREQ) { 229 | // wait until we have no other messages in flight 230 | if (!socketInterface.loop()) { 231 | return 0; 232 | } 233 | } 234 | uint16_t msg_id = this->increment_and_get_msg_id_counter(); 235 | publish_registration.topic_name = (char *) topic_name; 236 | // publish_registration.topic_name = (char *) topic_name; 237 | 238 | this->set_await_message(MQTTSN_REGACK); 239 | mqttSnMessageHandler.send_register(&gw_address, msg_id, topic_name); 240 | 241 | while (this->await_msg_type != MQTTSN_PINGREQ) { 242 | // wait until MQTTSN_REGACK arrived 243 | if (!socketInterface.loop()) { 244 | return 0; 245 | } 246 | } 247 | return publish_registration.topic_id; 248 | 249 | } 250 | 251 | void handle_regack(uint16_t topic_id, uint16_t msg_id, return_code_t return_code) { 252 | if (this->msg_id_counter == msg_id) { 253 | if (return_code == ACCEPTED) { 254 | publish_registration.topic_id = topic_id; 255 | } else if (return_code == REJECTED_CONGESTION) { 256 | publish_registration.topic_id = 0; 257 | } else if (return_code == REJECTED_INVALID_TOPIC_ID) { 258 | publish_registration.topic_id = 0; 259 | } else if (return_code == REJECTED_NOT_SUPPORTED) { 260 | // subscribe only gateway ? 261 | publish_registration.topic_id = 0; 262 | } 263 | this->set_await_message(MQTTSN_PINGREQ); 264 | } 265 | // this is not the druid eh ... message we are waiting for 266 | } 267 | 268 | 269 | message_type get_await_message() { 270 | return this->await_msg_type; 271 | } 272 | 273 | void set_mqttsn_connected() { 274 | this->mqttsn_connected = true; 275 | } 276 | 277 | void notify_socket_connected() { 278 | this->socket_disconnected = false; 279 | } 280 | 281 | 282 | void notify_pingresponse_arrived() { 283 | system.set_heartbeat(system.get_heartbeat()); 284 | ping_outstanding = false; 285 | //TODO mention: client observer his timout value and manages connections only by HIS pingreq 286 | // pingrequeest from the gateway to the client do NOT reset this timer 287 | // TODO enhancement: both pingrequests and pingreqsponse reset the timer OR better: 288 | // ALL answers reset the timer 289 | } 290 | 291 | uint16_t increment_and_get_msg_id_counter() { 292 | if (++msg_id_counter == 0) { 293 | msg_id_counter = 1; 294 | } 295 | return msg_id_counter; 296 | } 297 | 298 | uint16_t get_await_message_id() { 299 | return msg_id_counter; 300 | } 301 | 302 | void set_await_topic_id(uint16_t topic_id) { 303 | registration.topic_id = topic_id; 304 | } 305 | 306 | void set_granted_qos(int8_t granted_qos) { 307 | registration.granted_qos = (uint8_t) granted_qos; 308 | } 309 | 310 | bool is_mqttsn_connected() { 311 | return mqttsn_connected; 312 | } 313 | 314 | void handle_publish(device_address *address, uint8_t *data, uint16_t data_len, uint16_t topic_id, bool retain, 315 | int8_t qos) { 316 | // call callback :) 317 | if(topic_id == publish_registration.topic_id){ 318 | callback(publish_registration.topic_name, data, data_len, retain); 319 | } 320 | if (topic_id == registration.topic_id && qos == registration.granted_qos) { 321 | callback(registration.topic_name, data, data_len, retain); 322 | } 323 | } 324 | 325 | 326 | }; 327 | 328 | 329 | #endif //ARDUINO_MQTTSN_CLIENT_MQTTSNCLIENT_H 330 | -------------------------------------------------------------------------------- /mqttsn_messages.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (C) 2014 John Donovan heavily edited by Gabriel Nikol 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #ifndef ARDUINO_MQTTSN_CLIENT_MQTTSN_MESSAGES_H 26 | #define ARDUINO_MQTTSN_CLIENT_MQTTSN_MESSAGES_H 27 | 28 | #include "global_defines.h" 29 | #include 30 | 31 | #define PROTOCOL_ID 0x01 32 | 33 | #define FLAG_NO_FLAGS 0x00 34 | #define FLAG_DUP 0x80 35 | #define FLAG_QOS_0 0x00 36 | #define FLAG_QOS_1 0x20 37 | #define FLAG_QOS_2 0x40 38 | #define FLAG_QOS_M1 0x60 39 | #define FLAG_RETAIN 0x10 40 | #define FLAG_WILL 0x08 41 | #define FLAG_CLEAN 0x04 42 | #define FLAG_TOPIC_NAME 0x00 43 | #define FLAG_TOPIC_PREDEFINED_ID 0x01 44 | #define FLAG_TOPIC_SHORT_NAME 0x02 45 | 46 | #define QOS_MASK (FLAG_QOS_0 | FLAG_QOS_1 | FLAG_QOS_2 | FLAG_QOS_M1) 47 | #define TOPIC_MASK (FLAG_TOPIC_NAME | FLAG_TOPIC_PREDEFINED_ID | FLAG_TOPIC_SHORT_NAME) 48 | 49 | // Recommended values for timers and counters. All timers are in seconds. 50 | #define T_ADV 960 51 | #define N_ADV 3 52 | #define T_SEARCH_GW 5 53 | #define T_GW_INFO 5 54 | #define T_WAIT 360 55 | #define T_RETRY 15 56 | #define N_RETRY 5 57 | 58 | enum return_code_t : uint8_t { 59 | ACCEPTED = 0x00, 60 | REJECTED_CONGESTION = 0x01, 61 | REJECTED_INVALID_TOPIC_ID = 0x02, 62 | REJECTED_NOT_SUPPORTED = 0x03 63 | }; 64 | 65 | enum message_type : uint8_t { 66 | MQTTSN_ADVERTISE, 67 | MQTTSN_SEARCHGW, 68 | MQTTSN_GWINFO, 69 | MQTTSN_CONNECT = 0x04, 70 | MQTTSN_CONNACK, 71 | MQTTSN_WILLTOPICREQ, 72 | MQTTSN_WILLTOPIC, 73 | MQTTSN_WILLMSGREQ, 74 | MQTTSN_WILLMSG, 75 | MQTTSN_REGISTER, 76 | MQTTSN_REGACK, 77 | MQTTSN_PUBLISH, 78 | MQTTSN_PUBACK, 79 | MQTTSN_PUBCOMP, 80 | MQTTSN_PUBREC, 81 | MQTTSN_PUBREL, 82 | MQTTSN_SUBSCRIBE = 0x12, 83 | MQTTSN_SUBACK, 84 | MQTTSN_UNSUBSCRIBE, 85 | MQTTSN_UNSUBACK, 86 | MQTTSN_PINGREQ = 0x16, 87 | MQTTSN_PINGRESP, 88 | MQTTSN_DISCONNECT, 89 | MQTTSN_WILLTOPICUPD = 0x1a, 90 | MQTTSN_WILLTOPICRESP, 91 | MQTTSN_WILLMSGUPD, 92 | MQTTSN_WILLMSGRESP 93 | }; 94 | 95 | #ifndef MQTT_SNRF24L01P_NRF24MESSAGES_H 96 | #pragma pack(push, 1) 97 | 98 | struct message_header { 99 | uint8_t length; 100 | uint8_t type; 101 | 102 | void to_pingreq() { 103 | length = 2; 104 | type = MQTTSN_PINGREQ; 105 | } 106 | 107 | void to_disconnect() { 108 | length = 2; 109 | type = MQTTSN_DISCONNECT; 110 | } 111 | }; 112 | 113 | #pragma pack(pop) 114 | #endif 115 | 116 | #pragma pack(push, 1) 117 | 118 | struct msg_advertise : public message_header { 119 | uint8_t gw_id; 120 | uint16_t duration; 121 | 122 | msg_advertise(uint8_t gw_id, uint16_t duration) : gw_id(gw_id), duration(duration) { 123 | length = 5; 124 | type = MQTTSN_ADVERTISE; 125 | } 126 | }; 127 | 128 | #pragma pack(pop) 129 | 130 | struct msg_searchgw : public message_header { 131 | uint8_t radius; 132 | 133 | msg_searchgw(uint8_t radius) : radius(radius) { 134 | length = 3; 135 | type = MQTTSN_SEARCHGW; 136 | } 137 | }; 138 | 139 | struct msg_gwinfo : public message_header { 140 | uint8_t gw_id; 141 | uint8_t gw_address[sizeof(device_address)]; 142 | 143 | msg_gwinfo(uint8_t gw_id, uint8_t *gw_add) : gw_id(gw_id) { 144 | length = sizeof(msg_gwinfo); 145 | type = MQTTSN_GWINFO; 146 | memcpy(gw_address, gw_add, sizeof(device_address)); 147 | } 148 | }; 149 | 150 | struct msg_connect : public message_header { 151 | uint8_t flags; 152 | uint8_t protocol_id; 153 | uint16_t duration; 154 | char client_id[24]; 155 | 156 | msg_connect(bool will, bool clean_session, uint8_t protocol_id, uint16_t duration, const char *client_id) { 157 | 158 | uint8_t client_id_length = (uint8_t) strlen(client_id); 159 | if (client_id_length > 22) { 160 | client_id_length = 23; 161 | } 162 | length = ((uint8_t) (6 + 1)) + client_id_length; 163 | type = MQTTSN_CONNECT; 164 | flags = 0x0; 165 | if (will) { 166 | flags |= FLAG_WILL; 167 | } 168 | if (clean_session) { 169 | flags |= FLAG_CLEAN; 170 | } 171 | this->protocol_id = protocol_id; 172 | this->duration = duration; 173 | memset(this->client_id, 0x0, 24); 174 | memcpy(this->client_id, client_id, client_id_length); 175 | } 176 | 177 | }; 178 | #pragma pack(push, 1) 179 | 180 | struct msg_connack : public message_header { 181 | return_code_t return_code; 182 | 183 | msg_connack(return_code_t return_code) : return_code(return_code) { 184 | length = sizeof(msg_connack); 185 | type = MQTTSN_CONNACK; 186 | } 187 | }; 188 | 189 | #pragma pack(pop) 190 | 191 | 192 | 193 | struct msg_willtopic : public message_header { 194 | uint8_t flags; 195 | char will_topic[252]; 196 | 197 | msg_willtopic(const char *willtopic, int8_t qos, bool retain) { 198 | memset(this, 0, sizeof(this)); 199 | length = 3 + strlen(willtopic) + 1; 200 | type = MQTTSN_WILLTOPIC; 201 | if (retain) { 202 | this->flags |= FLAG_RETAIN; 203 | } 204 | if (qos == 0) { 205 | this->flags |= FLAG_QOS_0; 206 | } else if (qos == 1) { 207 | this->flags |= FLAG_QOS_1; 208 | } else if (qos == 2) { 209 | this->flags |= FLAG_QOS_2; 210 | } 211 | } 212 | }; 213 | 214 | struct msg_willmsg : public message_header { 215 | uint8_t willmsg[253]; 216 | 217 | msg_willmsg(const uint8_t *s_data, uint8_t s_data_len) { 218 | memset(this, 0, sizeof(this)); 219 | this->length = ((uint8_t) 2) + s_data_len; 220 | memcpy(&willmsg, s_data, s_data_len); 221 | } 222 | }; 223 | 224 | /* 225 | struct msg_willtopicreq : public message_header { 226 | msg_willtopicreq(){ 227 | length = 2; 228 | type = MQTTSN_WILLTOPICREQ; 229 | } 230 | }; 231 | 232 | struct msg_willmsgreq : public message_header { 233 | msg_willmsgreq(){ 234 | length = 2; 235 | type = MQTTSN_WILLMSGREQ; 236 | } 237 | }; 238 | */ 239 | #pragma pack(push, 1) 240 | 241 | struct msg_register : public message_header { 242 | uint16_t topic_id; 243 | uint16_t message_id; 244 | char topic_name[UINT8_MAX - 6]; 245 | 246 | msg_register(uint16_t topic_id, uint16_t message_id, const char *topic_name) : 247 | topic_id(topic_id), message_id(message_id) { 248 | length = (uint8_t) (6 + strlen(topic_name) + 1); 249 | type = MQTTSN_REGISTER; 250 | strcpy(this->topic_name, topic_name); 251 | //memcpy(this->topic_name, topic_name, strlen(topic_name) + 1); 252 | } 253 | }; 254 | 255 | #pragma pack(pop) 256 | 257 | #pragma pack(push, 1) 258 | 259 | struct msg_regack : public message_header { 260 | uint16_t topic_id; 261 | uint16_t message_id; 262 | return_code_t return_code; 263 | 264 | msg_regack(uint16_t topic_id, uint16_t message_id, return_code_t return_code) : 265 | topic_id(topic_id), message_id(message_id), return_code(return_code) { 266 | length = 7; 267 | type = MQTTSN_REGACK; 268 | } 269 | }; 270 | #pragma pack(pop) 271 | 272 | #pragma pack(push, 1) 273 | 274 | struct msg_publish : public message_header { 275 | uint8_t flags; 276 | uint16_t topic_id; 277 | uint16_t message_id; 278 | uint8_t data[UINT8_MAX - 7]; 279 | 280 | msg_publish(bool dup, int8_t qos, bool retain, bool short_topic, uint16_t topic_id, uint16_t msg_id, 281 | const uint8_t *s_data, uint8_t s_data_len) : topic_id(topic_id), message_id(msg_id) { 282 | memset(this, 0, sizeof(this)); 283 | this->length = ((uint8_t) 7) + s_data_len; 284 | this->type = MQTTSN_PUBLISH; 285 | this->flags = 0x0; 286 | if (dup) { 287 | this->flags |= FLAG_DUP; 288 | } 289 | if (retain) { 290 | this->flags |= FLAG_RETAIN; 291 | } 292 | if (short_topic) { 293 | this->flags |= FLAG_TOPIC_SHORT_NAME; 294 | } else { 295 | this->flags |= FLAG_TOPIC_PREDEFINED_ID; 296 | } 297 | if (qos == 0) { 298 | this->flags |= FLAG_QOS_0; 299 | } else if (qos == 1) { 300 | this->flags |= FLAG_QOS_1; 301 | } else if (qos == 2) { 302 | this->flags |= FLAG_QOS_2; 303 | } else if (qos == -1) { 304 | this->flags |= FLAG_QOS_M1; 305 | } 306 | this->topic_id = topic_id; 307 | this->message_id = msg_id; 308 | memcpy(this->data, s_data, s_data_len); 309 | } 310 | }; 311 | 312 | #pragma pack(pop) 313 | 314 | struct msg_publish_send : public message_header { 315 | uint8_t flags; 316 | uint8_t topic_id_msb; 317 | uint8_t topic_id_lsb; 318 | uint8_t message_id_msb; 319 | uint8_t message_id_lsb; 320 | uint8_t data[0]; 321 | }; 322 | 323 | 324 | struct msg_puback : public message_header { 325 | uint16_t topic_id; 326 | uint16_t message_id; 327 | return_code_t return_code; 328 | 329 | 330 | msg_puback(uint16_t topic_id, uint16_t msg_id, return_code_t return_code) : 331 | topic_id(topic_id), message_id(msg_id), return_code(return_code) { 332 | length = 7; 333 | type = MQTTSN_PUBACK; 334 | } 335 | }; 336 | 337 | 338 | struct msg_pubqos2 : public message_header { 339 | uint16_t message_id; 340 | }; 341 | 342 | struct msg_subscribe : public message_header { 343 | uint8_t flags; 344 | }; 345 | 346 | 347 | struct msg_subscribe_shorttopic : public msg_subscribe { 348 | uint16_t message_id; 349 | uint16_t topic_id; 350 | 351 | msg_subscribe_shorttopic(bool short_topic, uint16_t topic_id, uint16_t msg_id, uint8_t qos, bool dup) { 352 | memset(this, 0, sizeof(this)); 353 | 354 | this->length = 7; 355 | this->type = MQTTSN_SUBSCRIBE; 356 | 357 | if (dup) { 358 | this->flags |= FLAG_DUP; 359 | } 360 | if (short_topic) { 361 | this->flags |= FLAG_TOPIC_SHORT_NAME; 362 | } else { 363 | this->flags |= FLAG_TOPIC_PREDEFINED_ID; 364 | } 365 | 366 | if (qos == 0) { 367 | this->flags |= FLAG_QOS_0; 368 | } else if (qos == 1) { 369 | this->flags |= FLAG_QOS_1; 370 | } else if (qos == 2) { 371 | this->flags |= FLAG_QOS_2; 372 | } 373 | this->message_id = msg_id; 374 | this->topic_id = topic_id; 375 | } 376 | }; 377 | 378 | #pragma pack(push, 1) // exact fit - no padding 379 | 380 | struct msg_subscribe_topicname : public msg_subscribe { 381 | uint16_t message_id; 382 | char topic_name[250]; 383 | 384 | msg_subscribe_topicname(const char *topic_name, uint16_t msg_id, uint8_t qos, bool dup) { 385 | memset(this, 0, sizeof(this)); 386 | this->length = (uint8_t) (5 + strlen(topic_name) + 1); 387 | this->type = MQTTSN_SUBSCRIBE; 388 | if (dup) { 389 | this->flags |= FLAG_DUP; 390 | } 391 | if (qos == 0) { 392 | this->flags |= FLAG_QOS_0; 393 | } else if (qos == 1) { 394 | this->flags |= FLAG_QOS_1; 395 | } else if (qos == 2) { 396 | this->flags |= FLAG_QOS_2; 397 | } 398 | this->message_id = msg_id; 399 | strcpy(this->topic_name, topic_name); 400 | } 401 | }; 402 | 403 | #pragma pack(pop) //back to whatever the previous packing mode was 404 | 405 | #pragma pack(push, 1) 406 | 407 | struct msg_suback : public message_header { 408 | uint8_t flags; 409 | uint16_t topic_id; 410 | uint16_t message_id; 411 | return_code_t return_code; 412 | 413 | msg_suback(uint8_t qos, uint16_t topic_id, uint16_t msg_id, return_code_t return_code) { 414 | memset(this, 0, sizeof(msg_suback)); 415 | length = 8; 416 | type = MQTTSN_SUBACK; 417 | if (qos == 0) { 418 | this->flags |= FLAG_QOS_0; 419 | } else if (qos == 1) { 420 | this->flags |= FLAG_QOS_1; 421 | } else if (qos == 2) { 422 | this->flags |= FLAG_QOS_2; 423 | } 424 | this->topic_id = topic_id; 425 | this->message_id = msg_id; 426 | this->return_code = return_code; 427 | } 428 | }; 429 | #pragma pack(pop) //back to whatever the previous packing mode was 430 | 431 | struct msg_unsubscribe : public message_header { 432 | uint8_t flags; 433 | uint16_t message_id; 434 | union { 435 | char topic_name[0]; 436 | uint16_t topic_id; 437 | }; 438 | }; 439 | 440 | struct msg_unsubscribe_send : public message_header { 441 | uint8_t flags; 442 | uint8_t message_id_msb; 443 | uint8_t message_id_lsb; 444 | uint8_t topic_id_msb; 445 | uint8_t topic_id_lsb; 446 | }; 447 | 448 | 449 | struct msg_unsuback : public message_header { 450 | uint16_t message_id; 451 | 452 | msg_unsuback(uint16_t msg_id) : message_id(msg_id) { 453 | length = 4; 454 | type = MQTTSN_UNSUBACK; 455 | } 456 | }; 457 | 458 | struct msg_pingreq : public message_header { 459 | char client_id[0]; 460 | 461 | void init_msg_pingreq(msg_pingreq *pingreq, const char *client_id) { 462 | uint8_t client_id_length = (uint8_t) strlen(client_id); 463 | if (client_id_length > 22) { 464 | client_id_length = 23; 465 | } 466 | pingreq->length = ((uint8_t) (2 + 1)) + client_id_length; 467 | pingreq->type = MQTTSN_PINGREQ; 468 | memset(pingreq->client_id, 0x0, 24); 469 | memcpy(pingreq->client_id, client_id, client_id_length); 470 | }; 471 | }; 472 | 473 | struct msg_disconnect : public message_header { 474 | uint16_t duration; 475 | }; 476 | 477 | struct msg_willtopicresp : public message_header { 478 | uint8_t return_code; 479 | }; 480 | 481 | struct msg_willmsgresp : public message_header { 482 | uint8_t return_code; 483 | }; 484 | 485 | struct msg_pubrec : public message_header { 486 | uint16_t message_id; 487 | 488 | msg_pubrec(uint16_t msg_id) : message_id(msg_id) { 489 | length = 4; 490 | type = MQTTSN_PUBREC; 491 | } 492 | }; 493 | 494 | struct msg_pubrel : public message_header { 495 | uint16_t message_id; 496 | 497 | msg_pubrel(uint16_t msg_id) : message_id(msg_id) { 498 | length = 4; 499 | type = MQTTSN_PUBREL; 500 | } 501 | }; 502 | 503 | struct msg_pubcomp : public message_header { 504 | uint16_t message_id; 505 | 506 | msg_pubcomp(uint16_t msg_id) : message_id(msg_id) { 507 | length = 4; 508 | type = MQTTSN_PUBCOMP; 509 | } 510 | }; 511 | 512 | 513 | #endif //ARDUINO_MQTTSN_CLIENT_MQTTSN_MESSAGES_H 514 | -------------------------------------------------------------------------------- /TransmissionProtocolUartBridge.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (C) 2018 Copyright Gabriel Nikol 5 | */ 6 | 7 | #ifndef ARDUINO_MQTTSN_CLIENT_TRANSMISSIONPROTOCOLUARTBRDIGE_H 8 | #define ARDUINO_MQTTSN_CLIENT_TRANSMISSIONPROTOCOLUARTBRDIGE_H 9 | 10 | #include "MqttSnMessageHandler.h" 11 | #include "System.h" 12 | #include 13 | #include "global_defines.h" 14 | #include "mqttsn_messages.h" 15 | #include 16 | 17 | 18 | #if defined(ESP8266) 19 | #include 20 | #include 21 | #endif 22 | 23 | #if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_YUN) || defined(ARDUINO_AVR_MEGA2560) 24 | #ifndef LONG_MIN 25 | #define LONG_MIN -2147483647 26 | #endif // LONG_MIN 27 | #ifndef LONG_MAX 28 | #define LONG_MAX 2147483647 29 | #endif // LONG_MAX 30 | #endif 31 | 32 | enum TransmissionProtocolUartBridgeStatus { 33 | STARTING, 34 | IDLE, 35 | SEND, 36 | RECEIVE, 37 | CONFIGURATION, 38 | PARSE_FAILURE, 39 | ERROR 40 | }; 41 | 42 | enum SEND_STATUS { 43 | SEND_NONE, 44 | AWAIT_ADDRESS, 45 | AWAIT_DATA, 46 | SENDING 47 | }; 48 | 49 | enum RECEIVE_STATUS { 50 | RECEIVE_NONE, 51 | SEND_ADDRESS, 52 | SEND_DATA 53 | }; 54 | 55 | enum CONFIGURATION_STATUS { 56 | CONFIGURATION_NONE = 0, 57 | CONFIGURATION_STATUS = 1, 58 | CONFIGURATION_OWN_ADDRESS = 2, 59 | CONFIGURATION_BROADCAST_ADDRESS = 3, 60 | CONFIGURATION_MAXIMUM_MESSAGE_LENGTH = 4, 61 | CONFIGURATION_SERIAL_BUFFER_SIZE = 5 62 | }; 63 | 64 | // #define PARSERDATADEBUG 65 | // #define PARSERADDRESSDEBUG 66 | #define SERIAL_BUFFER_SIZE 200 67 | #define RECEIVE_BUFFER_SIZE 64 68 | #define SEND_BUFFER_SIZE 64 69 | 70 | template 71 | class TransmissionProtocolUartBridge { 72 | private: 73 | // SocketInterface 74 | TransmissionProtocolUartBridge_SocketInterface &socketInterface; 75 | // friend TransmissionProtocolUartBridge_SocketInterface; 76 | 77 | // Status 78 | TransmissionProtocolUartBridgeStatus status = STARTING; 79 | RECEIVE_STATUS receive_status = RECEIVE_NONE; 80 | SEND_STATUS send_status = SEND_NONE; 81 | uint8_t configuration_status = CONFIGURATION_NONE; 82 | 83 | 84 | // StreamBuffer 85 | bool lineReady = false; 86 | char serialBuffer[SERIAL_BUFFER_SIZE]; 87 | uint16_t serialBufferCounter = 0; 88 | 89 | // SendBuffer 90 | device_address destination_address; 91 | uint8_t data[SEND_BUFFER_SIZE]; 92 | uint16_t data_length = 0; 93 | 94 | // ReceiveBuffer 95 | device_address receive_address; 96 | uint8_t receive_buffer[RECEIVE_BUFFER_SIZE]; 97 | uint16_t receive_buffer_length = 0; 98 | Stream *stream; 99 | 100 | public: 101 | explicit TransmissionProtocolUartBridge(Stream *stream, 102 | TransmissionProtocolUartBridge_SocketInterface &socketInterface) : 103 | stream(stream), socketInterface(socketInterface) {} 104 | 105 | bool begin() { 106 | memset(serialBuffer, 0x0, sizeof(serialBuffer)); 107 | socketInterface.setTransmissionProtocolUartBridge(this); 108 | if (!socketInterface.begin()) { 109 | status = ERROR; 110 | return false; 111 | } 112 | status = IDLE; 113 | return true; 114 | } 115 | 116 | /* 117 | * Receive from Stream 118 | */ 119 | void putChar(char c) { 120 | serialBuffer[serialBufferCounter++] = c; 121 | if (c == '\n') { 122 | lineReady = true; 123 | } else if (serialBufferCounter == SERIAL_BUFFER_SIZE) { 124 | status = PARSE_FAILURE; 125 | } 126 | } 127 | 128 | void receiveData(device_address *address, uint8_t *bytes, uint16_t bytes_length) { 129 | reset_received_buffer(); 130 | 131 | memcpy(&receive_address, address, sizeof(device_address)); 132 | receive_buffer_length = bytes_length; 133 | memcpy(receive_buffer, bytes, bytes_length); 134 | /* 135 | if (bytes[0] != bytes_length) { 136 | return; 137 | } 138 | if (receive_buffer_length == 0 && sizeof(receive_buffer) > bytes[0]) { 139 | // buffer empty 140 | // received bytes less or equal to receive_buffer size 141 | reset_received_buffer(); 142 | 143 | memcpy(&receive_address, address, sizeof(device_address)); 144 | receive_buffer_length = bytes[0]; 145 | memcpy(receive_buffer, bytes, receive_buffer_length); 146 | } 147 | */ 148 | } 149 | 150 | bool print_received_address() { 151 | stream->print(F("ADDRESS")); 152 | for (uint16_t i = 0; i < sizeof(device_address); i++) { 153 | stream->print(F(" ")); 154 | stream->print(receive_address.bytes[i], DEC); 155 | } 156 | stream->print(F("\n")); 157 | return true; 158 | } 159 | 160 | bool print_received_data() { 161 | stream->print(F("DATA")); 162 | for (uint16_t i = 0; i < receive_buffer_length; i++) { 163 | stream->print(F(" ")); 164 | stream->print(receive_buffer[i], DEC); 165 | } 166 | stream->print(F("\n")); 167 | return true; 168 | } 169 | 170 | void reset_received_buffer() { 171 | memset(&receive_address, 0x0, sizeof(device_address)); 172 | memset(receive_buffer, 0x0, sizeof(receive_buffer)); 173 | receive_buffer_length = 0; 174 | } 175 | 176 | void notify_socket_disconnected() { 177 | status == ERROR; 178 | } 179 | 180 | void resetChip() { 181 | #if defined(ESP8266) 182 | stream->print(F("OK RESET\n")); 183 | delay(500); 184 | ESP.restart(); 185 | #elif defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_YUN) 186 | stream->print(F("OK RESET\n")); 187 | delay(500); 188 | asm volatile (" jmp 0"); 189 | #else 190 | #warning "resetChip() is not properly implemented. This means we cannot reset the TransmissionProtocolUartBridge." 191 | stream->print(F("ERROR RESET_NOT_SUPPORTED\n")); 192 | #endif 193 | } 194 | 195 | bool loop() { 196 | 197 | if (!socketInterface.loop()) { 198 | return false; 199 | } 200 | 201 | if (lineReady) { 202 | if (isReset(serialBuffer)) { 203 | resetSerialBuffer(); 204 | resetChip(); 205 | } 206 | } 207 | 208 | if (status == STARTING) { 209 | // begin should be already called 210 | stream->print(F("ERROR NOT_STARTED\n")); 211 | return false; 212 | } 213 | 214 | if (status == IDLE && lineReady) { 215 | // parse 216 | if (isSend(serialBuffer)) { 217 | status = SEND; 218 | send_status = SEND_NONE; 219 | resetSerialBuffer(); 220 | } else if (isReceived(serialBuffer)) { 221 | status = RECEIVE; 222 | receive_status = RECEIVE_NONE; 223 | resetSerialBuffer(); 224 | } else if (isConfiguration(serialBuffer)) { 225 | status = CONFIGURATION; 226 | configuration_status = CONFIGURATION_NONE; 227 | resetSerialBuffer(); 228 | } else if (isReset(serialBuffer)) { 229 | resetSerialBuffer(); 230 | resetChip(); 231 | } else { 232 | status = PARSE_FAILURE; 233 | } 234 | } 235 | 236 | 237 | if (status == SEND) { 238 | if (send_status == SEND_NONE) { 239 | stream->print(F("OK AWAIT_ADDRESS\n")); 240 | resetSendBuffer(); 241 | send_status = AWAIT_ADDRESS; 242 | } else if (send_status == AWAIT_ADDRESS && lineReady) { 243 | if (parseAddress(serialBuffer)) { 244 | stream->print(F("OK AWAIT_DATA\n")); 245 | resetSerialBuffer(); 246 | send_status = AWAIT_DATA; 247 | } else { 248 | status = PARSE_FAILURE; 249 | } 250 | } else if (send_status == AWAIT_DATA && lineReady) { 251 | if (parseData(serialBuffer)) { 252 | stream->print(F("OK SENDING\n")); 253 | resetSerialBuffer(); 254 | send_status = SENDING; 255 | } else { 256 | status = PARSE_FAILURE; 257 | } 258 | } else if (send_status == SENDING) { 259 | if (sendDataToAddress()) { 260 | stream->print(F("OK IDLE\n")); 261 | resetSendBuffer(); 262 | send_status = SEND_NONE; 263 | status = IDLE; 264 | } else { 265 | status = ERROR; 266 | } 267 | } 268 | } 269 | 270 | if (status == RECEIVE) { 271 | if (receive_status == RECEIVE_NONE) { 272 | stream->print(F("OK SEND_ADDRESS\n")); 273 | receive_status = SEND_ADDRESS; 274 | } else if (receive_status == SEND_ADDRESS) { 275 | if (send_receive_address()) { 276 | stream->print(F("OK SEND_DATA\n")); 277 | receive_status = SEND_DATA; 278 | } else { 279 | status = ERROR; 280 | } 281 | } else if (receive_status == SEND_DATA) { 282 | if (send_receive_data()) { 283 | stream->print(F("OK IDLE\n")); 284 | resetReceiveBuffer(); 285 | receive_status = RECEIVE_NONE; 286 | status = IDLE; 287 | } else { 288 | status = ERROR; 289 | } 290 | } 291 | } 292 | 293 | if (status == CONFIGURATION) { 294 | if (configuration_status == CONFIGURATION_NONE) { 295 | stream->print(F("OK SEND_STATUS\n")); 296 | configuration_status = CONFIGURATION_STATUS; 297 | } else if (configuration_status == CONFIGURATION_STATUS) { 298 | if (printStatus()) { 299 | stream->print(F("OK SEND_OWN_ADDRESS\n")); 300 | configuration_status = CONFIGURATION_OWN_ADDRESS; 301 | } else { 302 | status = ERROR; 303 | } 304 | } else if (configuration_status == CONFIGURATION_OWN_ADDRESS) { 305 | if (printOwnAddress()) { 306 | stream->print(F("OK SEND_BROADCAST_ADDRESS\n")); 307 | configuration_status = CONFIGURATION_BROADCAST_ADDRESS; 308 | } else { 309 | status = ERROR; 310 | } 311 | } else if (configuration_status == CONFIGURATION_BROADCAST_ADDRESS) { 312 | if (printBroadcastAddress()) { 313 | stream->print(F("OK SEND_MAXIMUM_MESSAGE_LENGTH\n")); 314 | configuration_status = CONFIGURATION_MAXIMUM_MESSAGE_LENGTH; 315 | } else { 316 | status = ERROR; 317 | } 318 | } else if (configuration_status == CONFIGURATION_MAXIMUM_MESSAGE_LENGTH) { 319 | if (printMaximumMessageLength()) { 320 | stream->print(F("OK SEND_SERIAL_BUFFER_SIZE\n")); 321 | configuration_status = CONFIGURATION_SERIAL_BUFFER_SIZE; 322 | } else { 323 | status = ERROR; 324 | } 325 | } else if (configuration_status == CONFIGURATION_SERIAL_BUFFER_SIZE) { 326 | if (printSerialBufferSize()) { 327 | stream->print(F("OK IDLE\n")); 328 | configuration_status = CONFIGURATION_NONE; 329 | status = IDLE; 330 | } else { 331 | status = ERROR; 332 | } 333 | } 334 | } 335 | 336 | if (status == PARSE_FAILURE) { 337 | stream->print(F("FAILURE PARSE_FAILURE\n")); 338 | resetSerialBuffer(); 339 | receive_status = RECEIVE_NONE; 340 | send_status = SEND_NONE; 341 | status = IDLE; 342 | } 343 | /* 344 | if (status == FAILURE) { 345 | stream->print(F("FAILURE\n")); 346 | resetSerialBuffer(); 347 | receive_status = RECEIVE_NONE; 348 | send_status = SEND_NONE; 349 | status = STARTING; 350 | } 351 | */ 352 | if (status == ERROR) { 353 | stream->print(F("ERROR\n")); 354 | resetSerialBuffer(); 355 | resetChip(); 356 | } 357 | 358 | } 359 | 360 | bool printStatus() { 361 | stream->print(F("STATUS")); 362 | stream->print(F(" ")); 363 | if (status == STARTING) { 364 | stream->print(F("STARTING")); 365 | } else if (status == IDLE) { 366 | stream->print(F("IDLE")); 367 | } else if (status == SEND) { 368 | stream->print(F("SEND")); 369 | } else if (status == CONFIGURATION) { 370 | stream->print(F("CONFIGURATION")); 371 | } else if (status == PARSE_FAILURE) { 372 | stream->print(F("PARSE_FAILURE")); 373 | } else if (status == ERROR) { 374 | stream->print(F("ERROR")); 375 | } else { 376 | stream->print(F("\n")); 377 | return false; 378 | } 379 | stream->print(F("\n")); 380 | return true; 381 | } 382 | 383 | bool printOwnAddress() { 384 | stream->print(F("OWN_ADDRESS")); 385 | device_address *address = socketInterface.getAddress(); 386 | if (address != nullptr) { 387 | for (uint16_t i = 0; i < sizeof(device_address); i++) { 388 | stream->print(F(" ")); 389 | stream->print(address->bytes[i], DEC); 390 | } 391 | } else { 392 | stream->print(F(" ")); 393 | stream->print(F("N/A")); 394 | } 395 | stream->print(F("\n")); 396 | return true; 397 | } 398 | 399 | bool printBroadcastAddress() { 400 | stream->print(F("BROADCAST_ADDRESS")); 401 | device_address *address = socketInterface.getBroadcastAddress(); 402 | if (address != nullptr) { 403 | for (uint16_t i = 0; i < sizeof(device_address); i++) { 404 | stream->print(F(" ")); 405 | stream->print(address->bytes[i], DEC); 406 | } 407 | } else { 408 | stream->print(F(" ")); 409 | stream->print(F("N/A")); 410 | } 411 | stream->print(F("\n")); 412 | return true; 413 | } 414 | 415 | bool printMaximumMessageLength() { 416 | stream->print(F("MAXIMUM_MESSAGE_LENGTH")); 417 | stream->print(F(" ")); 418 | uint8_t maximumMessageLength = socketInterface.getMaximumMessageLength(); 419 | stream->print(maximumMessageLength, DEC); 420 | stream->print(F("\n")); 421 | return true; 422 | } 423 | 424 | bool printSerialBufferSize() { 425 | stream->print(F("SERIAL_BUFFER_SIZE")); 426 | stream->print(F(" ")); 427 | stream->print(SERIAL_BUFFER_SIZE, DEC); 428 | stream->print(F("\n")); 429 | return true; 430 | } 431 | 432 | 433 | void printSerialBuffer() { 434 | if (lineReady) { 435 | for (uint16_t i = 0; i < serialBufferCounter; i++) { 436 | stream->print(serialBuffer[i]); 437 | } 438 | } else { 439 | stream->print(F("lineNotReady")); 440 | } 441 | } 442 | 443 | bool isReset(char *buffer) { 444 | /* 445 | char *token = strsep(&buffer, " "); 446 | if (token == NULL) { 447 | return false; 448 | } 449 | */ 450 | return strncmp(buffer, "RESET", strlen("RESET")) == 0; 451 | //return memcmp(token, "RESET", strlen("RESET")) == 0; 452 | } 453 | 454 | void resetReceiveBuffer() { 455 | reset_received_buffer(); 456 | } 457 | 458 | bool send_error() { 459 | stream->print(F("ERROR\n")); 460 | return true; 461 | } 462 | 463 | bool send_receive_data() { 464 | return print_received_data(); 465 | } 466 | 467 | bool send_receive_address() { 468 | return print_received_address(); 469 | } 470 | 471 | void resetSerialBuffer() { 472 | memset(serialBuffer, 0x0, sizeof(serialBuffer)); 473 | serialBufferCounter = 0; 474 | lineReady = false; 475 | } 476 | 477 | void resetSendBuffer() { 478 | memset(&destination_address, 0x0, sizeof(device_address)); 479 | memset(data, 0x0, sizeof(data)); 480 | data_length = 0; 481 | } 482 | 483 | bool sendDataToAddress() { 484 | return socketInterface.send(&destination_address, (uint8_t * ) & data, data_length); 485 | } 486 | 487 | bool parseData(char *buffer) { 488 | #if defined(PARSERDATADEBUG) 489 | stream->print(F("parseData\n")); 490 | #endif 491 | char *token = strsep(&buffer, " "); 492 | if (token == NULL) { 493 | #if defined(PARSERDATADEBUG) 494 | stream->print(F("token NULL\n")); 495 | #endif 496 | return false; 497 | } 498 | if (memcmp(token, "DATA", strlen("DATA")) != 0) { 499 | #if defined(PARSERDATADEBUG) 500 | stream->print(F("does not start with DATA\n")); 501 | #endif 502 | return false; 503 | } 504 | 505 | memset(data, 0x0, sizeof(data)); 506 | data_length = 0; 507 | 508 | while ((token = strsep(&buffer, " ")) != NULL) { 509 | long int number = 0; 510 | if (!parseLong(token, &number)) { 511 | #if defined(PARSERDATADEBUG) 512 | stream->print(F("failure parsing parseLong\n")); 513 | #endif 514 | return false; 515 | } 516 | if (number > UINT8_MAX || number < 0) { 517 | #if defined(PARSERDATADEBUG) 518 | stream->print(F("number out of range\n")); 519 | #endif 520 | return false; 521 | } 522 | #if defined(PARSERDATADEBUG) 523 | stream->print(number, DEC); 524 | stream->print(F("\n")); 525 | #endif 526 | data[data_length++] = (uint8_t) number; 527 | } 528 | return true; 529 | } 530 | 531 | bool parseAddress(char *buffer) { 532 | #if defined(PARSERADDRESSDEBUG) 533 | stream->print(F("parseAddress\n")); 534 | #endif 535 | char *token = strsep(&buffer, " "); 536 | if (token == NULL) { 537 | #if defined(PARSERADDRESSDEBUG) 538 | stream->print(F("token NULL\n")); 539 | #endif 540 | return false; 541 | } 542 | if (memcmp(token, "ADDRESS", strlen("ADDRESS")) != 0) { 543 | #if defined(PARSERADDRESSDEBUG) 544 | stream->print(F("does not start with ADDRESS\n")); 545 | #endif 546 | return false; 547 | } 548 | 549 | memset(&destination_address, 0x0, sizeof(device_address)); 550 | uint16_t destination_address_length = 0; 551 | 552 | while ((token = strsep(&buffer, " ")) != NULL) { 553 | long int number = 0; 554 | if (!parseLong(token, &number)) { 555 | #if defined(PARSERADDRESSDEBUG) 556 | stream->print(F("failure parsing parseLong\n")); 557 | #endif 558 | return false; 559 | } 560 | #if defined(PARSERADDRESSDEBUG) 561 | stream->print(number, DEC); 562 | stream->print(F("\n")); 563 | #endif 564 | if (number > UINT8_MAX || number < 0) { 565 | #if defined(PARSERADDRESSDEBUG) 566 | stream->print(F("number out of bounds: ")); 567 | stream->print(number, DEC); 568 | stream->print(F("\n")); 569 | #endif 570 | return false; 571 | } 572 | if (destination_address_length + 1 > sizeof(device_address)) { 573 | #if defined(PARSERADDRESSDEBUG) 574 | stream->print(F("address size too long")); 575 | #endif 576 | return false; 577 | } 578 | destination_address.bytes[destination_address_length++] = (uint8_t) number; 579 | } 580 | #if defined(PARSERADDRESSDEBUG) 581 | if (destination_address_length != sizeof(device_address)) { 582 | stream->print(F("destination_address_length unequal device_address length")); 583 | } 584 | #endif 585 | return destination_address_length == sizeof(device_address); 586 | } 587 | 588 | bool isReceived(char *buffer) { 589 | char *token = strsep(&buffer, " "); 590 | if (token == NULL) { 591 | return false; 592 | } 593 | return memcmp(token, "RECEIVE", strlen("RECEIVE")) == 0; 594 | } 595 | 596 | bool isSend(char *buffer) { 597 | char *token = strsep(&buffer, " "); 598 | if (token == NULL) { 599 | return false; 600 | } 601 | return memcmp(token, "SEND", strlen("SEND")) == 0; 602 | } 603 | 604 | bool isConfiguration(char *buffer) { 605 | char *token = strsep(&buffer, " "); 606 | if (token == NULL) { 607 | return false; 608 | } 609 | return memcmp(token, "CONFIGURATION", strlen("CONFIGURATION")) == 0; 610 | } 611 | 612 | 613 | bool parseLong(const char *str, long *val) { 614 | char *temp; 615 | bool rc = true; 616 | #if defined(ESP8266) 617 | errno = 0; 618 | #endif 619 | *val = strtol(str, &temp, 0); 620 | 621 | if (temp == str || (*temp != '\0' && *temp != '\n' && *temp != '\r') || 622 | #if defined(ESP8266) 623 | ((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE)) 624 | #else 625 | // see: strtol() function return values 626 | ((*val == LONG_MIN || *val == LONG_MAX) && true)) 627 | #endif 628 | { 629 | rc = false; 630 | } 631 | return rc; 632 | } 633 | 634 | 635 | }; 636 | 637 | 638 | #endif //ARDUINO_MQTTSN_CLIENT_TRANSMISSIONPROTOCOLUARTBRDIGE_H 639 | 640 | --------------------------------------------------------------------------------