* 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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<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);
|
||||
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<bool, uint8_t>(_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<char>(NIBBLE_TO_HEX_CHAR(HIGH_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;
|
||||
if(readResponse<uint8_t, uint8_t>(_sendSocketParser, &socket, &sent) == ResponseOK) {
|
||||
return sent;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return ((readResponse<uint8_t, uint8_t>(_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<uint8_t, char>(_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<char*>(malloc(250));
|
||||
memset(resultBuffer, 0, 250);
|
||||
|
||||
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
|
||||
* 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<char*>(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<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(buffer[i]))));
|
||||
print(static_cast<char>(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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user