diff --git a/src/sfe_ublox_cellular.cpp b/src/sfe_ublox_cellular.cpp index 484973c..6d61078 100644 --- a/src/sfe_ublox_cellular.cpp +++ b/src/sfe_ublox_cellular.cpp @@ -53,6 +53,21 @@ UBX_CELL::UBX_CELL(int powerPin, int resetPin, uint8_t maxInitTries) _saraRXBuffer = nullptr; _pruneBuffer = nullptr; _saraResponseBacklog = nullptr; + + // Add base URC handlers + addURCHandler(UBX_CELL_READ_SOCKET_URC, [this](const char* event){return this->urcHandlerReadSocket(event);}); + addURCHandler(UBX_CELL_READ_UDP_SOCKET_URC, [this](const char* event){return this->urcHandlerReadUDPSocket(event);}); + addURCHandler(UBX_CELL_LISTEN_SOCKET_URC, [this](const char* event){return this->urcHandlerListeningSocket(event);}); + addURCHandler(UBX_CELL_CLOSE_SOCKET_URC, [this](const char* event){return this->urcHandlerCloseSocket(event);}); + addURCHandler(UBX_CELL_GNSS_REQUEST_LOCATION_URC, [this](const char* event){return this->urcHandlerGNSSRequestLocation(event);}); + addURCHandler(UBX_CELL_SIM_STATE_URC, [this](const char* event){return this->urcHandlerSIMState(event);}); + addURCHandler(UBX_CELL_MESSAGE_PDP_ACTION_URC, [this](const char* event){return this->urcHandlerPDPAction(event);}); + addURCHandler(UBX_CELL_HTTP_COMMAND_URC, [this](const char* event){return this->urcHandlerHTTPCommand(event);}); + addURCHandler(UBX_CELL_MQTT_COMMAND_URC, [this](const char* event){return this->urcHandlerMQTTCommand(event);}); + addURCHandler(UBX_CELL_PING_COMMAND_URC, [this](const char* event){return this->urcHandlerPingCommand(event);}); + addURCHandler(UBX_CELL_FTP_COMMAND_URC, [this](const char* event){return this->urcHandlerFTPCommand(event);}); + addURCHandler(UBX_CELL_REGISTRATION_STATUS_URC, [this](const char* event){return this->urcHandlerRegistrationStatus(event);}); + addURCHandler(UBX_CELL_EPSREGISTRATION_STATUS_URC, [this](const char* event){return this->urcHandlerEPSRegistrationStatus(event);}); } UBX_CELL::~UBX_CELL(void) { @@ -313,445 +328,525 @@ bool UBX_CELL::bufferedPoll(void) return handled; } // /bufferedPoll -// Parse incoming URC's - the associated parse functions pass the data to the user via the callbacks (if defined) -bool UBX_CELL::processURCEvent(const char *event) +bool UBX_CELL::urcHandlerReadSocket(const char* event) { - { // URC: +UUSORD (Read Socket Data) - int socket, length; - char *searchPtr = strstr(event, UBX_CELL_READ_SOCKET_URC); - if (searchPtr != nullptr) + // URC: +UUSORD (Read Socket Data) + int socket, length; + char *searchPtr = strstr(event, UBX_CELL_READ_SOCKET_URC); + if (searchPtr != nullptr) + { + searchPtr += strlen(UBX_CELL_READ_SOCKET_URC); // Move searchPtr to first character - probably a space + while (*searchPtr == ' ') searchPtr++; // Skip spaces + int ret = sscanf(searchPtr, "%d,%d", &socket, &length); + if (ret == 2) { - searchPtr += strlen(UBX_CELL_READ_SOCKET_URC); // Move searchPtr to first character - probably a space - while (*searchPtr == ' ') searchPtr++; // Skip spaces - int ret = sscanf(searchPtr, "%d,%d", &socket, &length); - if (ret == 2) + if (_printDebug == true) + _debugPort->println(F("processReadEvent: read socket data")); + // From the UBX_CELL AT Commands Manual: + // "For the UDP socket type the URC +UUSORD: , notifies that a UDP packet has been received, + // either when buffer is empty or after a UDP packet has been read and one or more packets are stored in the + // buffer." + // So we need to check if this is a TCP socket or a UDP socket: + // If UDP, we call parseSocketReadIndicationUDP. + // Otherwise, we call parseSocketReadIndication. + if (_lastSocketProtocol[socket] == UBX_CELL_UDP) { if (_printDebug == true) - _debugPort->println(F("processReadEvent: read socket data")); - // From the UBX_CELL AT Commands Manual: - // "For the UDP socket type the URC +UUSORD: , notifies that a UDP packet has been received, - // either when buffer is empty or after a UDP packet has been read and one or more packets are stored in the - // buffer." - // So we need to check if this is a TCP socket or a UDP socket: - // If UDP, we call parseSocketReadIndicationUDP. - // Otherwise, we call parseSocketReadIndication. - if (_lastSocketProtocol[socket] == UBX_CELL_UDP) - { - if (_printDebug == true) - _debugPort->println(F("processReadEvent: received +UUSORD but socket is UDP. Calling parseSocketReadIndicationUDP")); - parseSocketReadIndicationUDP(socket, length); - } - else - parseSocketReadIndication(socket, length); - return true; + _debugPort->println(F("processReadEvent: received +UUSORD but socket is UDP. Calling parseSocketReadIndicationUDP")); + parseSocketReadIndicationUDP(socket, length); } + else + parseSocketReadIndication(socket, length); + return true; } } - { // URC: +UUSORF (Receive From command (UDP only)) - int socket, length; - char *searchPtr = strstr(event, UBX_CELL_READ_UDP_SOCKET_URC); - if (searchPtr != nullptr) + + return false; +} + +bool UBX_CELL::urcHandlerReadUDPSocket(const char* event) +{ + // URC: +UUSORF (Receive From command (UDP only)) + int socket, length; + char *searchPtr = strstr(event, UBX_CELL_READ_UDP_SOCKET_URC); + if (searchPtr != nullptr) + { + searchPtr += strlen(UBX_CELL_READ_UDP_SOCKET_URC); // Move searchPtr to first character - probably a space + while (*searchPtr == ' ') searchPtr++; // skip spaces + int ret = sscanf(searchPtr, "%d,%d", &socket, &length); + if (ret == 2) { - searchPtr += strlen(UBX_CELL_READ_UDP_SOCKET_URC); // Move searchPtr to first character - probably a space - while (*searchPtr == ' ') searchPtr++; // skip spaces - int ret = sscanf(searchPtr, "%d,%d", &socket, &length); - if (ret == 2) - { - if (_printDebug == true) - _debugPort->println(F("processReadEvent: UDP receive")); - parseSocketReadIndicationUDP(socket, length); - return true; - } + if (_printDebug == true) + _debugPort->println(F("processReadEvent: UDP receive")); + parseSocketReadIndicationUDP(socket, length); + return true; } } - { // URC: +UUSOLI (Set Listening Socket) - int socket = 0; - int listenSocket = 0; - unsigned int port = 0; - unsigned int listenPort = 0; - IPAddress remoteIP = {0,0,0,0}; - IPAddress localIP = {0,0,0,0}; - int remoteIPstore[4] = {0,0,0,0}; - int localIPstore[4] = {0,0,0,0}; - char *searchPtr = strstr(event, UBX_CELL_LISTEN_SOCKET_URC); - if (searchPtr != nullptr) + return false; +} + +bool UBX_CELL::urcHandlerListeningSocket(const char* event) +{ + // URC: +UUSOLI (Set Listening Socket) + int socket = 0; + int listenSocket = 0; + unsigned int port = 0; + unsigned int listenPort = 0; + IPAddress remoteIP = {0,0,0,0}; + IPAddress localIP = {0,0,0,0}; + int remoteIPstore[4] = {0,0,0,0}; + int localIPstore[4] = {0,0,0,0}; + + char *searchPtr = strstr(event, UBX_CELL_LISTEN_SOCKET_URC); + if (searchPtr != nullptr) + { + searchPtr += strlen(UBX_CELL_LISTEN_SOCKET_URC); // Move searchPtr to first character - probably a space + while (*searchPtr == ' ') searchPtr++; // skip spaces + int ret = sscanf(searchPtr, + "%d,\"%d.%d.%d.%d\",%u,%d,\"%d.%d.%d.%d\",%u", + &socket, + &remoteIPstore[0], &remoteIPstore[1], &remoteIPstore[2], &remoteIPstore[3], + &port, &listenSocket, + &localIPstore[0], &localIPstore[1], &localIPstore[2], &localIPstore[3], + &listenPort); + for (int i = 0; i <= 3; i++) { - searchPtr += strlen(UBX_CELL_LISTEN_SOCKET_URC); // Move searchPtr to first character - probably a space - while (*searchPtr == ' ') searchPtr++; // skip spaces - int ret = sscanf(searchPtr, - "%d,\"%d.%d.%d.%d\",%u,%d,\"%d.%d.%d.%d\",%u", - &socket, - &remoteIPstore[0], &remoteIPstore[1], &remoteIPstore[2], &remoteIPstore[3], - &port, &listenSocket, - &localIPstore[0], &localIPstore[1], &localIPstore[2], &localIPstore[3], - &listenPort); - for (int i = 0; i <= 3; i++) - { - if (ret >= 5) - remoteIP[i] = (uint8_t)remoteIPstore[i]; - if (ret >= 11) - localIP[i] = (uint8_t)localIPstore[i]; - } if (ret >= 5) - { - if (_printDebug == true) - _debugPort->println(F("processReadEvent: socket listen")); - parseSocketListenIndication(listenSocket, localIP, listenPort, socket, remoteIP, port); - return true; - } + remoteIP[i] = (uint8_t)remoteIPstore[i]; + if (ret >= 11) + localIP[i] = (uint8_t)localIPstore[i]; + } + if (ret >= 5) + { + if (_printDebug == true) + _debugPort->println(F("processReadEvent: socket listen")); + parseSocketListenIndication(listenSocket, localIP, listenPort, socket, remoteIP, port); + return true; } } - { // URC: +UUSOCL (Close Socket) - int socket; - char *searchPtr = strstr(event, UBX_CELL_CLOSE_SOCKET_URC); - if (searchPtr != nullptr) + + return false; +} + +bool UBX_CELL::urcHandlerCloseSocket(const char* event) +{ + // URC: +UUSOCL (Close Socket) + int socket; + char *searchPtr = strstr(event, UBX_CELL_CLOSE_SOCKET_URC); + if (searchPtr != nullptr) + { + searchPtr += strlen(UBX_CELL_CLOSE_SOCKET_URC); // Move searchPtr to first character - probably a space + while (*searchPtr == ' ') searchPtr++; // skip spaces + int ret = sscanf(searchPtr, "%d", &socket); + if (ret == 1) { - searchPtr += strlen(UBX_CELL_CLOSE_SOCKET_URC); // Move searchPtr to first character - probably a space - while (*searchPtr == ' ') searchPtr++; // skip spaces - int ret = sscanf(searchPtr, "%d", &socket); - if (ret == 1) + if (_printDebug == true) + _debugPort->println(F("processReadEvent: socket close")); + if ((socket >= 0) && (socket <= 6)) { - if (_printDebug == true) - _debugPort->println(F("processReadEvent: socket close")); - if ((socket >= 0) && (socket <= 6)) + if (_socketCloseCallback != nullptr) { - if (_socketCloseCallback != nullptr) - { - _socketCloseCallback(socket); - } + _socketCloseCallback(socket); } - return true; } + return true; } } - { // URC: +UULOC (Localization information - CellLocate and hybrid positioning) - ClockData clck; - PositionData gps; - SpeedData spd; - unsigned long uncertainty; - int scanNum; - int latH, lonH, alt; - unsigned int speedU, cogU; - char latL[10], lonL[10]; - int dateStore[5]; - // Maybe we should also scan for +UUGIND and extract the activated gnss system? + return false; +} - // This assumes the ULOC response type is "0" or "1" - as selected by gpsRequest detailed - char *searchPtr = strstr(event, UBX_CELL_GNSS_REQUEST_LOCATION_URC); - if (searchPtr != nullptr) - { - searchPtr += strlen(UBX_CELL_GNSS_REQUEST_LOCATION_URC); // Move searchPtr to first character - probably a space - while (*searchPtr == ' ') searchPtr++; // skip spaces - scanNum = sscanf(searchPtr, - "%d/%d/%d,%d:%d:%d.%d,%d.%[^,],%d.%[^,],%d,%lu,%u,%u,%*s", - &dateStore[0], &dateStore[1], &clck.date.year, - &dateStore[2], &dateStore[3], &dateStore[4], &clck.time.ms, - &latH, latL, &lonH, lonL, &alt, &uncertainty, - &speedU, &cogU); - clck.date.day = dateStore[0]; - clck.date.month = dateStore[1]; - clck.time.hour = dateStore[2]; - clck.time.minute = dateStore[3]; - clck.time.second = dateStore[4]; - - if (scanNum >= 13) +bool UBX_CELL::urcHandlerGNSSRequestLocation(const char* event) +{ + // URC: +UULOC (Localization information - CellLocate and hybrid positioning) + ClockData clck; + PositionData gps; + SpeedData spd; + unsigned long uncertainty; + int scanNum; + int latH, lonH, alt; + unsigned int speedU, cogU; + char latL[10], lonL[10]; + int dateStore[5]; + + // Maybe we should also scan for +UUGIND and extract the activated gnss system? + + // This assumes the ULOC response type is "0" or "1" - as selected by gpsRequest detailed + char *searchPtr = strstr(event, UBX_CELL_GNSS_REQUEST_LOCATION_URC); + if (searchPtr != nullptr) + { + searchPtr += strlen(UBX_CELL_GNSS_REQUEST_LOCATION_URC); // Move searchPtr to first character - probably a space + while (*searchPtr == ' ') searchPtr++; // skip spaces + scanNum = sscanf(searchPtr, + "%d/%d/%d,%d:%d:%d.%d,%d.%[^,],%d.%[^,],%d,%lu,%u,%u,%*s", + &dateStore[0], &dateStore[1], &clck.date.year, + &dateStore[2], &dateStore[3], &dateStore[4], &clck.time.ms, + &latH, latL, &lonH, lonL, &alt, &uncertainty, + &speedU, &cogU); + clck.date.day = dateStore[0]; + clck.date.month = dateStore[1]; + clck.time.hour = dateStore[2]; + clck.time.minute = dateStore[3]; + clck.time.second = dateStore[4]; + + if (scanNum >= 13) + { + // Found a Location string! + if (_printDebug == true) { - // Found a Location string! - if (_printDebug == true) - { - _debugPort->println(F("processReadEvent: location")); - } + _debugPort->println(F("processReadEvent: location")); + } - if (latH >= 0) - gps.lat = (float)latH + ((float)atol(latL) / pow(10, strlen(latL))); - else - gps.lat = (float)latH - ((float)atol(latL) / pow(10, strlen(latL))); - if (lonH >= 0) - gps.lon = (float)lonH + ((float)atol(lonL) / pow(10, strlen(lonL))); - else - gps.lon = (float)lonH - ((float)atol(lonL) / pow(10, strlen(lonL))); - gps.alt = (float)alt; - if (scanNum >= 15) // If detailed response, get speed data - { - spd.speed = (float)speedU; - spd.cog = (float)cogU; - } + if (latH >= 0) + gps.lat = (float)latH + ((float)atol(latL) / pow(10, strlen(latL))); + else + gps.lat = (float)latH - ((float)atol(latL) / pow(10, strlen(latL))); + if (lonH >= 0) + gps.lon = (float)lonH + ((float)atol(lonL) / pow(10, strlen(lonL))); + else + gps.lon = (float)lonH - ((float)atol(lonL) / pow(10, strlen(lonL))); + gps.alt = (float)alt; + if (scanNum >= 15) // If detailed response, get speed data + { + spd.speed = (float)speedU; + spd.cog = (float)cogU; + } - // if (_printDebug == true) - // { - // _debugPort->print(F("processReadEvent: location: lat: ")); - // _debugPort->print(gps.lat, 7); - // _debugPort->print(F(" lon: ")); - // _debugPort->print(gps.lon, 7); - // _debugPort->print(F(" alt: ")); - // _debugPort->print(gps.alt, 2); - // _debugPort->print(F(" speed: ")); - // _debugPort->print(spd.speed, 2); - // _debugPort->print(F(" cog: ")); - // _debugPort->println(spd.cog, 2); - // } - - if (_gpsRequestCallback != nullptr) - { - _gpsRequestCallback(clck, gps, spd, uncertainty); - } + // if (_printDebug == true) + // { + // _debugPort->print(F("processReadEvent: location: lat: ")); + // _debugPort->print(gps.lat, 7); + // _debugPort->print(F(" lon: ")); + // _debugPort->print(gps.lon, 7); + // _debugPort->print(F(" alt: ")); + // _debugPort->print(gps.alt, 2); + // _debugPort->print(F(" speed: ")); + // _debugPort->print(spd.speed, 2); + // _debugPort->print(F(" cog: ")); + // _debugPort->println(spd.cog, 2); + // } - return true; + if (_gpsRequestCallback != nullptr) + { + _gpsRequestCallback(clck, gps, spd, uncertainty); } + + return true; } } - { // URC: +UUSIMSTAT (SIM Status) - UBX_CELL_sim_states_t state; - int scanNum; - int stateStore; - char *searchPtr = strstr(event, UBX_CELL_SIM_STATE_URC); - if (searchPtr != nullptr) - { - searchPtr += strlen(UBX_CELL_SIM_STATE_URC); // Move searchPtr to first character - probably a space - while (*searchPtr == ' ') searchPtr++; // skip spaces - scanNum = sscanf(searchPtr, "%d", &stateStore); + return false; +} - if (scanNum == 1) - { - if (_printDebug == true) - _debugPort->println(F("processReadEvent: SIM status")); +bool UBX_CELL::urcHandlerSIMState(const char* event) +{ + // URC: +UUSIMSTAT (SIM Status) + UBX_CELL_sim_states_t state; + int scanNum; + int stateStore; - state = (UBX_CELL_sim_states_t)stateStore; + char *searchPtr = strstr(event, UBX_CELL_SIM_STATE_URC); + if (searchPtr != nullptr) + { + searchPtr += strlen(UBX_CELL_SIM_STATE_URC); // Move searchPtr to first character - probably a space + while (*searchPtr == ' ') searchPtr++; // skip spaces + scanNum = sscanf(searchPtr, "%d", &stateStore); - if (_simStateReportCallback != nullptr) - { - _simStateReportCallback(state); - } + if (scanNum == 1) + { + if (_printDebug == true) + _debugPort->println(F("processReadEvent: SIM status")); - return true; + state = (UBX_CELL_sim_states_t)stateStore; + + if (_simStateReportCallback != nullptr) + { + _simStateReportCallback(state); } + + return true; } } - { // URC: +UUPSDA (Packet Switched Data Action) - int result; - IPAddress remoteIP = {0, 0, 0, 0}; - int scanNum; - int remoteIPstore[4]; - char *searchPtr = strstr(event, UBX_CELL_MESSAGE_PDP_ACTION_URC); - if (searchPtr != nullptr) - { - searchPtr += strlen(UBX_CELL_MESSAGE_PDP_ACTION_URC); // Move searchPtr to first character - probably a space - while (*searchPtr == ' ') searchPtr++; // skip spaces - scanNum = sscanf(searchPtr, "%d,\"%d.%d.%d.%d\"", - &result, &remoteIPstore[0], &remoteIPstore[1], &remoteIPstore[2], &remoteIPstore[3]); + return false; +} - if (scanNum == 5) - { - if (_printDebug == true) - _debugPort->println(F("processReadEvent: packet switched data action")); +bool UBX_CELL::urcHandlerPDPAction(const char* event) +{ + // URC: +UUPSDA (Packet Switched Data Action) + int result; + IPAddress remoteIP = {0, 0, 0, 0}; + int scanNum; + int remoteIPstore[4]; - for (int i = 0; i <= 3; i++) - { - remoteIP[i] = (uint8_t)remoteIPstore[i]; - } + char *searchPtr = strstr(event, UBX_CELL_MESSAGE_PDP_ACTION_URC); + if (searchPtr != nullptr) + { + searchPtr += strlen(UBX_CELL_MESSAGE_PDP_ACTION_URC); // Move searchPtr to first character - probably a space + while (*searchPtr == ' ') searchPtr++; // skip spaces + scanNum = sscanf(searchPtr, "%d,\"%d.%d.%d.%d\"", + &result, &remoteIPstore[0], &remoteIPstore[1], &remoteIPstore[2], &remoteIPstore[3]); - if (_psdActionRequestCallback != nullptr) - { - _psdActionRequestCallback(result, remoteIP); - } + if (scanNum == 5) + { + if (_printDebug == true) + _debugPort->println(F("processReadEvent: packet switched data action")); + + for (int i = 0; i <= 3; i++) + { + remoteIP[i] = (uint8_t)remoteIPstore[i]; + } - return true; + if (_psdActionRequestCallback != nullptr) + { + _psdActionRequestCallback(result, remoteIP); } + + return true; } } - { // URC: +UUHTTPCR (HTTP Command Result) - int profile, command, result; - int scanNum; - char *searchPtr = strstr(event, UBX_CELL_HTTP_COMMAND_URC); - if (searchPtr != nullptr) + return false; +} + +bool UBX_CELL::urcHandlerHTTPCommand(const char* event) +{ + // URC: +UUHTTPCR (HTTP Command Result) + int profile, command, result; + int scanNum; + + char *searchPtr = strstr(event, UBX_CELL_HTTP_COMMAND_URC); + if (searchPtr != nullptr) + { + searchPtr += strlen(UBX_CELL_HTTP_COMMAND_URC); // Move searchPtr to first character - probably a space + while (*searchPtr == ' ') searchPtr++; // skip spaces + scanNum = sscanf(searchPtr, "%d,%d,%d", &profile, &command, &result); + + if (scanNum == 3) { - searchPtr += strlen(UBX_CELL_HTTP_COMMAND_URC); // Move searchPtr to first character - probably a space - while (*searchPtr == ' ') searchPtr++; // skip spaces - scanNum = sscanf(searchPtr, "%d,%d,%d", &profile, &command, &result); + if (_printDebug == true) + _debugPort->println(F("processReadEvent: HTTP command result")); - if (scanNum == 3) + if ((profile >= 0) && (profile < UBX_CELL_NUM_HTTP_PROFILES)) { - if (_printDebug == true) - _debugPort->println(F("processReadEvent: HTTP command result")); - - if ((profile >= 0) && (profile < UBX_CELL_NUM_HTTP_PROFILES)) + if (_httpCommandRequestCallback != nullptr) { - if (_httpCommandRequestCallback != nullptr) - { - _httpCommandRequestCallback(profile, command, result); - } + _httpCommandRequestCallback(profile, command, result); } - - return true; } + + return true; } } - { // URC: +UUMQTTC (MQTT Command Result) - int command, result; - int scanNum; - int qos = -1; - String topic; - char *searchPtr = strstr(event, UBX_CELL_MQTT_COMMAND_URC); - if (searchPtr != nullptr) - { - searchPtr += strlen(UBX_CELL_MQTT_COMMAND_URC); // Move searchPtr to first character - probably a space - while (*searchPtr == ' ') - { - searchPtr++; // skip spaces - } + return false; +} - scanNum = sscanf(searchPtr, "%d,%d", &command, &result); - if ((scanNum == 2) && (command == UBX_CELL_MQTT_COMMAND_SUBSCRIBE)) - { - char topicC[100] = ""; - scanNum = sscanf(searchPtr, "%*d,%*d,%d,\"%[^\"]\"", &qos, topicC); - topic = topicC; - } - if ((scanNum == 2) || (scanNum == 4)) - { - if (_printDebug == true) - { - _debugPort->println(F("processReadEvent: MQTT command result")); - } +bool UBX_CELL::urcHandlerMQTTCommand(const char* event) +{ + // URC: +UUMQTTC (MQTT Command Result) + int command, result; + int scanNum; + int qos = -1; + String topic; - if (_mqttCommandRequestCallback != nullptr) - { - _mqttCommandRequestCallback(command, result); - } + char *searchPtr = strstr(event, UBX_CELL_MQTT_COMMAND_URC); + if (searchPtr != nullptr) + { + searchPtr += strlen(UBX_CELL_MQTT_COMMAND_URC); // Move searchPtr to first character - probably a space + while (*searchPtr == ' ') + { + searchPtr++; // skip spaces + } - return true; - } + scanNum = sscanf(searchPtr, "%d,%d", &command, &result); + if ((scanNum == 2) && (command == UBX_CELL_MQTT_COMMAND_SUBSCRIBE)) + { + char topicC[100] = ""; + scanNum = sscanf(searchPtr, "%*d,%*d,%d,\"%[^\"]\"", &qos, topicC); + topic = topicC; } - } - { // URC: +UUFTPCR (FTP Command Result) - int ftpCmd; - int ftpResult; - int scanNum; - char *searchPtr = strstr(event, UBX_CELL_FTP_COMMAND_URC); - if (searchPtr != nullptr) + if ((scanNum == 2) || (scanNum == 4)) { - searchPtr += strlen(UBX_CELL_FTP_COMMAND_URC); // Move searchPtr to first character - probably a space - while (*searchPtr == ' ') + if (_printDebug == true) { - searchPtr++; // skip spaces + _debugPort->println(F("processReadEvent: MQTT command result")); } - scanNum = sscanf(searchPtr, "%d,%d", &ftpCmd, &ftpResult); - if (scanNum == 2 && _ftpCommandRequestCallback != nullptr) + if (_mqttCommandRequestCallback != nullptr) { - _ftpCommandRequestCallback(ftpCmd, ftpResult); - return true; + _mqttCommandRequestCallback(command, result); } + + return true; } } - { // URC: +UUPING (Ping Result) - int retry = 0; - int p_size = 0; - int ttl = 0; - String remote_host = ""; - IPAddress remoteIP = {0, 0, 0, 0}; - long rtt = 0; - int scanNum; - // Try to extract the UUPING retries and payload size - char *searchPtr = strstr(event, UBX_CELL_PING_COMMAND_URC); - if (searchPtr != nullptr) - { - searchPtr += strlen(UBX_CELL_PING_COMMAND_URC); // Move searchPtr to first character - probably a space - while (*searchPtr == ' ') searchPtr++; // skip spaces - scanNum = sscanf(searchPtr, "%d,%d,", &retry, &p_size); + return false; +} - if (scanNum == 2) +bool UBX_CELL::urcHandlerPingCommand(const char* event) +{ + // URC: +UUPING (Ping Result) + int retry = 0; + int p_size = 0; + int ttl = 0; + String remote_host = ""; + IPAddress remoteIP = {0, 0, 0, 0}; + long rtt = 0; + int scanNum; + + // Try to extract the UUPING retries and payload size + char *searchPtr = strstr(event, UBX_CELL_PING_COMMAND_URC); + if (searchPtr != nullptr) + { + searchPtr += strlen(UBX_CELL_PING_COMMAND_URC); // Move searchPtr to first character - probably a space + while (*searchPtr == ' ') searchPtr++; // skip spaces + scanNum = sscanf(searchPtr, "%d,%d,", &retry, &p_size); + + if (scanNum == 2) + { + if (_printDebug == true) { - if (_printDebug == true) - { - _debugPort->println(F("processReadEvent: ping")); - } + _debugPort->println(F("processReadEvent: ping")); + } + + searchPtr = strchr(++searchPtr, '\"'); // Search to the first quote - searchPtr = strchr(++searchPtr, '\"'); // Search to the first quote + // Extract the remote host name, stop at the next quote + while ((*(++searchPtr) != '\"') && (*searchPtr != '\0')) + { + remote_host.concat(*(searchPtr)); + } - // Extract the remote host name, stop at the next quote - while ((*(++searchPtr) != '\"') && (*searchPtr != '\0')) + if (*searchPtr != '\0') // Make sure we found a quote + { + int remoteIPstore[4]; + scanNum = sscanf(searchPtr, "\",\"%d.%d.%d.%d\",%d,%ld", + &remoteIPstore[0], &remoteIPstore[1], &remoteIPstore[2], &remoteIPstore[3], &ttl, &rtt); + for (int i = 0; i <= 3; i++) { - remote_host.concat(*(searchPtr)); + remoteIP[i] = (uint8_t)remoteIPstore[i]; } - if (*searchPtr != '\0') // Make sure we found a quote + if (scanNum == 6) // Make sure we extracted enough data { - int remoteIPstore[4]; - scanNum = sscanf(searchPtr, "\",\"%d.%d.%d.%d\",%d,%ld", - &remoteIPstore[0], &remoteIPstore[1], &remoteIPstore[2], &remoteIPstore[3], &ttl, &rtt); - for (int i = 0; i <= 3; i++) + if (_pingRequestCallback != nullptr) { - remoteIP[i] = (uint8_t)remoteIPstore[i]; - } - - if (scanNum == 6) // Make sure we extracted enough data - { - if (_pingRequestCallback != nullptr) - { - _pingRequestCallback(retry, p_size, remote_host, remoteIP, ttl, rtt); - } + _pingRequestCallback(retry, p_size, remote_host, remoteIP, ttl, rtt); } } - return true; } + return true; } } - { // URC: +CREG - int status = 0; - unsigned int lac = 0, ci = 0, Act = 0; - char *searchPtr = strstr(event, UBX_CELL_REGISTRATION_STATUS_URC); - if (searchPtr != nullptr) + + return false; +} + +bool UBX_CELL::urcHandlerFTPCommand(const char* event) +{ + // URC: +UUFTPCR (FTP Command Result) + int ftpCmd; + int ftpResult; + int scanNum; + char *searchPtr = strstr(event, UBX_CELL_FTP_COMMAND_URC); + if (searchPtr != nullptr) + { + searchPtr += strlen(UBX_CELL_FTP_COMMAND_URC); // Move searchPtr to first character - probably a space + while (*searchPtr == ' ') { - searchPtr += strlen(UBX_CELL_REGISTRATION_STATUS_URC); // Move searchPtr to first character - probably a space - while (*searchPtr == ' ') searchPtr++; // skip spaces - int scanNum = sscanf(searchPtr, "%d,\"%4x\",\"%4x\",%d", &status, &lac, &ci, &Act); - if (scanNum == 4) - { - if (_printDebug == true) - _debugPort->println(F("processReadEvent: CREG")); + searchPtr++; // skip spaces + } - if (_registrationCallback != nullptr) - { - _registrationCallback((UBX_CELL_registration_status_t)status, lac, ci, Act); - } + scanNum = sscanf(searchPtr, "%d,%d", &ftpCmd, &ftpResult); + if (scanNum == 2 && _ftpCommandRequestCallback != nullptr) + { + _ftpCommandRequestCallback(ftpCmd, ftpResult); + return true; + } + } + + return false; +} - return true; +bool UBX_CELL::urcHandlerRegistrationStatus(const char* event) +{ + // URC: +CREG + int status = 0; + unsigned int lac = 0, ci = 0, Act = 0; + char *searchPtr = strstr(event, UBX_CELL_REGISTRATION_STATUS_URC); + if (searchPtr != nullptr) + { + searchPtr += strlen(UBX_CELL_REGISTRATION_STATUS_URC); // Move searchPtr to first character - probably a space + while (*searchPtr == ' ') searchPtr++; // skip spaces + int scanNum = sscanf(searchPtr, "%d,\"%4x\",\"%4x\",%d", &status, &lac, &ci, &Act); + if (scanNum == 4) + { + if (_printDebug == true) + _debugPort->println(F("processReadEvent: CREG")); + + if (_registrationCallback != nullptr) + { + _registrationCallback((UBX_CELL_registration_status_t)status, lac, ci, Act); } + + return true; } } - { // URC: +CEREG - int status = 0; - unsigned int tac = 0, ci = 0, Act = 0; - char *searchPtr = strstr(event, UBX_CELL_EPSREGISTRATION_STATUS_URC); - if (searchPtr != nullptr) + + return false; +} + +bool UBX_CELL::urcHandlerEPSRegistrationStatus(const char* event) +{ + // URC: +CEREG + int status = 0; + unsigned int tac = 0, ci = 0, Act = 0; + char *searchPtr = strstr(event, UBX_CELL_EPSREGISTRATION_STATUS_URC); + if (searchPtr != nullptr) + { + searchPtr += strlen(UBX_CELL_EPSREGISTRATION_STATUS_URC); // Move searchPtr to first character - probably a space + while (*searchPtr == ' ') searchPtr++; // skip spaces + int scanNum = sscanf(searchPtr, "%d,\"%4x\",\"%4x\",%d", &status, &tac, &ci, &Act); + if (scanNum == 4) { - searchPtr += strlen(UBX_CELL_EPSREGISTRATION_STATUS_URC); // Move searchPtr to first character - probably a space - while (*searchPtr == ' ') searchPtr++; // skip spaces - int scanNum = sscanf(searchPtr, "%d,\"%4x\",\"%4x\",%d", &status, &tac, &ci, &Act); - if (scanNum == 4) + if (_printDebug == true) + _debugPort->println(F("processReadEvent: CEREG")); + + if (_epsRegistrationCallback != nullptr) { - if (_printDebug == true) - _debugPort->println(F("processReadEvent: CEREG")); + _epsRegistrationCallback((UBX_CELL_registration_status_t)status, tac, ci, Act); + } - if (_epsRegistrationCallback != nullptr) - { - _epsRegistrationCallback((UBX_CELL_registration_status_t)status, tac, ci, Act); - } + return true; + } + } - return true; - } + return false; +} + +void UBX_CELL::addURCHandler(const char* urcString, UBX_CELL_urc_handler_t urcHandler) +{ + _urcStrings.push_back(urcString); + _urcHandlers.push_back(urcHandler); +} + +// Parse incoming URC's - the associated parse functions pass the data to the user via the callbacks (if defined) +bool UBX_CELL::processURCEvent(const char *event) +{ + // Iterate through each URC handler to see if it can handle this message + for(auto urcHandler : _urcHandlers) + { + if (urcHandler(event)) + { + // This handler took care of it, so we're done! + return true; } } - // NOTE: When adding new URC messages, remember to update pruneBacklog too! + // None of the handlers took care of it return false; } @@ -6320,23 +6415,15 @@ void UBX_CELL::pruneBacklog() while (event != nullptr) //If event is actionable, add it to pruneBuffer. { // These are the events we want to keep so they can be processed by poll / bufferedPoll - if ((strstr(event, UBX_CELL_READ_SOCKET_URC) != nullptr) - || (strstr(event, UBX_CELL_READ_UDP_SOCKET_URC) != nullptr) - || (strstr(event, UBX_CELL_LISTEN_SOCKET_URC) != nullptr) - || (strstr(event, UBX_CELL_CLOSE_SOCKET_URC) != nullptr) - || (strstr(event, UBX_CELL_GNSS_REQUEST_LOCATION_URC) != nullptr) - || (strstr(event, UBX_CELL_SIM_STATE_URC) != nullptr) - || (strstr(event, UBX_CELL_MESSAGE_PDP_ACTION_URC) != nullptr) - || (strstr(event, UBX_CELL_HTTP_COMMAND_URC) != nullptr) - || (strstr(event, UBX_CELL_MQTT_COMMAND_URC) != nullptr) - || (strstr(event, UBX_CELL_PING_COMMAND_URC) != nullptr) - || (strstr(event, UBX_CELL_REGISTRATION_STATUS_URC) != nullptr) - || (strstr(event, UBX_CELL_EPSREGISTRATION_STATUS_URC) != nullptr) - || (strstr(event, UBX_CELL_FTP_COMMAND_URC) != nullptr)) - { - strcat(_pruneBuffer, event); // The URCs are all readable text so using strcat is OK - strcat(_pruneBuffer, "\r\n"); // strtok blows away delimiter, but we want that for later. - _saraResponseBacklogLength += strlen(event) + 2; // Add the length of this event to _saraResponseBacklogLength + for(auto urcString : _urcStrings) + { + if(strstr(event, urcString) != nullptr) + { + strcat(_pruneBuffer, event); // The URCs are all readable text so using strcat is OK + strcat(_pruneBuffer, "\r\n"); // strtok blows away delimiter, but we want that for later. + _saraResponseBacklogLength += strlen(event) + 2; // Add the length of this event to _saraResponseBacklogLength + break; // No need to check any other events + } } event = strtok_r(nullptr, "\r\n", &preservedEvent); // Walk though any remaining events diff --git a/src/sfe_ublox_cellular.h b/src/sfe_ublox_cellular.h index 8f2f224..3b32bff 100644 --- a/src/sfe_ublox_cellular.h +++ b/src/sfe_ublox_cellular.h @@ -71,6 +71,7 @@ #endif #include +#include #define UBX_CELL_POWER_PIN -1 // Default to no pin #define UBX_CELL_RESET_PIN -1 @@ -207,6 +208,9 @@ const char* const UBX_CELL_RESPONSE_ERROR = "\nERROR\r\n"; const char* const UBX_CELL_RESPONSE_CONNECT = "\r\nCONNECT\r\n"; #define UBX_CELL_RESPONSE_OK_OR_ERROR nullptr +// URC handler type definition +typedef std::function UBX_CELL_urc_handler_t; + // CTRL+Z and ESC ASCII codes for SMS message sends const char ASCII_CTRL_Z = 0x1A; const char ASCII_ESC = 0x1B; @@ -1010,6 +1014,9 @@ class UBX_CELL : public Print char *ubx_cell_calloc_char(size_t num); + // Add a URC handler + void addURCHandler(const char* urcString, UBX_CELL_urc_handler_t urcHandler); + protected: HardwareSerial *_hardSerial; #ifdef UBX_CELL_SOFTWARE_SERIAL_ENABLED @@ -1054,6 +1061,9 @@ class UBX_CELL : public Print void (*_registrationCallback)(UBX_CELL_registration_status_t status, unsigned int lac, unsigned int ci, int Act); void (*_epsRegistrationCallback)(UBX_CELL_registration_status_t status, unsigned int tac, unsigned int ci, int Act); + // Vectors of URC strings and handlers + std::vector _urcStrings; + std::vector _urcHandlers; int _lastSocketProtocol[UBX_CELL_NUM_SOCKETS]; // Record the protocol for each socket to avoid having to call querySocketType in parseSocketReadIndication @@ -1100,6 +1110,20 @@ class UBX_CELL : public Print UBX_CELL_error_t autobaud(unsigned long desiredBaud); + bool urcHandlerReadSocket(const char* event); + bool urcHandlerReadUDPSocket(const char* event); + bool urcHandlerListeningSocket(const char* event); + bool urcHandlerCloseSocket(const char* event); + bool urcHandlerGNSSRequestLocation(const char* event); + bool urcHandlerSIMState(const char* event); + bool urcHandlerPDPAction(const char* event); + bool urcHandlerHTTPCommand(const char* event); + bool urcHandlerMQTTCommand(const char* event); + bool urcHandlerPingCommand(const char* event); + bool urcHandlerFTPCommand(const char* event); + bool urcHandlerRegistrationStatus(const char* event); + bool urcHandlerEPSRegistrationStatus(const char* event); + bool processURCEvent(const char *event); void pruneBacklog(void);