diff --git a/module-bsp/board/linux/cellular/linux_cellular.cpp b/module-bsp/board/linux/cellular/linux_cellular.cpp index 5da7b360a..8bfc1efa8 100644 --- a/module-bsp/board/linux/cellular/linux_cellular.cpp +++ b/module-bsp/board/linux/cellular/linux_cellular.cpp @@ -100,6 +100,9 @@ namespace bsp { if ((ret == -1) && (errno == EINTR)) { goto retry; } + else if(errno){ + LOG_DEBUG("Read errno: %s",strerror(errno)); + } return ret; } diff --git a/module-cellular/Modem/ATParser.cpp b/module-cellular/Modem/ATParser.cpp index 58d6cabc3..51ac4adf3 100644 --- a/module-cellular/Modem/ATParser.cpp +++ b/module-cellular/Modem/ATParser.cpp @@ -13,6 +13,7 @@ #include "bsp/cellular/bsp_cellular.hpp" #include "ticks.hpp" #include "InOutSerialWorker.hpp" +#include "MuxDaemon.hpp" std::optional> ATParser::Create(MuxDaemon *mux, InOutSerialWorker *inOutSerial, bsp::Cellular *cellular) { @@ -25,10 +26,61 @@ ATParser::Create(MuxDaemon *mux, InOutSerialWorker *inOutSerial, bsp::Cellular * } } -ATParser::ATParser(MuxDaemon *mux, InOutSerialWorker *inOutSerial, bsp::Cellular *cellular) : mux(mux),inOutSerialWorker(inOutSerial),cellular(cellular) { +ATParser::ATParser(MuxDaemon *mux, InOutSerialWorker *inOutSerial, bsp::Cellular *cellular) : mux(mux), + inOutSerialWorker( + inOutSerial), + cellular(cellular) { isInitialized = true; } +std::vector ATParser::ParseURC() { + + std::vector resp; + size_t maxPos = 0; + + cpp_freertos::LockGuard lock(mutex); + + + auto pos = responseBuffer.find("RDY"); + if (pos != std::string::npos) { + resp.push_back(ATParser::Urc::MeInitializationSuccessful); + maxPos = std::max(pos + strlen("RDY"), maxPos); + } + + pos = responseBuffer.find("+CFUN: 1"); + if (pos != std::string::npos) { + resp.push_back(ATParser::Urc::FullFuncionalityAvailable); + maxPos = std::max(pos + strlen("+CFUN: 1"), maxPos); + } + pos = responseBuffer.find("+CPIN: READY"); + if (pos != std::string::npos) { + resp.push_back(ATParser::Urc::SimCardReady); + maxPos = std::max(pos + strlen("+CPIN: READY"), maxPos); + } + + pos = responseBuffer.find("+QIND: SMS DONE"); + if (pos != std::string::npos) { + resp.push_back(ATParser::Urc::SMSInitializationComplete); + maxPos = std::max(pos + strlen("+QIND: SMS DONE"), maxPos); + } + + pos = responseBuffer.find("+QIND: PB DONE"); + if (pos != std::string::npos) { + resp.push_back(ATParser::Urc::PhonebookInitializationComplete); + maxPos = std::max(pos + strlen("+QIND: PB DONE"), maxPos); + } + + // manage string buffer + if(responseBuffer.size() >= maxPos){ + responseBuffer.erase(); + } + else{ + responseBuffer = responseBuffer.substr(maxPos); + } + + return resp; +} + int ATParser::ProcessNewData() { char rawBuffer[256] = {0}; @@ -41,8 +93,17 @@ int ATParser::ProcessNewData() { } // Received response data without active request, drop it else { - responseBuffer.erase(); - LOG_INFO("Received unneeded data"); + urcs = ParseURC(); + // GSM modem is considered as fully operational when it outputs URCs specified below: + // 1) RDY + // 2) +CFUN: 1 + // 3) +CPIN: READY + // 4) +QIND: SMS DONE + // 5) +QIND: PB DONE + if(urcs.size() == 5){ + mux->StartMultiplexer(); + } + } return 1; } @@ -79,13 +140,12 @@ std::vector ATParser::SendCommand(const char *cmd, size_t rxCount, if (tokens.size() < rxCount) { goto wait_for_data; } - blockedTaskHandle = nullptr; - return tokens; - } else { - //timeout - blockedTaskHandle = nullptr; - return tokens; + } + + blockedTaskHandle = nullptr; + responseBuffer.erase(); // TODO:M.P is it okay to flush buffer here ? + return tokens; } std::vector ATParser::Tokenizer(std::string &input, uint32_t maxTokenCount, diff --git a/module-cellular/Modem/ATParser.hpp b/module-cellular/Modem/ATParser.hpp index a21dbaf62..3d9bfeba3 100644 --- a/module-cellular/Modem/ATParser.hpp +++ b/module-cellular/Modem/ATParser.hpp @@ -31,6 +31,16 @@ class InOutSerialWorker; class ATParser { public: + + enum class Urc{ + MeInitializationSuccessful, + FullFuncionalityAvailable, + SimCardReady, + SMSInitializationComplete, + PhonebookInitializationComplete + + }; + static std::optional> Create(MuxDaemon* mux,InOutSerialWorker* inOutSerial,bsp::Cellular* cellular); ATParser(MuxDaemon* mux,InOutSerialWorker* inOutSerial,bsp::Cellular* cellular); @@ -43,6 +53,8 @@ public: private: + std::vector ParseURC(); + MuxDaemon* mux = nullptr; InOutSerialWorker* inOutSerialWorker = nullptr; bsp::Cellular* cellular = nullptr; @@ -52,6 +64,8 @@ private: TaskHandle_t blockedTaskHandle = nullptr; cpp_freertos::MutexStandard mutex; + std::vector urcs; + bool isInitialized = false; diff --git a/module-cellular/Modem/InOutSerialWorker.cpp b/module-cellular/Modem/InOutSerialWorker.cpp index bbd665793..06281b330 100644 --- a/module-cellular/Modem/InOutSerialWorker.cpp +++ b/module-cellular/Modem/InOutSerialWorker.cpp @@ -71,7 +71,10 @@ void workerTaskFunction(void *ptr) { InOutSerialWorker *inst = reinterpret_cast(ptr); while (1) { - inst->cellular->Wait(UINT32_MAX); + auto ret = inst->cellular->Wait(UINT32_MAX); + if(ret == 0){ + continue; + } // AT mode is used only during initialization phase if (inst->mode == InOutSerialWorker::Mode::AT) { diff --git a/module-cellular/Modem/MuxDaemon.cpp b/module-cellular/Modem/MuxDaemon.cpp index abc357c72..00c4aecf6 100644 --- a/module-cellular/Modem/MuxDaemon.cpp +++ b/module-cellular/Modem/MuxDaemon.cpp @@ -83,7 +83,7 @@ MuxDaemon::MuxDaemon(NotificationMuxChannel::NotificationCallback_t callback) : } MuxDaemon::~MuxDaemon() { - CloseMux(); + CloseMultiplexer(); } std::unique_ptr MuxDaemon::Create(NotificationMuxChannel::NotificationCallback_t callback) { @@ -127,39 +127,32 @@ bool MuxDaemon::Start() { inOutSerialDataWorker->SendFrame(0, closeChannelCmd, sizeof(closeChannelCmd), static_cast(MuxDefines::GSM0710_TYPE_UIH)); - vTaskDelay(500); // give modem some time to establish mux - // Try sending AT command once again ret = inOutSerialDataWorker->SendATCommand("AT\r",2, 500); if(ret.size() == 1 || ret.size() == 2){ // Modem can send echo response or not, in either case it means that modem is operating in AT mode - + return StartMultiplexer(); } else{ LOG_INFO("Starting power up procedure..."); // If no response, power up modem and try again //TODO:M.P implement it cellular->PowerUp(); - uint32_t retries = 20; - while (--retries) { - ret = inOutSerialDataWorker->SendATCommand("AT\r", 500); - if ( ret.size() == 2) { - break; - } - } - - if (retries == 0) { - LOG_FATAL("No communication with GSM modem"); - return -1; - } - } } + else if ((ret.size() == 1 && ret[0] == "OK\r\n") || (ret.size() == 2 && ret[0] == "AT\r\n" && ret[1] == "OK\r\n")){ + return StartMultiplexer(); + } + +} + +bool MuxDaemon::StartMultiplexer() { + + // Factory reset + inOutSerialDataWorker->SendATCommand("AT&F\r", 1); // Turn off local echo inOutSerialDataWorker->SendATCommand("ATE0\r", 2); - // Factory reset - inOutSerialDataWorker->SendATCommand("AT&F\r", 1); // Set up modem configuration if (hardwareControlFlowEnable) { @@ -225,7 +218,7 @@ bool MuxDaemon::Start() { } -int MuxDaemon::CloseMux() { +int MuxDaemon::CloseMultiplexer() { // Virtual channels need to be deinitialized in reversed order i.e control channel should be closed at the end for (auto w = channels.size(); --w;) { diff --git a/module-cellular/Modem/MuxDaemon.hpp b/module-cellular/Modem/MuxDaemon.hpp index dc84c647c..a229df216 100644 --- a/module-cellular/Modem/MuxDaemon.hpp +++ b/module-cellular/Modem/MuxDaemon.hpp @@ -38,6 +38,7 @@ public: * Multiplexer states */ enum class States { + MUX_STATE_POWERUP, MUX_STATE_OPENING, MUX_STATE_INITILIZING, MUX_STATE_MUXING, @@ -62,6 +63,8 @@ public: void RemoveMuxChannel(MuxChannel::MuxChannelType chan); + bool StartMultiplexer(); + int uihPfBitReceived = 0; private: @@ -70,7 +73,7 @@ private: bool Start(); - int CloseMux(); + int CloseMultiplexer(); constexpr static unsigned char closeChannelCmd[] = {