Files
MuditaOS/module-cellular/Modem/TS0710/DLC_channel.cpp
breichel 1a165ee797 [EGD-5692] Change URC parsing mechanism
Improved the mechanism for processing URC messages
so that long messages and those containing end of line
inside messages can be handled also if income
in more than one data chunk.
2021-02-18 16:38:54 +01:00

212 lines
6.0 KiB
C++

// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
/**
* Project Untitled
*/
#include "DLC_channel.h"
#include "TS0710.h"
#include "TS0710_DATA.h"
#include "TS0710_DLC_ESTABL.h"
#include "TS0710_DLC_RELEASE.h"
#include "TS0710_Frame.h"
#include "log/log.hpp"
#include "ticks.hpp"
#include <Utils.hpp>
#include <cstdlib>
/**
* DLC_channel implementation
*/
DLC_channel::DLC_channel(DLCI_t DLCI, std::string name, bsp::Cellular *cellular, Callback_t callback)
{
LOG_DEBUG("Creating DLCI %i channel \"%s\"", DLCI, name.c_str());
pv_name = name;
pv_DLCI = DLCI;
pv_cellular = cellular;
if (callback != nullptr)
pv_callback = callback;
DLC_ESTABL_SystemParameters_t system_parameters;
system_parameters.TypeOfFrame = TypeOfFrame_e::SABM;
system_parameters.ConvergenceLayer = 1;
system_parameters.Priority = 1;
system_parameters.AckTime = 100; // 100ms default
system_parameters.MaxFrameSize = 128;
system_parameters.MaxNumOfRetransmissions = 3; // default 3
system_parameters.ErrRecovWindowSize = 2; // default 2
TS0710_DLC_ESTABL establ = TS0710_DLC_ESTABL(DLCI, system_parameters, cellular);
pv_chanParams = establ.getParams();
// wait for return & set active
active = establ.getResponse();
LOG_DEBUG("Create channel %s: %s", pv_name.c_str(), active ? "TRUE" : "FALSE");
}
DLC_channel::~DLC_channel()
{
TS0710_DLC_RELEASE release = TS0710_DLC_RELEASE(pv_DLCI);
}
void DLC_channel::SendData(std::vector<uint8_t> &data)
{
TS0710_DATA _data = TS0710_DATA(pv_DLCI, pv_chanParams, data, pv_cellular);
}
#if 0 // left here for reference
ssize_t DLC_channel::ReceiveData(std::vector<uint8_t> &data, uint32_t timeout) {
ssize_t ret = -1;
static uint8_t *buf = nullptr;
buf = reinterpret_cast<uint8_t*>(malloc(pv_chanParams.MaxFrameSize));
bool complete = false;
while((!complete) && (timeout--)) { //TODO: add timeout control
ret = pv_cellular->Read(reinterpret_cast<void *>(buf), pv_chanParams.MaxFrameSize);
if (ret > 0) {
LOG_DEBUG("Received %i bytes", ret);
for (int i = 0; i < ret; i++)
data.push_back(buf[i]);
complete = TS0710_Frame::isComplete(data);
}
sleep_ms(1);
}
if (!complete)
LOG_ERROR("Incomplete frame received");
if (timeout == 0)
LOG_ERROR("Timeout occured");
free(buf);
if (!TS0710_Frame::isMyChannel(data, pv_DLCI)) {
data.clear();
ret = -1;
}
return ret;
}
#endif
void DLC_channel::cmd_init()
{}
void DLC_channel::cmd_send(std::string cmd)
{
std::vector<uint8_t> data(cmd.begin(), cmd.end());
SendData(data);
}
std::string DLC_channel::cmd_receive()
{
cpp_freertos::LockGuard lock(mutex);
TS0710_Frame::frame_t frame;
std::vector<uint8_t> v(responseBuffer.begin(), responseBuffer.end());
responseBuffer.clear();
std::vector<std::vector<uint8_t>> mFrames;
std::vector<uint8_t> rawBuffer;
// get frames from buffer
for (size_t i = 0; i < v.size(); i++) {
rawBuffer.push_back(v[i]);
if (/*TS0710_Frame::isComplete(rawBuffer)*/ (rawBuffer.size() > 1) && (rawBuffer[0] == 0xF9) &&
(rawBuffer[rawBuffer.size() - 1] == 0xF9)) {
// LOGrawBufferEBUG("Pushing back FRAME");
mFrames.push_back(rawBuffer);
rawBuffer.clear();
}
}
// deseriaise data from received frames
std::string deserialisedData;
for (std::vector<uint8_t> vv : mFrames) {
frame.deserialize(vv);
std::string str(frame.data.begin(), frame.data.end());
// append deserialised buffer
deserialisedData += str;
}
mFrames.clear();
return deserialisedData;
}
void DLC_channel::cmd_post()
{}
std::vector<std::string> DLC_channel::SendCommandPrompt(const char *cmd, size_t rxCount, uint32_t timeout)
{
std::vector<std::string> tokens;
blockedTaskHandle = xTaskGetCurrentTaskHandle();
at::Result result;
cmd_init();
std::string cmdFixed = formatCommand(cmd);
cmd_send(cmdFixed);
uint32_t currentTime = cpp_freertos::Ticks::GetTicks();
uint32_t timeoutNeeded = timeout == UINT32_MAX ? UINT32_MAX : currentTime + timeout;
uint32_t timeElapsed = currentTime;
// wait_for_data:
while (1) {
if (timeElapsed >= timeoutNeeded) {
result.code = at::Result::Code::TIMEOUT;
break;
}
auto ret = ulTaskNotifyTake(pdTRUE, timeoutNeeded - timeElapsed);
timeElapsed = cpp_freertos::Ticks::GetTicks();
if (ret) {
std::vector<std::string> strings;
cpp_freertos::LockGuard lock(mutex);
TS0710_Frame::frame_t frame;
std::vector<uint8_t> v(responseBuffer.begin(), responseBuffer.end());
responseBuffer.clear();
frame.deserialize(v);
std::string str(frame.data.begin(), frame.data.end());
// tokenize responseBuffer
auto pos = str.find(">");
if (pos != std::string::npos) {
tokens.push_back(str.substr(pos, strlen(">")));
break;
}
if (tokens.size() >= rxCount) {
break;
}
}
}
cmd_log(cmdFixed, result, timeout);
cmd_post();
blockedTaskHandle = nullptr;
return tokens;
}
int DLC_channel::ParseInputData(std::vector<uint8_t> &data)
{
cpp_freertos::LockGuard lock(mutex);
if (blockedTaskHandle) {
responseBuffer.append(reinterpret_cast<char *>(data.data()), data.size());
xTaskNotifyGive(blockedTaskHandle);
}
else if (pv_callback != nullptr) {
TS0710_Frame frame(data);
auto deserialised = frame.getFrame().data;
std::string receivedData = std::string(deserialised.begin(), deserialised.end());
pv_callback(receivedData);
}
return 1;
}