diff --git a/module-bsp/board/linux/cellular/linux_cellular.cpp b/module-bsp/board/linux/cellular/linux_cellular.cpp index bd3b589e8..e842b7508 100644 --- a/module-bsp/board/linux/cellular/linux_cellular.cpp +++ b/module-bsp/board/linux/cellular/linux_cellular.cpp @@ -17,6 +17,7 @@ #include #include #include +#include @@ -33,12 +34,50 @@ namespace bsp } else{ // open serial port - fd = open(term,O_RDWR | O_NOCTTY | O_NONBLOCK); + fd = open(term,O_RDWR | O_NOCTTY); // Set serial port attributes //set_interface_attribs(); //set_mincount(0); + /* *** Configure Port *** */ + struct termios tty; + memset (&tty, 0, sizeof tty); + +/* Error Handling */ + if ( tcgetattr ( fd, &tty ) != 0 ) + { + std::cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << "\n"; + } + +/* Set Baud Rate */ + cfsetospeed (&tty, B115200); + cfsetispeed (&tty, B115200); + +/* Setting other Port Stuff */ + tty.c_cflag &= ~PARENB; // Make 8n1 + tty.c_cflag &= ~CSTOPB; + tty.c_cflag &= ~CSIZE; + tty.c_cflag |= CS8; + tty.c_cflag &= ~CRTSCTS; // no flow control + tty.c_lflag = 0; // no signaling chars, no echo, no canonical processing + tty.c_oflag = 0; // no remapping, no delays + tty.c_cc[VMIN] = 0; // read doesn't block + tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout + + tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines + tty.c_iflag &= ~(IXON | IXOFF | IXANY);// turn off s/w flow ctrl + tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw + tty.c_oflag &= ~OPOST; // make raw + +/* Flush Port, then applies attributes */ + tcflush( fd, TCIFLUSH ); + + if ( tcsetattr ( fd, TCSANOW, &tty ) != 0) + { + std::cout << "Error " << errno << " from tcsetattr" << "\n"; + } + } epoll_fd = epoll_create1(0); @@ -51,7 +90,6 @@ namespace bsp struct epoll_event event; event.events = EPOLLIN; - event.data.fd = fd; if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event)) { @@ -87,13 +125,14 @@ namespace bsp return ret; } - uint32_t LinuxCellular::Write(void *buf, size_t nbytes) { + ssize_t LinuxCellular::Write(void *buf, size_t nbytes) { return write(fd,buf,nbytes); } uint32_t LinuxCellular::Wait(uint32_t timeout) { retry: + auto event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, timeout); if(event_count == 0){ return 0; // timeout @@ -132,8 +171,8 @@ namespace bsp tty.c_oflag &= ~OPOST; /* fetch bytes as they become available */ - tty.c_cc[VMIN] = 1; - tty.c_cc[VTIME] = 1; + tty.c_cc[VMIN] = 0; + tty.c_cc[VTIME] = 0; if (tcsetattr(fd, TCSANOW, &tty) != 0) { printf("Error from tcsetattr: %s\n", strerror(errno)); diff --git a/module-bsp/board/linux/cellular/linux_cellular.hpp b/module-bsp/board/linux/cellular/linux_cellular.hpp index e09f3b69b..e80ab2389 100644 --- a/module-bsp/board/linux/cellular/linux_cellular.hpp +++ b/module-bsp/board/linux/cellular/linux_cellular.hpp @@ -38,7 +38,7 @@ namespace bsp { ssize_t Read(void *buf, size_t nbytes) override final; - uint32_t Write(void *buf, size_t nbytes) override final; + ssize_t Write(void *buf, size_t nbytes) override final; private: diff --git a/module-bsp/board/rt1051/cellular/rt1051_cellular.cpp b/module-bsp/board/rt1051/cellular/rt1051_cellular.cpp index e4abc0b1a..c274fa913 100644 --- a/module-bsp/board/rt1051/cellular/rt1051_cellular.cpp +++ b/module-bsp/board/rt1051/cellular/rt1051_cellular.cpp @@ -219,7 +219,7 @@ namespace bsp { return xStreamBufferReceive(uartRxStreamBuffer, buf, nbytes, 0); } - uint32_t RT1051Cellular::Wait(uint32_t timeout) { + ssize_t RT1051Cellular::Wait(uint32_t timeout) { if (blockedTaskHandle != nullptr) { LOG_FATAL("Wait called simultaneously from more than one thread!"); return 0; diff --git a/module-bsp/board/rt1051/cellular/rt1051_cellular.hpp b/module-bsp/board/rt1051/cellular/rt1051_cellular.hpp index 545956057..076812ceb 100644 --- a/module-bsp/board/rt1051/cellular/rt1051_cellular.hpp +++ b/module-bsp/board/rt1051/cellular/rt1051_cellular.hpp @@ -39,7 +39,7 @@ namespace bsp { ssize_t Read(void *buf, size_t nbytes) override final; - uint32_t Write(void *buf, size_t nbytes) override final; + ssize_t Write(void *buf, size_t nbytes) override final; diff --git a/module-bsp/bsp/cellular/bsp_cellular.hpp b/module-bsp/bsp/cellular/bsp_cellular.hpp index 689a7e8f9..91daeaf89 100644 --- a/module-bsp/bsp/cellular/bsp_cellular.hpp +++ b/module-bsp/bsp/cellular/bsp_cellular.hpp @@ -35,7 +35,7 @@ namespace bsp { virtual ssize_t Read(void *buf, size_t nbytes) = 0; - virtual uint32_t Write(void *buf, size_t nbytes) = 0; + virtual ssize_t Write(void *buf, size_t nbytes) = 0; }; diff --git a/module-cellular/Modem/GSM0710.cpp b/module-cellular/Modem/GSM0710.cpp index 3261e1b69..2009c34d8 100644 --- a/module-cellular/Modem/GSM0710.cpp +++ b/module-cellular/Modem/GSM0710.cpp @@ -14,9 +14,10 @@ #include "log/log.hpp" constexpr unsigned char GSM0710Buffer::crcTable[]; +const int GSM0710Buffer::cmux_N1; -std::unique_ptr GSM0710Buffer::GetCompleteFrame(std::unique_ptr frame) { +GSM0710Frame* GSM0710Buffer::GetCompleteFrame(GSM0710Frame* frame) { int end; unsigned int length_needed = 5;// channel, type, length, fcs, flag unsigned char fcs = 0xFF; @@ -121,7 +122,7 @@ std::unique_ptr GSM0710Buffer::GetCompleteFrame(std::unique_ptrlength; end++) fcs = crcTable[fcs ^ (frame->data[end])]; @@ -178,7 +179,7 @@ std::unique_ptr GSM0710Buffer::GetCompleteFrame(std::unique_ptrcontrol & ~static_cast(MuxDefines::GSM0710_PF)) == static_cast(type); } - inline bool GSM0710_COMMAND_IS(MuxDefines type,unsigned char frame){ + static inline bool GSM0710_COMMAND_IS(MuxDefines type,unsigned char frame){ return (frame & ~static_cast(MuxDefines::GSM0710_CR)) == static_cast(type); } @@ -154,7 +154,7 @@ public: int length); - std::unique_ptr GetCompleteFrame(std::unique_ptr frame); + GSM0710Frame* GetCompleteFrame(GSM0710Frame* frame); }; diff --git a/module-cellular/Modem/InputSerialWorker.cpp b/module-cellular/Modem/InputSerialWorker.cpp index 15fff6421..ac4de0def 100644 --- a/module-cellular/Modem/InputSerialWorker.cpp +++ b/module-cellular/Modem/InputSerialWorker.cpp @@ -104,7 +104,7 @@ int InputSerialWorker::ReadIncomingData() { LOG_INFO("READ SIZE : %d", length); } } else { - LOG_DEBUG("Free space is not enough"); + LOG_DEBUG("Not enough space in buffer"); } break; @@ -118,13 +118,14 @@ int InputSerialWorker::ReadIncomingData() { int InputSerialWorker::ExtractFrames() { int frames_extracted = 0; - std::unique_ptr frame; + GSM0710Frame local_frame; + GSM0710Frame *frame = &local_frame; - while (muxDaemon->inputBuffer->GetCompleteFrame(std::move(frame)) != NULL) { + while (muxDaemon->inputBuffer->GetCompleteFrame(frame) != NULL) { frames_extracted++; - if ((muxDaemon->inputBuffer->GSM0710_FRAME_IS(MuxDefines::GSM0710_TYPE_UI, frame.get()) || - muxDaemon->inputBuffer->GSM0710_FRAME_IS(MuxDefines::GSM0710_TYPE_UIH, frame.get()))) { + if ((muxDaemon->inputBuffer->GSM0710_FRAME_IS(MuxDefines::GSM0710_TYPE_UI, frame) || + muxDaemon->inputBuffer->GSM0710_FRAME_IS(MuxDefines::GSM0710_TYPE_UIH, frame))) { LOG_DEBUG("Frame is UI or UIH"); if (frame->control & static_cast(MuxDefines::GSM0710_PF)) { muxDaemon->uih_pf_bit_received = 1; @@ -157,8 +158,7 @@ int InputSerialWorker::ExtractFrames() { } else { //control channel command LOG_DEBUG("Frame channel == 0, control channel command"); - // TODO:M.P implement control channel command handling - //handle_command(frame); + HandleCtrlChannelCommands(frame); } } else { //not an information frame @@ -169,8 +169,8 @@ int InputSerialWorker::ExtractFrames() { case MuxDefines::GSM0710_TYPE_UA: LOG_DEBUG("Frame is UA"); if (muxDaemon->channels[frame->channel].GetState() == MuxChannel::State::Opened) { - //TODO:M.P implement logical channel close - // SYSCHECK(logical_channel_close(channellist+frame->channel)); + // 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()); } else { @@ -191,8 +191,8 @@ int InputSerialWorker::ExtractFrames() { break; case MuxDefines::GSM0710_TYPE_DM: if (muxDaemon->channels[frame->channel].GetState() == MuxChannel::State::Opened) { - //TODO:M.P implement logical channel close - // SYSCHECK(logical_channel_close(channellist+frame->channel)); + // 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()); } else { @@ -208,8 +208,11 @@ int InputSerialWorker::ExtractFrames() { case MuxDefines::GSM0710_TYPE_DISC: if (muxDaemon->channels[frame->channel].GetState() == MuxChannel::State::Opened) { muxDaemon->channels[frame->channel].SetState(MuxChannel::State::Closed); - //TODO:M.P implement write frame - // write_frame(frame->channel, NULL, 0, GSM0710_TYPE_UA | GSM0710_PF); + + 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; LOG_INFO("Control channel closed"); @@ -220,8 +223,10 @@ int InputSerialWorker::ExtractFrames() { //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()); - //TODO:M.P implement write frame - //write_frame(frame->channel, NULL, 0, GSM0710_TYPE_DM | GSM0710_PF); + // Send Mux frame + muxDaemon->WriteMuxFrame(frame->channel, NULL, 0, + static_cast(MuxDefines::GSM0710_TYPE_DM) | + static_cast(MuxDefines::GSM0710_PF)); } break; case MuxDefines::GSM0710_TYPE_SABM: @@ -237,8 +242,10 @@ int InputSerialWorker::ExtractFrames() { 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); - //TODO:M.P implement write frame - // write_frame(frame->channel, NULL, 0, GSM0710_TYPE_UA | GSM0710_PF); + // Send mux frame + muxDaemon->WriteMuxFrame(frame->channel, NULL, 0, + static_cast(MuxDefines::GSM0710_TYPE_UA) | + static_cast(MuxDefines::GSM0710_PF)); if (frame->channel == muxDaemon->virtualPortsCount) //TODO: M.P dunno what is this for ?? // ql_cmux_debug = 0; @@ -249,4 +256,146 @@ int InputSerialWorker::ExtractFrames() { return frames_extracted; +} + +int InputSerialWorker::HandleCtrlChannelCommands(GSM0710Frame* frame) { + unsigned char type, signals; + int length = 0, i, type_length, channel, supported = 1; + unsigned char *response; + + //struct ussp_operation op; + if (frame->length > 0) + { + type = frame->data[0];// only a byte long types are handled now skip extra bytes + for (i = 0; (frame->length > i && (frame->data[i] & static_cast(MuxDefines ::GSM0710_EA)) == 0); i++); + i++; + type_length = i; + if ((type & static_cast(MuxDefines ::GSM0710_CR)) == static_cast(MuxDefines ::GSM0710_CR)) + { +//command not ack extract frame length + while (frame->length > i) + { + length = (length * 128) + ((frame->data[i] & 254) >> 1); + if ((frame->data[i] & 1) == 1) + break; + i++; + } + i++; + MuxDefines ftype = static_cast(type & ~static_cast(MuxDefines ::GSM0710_CR)); + switch (ftype) + { + 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; + break; + case MuxDefines ::GSM0710_CONTROL_PSC: + LOG_INFO("Power Service Control command: ***"); + LOG_INFO("Frame->data = %s / frame->length = %d", frame->data + i, frame->length - i); + break; + case MuxDefines ::GSM0710_CONTROL_TEST: + LOG_INFO("Test command: "); + LOG_INFO("Frame->data = %s / frame->length = %d", frame->data + i, frame->length - i); + //serial->ping_number = 0; + break; + case MuxDefines ::GSM0710_CONTROL_MSC: + LOG_INFO("GET MSC"); + if (i + 1 < frame->length) + { + channel = ((frame->data[i] & 252) >> 2); + i++; + signals = (frame->data[i]); +//op.op = USSP_MSC; +//op.arg = USSP_RTS; +//op.len = 0; + LOG_INFO("Modem status command on channel %d", channel); + 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)) == static_cast(MuxDefines ::GSM0710_SIGNAL_FC)) + LOG_INFO("No frames allowed"); + else + { +//op.arg |= USSP_CTS; + LOG_INFO("Frames allowed"); + } + if ((signals & static_cast(MuxDefines ::GSM0710_SIGNAL_RTC)) == static_cast(MuxDefines ::GSM0710_SIGNAL_RTC)) + { +//op.arg |= USSP_DSR; + LOG_INFO("Signal RTC"); + } + if ((signals & static_cast(MuxDefines ::GSM0710_SIGNAL_IC)) == static_cast(MuxDefines ::GSM0710_SIGNAL_IC)) + { +//op.arg |= USSP_RI; + LOG_INFO("Signal Ring"); + } + if ((signals & static_cast(MuxDefines ::GSM0710_SIGNAL_DV)) == static_cast(MuxDefines ::GSM0710_SIGNAL_DV)) + { +//op.arg |= USSP_DCD; + LOG_INFO("Signal DV"); + } + } + else + LOG_ERROR("Modem status command, but no info. i: %d, len: %d, data-len: %d", + i, length, frame->length); + break; + default: + LOG_ERROR("Unknown command (%d) from the control channel", type); + if ((response = static_cast(malloc(sizeof(char) * (2 + type_length)))) != NULL) + { + i = 0; + response[i++] = static_cast(MuxDefines ::GSM0710_CONTROL_NSC); + type_length &= 127; //supposes that type length is less than 128 + response[i++] = static_cast(MuxDefines ::GSM0710_EA) | (type_length << 1); + while (type_length--) + { + response[i] = frame->data[i - 2]; + i++; + } + muxDaemon->WriteMuxFrame(0, response, i, static_cast(MuxDefines ::GSM0710_TYPE_UIH)); + free(response); + supported = 0; + } + else + LOG_ERROR("Out of memory, when allocating space for response"); + break; + } + if (supported) + { +//acknowledge the command + frame->data[0] = frame->data[0] & ~static_cast(MuxDefines ::GSM0710_CR); + LOG_INFO("response MSC..."); + muxDaemon->WriteMuxFrame(0, frame->data, frame->length, static_cast(MuxDefines ::GSM0710_TYPE_UIH)); + LOG_INFO("response MSC"); +#if 0 + switch ((type & ~GSM0710_CR)){ + case GSM0710_CONTROL_MSC: + if (frame->control & GSM0710_PF){ //Check if the P/F var needs to be set again (cleared in write_frame) + uih_pf_bit_received = 1; + } + LOGMUX(LOG_DEBUG, "Sending 1st MSC command App->Modem"); + frame->data[0] = frame->data[0] | GSM0710_CR; //setting the C/R bit to "command" + write_frame(0, frame->data, frame->length, GSM0710_TYPE_UIH); + break; + default: + break; + } +#endif + } + } + else + { +//received ack for a command + if (GSM0710Buffer::GSM0710_COMMAND_IS(static_cast(type), static_cast(MuxDefines ::GSM0710_CONTROL_NSC))) + LOG_ERROR("The mobile station didn't support the command sent"); + else if(GSM0710Buffer::GSM0710_COMMAND_IS(static_cast(type),static_cast(MuxDefines ::GSM0710_CONTROL_MSC))) + { + LOG_INFO("Channel:%d FC:%d",(frame->data[i] & 252) >> 2,frame->data[0]&0x2); + LOG_INFO("\n\nGET ACK FOR MSC\n\n"); + //sleep(1); + } + else + LOG_INFO("Command acknowledged by the mobile station"); + } + } + return 0; } \ No newline at end of file diff --git a/module-cellular/Modem/InputSerialWorker.hpp b/module-cellular/Modem/InputSerialWorker.hpp index 36f39c06d..ef9ea477b 100644 --- a/module-cellular/Modem/InputSerialWorker.hpp +++ b/module-cellular/Modem/InputSerialWorker.hpp @@ -14,6 +14,7 @@ #include "FreeRTOS.h" #include "task.h" +#include "GSM0710.hpp" class MuxDaemon; @@ -38,6 +39,7 @@ private: int ReadIncomingData(); int ExtractFrames(); + int HandleCtrlChannelCommands(GSM0710Frame* frame); //worker's task handle xTaskHandle taskHandle; diff --git a/module-cellular/Modem/MuxChannel.cpp b/module-cellular/Modem/MuxChannel.cpp index 544900aff..51bcae4e5 100644 --- a/module-cellular/Modem/MuxChannel.cpp +++ b/module-cellular/Modem/MuxChannel.cpp @@ -10,3 +10,25 @@ #include "MuxChannel.hpp" +#include "GSM0710.hpp" +#include "MuxDaemon.hpp" + +MuxChannel::MuxChannel(MuxDaemon *mux,uint32_t logicalNumber,const char *name) : + v24signals( + static_cast(MuxDefines::GSM0710_SIGNAL_DV ) | static_cast(MuxDefines::GSM0710_SIGNAL_RTR) | + static_cast(MuxDefines::GSM0710_SIGNAL_RTC) | static_cast(MuxDefines::GSM0710_EA)), + frameAllowed(1), + disc_ua_pending(0), + logicalNumber(logicalNumber), + name(name), + state(State::Closed), + mux(mux){ + + // Send virtrual channel request frame to GSM modem + mux->WriteMuxFrame(logicalNumber,NULL,0, static_cast(MuxDefines ::GSM0710_TYPE_SABM) | static_cast(MuxDefines ::GSM0710_PF)); + +} + +MuxChannel::~MuxChannel() { + +} \ No newline at end of file diff --git a/module-cellular/Modem/MuxChannel.hpp b/module-cellular/Modem/MuxChannel.hpp index 62a4747e8..cd36a5952 100644 --- a/module-cellular/Modem/MuxChannel.hpp +++ b/module-cellular/Modem/MuxChannel.hpp @@ -14,6 +14,8 @@ #include +class MuxDaemon; + class MuxChannel { public: @@ -22,6 +24,9 @@ public: Closed }; + MuxChannel(MuxDaemon* mux,uint32_t logicalNumber,const char* name="Default"); + virtual ~MuxChannel(); + std::string& GetName(){ return name; } @@ -34,11 +39,17 @@ public: state = state; } + int v24signals; + int frameAllowed; int disc_ua_pending; + uint32_t logicalNumber; + + private: std::string name; State state; + MuxDaemon* mux; }; diff --git a/module-cellular/Modem/MuxDaemon.cpp b/module-cellular/Modem/MuxDaemon.cpp index d23da5c24..6cd39bac8 100644 --- a/module-cellular/Modem/MuxDaemon.cpp +++ b/module-cellular/Modem/MuxDaemon.cpp @@ -18,104 +18,108 @@ #include "FreeRTOS.h" #include "task.h" +constexpr unsigned char MuxDaemon::closeChannelCmd[]; + + MuxDaemon::MuxDaemon() { cellular = bsp::Cellular::Create(); inSerialDataWorker = std::make_unique(this); + inputBuffer = std::make_unique(); } MuxDaemon::~MuxDaemon() { - + Exit();//TODO: M.P only temporary solution } int MuxDaemon::Start() { // At first send AT command to check if modem is turned on - if(SendAT("AT\r\n",500) == -1){ + if (SendAT("AT\r\n", 500) == -1) { // If no response, power up modem and try again cellular->PowerUp(); uint32_t retries = 10; - while(--retries){ - if(SendAT("AT\r\n",500) == 0){ + while (--retries) { + if (SendAT("AT\r\n", 500) == 0) { break; } } - if(retries == 0){ + if (retries == 0) { LOG_FATAL("No communication with GSM modem"); return -1; } } - // Spawn input serial stream worker - inSerialDataWorker->Init(); // Set up modem configuration // Set fixed baudrate = 115200 - SendAT("AT+IPR=115200\r",500); + SendAT("AT+IPR=115200\r", 500); // Turn off local echo - SendAT("ATE0\r",500); + SendAT("ATE0\r", 500); // Route URCs to first MUX channel - SendAT("AT+QCFG=\"cmux/urcport\",1\r\n",500); + SendAT("AT+QCFG=\"cmux/urcport\",1\r\n", 500); // Turn off RI pin for incoming calls SendAT("AT+QCFG=\"urc/ri/ring\",\"off\"\r\n", 500); // Turn off RI pin for incoming sms - SendAT("AT+QCFG=\"urc/ri/smsincoming\",\"off\"\r\n",500); + SendAT("AT+QCFG=\"urc/ri/smsincoming\",\"off\"\r\n", 500); // Route URCs to UART1 SendAT("AT+QURCCFG=\"urcport\",\"uart1\"\r\n", 500); char gsm_command[128] = {}; - if (inputBuffer->cmux_mode){ + if (inputBuffer->cmux_mode) { snprintf(gsm_command, sizeof(gsm_command), "AT+CMUX=1\r\n"); - } - else { - snprintf(gsm_command, sizeof(gsm_command), "AT+CMUX=%d,%d,%d,%d\r\n" - , inputBuffer->cmux_mode - , inputBuffer->cmux_subset - , quectel_speeds[inputBuffer->cmux_port_speed] - , inputBuffer->cmux_N1 + } else { + snprintf(gsm_command, sizeof(gsm_command), "AT+CMUX=%d,%d,%d,%d\r\n", inputBuffer->cmux_mode, + inputBuffer->cmux_subset, quectel_speeds[inputBuffer->cmux_port_speed], inputBuffer->cmux_N1 ); } // Start CMUX multiplexer SendAT(gsm_command, 500); - state = States ::MUX_STATE_MUXING; + // Spawn input serial stream worker + inSerialDataWorker->Init(); + + // Create virtual channels + for (uint32_t i = 0; i < virtualPortsCount; ++i) { + channels.push_back(MuxChannel(this,i)); + } + + state = States::MUX_STATE_MUXING; } int MuxDaemon::Exit() { inSerialDataWorker->Deinit(); + CloseMux(); } int MuxDaemon::SendAT(const char *cmd, uint32_t timeout) { char buff[256] = {0}; - cellular->Write(const_cast(cmd),strlen(cmd)); + auto bytesWritten = cellular->Write(const_cast(cmd), strlen(cmd)); + LOG_DEBUG("BytesWritten: %d",bytesWritten); - if(cellular->Wait(500)){ + if (cellular->Wait(500)) { - vTaskDelay(500); - auto bytesRead = cellular->Read(buff,sizeof buff); + //vTaskDelay(500); + usleep(1000*500); + auto bytesRead = cellular->Read(buff, sizeof buff); - if (memstr((char *) buff, bytesRead, "OK")) - { + if (memstr((char *) buff, bytesRead, "OK")) { LOG_DEBUG("Received OK"); return 0; - } - else if (memstr((char *) buff, bytesRead, "ERROR")) - { + } else if (memstr((char *) buff, bytesRead, "ERROR")) { LOG_DEBUG("Received ERROR"); return -1; - } - else{ + } else { LOG_DEBUG("Received unknown response"); return -1; } - } - else{ + } else { return -1; } } @@ -123,9 +127,10 @@ int MuxDaemon::SendAT(const char *cmd, uint32_t timeout) { ssize_t MuxDaemon::WriteMuxFrame(int channel, const unsigned char *input, int length, unsigned char type) { /* flag, GSM0710_EA=1 C channel, frame type, length 1-2 */ - unsigned char prefix[5] = { static_cast(MuxDefines ::GSM0710_FRAME_FLAG), - static_cast(MuxDefines ::GSM0710_EA) | static_cast(MuxDefines ::GSM0710_CR), 0, 0, 0 }; - unsigned char postfix[2] = { 0xFF, static_cast(MuxDefines ::GSM0710_FRAME_FLAG )}; + unsigned char prefix[5] = {static_cast(MuxDefines::GSM0710_FRAME_FLAG), + static_cast(MuxDefines::GSM0710_EA) | + static_cast(MuxDefines::GSM0710_CR), 0, 0, 0}; + unsigned char postfix[2] = {0xFF, static_cast(MuxDefines::GSM0710_FRAME_FLAG )}; ssize_t prefix_length = 4; int c; unsigned char tmp[GSM0710Buffer::cmux_FRAME]; @@ -136,10 +141,12 @@ ssize_t MuxDaemon::WriteMuxFrame(int channel, const unsigned char *input, int le prefix[1] = prefix[1] | ((63 & (unsigned char) channel) << 2); /* let's set control field */ prefix[2] = type; - if ((type == static_cast(MuxDefines ::GSM0710_TYPE_UIH) || type == static_cast(MuxDefines ::GSM0710_TYPE_UI)) && + if ((type == static_cast(MuxDefines::GSM0710_TYPE_UIH) || + type == static_cast(MuxDefines::GSM0710_TYPE_UI)) && uih_pf_bit_received == 1 && - inputBuffer->GSM0710_COMMAND_IS(MuxDefines ::GSM0710_CONTROL_MSC, input[0]) ){ - prefix[2] = prefix[2] | static_cast(MuxDefines ::GSM0710_PF); //Set the P/F bit in Response if Command from modem had it set + inputBuffer->GSM0710_COMMAND_IS(MuxDefines::GSM0710_CONTROL_MSC, input[0])) { + prefix[2] = prefix[2] | + static_cast(MuxDefines::GSM0710_PF); //Set the P/F bit in Response if Command from modem had it set uih_pf_bit_received = 0; //Reset the variable, so it is ready for next command } /* let's not use too big frames */ @@ -149,46 +156,67 @@ ssize_t MuxDaemon::WriteMuxFrame(int channel, const unsigned char *input, int le /* Modified acording PATCH CRC checksum */ /* postfix[0] = frame_calc_crc (prefix + 1, prefix_length - 1); */ /* length */ - if (length > 127) - { + if (length > 127) { prefix_length = 5; prefix[3] = (0x007F & length) << 1; prefix[4] = (0x7F80 & length) >> 7; - } - else + } else { prefix[3] = 1 | (length << 1); + } postfix[0] = GSM0710Buffer::frameCalcCRC(prefix + 1, prefix_length - 1); memcpy(tmp, prefix, prefix_length); - if (length > 0) - { + if (length > 0) { memcpy(tmp + prefix_length, input, length); } memcpy(tmp + prefix_length + length, postfix, 2); c = prefix_length + length + 2; - syslogdump(">s ", tmp, c); - serial_device_write(&serial, tmp, c); + //Write newly created frame into serial output buffer + WriteSerialCache(tmp, c); } return length; } +ssize_t MuxDaemon::WriteSerialCache(unsigned char *input, size_t length) { + //TODO: M.P implement actual caching + cpp_freertos::LockGuard lock(serOutMutex); + cellular->Write(input, length); +} + +int MuxDaemon::CloseMux() { + + for (auto &w : channels) { + if (w.GetState() == MuxChannel::State::Opened) { + if (inputBuffer->cmux_mode) { + WriteMuxFrame(w.logicalNumber, NULL, 0, + static_cast(MuxDefines::GSM0710_CONTROL_CLD ) | + static_cast(MuxDefines::GSM0710_CR)); + } else { + WriteMuxFrame(w.logicalNumber, closeChannelCmd, sizeof(closeChannelCmd), static_cast(MuxDefines ::GSM0710_TYPE_UIH)); + } + + LOG_INFO("Logical channel %d closed", w.logicalNumber); + } + } + + channels.clear(); +} + int MuxDaemon::memstr(const char *haystack, int length, const char *needle) { int i; int j = 0; if (needle[0] == '\0') return 1; for (i = 0; i < length; i++) - if (needle[j] == haystack[i]) - { + if (needle[j] == haystack[i]) { j++; if (needle[j] == '\0') // Entire needle was found return 1; - } - else + } else j = 0; return 0; } \ No newline at end of file diff --git a/module-cellular/Modem/MuxDaemon.hpp b/module-cellular/Modem/MuxDaemon.hpp index 55a50d0a2..47f94b593 100644 --- a/module-cellular/Modem/MuxDaemon.hpp +++ b/module-cellular/Modem/MuxDaemon.hpp @@ -19,29 +19,38 @@ #include "Service/Worker.hpp" #include "InputSerialWorker.hpp" #include "GSM0710.hpp" +#include "mutex.hpp" class MuxDaemon { friend InputSerialWorker; - friend void workerTaskFunction( void* ptr ); + friend MuxChannel; + + friend void workerTaskFunction(void *ptr); public: MuxDaemon(); + ~MuxDaemon(); int Start(); + int Exit(); private: - int SendAT(const char* cmd,uint32_t timeout); + int SendAT(const char *cmd, uint32_t timeout); + ssize_t WriteMuxFrame(int channel, const unsigned char *input, int length, unsigned char type); + ssize_t WriteSerialCache(unsigned char *input, size_t length); + + int CloseMux(); /* @@ -58,8 +67,7 @@ private: int length, const char *needle); - enum class States - { + enum class States { MUX_STATE_OPENING, MUX_STATE_INITILIZING, MUX_STATE_MUXING, @@ -81,6 +89,10 @@ private: 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 20, 23, 26 }; + constexpr static unsigned char closeChannelCmd[] = { + static_cast(MuxDefines::GSM0710_CONTROL_CLD ) | + static_cast(MuxDefines::GSM0710_CR), + static_cast(MuxDefines::GSM0710_EA ) | (0 << 1)}; std::unique_ptr cellular; @@ -92,14 +104,12 @@ private: std::unique_ptr inputBuffer; std::vector channels; + cpp_freertos::MutexStandard serOutMutex; + uint32_t virtualPortsCount = 3; int uih_pf_bit_received = 0; - - - - };