* 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
This commit is contained in:
Dávid Danyi 2018-02-15 18:48:07 +01:00
parent cfae7d6ba8
commit e0f54a37cd
10 changed files with 1077 additions and 198 deletions

View File

@ -0,0 +1,147 @@
#include <Arduino.h>
#include <Sodaq_nbIOT.h>
#include <Sodaq_UBlox_GPS.h>
#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);
}
}

View File

@ -0,0 +1,81 @@
#include <Arduino.h>
#include <Wire.h>
// #include <SoftwareSerial.h> // Uno
#include <Sodaq_nbIOT.h>
#include <Sodaq_HTS221.h>
#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
}

View File

@ -0,0 +1,136 @@
#include <Arduino.h>
#include <Wire.h>
#include <Sodaq_wdt.h>
#include <Sodaq_nbIOT.h>
#include <Sodaq_HTS221.h>
#if defined(ARDUINO_AVR_UNO)
#include <SoftwareSerial.h> // 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"
}
}
]
}
*/

View File

@ -0,0 +1,71 @@
#include <Wire.h>
#include <Sodaq_nbIOT.h>
#include <Sodaq_LPS22HB.h>
#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
}

View File

@ -0,0 +1,255 @@
#include <Arduino.h>
#include <Wire.h>
#include <Sodaq_nbIOT.h>
#include <Sodaq_HTS221.h>
#include <Sodaq_LPS22HB.h>
#include <Sodaq_UBlox_GPS.h>
#if defined(ARDUINO_AVR_UNO)
#include <SoftwareSerial.h> // 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"
}
}
}
]
}
*/

View File

@ -0,0 +1,86 @@
#include <Arduino.h>
#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
}

View File

@ -22,13 +22,48 @@
#include <Sodaq_wdt.h> #include <Sodaq_wdt.h>
#ifdef ARDUINO_SODAQ_EXPLORER #ifdef ARDUINO_SODAQ_EXPLORER
/* SODAQ Explorer + SODAQ NB-IoT Shield */
#define DEBUG_STREAM SerialUSB
#define MODEM_ON_OFF_PIN 7 #define MODEM_ON_OFF_PIN 7
#define MODEM_STREAM Serial #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 #else
#error "You need to declare the modem on/off pin and stream for your particular board!" #error "You need to declare the modem on/off pin and stream for your particular board!"
#endif #endif
#define DEBUG_STREAM SerialUSB
#define DEBUG_STREAM_BAUD 115200 #define DEBUG_STREAM_BAUD 115200
#define STARTUP_DELAY 5000 #define STARTUP_DELAY 5000
@ -50,19 +85,21 @@ void setup()
DEBUG_STREAM.print("Initializing and connecting... "); 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.init(MODEM_STREAM, MODEM_ON_OFF_PIN);
nbiot.setDiag(DEBUG_STREAM); nbiot.setDiag(DEBUG_STREAM);
if (nbiot.connect(apn, cdp, forceOperator)) { connectModem();
DEBUG_STREAM.println("Connected succesfully!"); }
}
else {
DEBUG_STREAM.println("Failed to connect!");
return;
}
showMessageCountFromModem();
void loop()
{
if (nbiot.isConnected()) {
const char* message = "Hello World!"; const char* message = "Hello World!";
DEBUG_STREAM.print("Sending message: \""); DEBUG_STREAM.print("Sending message: \"");
DEBUG_STREAM.print(message); DEBUG_STREAM.print(message);
@ -74,17 +111,26 @@ void setup()
else { else {
DEBUG_STREAM.println("Message queued for transmission!"); DEBUG_STREAM.println("Message queued for transmission!");
} }
}
void loop()
{
if (nbiot.isConnected()) {
showMessageCountFromModem(); showMessageCountFromModem();
} }
else {
connectModem();
}
sodaq_wdt_safe_delay(5000); sodaq_wdt_safe_delay(5000);
} }
void connectModem() {
if (nbiot.connect(apn, cdp, forceOperator)) {
DEBUG_STREAM.println("Connected succesfully!");
}
else {
DEBUG_STREAM.println("Failed to connect!");
return;
}
}
void showMessageCountFromModem() void showMessageCountFromModem()
{ {
DEBUG_STREAM.print("Pending Messages: "); DEBUG_STREAM.print("Pending Messages: ");

View File

@ -266,7 +266,7 @@ size_t Sodaq_AT_Device::println(const Printable& x)
size_t Sodaq_AT_Device::println(void) size_t Sodaq_AT_Device::println(void)
{ {
debugPrintLn(); debugPrintLn();
size_t i = print(SODAQ_AT_DEVICE_TERMINATOR); size_t i = print('\r');
_appendCommand = false; _appendCommand = false;
return i; return i;
} }

View File

@ -74,30 +74,29 @@
#define NOW (uint32_t)millis() #define NOW (uint32_t)millis()
typedef struct NameValuePair { typedef struct NameValuePair {
const char *Name; const char* Name;
const char *Value; const char* Value;
} NameValuePair; } NameValuePair;
const uint8_t nConfigCount = 3; const uint8_t nConfigCount = 6;
static NameValuePair nConfig[nConfigCount] = { static NameValuePair nConfig[nConfigCount] = {
{"AUTOCONNECT", "FALSE"}, { "AUTOCONNECT", "TRUE" },
{"CR_0354_0338_SCRAMBLING", "FALSE"}, { "CR_0354_0338_SCRAMBLING", "TRUE" },
{"CR_0859_SI_AVOID", "FALSE"} { "CR_0859_SI_AVOID", "TRUE" },
{ "COMBINE_ATTACH" , "FALSE" },
{ "CELL_RESELECTION" , "FALSE" },
{ "ENABLE_BIP" , "FALSE" },
}; };
class Sodaq_nbIotOnOff : public Sodaq_OnOffBee { class Sodaq_nbIotOnOff : public Sodaq_OnOffBee
public: {
public:
Sodaq_nbIotOnOff(); Sodaq_nbIotOnOff();
void init(int onoffPin); void init(int onoffPin);
void on(); void on();
void off(); void off();
bool isOn(); bool isOn();
private:
private:
int8_t _onoffPin; int8_t _onoffPin;
bool _onoff_status; bool _onoff_status;
}; };
@ -105,8 +104,8 @@ private:
static Sodaq_nbIotOnOff sodaq_nbIotOnOff; 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) __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; return (millis() - from) > nr_ms;
} }
@ -119,17 +118,17 @@ Sodaq_nbIOT::Sodaq_nbIOT() :
} }
// Returns true if the modem replies to "AT" commands without timing out. // Returns true if the modem replies to "AT" commands without timing out.
bool Sodaq_nbIOT::isAlive() { bool Sodaq_nbIOT::isAlive()
{
_disableDiag = true; _disableDiag = true;
println(STR_AT); println(STR_AT);
// @todo check if necessary
delay(150);
return (readResponse(NULL, 450) == ResponseOK); return (readResponse(NULL, 450) == ResponseOK);
} }
// Initializes the modem instance. Sets the modem stream and the on-off power pins. // 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."); debugPrintLn("[init] started.");
initBuffer(); // safe to call multiple times initBuffer(); // safe to call multiple times
@ -140,14 +139,16 @@ void Sodaq_nbIOT::init(Stream &stream, int8_t onoffPin) {
_onoff = &sodaq_nbIotOnOff; _onoff = &sodaq_nbIotOnOff;
} }
bool Sodaq_nbIOT::setRadioActive(bool on) { bool Sodaq_nbIOT::setRadioActive(bool on)
{
print("AT+CFUN="); print("AT+CFUN=");
println(on ? "1" : "0"); println(on ? "1" : "0");
return (readResponse() == ResponseOK); return (readResponse() == ResponseOK);
} }
bool Sodaq_nbIOT::setIndicationsActive(bool on) { bool Sodaq_nbIOT::setIndicationsActive(bool on)
{
print("AT+NSMI="); print("AT+NSMI=");
println(on ? "1" : "0"); println(on ? "1" : "0");
@ -169,16 +170,16 @@ bool Sodaq_nbIOT::setIndicationsActive(bool on) {
_socketPendingBytes[] if +UUSORD: is seen _socketPendingBytes[] if +UUSORD: is seen
_socketClosedBit[] if +UUSOCL: is seen _socketClosedBit[] if +UUSOCL: is seen
*/ */
ResponseTypes Sodaq_nbIOT::readResponse(char *buffer, size_t size, ResponseTypes Sodaq_nbIOT::readResponse(char* buffer, size_t size,
CallbackMethodPtr parserMethod, void *callbackParameter, CallbackMethodPtr parserMethod, void* callbackParameter, void* callbackParameter2,
void *callbackParameter2, size_t* outSize, uint32_t timeout)
size_t *outSize, uint32_t timeout) { {
ResponseTypes response = ResponseNotFound; ResponseTypes response = ResponseNotFound;
uint32_t from = NOW; uint32_t from = NOW;
do { do {
// 250ms, how many bytes at which baudrate? // 250ms, how many bytes at which baudrate?
int count = readLn(buffer, size, 500); int count = readLn(buffer, size, 250);
sodaq_wdt_reset(); sodaq_wdt_reset();
if (count > 0) { if (count > 0) {
@ -189,11 +190,25 @@ ResponseTypes Sodaq_nbIOT::readResponse(char *buffer, size_t size,
if (_disableDiag && strncmp(buffer, "OK", 2) != 0) { if (_disableDiag && strncmp(buffer, "OK", 2) != 0) {
_disableDiag = false; _disableDiag = false;
} }
debugPrint("[rdResp]: "); debugPrint("[rdResp]: ");
debugPrintLn(buffer); debugPrintLn(buffer);
// TODO handle socket URC // TODO handle socket URC
int param1, param2;
if (sscanf(buffer, "+NSONMI: %d,%d", &param1, &param2) == 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; //int param1, param2;
//if (sscanf(buffer, "+UUSORD: %d,%d", &param1, &param2) == 2) { //if (sscanf(buffer, "+UUSORD: %d,%d", &param1, &param2) == 2) {
// uint16_t socket_nr = param1; // uint16_t socket_nr = param1;
@ -245,8 +260,7 @@ ResponseTypes Sodaq_nbIOT::readResponse(char *buffer, size_t size,
} }
if (parserMethod) { if (parserMethod) {
ResponseTypes parserResponse = parserMethod(response, buffer, count, callbackParameter, ResponseTypes parserResponse = parserMethod(response, buffer, count, callbackParameter, callbackParameter2);
callbackParameter2);
if ((parserResponse != ResponseEmpty) && (parserResponse != ResponsePendingExtra)) { if ((parserResponse != ResponseEmpty) && (parserResponse != ResponsePendingExtra)) {
return parserResponse; return parserResponse;
@ -285,7 +299,8 @@ ResponseTypes Sodaq_nbIOT::readResponse(char *buffer, size_t size,
return ResponseTimeout; return ResponseTimeout;
} }
bool Sodaq_nbIOT::setApn(const char *apn) { bool Sodaq_nbIOT::setApn(const char* apn)
{
print("AT+CGDCONT=" DEFAULT_CID ",\"IP\",\""); print("AT+CGDCONT=" DEFAULT_CID ",\"IP\",\"");
print(apn); print(apn);
println("\""); println("\"");
@ -293,19 +308,32 @@ bool Sodaq_nbIOT::setApn(const char *apn) {
return (readResponse() == ResponseOK); return (readResponse() == ResponseOK);
} }
bool Sodaq_nbIOT::setCdp(const char *cdp) { bool Sodaq_nbIOT::setCdp(const char* cdp)
print("AT+NCDP="); {
println(cdp); print("AT+NCDP=\"");
print(cdp);
println("\"");
return (readResponse() == ResponseOK); 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. // 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()) { if (!on()) {
return false; return false;
} }
purgeAllResponsesRead();
if (!setRadioActive(false)) { if (!setRadioActive(false)) {
return false; return false;
} }
@ -320,6 +348,8 @@ bool Sodaq_nbIOT::connect(const char *apn, const char *cdp, const char *forceOpe
return false; return false;
} }
purgeAllResponsesRead();
if (!setApn(apn) || !setCdp(cdp)) { if (!setApn(apn) || !setCdp(cdp)) {
return false; return false;
} }
@ -351,11 +381,18 @@ bool Sodaq_nbIOT::connect(const char *apn, const char *cdp, const char *forceOpe
return false; return false;
} }
#ifdef DEBUG
println("AT+CPSMS?");
readResponse();
readResponse();
#endif
// If we got this far we succeeded // If we got this far we succeeded
return true; return true;
} }
void Sodaq_nbIOT::reboot() { void Sodaq_nbIOT::reboot()
{
println("AT+NRB"); println("AT+NRB");
// wait up to 2000ms for the modem to come up // 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)) {} while ((readResponse() != ResponseOK) && !is_timedout(start, 2000)) {}
} }
bool Sodaq_nbIOT::checkAndApplyNconfig() { bool Sodaq_nbIOT::checkAndApplyNconfig()
{
bool applyParam[nConfigCount]; bool applyParam[nConfigCount];
println("AT+NCONFIG?"); println("AT+NCONFIG?");
if (readResponse<bool, uint8_t>(_nconfigParser, applyParam, NULL) == ResponseOK) { if (readResponse<bool, uint8_t>(_nconfigParser, applyParam, NULL) == ResponseOK) {
for (uint8_t i = 0; i < nConfigCount; i++) { for (uint8_t i = 0; i < nConfigCount; i++)
{
debugPrint(nConfig[i].Name); debugPrint(nConfig[i].Name);
if (!applyParam[i]) { if (!applyParam[i]) {
debugPrintLn("... CHANGE"); debugPrintLn("... CHANGE");
@ -385,26 +424,28 @@ bool Sodaq_nbIOT::checkAndApplyNconfig() {
return false; return false;
} }
bool Sodaq_nbIOT::setNconfigParam(const char *param, const char *value) { bool Sodaq_nbIOT::setNconfigParam(const char* param, const char* value)
print("AT+NCONFIG="); {
print("AT+NCONFIG=\"");
print(param); print(param);
print(","); print("\",\"");
println(value); print(value);
println("\"");
return readResponse() == ResponseOK; return readResponse() == ResponseOK;
} }
ResponseTypes ResponseTypes Sodaq_nbIOT::_nconfigParser(ResponseTypes& response, const char* buffer, size_t size, bool* nconfigEqualsArray, uint8_t* dummy)
Sodaq_nbIOT::_nconfigParser(ResponseTypes &response, const char *buffer, size_t size, bool *nconfigEqualsArray, {
uint8_t *dummy) {
if (!nconfigEqualsArray) { if (!nconfigEqualsArray) {
return ResponseError; return ResponseError;
} }
char name[32]; char name[32];
char value[32]; char value[32];
if (sscanf(buffer, "+NCONFIG: %[^,],%[^\r]", name, value) == 2) { if (sscanf(buffer, "+NCONFIG: \"%[^\"]\",\"%[^\"]\"", name, value) == 2) {
for (uint8_t i = 0; i < nConfigCount; i++) { for (uint8_t i = 0; i < nConfigCount; i++)
{
if (strcmp(nConfig[i].Name, name) == 0) { if (strcmp(nConfig[i].Name, name) == 0) {
if (strcmp(nConfig[i].Value, value) == 0) { if (strcmp(nConfig[i].Value, value) == 0) {
nconfigEqualsArray[i] = true; nconfigEqualsArray[i] = true;
@ -420,16 +461,20 @@ Sodaq_nbIOT::_nconfigParser(ResponseTypes &response, const char *buffer, size_t
return ResponseError; return ResponseError;
} }
bool Sodaq_nbIOT::attachGprs(uint32_t timeout) { bool Sodaq_nbIOT::attachGprs(uint32_t timeout)
{
uint32_t start = millis(); uint32_t start = millis();
uint32_t delay_count = 500; uint32_t delay_count = 500;
while (!is_timedout(start, timeout)) { while (!is_timedout(start, timeout)) {
println("AT+CGATT=1"); if (isConnected()) {
if (readResponse() == ResponseOK) {
return true; return true;
} }
//println("AT+CGATT=1");
//if (readResponse() == ResponseOK) {
// return true;
//}
sodaq_wdt_safe_delay(delay_count); sodaq_wdt_safe_delay(delay_count);
@ -450,59 +495,74 @@ bool Sodaq_nbIOT::attachGprs(uint32_t timeout) {
* @param forceOperator * @param forceOperator
* @return * @return
*/ */
bool Sodaq_nbIOT::connectSocket() { bool Sodaq_nbIOT::connectSocket()
// if (!on()) { {
// return false; if (!on()) {
// } return false;
}
// if (!setRadioActive(false)) { purgeAllResponsesRead();
// return false;
// }
// if (!checkAndApplyNconfig()) { if (!setRadioActive(false)) {
// return false; return false;
// } }
if (!checkAndApplyNconfig()) {
return false;
}
reboot(); reboot();
//
// if (!on()) {
// return false;
// }
// TODO turn on if (!on()) {
// if (!setIndicationsActive(false)) { return false;
// return false; }
// }
// if (!setRadioActive(true)) { purgeAllResponsesRead();
// return false;
// }
// if (forceOperator && forceOperator[0] != '\0') { if (!setRadioActive(true)) {
// print("AT+COPS=1,2,\""); return false;
// print(forceOperator); }
// println("\"");
//
// if (readResponse() != ResponseOK) {
// return false;
// }
// }
// if (!waitForSignalQuality()) { println("AT+COPS=1,2,\"21630\"");
// return false; readResponse();
// }
// if (!attachGprs()) { bool registered = false;
// return 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 if (readResponse<bool, uint8_t>(_registeredParser, &registered, NULL) != ResponseOK) {
return true; 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) { int Sodaq_nbIOT::createSocket(uint16_t localPort) {
// only Datagram/UDP is supported print("AT+NSOCR=\"DGRAM\",17,");
print("AT+NSOCR=DGRAM,17,");
print(localPort); print(localPort);
println(",1"); // enable incoming message URC (NSONMI) println(",1"); // enable incoming message URC (NSONMI)
delay(500); delay(500);
@ -533,28 +593,26 @@ ResponseTypes Sodaq_nbIOT::_createSocketParser(ResponseTypes &response, const ch
return ResponseError; 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("AT+NSOST=");
print(socket); print(socket);
print(","); print(",\"");
print(host); print(host);
print(","); print("\",");
print(port); print(port);
print(","); print(",");
print(size); // why size? not encoded hex size? no idea... print(size); // why size? not encoded hex size? no idea...
print(","); print(",\"");
for (uint16_t i = 0; i < size; ++i) { for (uint16_t i = 0; i < size; ++i) {
print(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(buffer[i])))); print(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(buffer[i]))));
print(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(buffer[i])))); print(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(buffer[i]))));
} }
println(); println("\"");
delay(AT_CMD_SLEEP_TIME);
uint8_t sent; uint8_t sent;
if(readResponse<uint8_t, uint8_t>(_sendSocketParser, &socket, &sent) == ResponseOK) { return ((readResponse<uint8_t, uint8_t>(_sendSocketParser, &socket, &sent) == ResponseOK) && (sent > 0));
return sent;
}
return -1;
} }
ResponseTypes Sodaq_nbIOT::_sendSocketParser(ResponseTypes &response, const char *buffer, size_t size, 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 value;
int value2;
if (sscanf(buffer, "%d,%d", &value, &value2) == 2) {
*sent = value2;
if (sscanf(buffer, "%*d,%d", &value) == 1) {
*sent = value;
return ResponseEmpty; return ResponseEmpty;
} }
SerialUSB.println(F(__FILE__"sockparserr")); SerialUSB.println(F(__FILE__"sockparserr"));
@ -585,6 +641,7 @@ size_t Sodaq_nbIOT::socketReceive(uint8_t socket, char *buffer, size_t size) {
if (readResponse<uint8_t, char>(_socketReceiveParser, &socket, buffer, &size) == ResponseOK) { if (readResponse<uint8_t, char>(_socketReceiveParser, &socket, buffer, &size) == ResponseOK) {
debugPrintLn(__FILE__": socketReceive() OK"); debugPrintLn(__FILE__": socketReceive() OK");
_socketPendingBytes[socket] -= size;
return size; return size;
} }
debugPrintLn(__FILE__": socketReceive() ERR"); debugPrintLn(__FILE__": socketReceive() ERR");
@ -597,33 +654,23 @@ ResponseTypes Sodaq_nbIOT::_socketReceiveParser(ResponseTypes &response, const c
return ResponseError; return ResponseError;
} }
int tmp_sock = 0; int length = 0;
char tmp_ip[16] = ""; auto * resultBuffer = static_cast<char*>(malloc(250));
int tmp_port = 0; memset(resultBuffer, 0, 250);
int tpm_length = 0;
int tpm_length_rem = 0;
SerialUSB.println(__FILE__": _socketReceiveParser() sscanf"); SerialUSB.println(__FILE__": _socketReceiveParser() sscanf");
// <socket>,<ip_addr>,<port>,<length>,<data>,<remaining_length>
SerialUSB.println(__FILE__": _socketReceiveParser() buffer:");
SerialUSB.println(buffer);
/** /**
* create a result buffer for the HEX string input * create a result buffer for the HEX string input
* 250 is SODAQ_AT_DEVICE_DEFAULT_INPUT_BUFFER_SIZE defined in Sodaq_AT_Device.h * 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 * should probably refactor some more and move it to Sodaq_AT_Device.h
* we probably only need half of this (+1) * we probably only need half of this (+1)
*/ */
auto * resultBuffer = static_cast<char*>(malloc(250)); if (sscanf(buffer, R"(%*d,"%*[^"]",%*d,%d,"%[^"]",%*d)", &length, resultBuffer) == 2) {
memset(resultBuffer, 0, 250); for(int i=0; i < length;i++) {
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++) {
parsedBuffer[i] = HEX_PAIR_TO_BYTE(resultBuffer[i*2], resultBuffer[i*2+1]); parsedBuffer[i] = HEX_PAIR_TO_BYTE(resultBuffer[i*2], resultBuffer[i*2+1]);
} }
free(resultBuffer); free(resultBuffer);
SerialUSB.println(__FILE__": _socketReceiveParser() OK");
return ResponseEmpty; return ResponseEmpty;
} }
@ -633,20 +680,7 @@ ResponseTypes Sodaq_nbIOT::_socketReceiveParser(ResponseTypes &response, const c
} }
size_t Sodaq_nbIOT::socketBytesPending(uint8_t socket) { size_t Sodaq_nbIOT::socketBytesPending(uint8_t socket) {
return _socketPendingBytes[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;
}
} }
bool Sodaq_nbIOT::closeSocket(uint8_t 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. // Disconnects the modem from the network.
bool Sodaq_nbIOT::disconnect() { bool Sodaq_nbIOT::disconnect()
{
println("AT+CGATT=0"); println("AT+CGATT=0");
return (readResponse(NULL, 40000) == ResponseOK); return (readResponse(NULL, 40000) == ResponseOK);
} }
// Returns true if the modem is connected to the network and has an activated data connection. // 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; uint8_t value = 0;
println("AT+CGATT?"); println("AT+CGATT?");
@ -677,8 +713,9 @@ bool Sodaq_nbIOT::isConnected() {
// Gets the Received Signal Strength Indication in dBm and Bit Error Rate. // Gets the Received Signal Strength Indication in dBm and Bit Error Rate.
// Returns true if successful. // Returns true if successful.
bool Sodaq_nbIOT::getRSSIAndBER(int8_t *rssi, uint8_t *ber) { 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 {
static char berValues[] = { 49, 43, 37, 25, 19, 13, 7, 0 }; // 3GPP TS 45.008 [20] subclause 8.2.4
println("AT+CSQ"); println("AT+CSQ");
@ -703,23 +740,28 @@ bool Sodaq_nbIOT::getRSSIAndBER(int8_t *rssi, uint8_t *ber) {
31: -51 dBm or greater 31: -51 dBm or greater
99: not known or not detectable or currently not available 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; 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; 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); 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)); 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 segs = 0; // Segment count
uint8_t chcnt = 0; // Character count within segment uint8_t chcnt = 0; // Character count within segment
uint8_t accum = 0; // Accumulator for segment uint8_t accum = 0; // Accumulator for segment
@ -777,7 +819,8 @@ bool Sodaq_nbIOT::isValidIPv4(const char *str) {
return true; return true;
} }
bool Sodaq_nbIOT::waitForSignalQuality(uint32_t timeout) { bool Sodaq_nbIOT::waitForSignalQuality(uint32_t timeout)
{
uint32_t start = millis(); uint32_t start = millis();
const int8_t minRSSI = getMinRSSI(); const int8_t minRSSI = getMinRSSI();
int8_t rssi; int8_t rssi;
@ -789,7 +832,7 @@ bool Sodaq_nbIOT::waitForSignalQuality(uint32_t timeout) {
if (getRSSIAndBER(&rssi, &ber)) { if (getRSSIAndBER(&rssi, &ber)) {
if (rssi != 0 && rssi >= minRSSI) { if (rssi != 0 && rssi >= minRSSI) {
_lastRSSI = rssi; _lastRSSI = rssi;
_CSQtime = (int32_t) (millis() - start) / 1000; _CSQtime = (int32_t)(millis() - start) / 1000;
return true; return true;
} }
} }
@ -805,8 +848,8 @@ bool Sodaq_nbIOT::waitForSignalQuality(uint32_t timeout) {
return false; return false;
} }
ResponseTypes ResponseTypes Sodaq_nbIOT::_cgattParser(ResponseTypes& response, const char* buffer, size_t size, uint8_t* result, uint8_t* dummy)
Sodaq_nbIOT::_cgattParser(ResponseTypes &response, const char *buffer, size_t size, uint8_t *result, uint8_t *dummy) { {
if (!result) { if (!result) {
return ResponseError; return ResponseError;
} }
@ -820,8 +863,9 @@ Sodaq_nbIOT::_cgattParser(ResponseTypes &response, const char *buffer, size_t si
return ResponseError; return ResponseError;
} }
ResponseTypes Sodaq_nbIOT::_csqParser(ResponseTypes &response, const char *buffer, size_t size, ResponseTypes Sodaq_nbIOT::_csqParser(ResponseTypes& response, const char* buffer, size_t size,
int *rssi, int *ber) { int* rssi, int* ber)
{
if (!rssi || !ber) { if (!rssi || !ber) {
return ResponseError; return ResponseError;
} }
@ -833,26 +877,28 @@ ResponseTypes Sodaq_nbIOT::_csqParser(ResponseTypes &response, const char *buffe
return ResponseError; 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) { if (size > 512) {
return false; return false;
} }
print("AT+NMGS="); print("AT+NMGS=");
print(size); print(size);
print(","); print(",\"");
for (uint16_t i = 0; i < size; ++i) { for (uint16_t i = 0; i < size; ++i) {
print(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(buffer[i])))); print(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(buffer[i]))));
print(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(buffer[i])))); print(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(buffer[i]))));
} }
println(); println("\"");
return (readResponse() == ResponseOK); return (readResponse() == ResponseOK);
} }
int Sodaq_nbIOT::getSentMessagesCount(SentMessageStatus filter) { int Sodaq_nbIOT::getSentMessagesCount(SentMessageStatus filter)
{
println("AT+NQMGS"); println("AT+NQMGS");
uint16_t pendingCount = 0; uint16_t pendingCount = 0;
@ -869,9 +915,8 @@ int Sodaq_nbIOT::getSentMessagesCount(SentMessageStatus filter) {
return -1; return -1;
} }
ResponseTypes ResponseTypes Sodaq_nbIOT::_nqmgsParser(ResponseTypes& response, const char* buffer, size_t size, uint16_t* pendingCount, uint16_t* errorCount)
Sodaq_nbIOT::_nqmgsParser(ResponseTypes &response, const char *buffer, size_t size, uint16_t *pendingCount, {
uint16_t *errorCount) {
if (!pendingCount || !errorCount) { if (!pendingCount || !errorCount) {
return ResponseError; return ResponseError;
} }
@ -889,24 +934,28 @@ Sodaq_nbIOT::_nqmgsParser(ResponseTypes &response, const char *buffer, size_t si
return ResponseError; return ResponseError;
} }
bool Sodaq_nbIOT::sendMessage(const char *str) { bool Sodaq_nbIOT::sendMessage(const char* str)
return sendMessage((const uint8_t *) str, strlen(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()); return sendMessage(str.c_str());
} }
// ============================== // ==============================
// on/off class // on/off class
// ============================== // ==============================
Sodaq_nbIotOnOff::Sodaq_nbIotOnOff() { Sodaq_nbIotOnOff::Sodaq_nbIotOnOff()
{
_onoffPin = -1; _onoffPin = -1;
_onoff_status = false; _onoff_status = false;
} }
// Initializes the instance // Initializes the instance
void Sodaq_nbIotOnOff::init(int onoffPin) { void Sodaq_nbIotOnOff::init(int onoffPin)
{
if (onoffPin >= 0) { if (onoffPin >= 0) {
_onoffPin = onoffPin; _onoffPin = onoffPin;
// First write the output value, and only then set the output mode. // 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) { if (_onoffPin >= 0) {
digitalWrite(_onoffPin, HIGH); digitalWrite(_onoffPin, HIGH);
} }
@ -923,7 +973,8 @@ void Sodaq_nbIotOnOff::on() {
_onoff_status = true; _onoff_status = true;
} }
void Sodaq_nbIotOnOff::off() { void Sodaq_nbIotOnOff::off()
{
// The GPRSbee is switched off immediately // The GPRSbee is switched off immediately
if (_onoffPin >= 0) { if (_onoffPin >= 0) {
digitalWrite(_onoffPin, LOW); digitalWrite(_onoffPin, LOW);
@ -935,7 +986,8 @@ void Sodaq_nbIotOnOff::off() {
_onoff_status = false; _onoff_status = false;
} }
bool Sodaq_nbIotOnOff::isOn() { bool Sodaq_nbIotOnOff::isOn()
{
#if defined(ARDUINO_ARCH_AVR) #if defined(ARDUINO_ARCH_AVR)
// Use the onoff pin, which is close to useless // Use the onoff pin, which is close to useless
bool status = digitalRead(_onoffPin); bool status = digitalRead(_onoffPin);

View File

@ -24,6 +24,8 @@
#include "Arduino.h" #include "Arduino.h"
#include "Sodaq_AT_Device.h" #include "Sodaq_AT_Device.h"
#define SOCKET_COUNT 7
class Sodaq_nbIOT: public Sodaq_AT_Device class Sodaq_nbIOT: public Sodaq_AT_Device
{ {
public: public:
@ -73,9 +75,9 @@ class Sodaq_nbIOT: public Sodaq_AT_Device
uint8_t getCSQtime() const { return _CSQtime; } uint8_t getCSQtime() const { return _CSQtime; }
int8_t getLastRSSI() const { return _lastRSSI; } int8_t getLastRSSI() const { return _lastRSSI; }
bool connectSocket();
int createSocket(uint16_t localPort = 0); 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 socketReceive(uint8_t socket, char* buffer, size_t size);
size_t socketBytesPending(uint8_t socket); size_t socketBytesPending(uint8_t socket);
bool closeSocket(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*)callbackParameter, (void*)callbackParameter2, outSize, timeout);
}; };
void purgeAllResponsesRead();
private: private:
//uint16_t _socketPendingBytes[SOCKET_COUNT]; // TODO add getter uint16_t _socketPendingBytes[SOCKET_COUNT]; // TODO add getter
//bool _socketClosedBit[SOCKET_COUNT]; //bool _socketClosedBit[SOCKET_COUNT];
// This is the value of the most recent CSQ // This is the value of the most recent CSQ
@ -150,6 +153,8 @@ class Sodaq_nbIOT: public Sodaq_AT_Device
void reboot(); void reboot();
static ResponseTypes _csqParser(ResponseTypes& response, const char* buffer, size_t size, int* rssi, int* ber); 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, static ResponseTypes _createSocketParser(ResponseTypes& response, const char* buffer, size_t size,
uint8_t* socket, uint8_t* dummy); uint8_t* socket, uint8_t* dummy);
static ResponseTypes _sendSocketParser(ResponseTypes &response, const char *buffer, size_t size, static ResponseTypes _sendSocketParser(ResponseTypes &response, const char *buffer, size_t size,