From e0f54a37cd529fd3271ebd4247a27c7ececad734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Danyi?= Date: Thu, 15 Feb 2018 18:48:07 +0100 Subject: [PATCH] * updated from upstream * forced connection attempt is now hardcoded in Sodaq_nbIOT::connectSocket() * udp send recieve now works, may contain bugs on fast multiple incoming messages, have to check if this can be an issue or not --- examples/nbIOT_GPS/nbIOT_GPS.ino | 147 +++++++ .../nbIOT_Humidity_Temperature.ino | 81 ++++ ...IOT_Humidity_Temperature_AllThingsTalk.ino | 136 ++++++ .../nbIOT_Pressure_Temperature.ino | 71 ++++ .../nbIOT_Shield_AllThingsTalk.ino | 255 ++++++++++++ .../nbIOT_serial_passthrough.ino | 86 ++++ examples/nbIOT_test/nbIOT_test.ino | 94 +++-- src/Sodaq_AT_Device.cpp | 2 +- src/Sodaq_nbIOT.cpp | 392 ++++++++++-------- src/Sodaq_nbIOT.h | 11 +- 10 files changed, 1077 insertions(+), 198 deletions(-) create mode 100644 examples/nbIOT_GPS/nbIOT_GPS.ino create mode 100644 examples/nbIOT_Humidity_Temperature/nbIOT_Humidity_Temperature.ino create mode 100644 examples/nbIOT_Humidity_Temperature_AllThingsTalk/nbIOT_Humidity_Temperature_AllThingsTalk.ino create mode 100644 examples/nbIOT_Pressure_Temperature/nbIOT_Pressure_Temperature.ino create mode 100644 examples/nbIOT_Shield_AllThingsTalk/nbIOT_Shield_AllThingsTalk.ino create mode 100644 examples/nbIOT_serial_passthrough/nbIOT_serial_passthrough.ino diff --git a/examples/nbIOT_GPS/nbIOT_GPS.ino b/examples/nbIOT_GPS/nbIOT_GPS.ino new file mode 100644 index 0000000..7b4d208 --- /dev/null +++ b/examples/nbIOT_GPS/nbIOT_GPS.ino @@ -0,0 +1,147 @@ +#include +#include +#include + +#if defined(ARDUINO_AVR_LEONARDO) +#define DEBUG_STREAM Serial +#define MODEM_STREAM Serial1 + +#elif defined(ARDUINO_SODAQ_EXPLORER) +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial + +#elif defined(ARDUINO_SAM_ZERO) +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial1 + +#else +#error "Please select one of the listed boards." +#endif + +#define ARRAY_DIM(arr) (sizeof(arr) / sizeof(arr[0])) + +Sodaq_nbIOT nbiot; + +// List of interval values to be used in loop() +// to measure how long it takes to get a fix. +uint32_t intervals[] = { + + // Do a few tests with 1 minute delay + 1UL * 60 * 1000, + 1UL * 60 * 1000, + 1UL * 60 * 1000, + + // Try a few longer delays + 2UL * 60 * 1000, + 2UL * 60 * 1000, + 5UL * 60 * 1000, + 5UL * 60 * 1000, + + // Slowly increase the delays + 15UL * 60 * 1000, + 30UL * 60 * 1000, + 1UL * 60 * 60 * 1000, + 3UL * 60 * 60 * 1000, + 4UL * 60 * 60 * 1000, + 8UL * 60 * 60 * 1000, +}; +size_t interval_ix = 0; + +void find_fix(uint32_t delay_until); +void do_flash_led(int pin); + +void setup() +{ + while ((!DEBUG_STREAM) && (millis() < 10000)) { + // Wait for serial monitor for 10 seconds + } + + DEBUG_STREAM.begin(57600); + MODEM_STREAM.begin(nbiot.getDefaultBaudrate()); + + nbiot.init(MODEM_STREAM, 7); + nbiot.setDiag(DEBUG_STREAM); + + if (nbiot.connect("oceanconnect.t-mobile.nl", "172.16.14.22", "20416")) { + DEBUG_STREAM.println("Connected succesfully!"); + } + else { + DEBUG_STREAM.println("Failed to connect!"); + return; + } + + digitalWrite(13, HIGH); + pinMode(13, OUTPUT); + //digitalWrite(LED_GREEN, HIGH); + //pinMode(LED_GREEN, OUTPUT); + //digitalWrite(LED_BLUE, HIGH); + //pinMode(LED_BLUE, OUTPUT); + + do_flash_led(13); + //do_flash_led(LED_GREEN); + //do_flash_led(LED_BLUE); + + DEBUG_STREAM.println("SODAQ NB-IoT SAM-M8Q test is starting ..."); + + sodaq_gps.init(6); + + // This is for debugging to see more details, more messages + // Use this in combination with setDiag() + //sodaq_gps.setMinNumOfLines(10); + + // Uncomment the next line if you want to see the incoming $GPxxx messages + sodaq_gps.setDiag(DEBUG_STREAM); + + // First time finding a fix + find_fix(0); +} + +void loop() +{ + uint32_t wait_ms = intervals[interval_ix]; + if (++interval_ix > ARRAY_DIM(intervals)) { + interval_ix = 0; + } + find_fix(wait_ms); +} + +/*! + * Find a GPS fix, but first wait a while + */ +void find_fix(uint32_t delay_until) +{ + DEBUG_STREAM.println(String("delay ... ") + delay_until + String("ms")); + delay(delay_until); + + uint32_t start = millis(); + uint32_t timeout = 900L * 1000; + DEBUG_STREAM.println(String("waiting for fix ..., timeout=") + timeout + String("ms")); + if (sodaq_gps.scan(false, timeout)) { + String message = ""; + message += (String(" time to find fix: ") + (millis() - start) + String("ms")); + message += (String(" datetime = ") + sodaq_gps.getDateTimeString()); + message += (String(" lat = ") + String(sodaq_gps.getLat(), 7)); + message += (String(" lon = ") + String(sodaq_gps.getLon(), 7)); + message += (String(" num sats = ") + String(sodaq_gps.getNumberOfSatellites())); + + if (!nbiot.sendMessage(message)) { + DEBUG_STREAM.println("Could not queue message!"); + } + } + else { + DEBUG_STREAM.println("No Fix"); + if (!nbiot.sendMessage("No Fix")) { + DEBUG_STREAM.println("Could not queue message!"); + } + } +} + +void do_flash_led(int pin) +{ + for (size_t i = 0; i < 2; ++i) { + delay(100); + digitalWrite(pin, LOW); + delay(100); + digitalWrite(pin, HIGH); + } +} \ No newline at end of file diff --git a/examples/nbIOT_Humidity_Temperature/nbIOT_Humidity_Temperature.ino b/examples/nbIOT_Humidity_Temperature/nbIOT_Humidity_Temperature.ino new file mode 100644 index 0000000..476b657 --- /dev/null +++ b/examples/nbIOT_Humidity_Temperature/nbIOT_Humidity_Temperature.ino @@ -0,0 +1,81 @@ +#include +#include +// #include // Uno +#include +#include + +#if defined(ARDUINO_AVR_LEONARDO) +#define DEBUG_STREAM Serial +#define MODEM_STREAM Serial1 + +#elif defined(ARDUINO_AVR_UNO) +SoftwareSerial softSerial(10, 11); // RX, TX +// You can connect an uartsbee or other board (e.g. 2nd Uno) to connect the softserial. +#define DEBUG_STREAM softSerial +#define MODEM_STREAM Serial + +#elif defined(ARDUINO_SODAQ_EXPLORER) +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial + +#elif defined(ARDUINO_SAM_ZERO) +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial1 + +#else +#error "Please select one of the listed boards." +#endif + +Sodaq_nbIOT nbiot; +Sodaq_HTS221 humiditySensor; + +void setup() +{ + while ((!DEBUG_STREAM) && (millis() < 10000)) { + // Wait for serial monitor for 10 seconds + } + + Wire.begin(); + + DEBUG_STREAM.begin(9600); + MODEM_STREAM.begin(nbiot.getDefaultBaudrate()); + + DEBUG_STREAM.println("\r\nSODAQ Humidity and Temperature Example\r\n"); + + nbiot.init(MODEM_STREAM, 7); + nbiot.setDiag(DEBUG_STREAM); + + delay(2000); + + if (nbiot.connect("oceanconnect.t-mobile.nl", "172.16.14.22", "20416")) { + DEBUG_STREAM.println("Connected succesfully!"); + } + else { + DEBUG_STREAM.println("Failed to connect!"); + } + + if (humiditySensor.init()) { + DEBUG_STREAM.println("Temperature + humidity sensor initialized."); + humiditySensor.enableSensor(); + } + else { + DEBUG_STREAM.println("Temperature + humidity initialization failed!"); + } +} + + +void loop() +{ + // Create the message + String message = String(humiditySensor.readTemperature()) + "C" + + ", " + String(humiditySensor.readHumidity()) + "%"; + + // Print the message we want to send + DEBUG_STREAM.println(message); + + // Send the message + nbiot.sendMessage(message); + + // Wait some time between messages + delay(10000); // 1000 = 1 sec +} diff --git a/examples/nbIOT_Humidity_Temperature_AllThingsTalk/nbIOT_Humidity_Temperature_AllThingsTalk.ino b/examples/nbIOT_Humidity_Temperature_AllThingsTalk/nbIOT_Humidity_Temperature_AllThingsTalk.ino new file mode 100644 index 0000000..c104806 --- /dev/null +++ b/examples/nbIOT_Humidity_Temperature_AllThingsTalk/nbIOT_Humidity_Temperature_AllThingsTalk.ino @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include +#if defined(ARDUINO_AVR_UNO) +#include // Uno +#endif + +#if defined(ARDUINO_AVR_LEONARDO) +#define DEBUG_STREAM Serial +#define MODEM_STREAM Serial1 + +#elif defined(ARDUINO_AVR_UNO) +SoftwareSerial softSerial(10, 11); // RX, TX +// You can connect an uartsbee or other board (e.g. 2nd Uno) to connect the softserial. +#define DEBUG_STREAM softSerial +#define MODEM_STREAM Serial + +#elif defined(ARDUINO_SODAQ_EXPLORER) +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial + +#elif defined(ARDUINO_SAM_ZERO) +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial1 + +#else +#error "Please select a Sodaq ExpLoRer, Arduino Leonardo or add your board." +#endif + +Sodaq_nbIOT nbiot; +Sodaq_HTS221 humiditySensor; + +void setup() +{ + while ((!DEBUG_STREAM) && (millis() < 10000)) { + // Wait for serial monitor for 10 seconds + } + + Wire.begin(); + + DEBUG_STREAM.begin(9600); + MODEM_STREAM.begin(nbiot.getDefaultBaudrate()); + + DEBUG_STREAM.println("\r\nSODAQ Temperature and Humidity AllThingsTalk Example\r\n"); + + nbiot.init(MODEM_STREAM, 7); + nbiot.setDiag(DEBUG_STREAM); + + delay(2000); + + if (nbiot.connect("oceanconnect.t-mobile.nl", "172.16.14.22", "20416")) { + DEBUG_STREAM.println("Connected succesfully!"); + } + else { + DEBUG_STREAM.println("Failed to connect!"); + return; + } + + if (humiditySensor.init()) { + DEBUG_STREAM.println("Temperature + humidity sensor initialized."); + humiditySensor.enableSensor(); + } + else { + DEBUG_STREAM.println("Temperature + humidity initialization failed!"); + } +} + + +void loop() +{ + // Create the message + byte message[8]; + uint16_t cursor = 0; + int16_t temperature; + int16_t humidity; + + temperature = humiditySensor.readTemperature() * 100; + DEBUG_STREAM.println(temperature); + message[cursor++] = temperature >> 8; + message[cursor++] = temperature; + + humidity = humiditySensor.readHumidity() * 100; + DEBUG_STREAM.println(humidity); + message[cursor++] = humidity >> 8; + message[cursor++] = humidity; + + // Print the message we want to send + // DEBUG_STREAM.println(message); + for (int i = 0; i < cursor; i++) { + if (message[i] < 10) { + DEBUG_STREAM.print("0"); + } + DEBUG_STREAM.print(message[i], HEX); + DEBUG_STREAM.print(":"); + } + DEBUG_STREAM.println(); + + // Send the message + nbiot.sendMessage(message, cursor); + + // Wait some time between messages + delay(10000); // 1000 = 1 sec +} + +/***** +* ATT Settings +* +* create a new asset as Number +* +* device decoding: + +{ +"sense": [ +{ +"asset": "temperature", +"value" : { +"byte": 0, +"bytelength" : 2, +"type" : "integer", +"calculation" : "val / 100" +} +}, +{ +"asset": "humidity", +"value" : { +"byte": 2, +"bytelength" : 2, +"type" : "integer", +"calculation" : "val / 100" +} +} +] +} +*/ \ No newline at end of file diff --git a/examples/nbIOT_Pressure_Temperature/nbIOT_Pressure_Temperature.ino b/examples/nbIOT_Pressure_Temperature/nbIOT_Pressure_Temperature.ino new file mode 100644 index 0000000..778c06b --- /dev/null +++ b/examples/nbIOT_Pressure_Temperature/nbIOT_Pressure_Temperature.ino @@ -0,0 +1,71 @@ +#include +#include +#include + +#if defined(ARDUINO_AVR_LEONARDO) +#define DEBUG_STREAM Serial +#define MODEM_STREAM Serial1 + +#elif defined(ARDUINO_SODAQ_EXPLORER) +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial + +#elif defined(ARDUINO_SAM_ZERO) +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial1 + +#else +#error "Please select one of the listed boards." +#endif + +Sodaq_nbIOT nbiot; +Sodaq_LPS22HB barometricSensor; + +void setup() +{ + while ((!DEBUG_STREAM) && (millis() < 10000)) { + // Wait for serial monitor for 10 seconds + } + + Wire.begin(); + + DEBUG_STREAM.begin(9600); + MODEM_STREAM.begin(nbiot.getDefaultBaudrate()); + + DEBUG_STREAM.println("\r\nSODAQ LPS22HB Arduino Example\r\n"); + + nbiot.init(MODEM_STREAM, 7); + nbiot.setDiag(DEBUG_STREAM); + + if (nbiot.connect("oceanconnect.t-mobile.nl", "172.16.14.22", "20416")) { + DEBUG_STREAM.println("Connected succesfully!"); + } + else { + DEBUG_STREAM.println("Failed to connect!"); + } + + if (barometricSensor.init()) { + DEBUG_STREAM.println("Barometric sensor initialization succeeded!"); + barometricSensor.enableSensor(Sodaq_LPS22HB::OdrOneShot); + } + else { + DEBUG_STREAM.println("Barometric sensor initialization failed!"); + } + + DEBUG_STREAM.println("Done with setup!"); +} + +void loop() +{ + // Create the message + String message = String(barometricSensor.readPressureHPA()) + " mbar"; + + // Print the message we want to send + DEBUG_STREAM.println(message); + + // Send the message + nbiot.sendMessage(message); + + // Wait some time between messages + delay(10000); // 1000 = 1 sec +} diff --git a/examples/nbIOT_Shield_AllThingsTalk/nbIOT_Shield_AllThingsTalk.ino b/examples/nbIOT_Shield_AllThingsTalk/nbIOT_Shield_AllThingsTalk.ino new file mode 100644 index 0000000..ebcc7c7 --- /dev/null +++ b/examples/nbIOT_Shield_AllThingsTalk/nbIOT_Shield_AllThingsTalk.ino @@ -0,0 +1,255 @@ +#include +#include +#include +#include +#include +#include +#if defined(ARDUINO_AVR_UNO) +#include // Uno +#endif + +#if defined(ARDUINO_AVR_LEONARDO) +#define DEBUG_STREAM Serial +#define MODEM_STREAM Serial1 + +#elif defined(ARDUINO_AVR_UNO) +SoftwareSerial softSerial(10, 11); // RX, TX +// You can connect an uartsbee or other board (e.g. 2nd Uno) to connect the softserial. +#define DEBUG_STREAM softSerial +#define MODEM_STREAM Serial + +#elif defined(ARDUINO_SODAQ_EXPLORER) +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial + +#elif defined(ARDUINO_SAM_ZERO) +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial1 + +#else +#error "Please select one of the listed boards." +#endif + +Sodaq_nbIOT nbiot; +Sodaq_HTS221 humiditySensor; +Sodaq_LPS22HB barometricSensor; + +uint32_t lat = 0; +uint32_t lon = 0; + +void setup(); +bool connectToNetwork(); +void initHumidityTemperature(); +void initPressureSensor(); +void initGPS(); +void loop(); +void do_flash_led(int pin); + +void setup() +{ + pinMode(13, OUTPUT); + digitalWrite(13, LOW); + + while ((!DEBUG_STREAM) && (millis() < 10000)) { + // Wait for serial monitor for 10 seconds + } + + DEBUG_STREAM.begin(9600); + MODEM_STREAM.begin(nbiot.getDefaultBaudrate()); + + DEBUG_STREAM.println("\r\nSODAQ NB-IoT Shield AllThingsTalk Example\r\n"); + + Wire.begin(); + + nbiot.init(MODEM_STREAM, 7); + nbiot.setDiag(DEBUG_STREAM); + + delay(2000); + + while (!connectToNetwork()); + + initHumidityTemperature(); + initPressureSensor(); + initGPS(); + + digitalWrite(13, LOW); +} + +bool connectToNetwork() { + if (nbiot.connect("oceanconnect.t-mobile.nl", "172.16.14.22", "20416")) { + DEBUG_STREAM.println("Connected succesfully!"); + return true; + } + else { + DEBUG_STREAM.println("Failed to connect!"); + delay(2000); + return false; + } +} + +void initHumidityTemperature() { + if (humiditySensor.init()) { + DEBUG_STREAM.println("Temperature + humidity sensor initialized."); + humiditySensor.enableSensor(); + } + else { + DEBUG_STREAM.println("Temperature + humidity initialization failed!"); + } +} + +void initPressureSensor() { + if (barometricSensor.init()) { + DEBUG_STREAM.println("Barometric sensor initialization succeeded!"); + barometricSensor.enableSensor(Sodaq_LPS22HB::OdrOneShot); + } + else { + DEBUG_STREAM.println("Barometric sensor initialization failed!"); + } +} + +void initGPS() { + sodaq_gps.init(6); + // sodaq_gps.setDiag(DEBUG_STREAM); +} + + +void loop() +{ + do_flash_led(13); + // Create the message + byte message[14]; + uint16_t cursor = 0; + int16_t temperature; + int16_t humidity; + int16_t pressure; + + temperature = humiditySensor.readTemperature() * 100; + DEBUG_STREAM.println("Temperature x100 : " + (String)temperature); + message[cursor++] = temperature >> 8; + message[cursor++] = temperature; + + delay(100); + + humidity = humiditySensor.readHumidity() * 100; + DEBUG_STREAM.println("Humidity x100 : " + (String)humidity); + message[cursor++] = humidity >> 8; + message[cursor++] = humidity; + + delay(100); + + pressure = barometricSensor.readPressureHPA(); + DEBUG_STREAM.println("Pressure:" + (String)pressure); + message[cursor++] = pressure >> 8; + message[cursor++] = pressure; + + uint32_t start = millis(); + uint32_t timeout = 1UL * 10 * 1000; // 10 sec timeout + + DEBUG_STREAM.println(String("waiting for fix ..., timeout=") + timeout + String("ms")); + if (sodaq_gps.scan(true, timeout)) { + + lat = sodaq_gps.getLat() * 100000; + lon = sodaq_gps.getLon() * 100000; + } + else { + DEBUG_STREAM.println("No Fix"); + } + + message[cursor++] = lat >> 24; + message[cursor++] = lat >> 16; + message[cursor++] = lat >> 8; + message[cursor++] = lat; + + + message[cursor++] = lon >> 24; + message[cursor++] = lon >> 16; + message[cursor++] = lon >> 8; + message[cursor++] = lon; + + // Print the message we want to send + // DEBUG_STREAM.println(message); + for (int i = 0; i < cursor; i++) { + if (message[i] < 0x10) { + DEBUG_STREAM.print("0"); + } + DEBUG_STREAM.print(message[i], HEX); + if (i < (cursor - 1)) { + DEBUG_STREAM.print(":"); + } + } + DEBUG_STREAM.println(); + + // Send the message + nbiot.sendMessage(message, cursor); + + // Wait some time between messages + delay(10000); // 1000 = 1 sec +} + +void do_flash_led(int pin) +{ + for (size_t i = 0; i < 2; ++i) { + delay(100); + digitalWrite(pin, LOW); + delay(100); + digitalWrite(pin, HIGH); + delay(100); + digitalWrite(pin, LOW); + } +} + +/***** + * ATT Settings + * + * create a new asset as Number + * + * device decoding: + + { + "sense": [ + { + "asset": "my_temperature", + "value": { + "byte": 0, + "bytelength": 2, + "type": "integer", + "calculation": "val / 100" + } + }, + { + "asset": "my_humidity", + "value": { + "byte": 2, + "bytelength": 2, + "type": "integer", + "calculation": "val / 100" + } + }, + { + "asset": "my_pressure", + "value": { + "byte": 4, + "bytelength": 2, + "type": "integer" + } + }, + { + "asset": "my_gps", + "value": { + "latitude": { + "byte": 6, + "bytelength": 4, + "type": "integer", + "calculation": "val / 100000" + }, + "longitude": { + "byte": 10, + "bytelength": 4, + "type": "integer", + "calculation": "val / 100000" + } + } + } + ] + } + */ diff --git a/examples/nbIOT_serial_passthrough/nbIOT_serial_passthrough.ino b/examples/nbIOT_serial_passthrough/nbIOT_serial_passthrough.ino new file mode 100644 index 0000000..00ae6d5 --- /dev/null +++ b/examples/nbIOT_serial_passthrough/nbIOT_serial_passthrough.ino @@ -0,0 +1,86 @@ +#include + +#if defined(ARDUINO_AVR_LEONARDO) +/* Arduino Leonardo + SODAQ NB-IoT Shield */ +#define DEBUG_STREAM Serial +#define MODEM_STREAM Serial1 +#define powerPin 7 + +#elif defined(ARDUINO_SODAQ_EXPLORER) +/* SODAQ Explorer + SODAQ NB-IoT Shield */ +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial +#define powerPin 7 + +#elif defined(ARDUINO_SAM_ZERO) +/* Arduino Zero / M0 + SODAQ NB-IoT Shield */ +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial1 +#define powerPin 7 + +#elif defined(ARDUINO_SODAQ_AUTONOMO) +/* SODAQ AUTONOMO + SODAQ NB-IoT Bee */ +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial1 +#define powerPin BEE_VCC +#define enablePin BEEDTR + +#elif defined(ARDUINO_AVR_SODAQ_MBILI) +/* SODAQ MBILI + SODAQ NB-IoT Bee */ +#define DEBUG_STREAM Serial +#define MODEM_STREAM Serial1 +#define enablePin BEEDTR + +#elif defined(ARDUINO_SODAQ_SARA) +/* SODAQ SARA */ +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial1 +#define powerPin SARA_ENABLE +#define enablePin SARA_TX_ENABLE + +#else +#error "Please use one of the listed boards or add your board." +#endif + +unsigned long baud = 9600; //start at 9600 allow the USB port to change the Baudrate + +void setup() +{ +#ifdef powerPin + // Turn the nb-iot module on + pinMode(powerPin, OUTPUT); + digitalWrite(powerPin, HIGH); +#endif + +#ifdef enablePin + // Set state to active + pinMode(enablePin, OUTPUT); + digitalWrite(enablePin, HIGH); +#endif // enablePin + + // Start communication + DEBUG_STREAM.begin(baud); + MODEM_STREAM.begin(baud); +} + +// Forward every message to the other serial +void loop() +{ + while (DEBUG_STREAM.available()) + { + MODEM_STREAM.write(DEBUG_STREAM.read()); + } + + while (MODEM_STREAM.available()) + { + DEBUG_STREAM.write(MODEM_STREAM.read()); + } + +#ifndef ARDUINO_AVR_SODAQ_MBILI + // check if the USB virtual serial wants a new baud rate + if (DEBUG_STREAM.baud() != baud) { + baud = DEBUG_STREAM.baud(); + MODEM_STREAM.begin(baud); + } +#endif // !ARDUINO_AVR_SODAQ_MBILI +} diff --git a/examples/nbIOT_test/nbIOT_test.ino b/examples/nbIOT_test/nbIOT_test.ino index 65a9309..47cac3e 100644 --- a/examples/nbIOT_test/nbIOT_test.ino +++ b/examples/nbIOT_test/nbIOT_test.ino @@ -22,13 +22,48 @@ #include #ifdef ARDUINO_SODAQ_EXPLORER +/* SODAQ Explorer + SODAQ NB-IoT Shield */ +#define DEBUG_STREAM SerialUSB #define MODEM_ON_OFF_PIN 7 #define MODEM_STREAM Serial + +#elif defined(ARDUINO_SAM_ZERO) +/* Arduino Zero / M0 + SODAQ NB-IoT Shield */ +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial1 +#define MODEM_ON_OFF_PIN 7 + +#elif defined(ARDUINO_AVR_LEONARDO) +/* Arduino Leonardo + SODAQ NB-IoT Shield */ +#define DEBUG_STREAM Serial +#define MODEM_STREAM Serial1 +#define MODEM_ON_OFF_PIN 7 + +#elif defined(ARDUINO_SODAQ_AUTONOMO) +/* SODAQ AUTONOMO + SODAQ NB-IoT Bee */ +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial1 +#define MODEM_ON_OFF_PIN BEE_VCC +#define MODEM_DTR BEEDTR + +#elif defined(ARDUINO_AVR_SODAQ_MBILI) +/* SODAQ MBILI + SODAQ NB-IoT Bee */ +#define DEBUG_STREAM Serial +#define MODEM_STREAM Serial1 +#define MODEM_DTR BEEDTR + +#elif defined(ARDUINO_SODAQ_SARA) +/* SODAQ SARA */ +#define DEBUG_STREAM SerialUSB +#define MODEM_STREAM Serial1 +#define MODEM_ON_OFF_PIN SARA_ENABLE +#define MODEM_DTR SARA_TX_ENABLE + #else #error "You need to declare the modem on/off pin and stream for your particular board!" #endif -#define DEBUG_STREAM SerialUSB + #define DEBUG_STREAM_BAUD 115200 #define STARTUP_DELAY 5000 @@ -50,9 +85,43 @@ void setup() DEBUG_STREAM.print("Initializing and connecting... "); +#ifdef MODEM_DTR + // Set state to active + pinMode(MODEM_DTR, OUTPUT); + digitalWrite(MODEM_DTR, HIGH); +#endif // MODEM_DTR + nbiot.init(MODEM_STREAM, MODEM_ON_OFF_PIN); nbiot.setDiag(DEBUG_STREAM); + connectModem(); +} + +void loop() +{ + if (nbiot.isConnected()) { + const char* message = "Hello World!"; + DEBUG_STREAM.print("Sending message: \""); + DEBUG_STREAM.print(message); + DEBUG_STREAM.print("\"... "); + + if (!nbiot.sendMessage(message)) { + DEBUG_STREAM.println("Could not queue message!"); + } + else { + DEBUG_STREAM.println("Message queued for transmission!"); + } + + showMessageCountFromModem(); + } + else { + connectModem(); + } + + sodaq_wdt_safe_delay(5000); +} + +void connectModem() { if (nbiot.connect(apn, cdp, forceOperator)) { DEBUG_STREAM.println("Connected succesfully!"); } @@ -60,29 +129,6 @@ void setup() DEBUG_STREAM.println("Failed to connect!"); return; } - - showMessageCountFromModem(); - - const char* message = "Hello World!"; - DEBUG_STREAM.print("Sending message: \""); - DEBUG_STREAM.print(message); - DEBUG_STREAM.print("\"... "); - - if (!nbiot.sendMessage(message)) { - DEBUG_STREAM.println("Could not queue message!"); - } - else { - DEBUG_STREAM.println("Message queued for transmission!"); - } -} - -void loop() -{ - if (nbiot.isConnected()) { - showMessageCountFromModem(); - } - - sodaq_wdt_safe_delay(5000); } void showMessageCountFromModem() diff --git a/src/Sodaq_AT_Device.cpp b/src/Sodaq_AT_Device.cpp index 648da5c..768bb45 100644 --- a/src/Sodaq_AT_Device.cpp +++ b/src/Sodaq_AT_Device.cpp @@ -266,7 +266,7 @@ size_t Sodaq_AT_Device::println(const Printable& x) size_t Sodaq_AT_Device::println(void) { debugPrintLn(); - size_t i = print(SODAQ_AT_DEVICE_TERMINATOR); + size_t i = print('\r'); _appendCommand = false; return i; } diff --git a/src/Sodaq_nbIOT.cpp b/src/Sodaq_nbIOT.cpp index 41269a6..df08249 100644 --- a/src/Sodaq_nbIOT.cpp +++ b/src/Sodaq_nbIOT.cpp @@ -74,30 +74,29 @@ #define NOW (uint32_t)millis() typedef struct NameValuePair { - const char *Name; - const char *Value; + const char* Name; + const char* Value; } NameValuePair; -const uint8_t nConfigCount = 3; +const uint8_t nConfigCount = 6; static NameValuePair nConfig[nConfigCount] = { - {"AUTOCONNECT", "FALSE"}, - {"CR_0354_0338_SCRAMBLING", "FALSE"}, - {"CR_0859_SI_AVOID", "FALSE"} + { "AUTOCONNECT", "TRUE" }, + { "CR_0354_0338_SCRAMBLING", "TRUE" }, + { "CR_0859_SI_AVOID", "TRUE" }, + { "COMBINE_ATTACH" , "FALSE" }, + { "CELL_RESELECTION" , "FALSE" }, + { "ENABLE_BIP" , "FALSE" }, }; -class Sodaq_nbIotOnOff : public Sodaq_OnOffBee { -public: +class Sodaq_nbIotOnOff : public Sodaq_OnOffBee +{ + public: Sodaq_nbIotOnOff(); - void init(int onoffPin); - void on(); - void off(); - bool isOn(); - -private: + private: int8_t _onoffPin; bool _onoff_status; }; @@ -105,31 +104,31 @@ private: static Sodaq_nbIotOnOff sodaq_nbIotOnOff; static inline bool is_timedout(uint32_t from, uint32_t nr_ms) __attribute__((always_inline)); - -static inline bool is_timedout(uint32_t from, uint32_t nr_ms) { +static inline bool is_timedout(uint32_t from, uint32_t nr_ms) +{ return (millis() - from) > nr_ms; } Sodaq_nbIOT::Sodaq_nbIOT() : - _lastRSSI(0), - _CSQtime(0), - _minRSSI(-113) // dBm + _lastRSSI(0), + _CSQtime(0), + _minRSSI(-113) // dBm { } // Returns true if the modem replies to "AT" commands without timing out. -bool Sodaq_nbIOT::isAlive() { +bool Sodaq_nbIOT::isAlive() +{ _disableDiag = true; println(STR_AT); - // @todo check if necessary - delay(150); return (readResponse(NULL, 450) == ResponseOK); } // Initializes the modem instance. Sets the modem stream and the on-off power pins. -void Sodaq_nbIOT::init(Stream &stream, int8_t onoffPin) { +void Sodaq_nbIOT::init(Stream& stream, int8_t onoffPin) +{ debugPrintLn("[init] started."); initBuffer(); // safe to call multiple times @@ -140,14 +139,16 @@ void Sodaq_nbIOT::init(Stream &stream, int8_t onoffPin) { _onoff = &sodaq_nbIotOnOff; } -bool Sodaq_nbIOT::setRadioActive(bool on) { +bool Sodaq_nbIOT::setRadioActive(bool on) +{ print("AT+CFUN="); println(on ? "1" : "0"); return (readResponse() == ResponseOK); } -bool Sodaq_nbIOT::setIndicationsActive(bool on) { +bool Sodaq_nbIOT::setIndicationsActive(bool on) +{ print("AT+NSMI="); println(on ? "1" : "0"); @@ -169,16 +170,16 @@ bool Sodaq_nbIOT::setIndicationsActive(bool on) { _socketPendingBytes[] if +UUSORD: is seen _socketClosedBit[] if +UUSOCL: is seen */ -ResponseTypes Sodaq_nbIOT::readResponse(char *buffer, size_t size, - CallbackMethodPtr parserMethod, void *callbackParameter, - void *callbackParameter2, - size_t *outSize, uint32_t timeout) { +ResponseTypes Sodaq_nbIOT::readResponse(char* buffer, size_t size, + CallbackMethodPtr parserMethod, void* callbackParameter, void* callbackParameter2, + size_t* outSize, uint32_t timeout) +{ ResponseTypes response = ResponseNotFound; uint32_t from = NOW; do { // 250ms, how many bytes at which baudrate? - int count = readLn(buffer, size, 500); + int count = readLn(buffer, size, 250); sodaq_wdt_reset(); if (count > 0) { @@ -189,11 +190,25 @@ ResponseTypes Sodaq_nbIOT::readResponse(char *buffer, size_t size, if (_disableDiag && strncmp(buffer, "OK", 2) != 0) { _disableDiag = false; } + debugPrint("[rdResp]: "); debugPrintLn(buffer); // TODO handle socket URC - + int param1, param2; + if (sscanf(buffer, "+NSONMI: %d,%d", ¶m1, ¶m2) == 2) { + uint16_t socket_nr = param1; + uint16_t nr_bytes = param2; + debugPrint("Unsolicited: Socket "); + debugPrint(socket_nr); + debugPrint(": "); + debugPrint(param2); + debugPrintLn(" bytes pending"); + if (socket_nr < ARRAY_SIZE(_socketPendingBytes)) { + _socketPendingBytes[socket_nr] = nr_bytes; + } + continue; + } //int param1, param2; //if (sscanf(buffer, "+UUSORD: %d,%d", ¶m1, ¶m2) == 2) { // uint16_t socket_nr = param1; @@ -239,14 +254,13 @@ ResponseTypes Sodaq_nbIOT::readResponse(char *buffer, size_t size, } if (startsWith(STR_RESPONSE_ERROR, buffer) || - startsWith(STR_RESPONSE_CME_ERROR, buffer) || - startsWith(STR_RESPONSE_CMS_ERROR, buffer)) { + startsWith(STR_RESPONSE_CME_ERROR, buffer) || + startsWith(STR_RESPONSE_CMS_ERROR, buffer)) { return ResponseError; } if (parserMethod) { - ResponseTypes parserResponse = parserMethod(response, buffer, count, callbackParameter, - callbackParameter2); + ResponseTypes parserResponse = parserMethod(response, buffer, count, callbackParameter, callbackParameter2); if ((parserResponse != ResponseEmpty) && (parserResponse != ResponsePendingExtra)) { return parserResponse; @@ -285,7 +299,8 @@ ResponseTypes Sodaq_nbIOT::readResponse(char *buffer, size_t size, return ResponseTimeout; } -bool Sodaq_nbIOT::setApn(const char *apn) { +bool Sodaq_nbIOT::setApn(const char* apn) +{ print("AT+CGDCONT=" DEFAULT_CID ",\"IP\",\""); print(apn); println("\""); @@ -293,19 +308,32 @@ bool Sodaq_nbIOT::setApn(const char *apn) { return (readResponse() == ResponseOK); } -bool Sodaq_nbIOT::setCdp(const char *cdp) { - print("AT+NCDP="); - println(cdp); +bool Sodaq_nbIOT::setCdp(const char* cdp) +{ + print("AT+NCDP=\""); + print(cdp); + println("\""); return (readResponse() == ResponseOK); } +void Sodaq_nbIOT::purgeAllResponsesRead() +{ + uint32_t start = millis(); + + // make sure all the responses within the timeout have been read + while ((readResponse(0, 1000) != ResponseTimeout) && !is_timedout(start, 2000)) {} +} + // Turns on and initializes the modem, then connects to the network and activates the data connection. -bool Sodaq_nbIOT::connect(const char *apn, const char *cdp, const char *forceOperator) { +bool Sodaq_nbIOT::connect(const char* apn, const char* cdp, const char* forceOperator) +{ if (!on()) { return false; } + purgeAllResponsesRead(); + if (!setRadioActive(false)) { return false; } @@ -320,6 +348,8 @@ bool Sodaq_nbIOT::connect(const char *apn, const char *cdp, const char *forceOpe return false; } + purgeAllResponsesRead(); + if (!setApn(apn) || !setCdp(cdp)) { return false; } @@ -351,11 +381,18 @@ bool Sodaq_nbIOT::connect(const char *apn, const char *cdp, const char *forceOpe return false; } + #ifdef DEBUG + println("AT+CPSMS?"); + readResponse(); + readResponse(); + #endif + // If we got this far we succeeded return true; } -void Sodaq_nbIOT::reboot() { +void Sodaq_nbIOT::reboot() +{ println("AT+NRB"); // wait up to 2000ms for the modem to come up @@ -363,13 +400,15 @@ void Sodaq_nbIOT::reboot() { while ((readResponse() != ResponseOK) && !is_timedout(start, 2000)) {} } -bool Sodaq_nbIOT::checkAndApplyNconfig() { +bool Sodaq_nbIOT::checkAndApplyNconfig() +{ bool applyParam[nConfigCount]; println("AT+NCONFIG?"); if (readResponse(_nconfigParser, applyParam, NULL) == ResponseOK) { - for (uint8_t i = 0; i < nConfigCount; i++) { + for (uint8_t i = 0; i < nConfigCount; i++) + { debugPrint(nConfig[i].Name); if (!applyParam[i]) { debugPrintLn("... CHANGE"); @@ -385,26 +424,28 @@ bool Sodaq_nbIOT::checkAndApplyNconfig() { return false; } -bool Sodaq_nbIOT::setNconfigParam(const char *param, const char *value) { - print("AT+NCONFIG="); +bool Sodaq_nbIOT::setNconfigParam(const char* param, const char* value) +{ + print("AT+NCONFIG=\""); print(param); - print(","); - println(value); + print("\",\""); + print(value); + println("\""); return readResponse() == ResponseOK; } -ResponseTypes -Sodaq_nbIOT::_nconfigParser(ResponseTypes &response, const char *buffer, size_t size, bool *nconfigEqualsArray, - uint8_t *dummy) { +ResponseTypes Sodaq_nbIOT::_nconfigParser(ResponseTypes& response, const char* buffer, size_t size, bool* nconfigEqualsArray, uint8_t* dummy) +{ if (!nconfigEqualsArray) { return ResponseError; } char name[32]; char value[32]; - if (sscanf(buffer, "+NCONFIG: %[^,],%[^\r]", name, value) == 2) { - for (uint8_t i = 0; i < nConfigCount; i++) { + if (sscanf(buffer, "+NCONFIG: \"%[^\"]\",\"%[^\"]\"", name, value) == 2) { + for (uint8_t i = 0; i < nConfigCount; i++) + { if (strcmp(nConfig[i].Name, name) == 0) { if (strcmp(nConfig[i].Value, value) == 0) { nconfigEqualsArray[i] = true; @@ -420,16 +461,20 @@ Sodaq_nbIOT::_nconfigParser(ResponseTypes &response, const char *buffer, size_t return ResponseError; } -bool Sodaq_nbIOT::attachGprs(uint32_t timeout) { +bool Sodaq_nbIOT::attachGprs(uint32_t timeout) +{ uint32_t start = millis(); uint32_t delay_count = 500; while (!is_timedout(start, timeout)) { - println("AT+CGATT=1"); - - if (readResponse() == ResponseOK) { + if (isConnected()) { return true; } + //println("AT+CGATT=1"); + + //if (readResponse() == ResponseOK) { + // return true; + //} sodaq_wdt_safe_delay(delay_count); @@ -450,59 +495,74 @@ bool Sodaq_nbIOT::attachGprs(uint32_t timeout) { * @param forceOperator * @return */ -bool Sodaq_nbIOT::connectSocket() { -// if (!on()) { -// return false; -// } +bool Sodaq_nbIOT::connectSocket() +{ + if (!on()) { + return false; + } -// if (!setRadioActive(false)) { -// return false; -// } + purgeAllResponsesRead(); -// if (!checkAndApplyNconfig()) { -// return false; -// } + if (!setRadioActive(false)) { + return false; + } + + if (!checkAndApplyNconfig()) { + return false; + } reboot(); -// -// if (!on()) { -// return false; -// } -// TODO turn on -// if (!setIndicationsActive(false)) { -// return false; -// } + if (!on()) { + return false; + } -// if (!setRadioActive(true)) { -// return false; -// } + purgeAllResponsesRead(); -// if (forceOperator && forceOperator[0] != '\0') { -// print("AT+COPS=1,2,\""); -// print(forceOperator); -// println("\""); -// -// if (readResponse() != ResponseOK) { -// return false; -// } -// } + if (!setRadioActive(true)) { + return false; + } -// if (!waitForSignalQuality()) { -// return false; -// } + println("AT+COPS=1,2,\"21630\""); + readResponse(); -// if (!attachGprs()) { -// return false; -// } + bool registered = false; + while (!registered) { + debugPrint("Checking registration state ... "); + println("AT+CEREG?"); + sodaq_wdt_safe_delay(AT_CMD_SLEEP_TIME); -// If we got this far we succeeded - return true; + if (readResponse(_registeredParser, ®istered, NULL) != ResponseOK) { + debugPrintLn(" ... REG ERROR"); + return false; + } + debugPrintLn(" ... WAITING"); + sodaq_wdt_safe_delay(3000); + } + debugPrintLn("REGISTRATION DONE"); + + if (!waitForSignalQuality()) { + return false; + } + + return registered; +} + +ResponseTypes Sodaq_nbIOT::_registeredParser(ResponseTypes &response, const char *buffer, size_t size, + bool *registered, uint8_t *dummy) { + + int value; + + if (sscanf(buffer, "+CEREG: %d,%d", NULL, &value) == 2) { + *registered = (value == 1); + return ResponseEmpty; + } + + return ResponseError; } int Sodaq_nbIOT::createSocket(uint16_t localPort) { - // only Datagram/UDP is supported - print("AT+NSOCR=DGRAM,17,"); + print("AT+NSOCR=\"DGRAM\",17,"); print(localPort); println(",1"); // enable incoming message URC (NSONMI) delay(500); @@ -533,28 +593,26 @@ ResponseTypes Sodaq_nbIOT::_createSocketParser(ResponseTypes &response, const ch return ResponseError; } -int Sodaq_nbIOT::sendSocket(uint8_t socket, const char *host, uint16_t port, const char *buffer, size_t size) { +bool Sodaq_nbIOT::sendSocket(uint8_t socket, const char *host, uint16_t port, const char *buffer, size_t size) { print("AT+NSOST="); print(socket); - print(","); + print(",\""); print(host); - print(","); + print("\","); print(port); print(","); print(size); // why size? not encoded hex size? no idea... - print(","); + print(",\""); for (uint16_t i = 0; i < size; ++i) { print(static_cast(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(buffer[i])))); print(static_cast(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(buffer[i])))); } - println(); + println("\""); + + delay(AT_CMD_SLEEP_TIME); uint8_t sent; - if(readResponse(_sendSocketParser, &socket, &sent) == ResponseOK) { - return sent; - } - - return -1; + return ((readResponse(_sendSocketParser, &socket, &sent) == ResponseOK) && (sent > 0)); } ResponseTypes Sodaq_nbIOT::_sendSocketParser(ResponseTypes &response, const char *buffer, size_t size, @@ -564,11 +622,9 @@ ResponseTypes Sodaq_nbIOT::_sendSocketParser(ResponseTypes &response, const char } int value; - int value2; - - if (sscanf(buffer, "%d,%d", &value, &value2) == 2) { - *sent = value2; + if (sscanf(buffer, "%*d,%d", &value) == 1) { + *sent = value; return ResponseEmpty; } SerialUSB.println(F(__FILE__"sockparserr")); @@ -585,6 +641,7 @@ size_t Sodaq_nbIOT::socketReceive(uint8_t socket, char *buffer, size_t size) { if (readResponse(_socketReceiveParser, &socket, buffer, &size) == ResponseOK) { debugPrintLn(__FILE__": socketReceive() OK"); + _socketPendingBytes[socket] -= size; return size; } debugPrintLn(__FILE__": socketReceive() ERR"); @@ -597,33 +654,23 @@ ResponseTypes Sodaq_nbIOT::_socketReceiveParser(ResponseTypes &response, const c return ResponseError; } - int tmp_sock = 0; - char tmp_ip[16] = ""; - int tmp_port = 0; - int tpm_length = 0; - int tpm_length_rem = 0; - - + int length = 0; + auto * resultBuffer = static_cast(malloc(250)); + memset(resultBuffer, 0, 250); SerialUSB.println(__FILE__": _socketReceiveParser() sscanf"); - // ,,,,, - SerialUSB.println(__FILE__": _socketReceiveParser() buffer:"); - SerialUSB.println(buffer); /** * create a result buffer for the HEX string input * 250 is SODAQ_AT_DEVICE_DEFAULT_INPUT_BUFFER_SIZE defined in Sodaq_AT_Device.h * should probably refactor some more and move it to Sodaq_AT_Device.h * we probably only need half of this (+1) */ - auto * resultBuffer = static_cast(malloc(250)); - memset(resultBuffer, 0, 250); - if (sscanf(buffer, "%d,%[^,],%d,%d,%[^,],%d", &tmp_sock, tmp_ip, &tmp_port, &tpm_length, resultBuffer, &tpm_length_rem) == 6) { - SerialUSB.println(__FILE__": _socketReceiveParser() OK"); - int i; - for(i=0; i < tpm_length;i++) { + if (sscanf(buffer, R"(%*d,"%*[^"]",%*d,%d,"%[^"]",%*d)", &length, resultBuffer) == 2) { + for(int i=0; i < length;i++) { parsedBuffer[i] = HEX_PAIR_TO_BYTE(resultBuffer[i*2], resultBuffer[i*2+1]); } free(resultBuffer); + SerialUSB.println(__FILE__": _socketReceiveParser() OK"); return ResponseEmpty; } @@ -633,20 +680,7 @@ ResponseTypes Sodaq_nbIOT::_socketReceiveParser(ResponseTypes &response, const c } size_t Sodaq_nbIOT::socketBytesPending(uint8_t socket) { - - int count = readLn(_inputBuffer, _inputBufferSize, 1000); - - if (count == 0) { - return 0; - } - - int inc_socket; - int length; - - if (startsWith("+NSONMI:", _inputBuffer)) { - sscanf(_inputBuffer, "+NSONMI:%d,%d", &inc_socket, &length); - return length; - } + return _socketPendingBytes[socket]; } bool Sodaq_nbIOT::closeSocket(uint8_t socket) { @@ -656,14 +690,16 @@ bool Sodaq_nbIOT::closeSocket(uint8_t socket) { } // Disconnects the modem from the network. -bool Sodaq_nbIOT::disconnect() { +bool Sodaq_nbIOT::disconnect() +{ println("AT+CGATT=0"); return (readResponse(NULL, 40000) == ResponseOK); } // Returns true if the modem is connected to the network and has an activated data connection. -bool Sodaq_nbIOT::isConnected() { +bool Sodaq_nbIOT::isConnected() +{ uint8_t value = 0; println("AT+CGATT?"); @@ -677,8 +713,9 @@ bool Sodaq_nbIOT::isConnected() { // Gets the Received Signal Strength Indication in dBm and Bit Error Rate. // Returns true if successful. -bool Sodaq_nbIOT::getRSSIAndBER(int8_t *rssi, uint8_t *ber) { - static char berValues[] = {49, 43, 37, 25, 19, 13, 7, 0}; // 3GPP TS 45.008 [20] subclause 8.2.4 +bool Sodaq_nbIOT::getRSSIAndBER(int8_t* rssi, uint8_t* ber) +{ + static char berValues[] = { 49, 43, 37, 25, 19, 13, 7, 0 }; // 3GPP TS 45.008 [20] subclause 8.2.4 println("AT+CSQ"); @@ -703,23 +740,28 @@ bool Sodaq_nbIOT::getRSSIAndBER(int8_t *rssi, uint8_t *ber) { 31: -51 dBm or greater 99: not known or not detectable or currently not available */ -int8_t Sodaq_nbIOT::convertCSQ2RSSI(uint8_t csq) const { +int8_t Sodaq_nbIOT::convertCSQ2RSSI(uint8_t csq) const +{ return -113 + 2 * csq; } -uint8_t Sodaq_nbIOT::convertRSSI2CSQ(int8_t rssi) const { +uint8_t Sodaq_nbIOT::convertRSSI2CSQ(int8_t rssi) const +{ return (rssi + 113) / 2; } -bool Sodaq_nbIOT::startsWith(const char *pre, const char *str) { +bool Sodaq_nbIOT::startsWith(const char* pre, const char* str) +{ return (strncmp(pre, str, strlen(pre)) == 0); } -size_t Sodaq_nbIOT::ipToString(IP_t ip, char *buffer, size_t size) { +size_t Sodaq_nbIOT::ipToString(IP_t ip, char* buffer, size_t size) +{ return snprintf(buffer, size, IP_FORMAT, IP_TO_TUPLE(ip)); } -bool Sodaq_nbIOT::isValidIPv4(const char *str) { +bool Sodaq_nbIOT::isValidIPv4(const char* str) +{ uint8_t segs = 0; // Segment count uint8_t chcnt = 0; // Character count within segment uint8_t accum = 0; // Accumulator for segment @@ -777,7 +819,8 @@ bool Sodaq_nbIOT::isValidIPv4(const char *str) { return true; } -bool Sodaq_nbIOT::waitForSignalQuality(uint32_t timeout) { +bool Sodaq_nbIOT::waitForSignalQuality(uint32_t timeout) +{ uint32_t start = millis(); const int8_t minRSSI = getMinRSSI(); int8_t rssi; @@ -789,7 +832,7 @@ bool Sodaq_nbIOT::waitForSignalQuality(uint32_t timeout) { if (getRSSIAndBER(&rssi, &ber)) { if (rssi != 0 && rssi >= minRSSI) { _lastRSSI = rssi; - _CSQtime = (int32_t) (millis() - start) / 1000; + _CSQtime = (int32_t)(millis() - start) / 1000; return true; } } @@ -805,8 +848,8 @@ bool Sodaq_nbIOT::waitForSignalQuality(uint32_t timeout) { return false; } -ResponseTypes -Sodaq_nbIOT::_cgattParser(ResponseTypes &response, const char *buffer, size_t size, uint8_t *result, uint8_t *dummy) { +ResponseTypes Sodaq_nbIOT::_cgattParser(ResponseTypes& response, const char* buffer, size_t size, uint8_t* result, uint8_t* dummy) +{ if (!result) { return ResponseError; } @@ -820,8 +863,9 @@ Sodaq_nbIOT::_cgattParser(ResponseTypes &response, const char *buffer, size_t si return ResponseError; } -ResponseTypes Sodaq_nbIOT::_csqParser(ResponseTypes &response, const char *buffer, size_t size, - int *rssi, int *ber) { +ResponseTypes Sodaq_nbIOT::_csqParser(ResponseTypes& response, const char* buffer, size_t size, + int* rssi, int* ber) +{ if (!rssi || !ber) { return ResponseError; } @@ -833,26 +877,28 @@ ResponseTypes Sodaq_nbIOT::_csqParser(ResponseTypes &response, const char *buffe return ResponseError; } -bool Sodaq_nbIOT::sendMessage(const uint8_t *buffer, size_t size) { +bool Sodaq_nbIOT::sendMessage(const uint8_t* buffer, size_t size) +{ if (size > 512) { return false; } print("AT+NMGS="); print(size); - print(","); + print(",\""); for (uint16_t i = 0; i < size; ++i) { print(static_cast(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(buffer[i])))); print(static_cast(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(buffer[i])))); } - println(); + println("\""); return (readResponse() == ResponseOK); } -int Sodaq_nbIOT::getSentMessagesCount(SentMessageStatus filter) { +int Sodaq_nbIOT::getSentMessagesCount(SentMessageStatus filter) +{ println("AT+NQMGS"); uint16_t pendingCount = 0; @@ -869,9 +915,8 @@ int Sodaq_nbIOT::getSentMessagesCount(SentMessageStatus filter) { return -1; } -ResponseTypes -Sodaq_nbIOT::_nqmgsParser(ResponseTypes &response, const char *buffer, size_t size, uint16_t *pendingCount, - uint16_t *errorCount) { +ResponseTypes Sodaq_nbIOT::_nqmgsParser(ResponseTypes& response, const char* buffer, size_t size, uint16_t* pendingCount, uint16_t* errorCount) +{ if (!pendingCount || !errorCount) { return ResponseError; } @@ -889,24 +934,28 @@ Sodaq_nbIOT::_nqmgsParser(ResponseTypes &response, const char *buffer, size_t si return ResponseError; } -bool Sodaq_nbIOT::sendMessage(const char *str) { - return sendMessage((const uint8_t *) str, strlen(str)); +bool Sodaq_nbIOT::sendMessage(const char* str) +{ + return sendMessage((const uint8_t*)str, strlen(str)); } -bool Sodaq_nbIOT::sendMessage(String str) { +bool Sodaq_nbIOT::sendMessage(String str) +{ return sendMessage(str.c_str()); } // ============================== // on/off class // ============================== -Sodaq_nbIotOnOff::Sodaq_nbIotOnOff() { +Sodaq_nbIotOnOff::Sodaq_nbIotOnOff() +{ _onoffPin = -1; _onoff_status = false; } // Initializes the instance -void Sodaq_nbIotOnOff::init(int onoffPin) { +void Sodaq_nbIotOnOff::init(int onoffPin) +{ if (onoffPin >= 0) { _onoffPin = onoffPin; // First write the output value, and only then set the output mode. @@ -915,7 +964,8 @@ void Sodaq_nbIotOnOff::init(int onoffPin) { } } -void Sodaq_nbIotOnOff::on() { +void Sodaq_nbIotOnOff::on() +{ if (_onoffPin >= 0) { digitalWrite(_onoffPin, HIGH); } @@ -923,7 +973,8 @@ void Sodaq_nbIotOnOff::on() { _onoff_status = true; } -void Sodaq_nbIotOnOff::off() { +void Sodaq_nbIotOnOff::off() +{ // The GPRSbee is switched off immediately if (_onoffPin >= 0) { digitalWrite(_onoffPin, LOW); @@ -935,7 +986,8 @@ void Sodaq_nbIotOnOff::off() { _onoff_status = false; } -bool Sodaq_nbIotOnOff::isOn() { +bool Sodaq_nbIotOnOff::isOn() +{ #if defined(ARDUINO_ARCH_AVR) // Use the onoff pin, which is close to useless bool status = digitalRead(_onoffPin); diff --git a/src/Sodaq_nbIOT.h b/src/Sodaq_nbIOT.h index cca0d20..412ede2 100644 --- a/src/Sodaq_nbIOT.h +++ b/src/Sodaq_nbIOT.h @@ -24,6 +24,8 @@ #include "Arduino.h" #include "Sodaq_AT_Device.h" +#define SOCKET_COUNT 7 + class Sodaq_nbIOT: public Sodaq_AT_Device { public: @@ -73,9 +75,9 @@ class Sodaq_nbIOT: public Sodaq_AT_Device uint8_t getCSQtime() const { return _CSQtime; } int8_t getLastRSSI() const { return _lastRSSI; } - bool connectSocket(); int createSocket(uint16_t localPort = 0); - int sendSocket(uint8_t socket, const char *host, uint16_t port, const char *buffer, size_t size); + bool connectSocket(); + bool sendSocket(uint8_t socket, const char *host, uint16_t port, const char *buffer, size_t size); size_t socketReceive(uint8_t socket, char* buffer, size_t size); size_t socketBytesPending(uint8_t socket); bool closeSocket(uint8_t socket); @@ -117,8 +119,9 @@ class Sodaq_nbIOT: public Sodaq_AT_Device (void*)callbackParameter, (void*)callbackParameter2, outSize, timeout); }; + void purgeAllResponsesRead(); private: - //uint16_t _socketPendingBytes[SOCKET_COUNT]; // TODO add getter + uint16_t _socketPendingBytes[SOCKET_COUNT]; // TODO add getter //bool _socketClosedBit[SOCKET_COUNT]; // This is the value of the most recent CSQ @@ -150,6 +153,8 @@ class Sodaq_nbIOT: public Sodaq_AT_Device void reboot(); static ResponseTypes _csqParser(ResponseTypes& response, const char* buffer, size_t size, int* rssi, int* ber); + static ResponseTypes _registeredParser(ResponseTypes& response, const char* buffer, size_t size, + bool* registered, uint8_t* dummy); static ResponseTypes _createSocketParser(ResponseTypes& response, const char* buffer, size_t size, uint8_t* socket, uint8_t* dummy); static ResponseTypes _sendSocketParser(ResponseTypes &response, const char *buffer, size_t size,