diff --git a/module-cellular/Modem/CommunicationMuxChannel.cpp b/module-cellular/Modem/CommunicationMuxChannel.cpp index 4bd0c9b90..1e06659ab 100644 --- a/module-cellular/Modem/CommunicationMuxChannel.cpp +++ b/module-cellular/Modem/CommunicationMuxChannel.cpp @@ -23,8 +23,8 @@ CommunicationMuxChannel::~CommunicationMuxChannel() { } -int CommunicationMuxChannel::ParseInMessage(MuxChannel::MuxChannelMsg *msg) { - LOG_FATAL((name + " received message: " + msg->m_data).c_str()); +int CommunicationMuxChannel::ParseInputData(uint8_t* data, size_t size) { + //LOG_FATAL((name + " received message: " + msg->m_data).c_str()); } ssize_t CommunicationMuxChannel::SendCommand(const char *cmd, uint32_t timeout) { diff --git a/module-cellular/Modem/CommunicationMuxChannel.hpp b/module-cellular/Modem/CommunicationMuxChannel.hpp index 2cb111d11..d2b610d6a 100644 --- a/module-cellular/Modem/CommunicationMuxChannel.hpp +++ b/module-cellular/Modem/CommunicationMuxChannel.hpp @@ -22,7 +22,7 @@ public: - int ParseInMessage(MuxChannelMsg* msg) override final; + int ParseInputData(uint8_t* data, size_t size) override final; ssize_t SendCommand(const char* cmd,uint32_t timeout = 1000); }; diff --git a/module-cellular/Modem/InputSerialWorker.cpp b/module-cellular/Modem/InputSerialWorker.cpp index 6889adbd8..58348f0c8 100644 --- a/module-cellular/Modem/InputSerialWorker.cpp +++ b/module-cellular/Modem/InputSerialWorker.cpp @@ -59,7 +59,7 @@ void workerTaskFunction(void *ptr) { int InputSerialWorker::ReadIncomingData() { int length = 0; - switch (muxDaemon->state) { + switch (muxDaemon->GetState()) { case MuxDaemon::States::MUX_STATE_MUXING: length = std::min(inputBuffer->GetFreeSpace(), (uint32_t) (inputBuffer->endp - inputBuffer->writep)); @@ -94,7 +94,7 @@ int InputSerialWorker::ReadIncomingData() { break; default: - LOG_WARN("Don't know how to handle reading in state %d", muxDaemon->state); + LOG_WARN("Don't know how to handle reading in state %d", muxDaemon->GetState()); break; } @@ -119,15 +119,15 @@ int InputSerialWorker::ExtractFrames() { //data from logical channel if (frame->channel > 0) { LOG_DEBUG("Writing %d byte frame received on channel %d to %s", frame->length, frame->channel, - muxDaemon->channels[frame->channel].GetName().c_str()); + muxDaemon->channels[frame->channel]->GetName().c_str()); int write_result = 0; - if (muxDaemon->channels[frame->channel].GetState() == + if (muxDaemon->channels[frame->channel]->GetState() == MuxChannel::State::Opened) {//reopening, discard the data // Send received message to virtual channel for further processing - write_result = muxDaemon->channels[frame->channel].DistributeMsg(frame->data, frame->length); + write_result = muxDaemon->channels[frame->channel]->SendData(frame->data, frame->length); } else { LOG_INFO("channel %d closed, discard the frame", frame->channel); write_result = frame->length; @@ -135,7 +135,7 @@ int InputSerialWorker::ExtractFrames() { if (write_result < frame->length) { LOG_INFO("write() returned. Written %d/%d bytes of frame to %s", - write_result, frame->length, muxDaemon->channels[frame->channel].GetName().c_str()); + write_result, frame->length, muxDaemon->channels[frame->channel]->GetName().c_str()); //send_modem_status(frame->channel,1); //fill_in_list(frame->channel,frame->data + write_result,frame->length - write_result); @@ -154,59 +154,59 @@ int InputSerialWorker::ExtractFrames() { switch (frameType) { case MuxDefines::GSM0710_TYPE_UA: LOG_DEBUG("Frame is UA"); - if (muxDaemon->channels[frame->channel].GetState() == MuxChannel::State::Opened) { + if (muxDaemon->channels[frame->channel]->GetState() == MuxChannel::State::Opened) { // Remove channel muxDaemon->channels.erase(muxDaemon->channels.begin() + frame->channel); LOG_INFO("Logical channel %d for %s closed", - frame->channel, muxDaemon->channels[frame->channel].GetName().c_str()); + frame->channel, muxDaemon->channels[frame->channel]->GetName().c_str()); } else { - if (muxDaemon->channels[frame->channel].disc_ua_pending == 0) { - muxDaemon->channels[frame->channel].SetState(MuxChannel::State::Opened); + if (muxDaemon->channels[frame->channel]->disc_ua_pending == 0) { + muxDaemon->channels[frame->channel]->SetState(MuxChannel::State::Opened); if (frame->channel == 0) { LOG_DEBUG("Control channel opened"); } else LOG_INFO("Logical channel %d opened", frame->channel); } else { - LOG_INFO("UA to acknowledgde DISC on channel %d received", frame->channel); - muxDaemon->channels[frame->channel].disc_ua_pending = 0; + LOG_INFO("UA to acknowledge DISC on channel %d received", frame->channel); + muxDaemon->channels[frame->channel]->disc_ua_pending = 0; } } break; case MuxDefines::GSM0710_TYPE_DM: - if (muxDaemon->channels[frame->channel].GetState() == MuxChannel::State::Opened) { + if (muxDaemon->channels[frame->channel]->GetState() == MuxChannel::State::Opened) { // Remove channel muxDaemon->channels.erase(muxDaemon->channels.begin() + frame->channel); LOG_INFO("DM received, so the channel %d for %s was already closed", - frame->channel, muxDaemon->channels[frame->channel].GetName().c_str()); + frame->channel, muxDaemon->channels[frame->channel]->GetName().c_str()); } else { if (frame->channel == 0) { LOG_INFO("Couldn't open control channel.\n->Terminating"); - muxDaemon->state = MuxDaemon::States::MUX_STATE_CLOSING; + muxDaemon->SetState(MuxDaemon::States::MUX_STATE_CLOSING); //close channels } else LOG_INFO("Logical channel %d for %s couldn't be opened", frame->channel, - muxDaemon->channels[frame->channel].GetName().c_str()); + muxDaemon->channels[frame->channel]->GetName().c_str()); } break; case MuxDefines::GSM0710_TYPE_DISC: - if (muxDaemon->channels[frame->channel].GetState() == MuxChannel::State::Opened) { - muxDaemon->channels[frame->channel].SetState(MuxChannel::State::Closed); + if (muxDaemon->channels[frame->channel]->GetState() == MuxChannel::State::Opened) { + muxDaemon->channels[frame->channel]->SetState(MuxChannel::State::Closed); muxDaemon->WriteMuxFrame(frame->channel, NULL, 0, static_cast(MuxDefines::GSM0710_TYPE_UA) | static_cast(MuxDefines::GSM0710_PF)); if (frame->channel == 0) { - muxDaemon->state = MuxDaemon::States::MUX_STATE_CLOSING; + muxDaemon->SetState(MuxDaemon::States::MUX_STATE_CLOSING); LOG_INFO("Control channel closed"); } else LOG_INFO("Logical channel %d for %s closed", frame->channel, - muxDaemon->channels[frame->channel].GetName().c_str()); + muxDaemon->channels[frame->channel]->GetName().c_str()); } else { //channel already closed LOG_WARN("Received DISC even though channel %d for %s was already closed", - frame->channel, muxDaemon->channels[frame->channel].GetName().c_str()); + frame->channel, muxDaemon->channels[frame->channel]->GetName().c_str()); // Send Mux frame muxDaemon->WriteMuxFrame(frame->channel, NULL, 0, static_cast(MuxDefines::GSM0710_TYPE_DM) | @@ -215,17 +215,17 @@ int InputSerialWorker::ExtractFrames() { break; case MuxDefines::GSM0710_TYPE_SABM: //channel open request - if (muxDaemon->channels[frame->channel].GetState() == MuxChannel::State::Opened) { + if (muxDaemon->channels[frame->channel]->GetState() == MuxChannel::State::Opened) { if (frame->channel == 0) LOG_INFO("Control channel opened"); else LOG_INFO("Logical channel %d for %s opened", - frame->channel, muxDaemon->channels[frame->channel].GetName().c_str()); + frame->channel, muxDaemon->channels[frame->channel]->GetName().c_str()); } else //channel already opened LOG_WARN("Received SABM even though channel %d for %s was already closed", - frame->channel, muxDaemon->channels[frame->channel].GetName().c_str()); - muxDaemon->channels[frame->channel].SetState(MuxChannel::State::Opened); + frame->channel, muxDaemon->channels[frame->channel]->GetName().c_str()); + muxDaemon->channels[frame->channel]->SetState(MuxChannel::State::Opened); // Send mux frame muxDaemon->WriteMuxFrame(frame->channel, NULL, 0, static_cast(MuxDefines::GSM0710_TYPE_UA) | @@ -270,7 +270,7 @@ int InputSerialWorker::HandleCtrlChannelCommands(GSM0710Frame *frame) { case MuxDefines::GSM0710_CONTROL_CLD: //TODO: M.P implement CMUX close LOG_INFO("The mobile station requested mux-mode termination"); - muxDaemon->state = MuxDaemon::States::MUX_STATE_CLOSING; + muxDaemon->SetState(MuxDaemon::States::MUX_STATE_CLOSING); break; case MuxDefines::GSM0710_CONTROL_PSC: LOG_INFO("Power Service Control command: ***"); @@ -291,7 +291,7 @@ int InputSerialWorker::HandleCtrlChannelCommands(GSM0710Frame *frame) { //op.arg = USSP_RTS; //op.len = 0; LOG_INFO("Modem status command on channel %d", channel); - muxDaemon->channels[channel].frameAllowed = ((signals & + muxDaemon->channels[channel]->frameAllowed = ((signals & static_cast(MuxDefines::GSM0710_SIGNAL_FC)) != static_cast(MuxDefines::GSM0710_SIGNAL_FC)); if ((signals & static_cast(MuxDefines::GSM0710_SIGNAL_FC)) == diff --git a/module-cellular/Modem/MuxChannel.cpp b/module-cellular/Modem/MuxChannel.cpp index 9b533ae4f..7afe33e2c 100644 --- a/module-cellular/Modem/MuxChannel.cpp +++ b/module-cellular/Modem/MuxChannel.cpp @@ -18,33 +18,41 @@ void MuxChannelWorker(void *pvp) { MuxChannel *inst = reinterpret_cast(pvp); - while (1) { + while (inst->enableWorkerLoop) { - MuxChannel::MuxChannelMsg *msgReceived = nullptr; - xQueueReceive(inst->workerQueueHandle, &msgReceived, portMAX_DELAY); + uint8_t buffer[MuxChannel::inputBufferSize] = {0}; + auto bytesReceived = xStreamBufferReceive(inst->inputBuffer, buffer,MuxChannel::inputBufferSize,pdMS_TO_TICKS(portMAX_DELAY)); + + // Check if incoming data is actually signal to close + if((inst->enableWorkerLoop == false) && (buffer[0] == 0) && (bytesReceived == 1)){ + goto exit; + } switch (inst->type) { case MuxChannel::MuxChannelType::Notification: { NotificationMuxChannel *muxChan = reinterpret_cast(pvp); - muxChan->ParseInMessage(msgReceived); + muxChan->ParseInputData(buffer,bytesReceived); } break; case MuxChannel::MuxChannelType ::Communication:{ CommunicationMuxChannel *muxChan = reinterpret_cast(pvp); - muxChan->ParseInMessage(msgReceived); + muxChan->ParseInputData(buffer,bytesReceived); break; } default: // The rest of mux channels aren't currently supported - inst->ParseInMessage(msgReceived); + inst->ParseInputData(buffer,bytesReceived);; break; } - - delete (msgReceived); - } + + exit: + LOG_DEBUG("Closing worker thread."); + vStreamBufferDelete(inst->inputBuffer); + + vTaskDelete(NULL); } @@ -55,7 +63,6 @@ MuxChannel::MuxChannel(MuxDaemon *mux, uint32_t logicalNumber, MuxChannelType ty static_cast(MuxDefines::GSM0710_SIGNAL_RTC) | static_cast(MuxDefines::GSM0710_EA)), frameAllowed(1), disc_ua_pending(0), - workerQueueSize(queueSize), workerStackSize(stackSize), state(State::Closed), type(type), @@ -71,9 +78,11 @@ MuxChannel::~MuxChannel() { int MuxChannel::Open() { - workerQueueHandle = xQueueCreate(workerQueueSize, sizeof(MuxChannelMsg *)); + enableWorkerLoop = true; + inputBuffer = xStreamBufferCreate(inputBufferSize,1); xTaskCreate(MuxChannelWorker, (name + "_Worker").c_str(), workerStackSize / 4, this, 0, &workerHandle); + // Send virtual channel request frame to GSM modem mux->WriteMuxFrame(GetChannelNumber(), NULL, 0, static_cast(MuxDefines::GSM0710_TYPE_SABM) | static_cast(MuxDefines::GSM0710_PF)); @@ -83,24 +92,24 @@ int MuxChannel::Open() { int MuxChannel::Close() { - vQueueDelete(workerQueueHandle); - vTaskDelete(workerHandle); + enableWorkerLoop = false; - mux->WriteMuxFrame(GetChannelNumber(), mux->closeChannelCmd, sizeof(mux->closeChannelCmd), - static_cast(MuxDefines::GSM0710_TYPE_UIH)); + uint8_t dummy = 0; + // Send dummy data to kick worker thread out of suspend state + SendData(&dummy,sizeof dummy); + + mux->WriteMuxFrame(GetChannelNumber(), NULL, 0, + static_cast(MuxDefines::GSM0710_TYPE_DISC)); return 0; } -int MuxChannel::DistributeMsg(uint8_t *data, size_t size) { - - MuxChannelMsg *msg = new MuxChannelMsg(data, size); - xQueueSend(workerQueueHandle, &msg, 500); - return size; +ssize_t MuxChannel::SendData(uint8_t *data, size_t size) { + return xStreamBufferSend(inputBuffer,data,size,100); } -int MuxChannel::ParseInMessage(MuxChannel::MuxChannelMsg *msg) { - LOG_FATAL((name + " received message: " + msg->m_data).c_str()); +int MuxChannel::ParseInputData(uint8_t *data, size_t size){ + //LOG_FATAL((name + " received message: " + msg->m_data).c_str()); return 0; } \ No newline at end of file diff --git a/module-cellular/Modem/MuxChannel.hpp b/module-cellular/Modem/MuxChannel.hpp index 34ad22e90..8ed811728 100644 --- a/module-cellular/Modem/MuxChannel.hpp +++ b/module-cellular/Modem/MuxChannel.hpp @@ -15,9 +15,10 @@ #include #include #include "FreeRTOS.h" -#include "queue.h" +#include "stream_buffer.h" #include "task.h" + void MuxChannelWorker(void* pvp); class MuxDaemon; @@ -60,9 +61,11 @@ public: int Open(); // Close mux channel int Close(); - // Send message to specific mux channel thread - int DistributeMsg(uint8_t* data, size_t size); - virtual ssize_t SendCommand(const char* cmd,uint32_t timeout = 1000){} + + //Distribute data to mux channel + ssize_t SendData(uint8_t* data, size_t size); + + virtual ssize_t SendCommand(const char* cmd,uint32_t timeout = 1000){return 0;} std::string& GetName(){ @@ -89,18 +92,20 @@ private: friend void MuxChannelWorker(void* pvp); - uint32_t workerQueueSize; + static const uint32_t inputBufferSize = 512; // in bytes + + bool enableWorkerLoop = false; + uint32_t workerStackSize; // in bytes TaskHandle_t workerHandle = nullptr; - QueueHandle_t workerQueueHandle = nullptr; - + StreamBufferHandle_t inputBuffer; State state; MuxChannelType type; protected: - virtual int ParseInMessage(MuxChannelMsg* msg); + virtual int ParseInputData(uint8_t* data, size_t size); std::string name; MuxDaemon* mux; diff --git a/module-cellular/Modem/MuxDaemon.cpp b/module-cellular/Modem/MuxDaemon.cpp index 36513e99e..960ce0c43 100644 --- a/module-cellular/Modem/MuxDaemon.cpp +++ b/module-cellular/Modem/MuxDaemon.cpp @@ -163,17 +163,17 @@ int MuxDaemon::Start() { // Create virtual channels // Control channel is used for controlling Mux. It is not considered as logical channel i.e it can't receive normal data messages - channels.push_back(ControlMuxChannel(this)); + channels.push_back(std::make_unique(this)); // Notificiation channel is used mainly for receiving URC messages and handling various async requests - channels.push_back(NotificationMuxChannel(this)); + channels.push_back(std::make_unique(this)); // Communication channel is used for sending various requests to GSM modem (SMS/Dial and so on) in blocking manner - channels.push_back(CommunicationMuxChannel(this)); + channels.push_back(std::make_unique(this)); // Mux channels must be initialized in sequence for (auto &w : channels) { - w.Open(); + w->Open(); vTaskDelay(200); } @@ -280,13 +280,12 @@ int MuxDaemon::CloseMux() { // 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;) { - if (channels[w].GetState() == MuxChannel::State::Opened) { - LOG_INFO("Logical channel %d closed", channels[w].GetChannelNumber()); - channels[w].Close(); + if (channels[w]->GetState() == MuxChannel::State::Opened) { + LOG_INFO("Logical channel %d closed", channels[w]->GetChannelNumber()); + channels[w]->Close(); } } - channels.clear(); return 0; } diff --git a/module-cellular/Modem/MuxDaemon.hpp b/module-cellular/Modem/MuxDaemon.hpp index f451647cc..4ad9d12b6 100644 --- a/module-cellular/Modem/MuxDaemon.hpp +++ b/module-cellular/Modem/MuxDaemon.hpp @@ -31,9 +31,21 @@ public: */ const static uint32_t baudRate = 115200; - const static uint32_t virtualPortsCount = 4; // max number of virtual channels supported by EG25 + const static uint32_t virtualPortsCount = 3; const static bool hardwareControlFlowEnable = false; + /** + * Multiplexer states + */ + enum class States { + MUX_STATE_OPENING, + MUX_STATE_INITILIZING, + MUX_STATE_MUXING, + MUX_STATE_CLOSING, + MUX_STATE_OFF, + MUX_STATES_COUNT // keep this the last + }; + MuxDaemon(); ~MuxDaemon(); @@ -47,6 +59,9 @@ public: int length, unsigned char type); + inline MuxDaemon::States GetState(){return state;} + inline void SetState(MuxDaemon::States st){state = st;} + private: friend InputSerialWorker; @@ -76,14 +91,7 @@ private: int length, const char *needle); - enum class States { - MUX_STATE_OPENING, - MUX_STATE_INITILIZING, - MUX_STATE_MUXING, - MUX_STATE_CLOSING, - MUX_STATE_OFF, - MUX_STATES_COUNT // keep this the last - }; + constexpr static unsigned char closeChannelCmd[] = { @@ -98,7 +106,7 @@ private: States state = States::MUX_STATE_OPENING; - std::vector channels; + std::vector> channels; cpp_freertos::MutexStandard serOutMutex; diff --git a/module-cellular/Modem/NotificationMuxChannel.cpp b/module-cellular/Modem/NotificationMuxChannel.cpp index 8cb22cca3..1184a749b 100644 --- a/module-cellular/Modem/NotificationMuxChannel.cpp +++ b/module-cellular/Modem/NotificationMuxChannel.cpp @@ -24,31 +24,41 @@ NotificationMuxChannel::~NotificationMuxChannel() { } -int NotificationMuxChannel::ParseInMessage(MuxChannel::MuxChannelMsg *msg) { +int NotificationMuxChannel::ParseInputData(uint8_t* data, size_t size) { + + std::string msgStr(data,data+size); // Incoming call - if (msg->m_data.find("RING") != std::string::npos) { + if (msgStr.find("RING") != std::string::npos) { //TODO:M.P incoming call URC action LOG_DEBUG((name + ": incoming call...").c_str()); - char* resp = "AT\r"; + char* resp = "ATA\r"; mux->WriteMuxFrame(GetChannelNumber(), reinterpret_cast(resp),strlen(resp), static_cast(MuxDefines::GSM0710_TYPE_UIH)); } // Incoming call - if (msg->m_data.find("+CRING") != std::string::npos) { + if (msgStr.find("+CRING") != std::string::npos) { //TODO:M.P incoming call URC action LOG_DEBUG((name + ": incoming call...").c_str()); } // Call aborted/failed - if (msg->m_data.find("NO CARRIER") != std::string::npos) { + if (msgStr.find("NO CARRIER") != std::string::npos) { //TODO:M.P handle it LOG_DEBUG((name + ": call failed/aborted").c_str()); } // Received new SMS - if (msg->m_data.find("+CMTI: ") != std::string::npos) { + if (msgStr.find("+CMTI: ") != std::string::npos) { //TODO:M.P handle new SMS - LOG_DEBUG((name + ": received new SMS: " + msg->m_data).c_str()); + LOG_DEBUG((name + ": received new SMS notification").c_str()); } + + // Received signal strength change + if (msgStr.find("+QIND: \"csq\" ") != std::string::npos) { + //TODO:M.P handle new SMS + LOG_DEBUG((name + ": received signal strength change notification").c_str()); + } + + return 0; } diff --git a/module-cellular/Modem/NotificationMuxChannel.hpp b/module-cellular/Modem/NotificationMuxChannel.hpp index 7db81a853..8fd227944 100644 --- a/module-cellular/Modem/NotificationMuxChannel.hpp +++ b/module-cellular/Modem/NotificationMuxChannel.hpp @@ -24,7 +24,7 @@ public: - int ParseInMessage(MuxChannelMsg* msg) override final; + int ParseInputData(uint8_t* data, size_t size) override final; }; diff --git a/module-services/service-cellular/ServiceCellular.cpp b/module-services/service-cellular/ServiceCellular.cpp index bb68597fb..eed9fa627 100644 --- a/module-services/service-cellular/ServiceCellular.cpp +++ b/module-services/service-cellular/ServiceCellular.cpp @@ -31,6 +31,9 @@ ServiceCellular::ServiceCellular() muxdaemon->Start(); + //vTaskDelay(3000); + //muxdaemon->Exit(); + } ServiceCellular::~ServiceCellular() {