mirror of
https://github.com/mudita/MuditaOS.git
synced 2026-04-18 22:18:38 -04:00
* Adding document describing how to use logger * Adjusting logs to follow a new guide * Change order in log header: line number is now before function name
197 lines
6.0 KiB
C++
197 lines
6.0 KiB
C++
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
|
|
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
|
|
|
#include "DLCChannel.h"
|
|
|
|
#include "CellularMuxData.h"
|
|
#include "CellularMuxFrame.h"
|
|
|
|
#include <log/log.hpp>
|
|
#include <ticks.hpp>
|
|
#include <Utils.hpp>
|
|
#include <magic_enum.hpp>
|
|
#include <gsl/util>
|
|
|
|
DLCChannel::DLCChannel(DLCI_t DLCI, const std::string &name, bsp::Cellular *cellular, const Callback_t &callback)
|
|
: Channel{new uint8_t[at::defaultReceiveBufferSize]}, name{name}, DLCI{DLCI}, pvCellular{cellular}
|
|
{
|
|
LOG_DEBUG("Creating DLCI %i channel \"%s\"", DLCI, name.c_str());
|
|
|
|
if (callback != nullptr) {
|
|
pvCallback = callback;
|
|
}
|
|
|
|
chanParams.TypeOfFrame = TypeOfFrame_e::SABM;
|
|
chanParams.ConvergenceLayer = 1;
|
|
chanParams.Priority = 1;
|
|
chanParams.AckTime = 100; // 100ms default
|
|
chanParams.MaxFrameSize = 128;
|
|
chanParams.MaxNumOfRetransmissions = 3; // default 3
|
|
chanParams.ErrRecovWindowSize = 2; // default 2
|
|
|
|
responseBuffer = xMessageBufferCreate(at::defaultMessageBufferSize);
|
|
}
|
|
|
|
bool DLCChannel::init()
|
|
{
|
|
active = establish();
|
|
LOG_INFO("Create channel %s: %s", name.c_str(), active ? "TRUE" : "FALSE");
|
|
|
|
return active;
|
|
}
|
|
|
|
void DLCChannel::sendData(std::vector<uint8_t> &data)
|
|
{
|
|
CellularMuxData(DLCI, chanParams, data, pvCellular);
|
|
}
|
|
|
|
bool DLCChannel::establish()
|
|
{
|
|
LOG_SENSITIVE(LOGDEBUG, "Sending %s frame to DLCI %i", TypeOfFrame_text[chanParams.TypeOfFrame].c_str(), DLCI);
|
|
|
|
CellularMuxFrame frame_c(CellularMuxFrame::frame_t(static_cast<uint8_t>(DLCI << 2) | (1 << 1),
|
|
static_cast<uint8_t>(chanParams.TypeOfFrame)));
|
|
|
|
awaitingResponseFlag.set();
|
|
|
|
bool result = false;
|
|
|
|
for (int retries = 0; retries < chanParams.MaxNumOfRetransmissions; ++retries) {
|
|
pvCellular->write(static_cast<void *>(frame_c.getSerData().data()), frame_c.getSerData().size());
|
|
|
|
auto startTime = std::chrono::steady_clock::now();
|
|
auto endTime = startTime + std::chrono::milliseconds{300};
|
|
|
|
// Wait for response:
|
|
while (true) {
|
|
if (std::chrono::steady_clock::now() > endTime) {
|
|
break;
|
|
}
|
|
|
|
if (size_t bytesRead = cmdReceive(receiveBuffer.get(), std::chrono::milliseconds{0}); bytesRead > 0) {
|
|
auto cellularResult = bsp::cellular::CellularResult{receiveBuffer.get(), bytesRead};
|
|
if (evaluateEstablishResponse(cellularResult)) {
|
|
result = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
awaitingResponseFlag.clear();
|
|
|
|
return result;
|
|
}
|
|
|
|
void DLCChannel::cmdInit()
|
|
{}
|
|
|
|
void DLCChannel::cmdSend(std::string cmd)
|
|
{
|
|
std::vector<uint8_t> data(cmd.begin(), cmd.end());
|
|
sendData(data);
|
|
}
|
|
|
|
size_t DLCChannel::cmdReceive(uint8_t *result, std::chrono::milliseconds timeout)
|
|
{
|
|
return xMessageBufferReceive(responseBuffer, result, 2 * chanParams.MaxFrameSize, pdMS_TO_TICKS(timeout.count()));
|
|
}
|
|
|
|
void DLCChannel::cmdPost()
|
|
{}
|
|
|
|
std::vector<std::string> DLCChannel::sendCommandPrompt(const char *cmd,
|
|
size_t rxCount,
|
|
std::chrono::milliseconds timeout)
|
|
{
|
|
std::vector<std::string> tokens;
|
|
|
|
if (onWakeUpModem != nullptr) {
|
|
onWakeUpModem();
|
|
}
|
|
auto _ = gsl::finally([this] {
|
|
if (onSleepModem != nullptr) {
|
|
onSleepModem();
|
|
}
|
|
});
|
|
|
|
awaitingResponseFlag.set();
|
|
|
|
at::Result result;
|
|
|
|
cmdInit();
|
|
std::string cmdFixed = formatCommand(cmd);
|
|
cmdSend(cmdFixed);
|
|
|
|
auto startTime = std::chrono::steady_clock::now();
|
|
auto endTime = startTime + timeout;
|
|
|
|
// Wait for response:
|
|
while (true) {
|
|
if (std::chrono::steady_clock::now() > endTime) {
|
|
result.code = at::Result::Code::TIMEOUT;
|
|
break;
|
|
}
|
|
|
|
if (size_t bytesRead = cmdReceive(receiveBuffer.get(), std::chrono::milliseconds{0}); bytesRead > 0) {
|
|
auto cellularResult = bsp::cellular::CellularResult{receiveBuffer.get(), bytesRead};
|
|
auto str = cellularResult.getDataAsString();
|
|
|
|
auto cellResult = checkResult(cellularResult.getResultCode());
|
|
if (cellResult.code != at::Result::Code::OK) {
|
|
LOG_DEBUG("SendCommandPrompt cmd response code: %s",
|
|
std::string(magic_enum::enum_name(cellResult.code)).c_str());
|
|
break;
|
|
}
|
|
|
|
// tokenize responseBuffer
|
|
auto pos = str.find('>');
|
|
if (pos != std::string::npos) {
|
|
tokens.push_back(str.substr(pos, strlen(">")));
|
|
break;
|
|
}
|
|
if (tokens.size() >= rxCount) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
cmdLog(cmdFixed, result, timeout);
|
|
cmdPost();
|
|
|
|
awaitingResponseFlag.clear();
|
|
|
|
return tokens;
|
|
}
|
|
|
|
at::Result DLCChannel::parseInputData(bsp::cellular::CellularResult *cellularResult) const
|
|
{
|
|
at::Result result;
|
|
|
|
if (awaitingResponseFlag.state()) {
|
|
if (!xMessageBufferSend(responseBuffer,
|
|
(void *)cellularResult->getSerialized().get(),
|
|
cellularResult->getSerializedSize(),
|
|
pdMS_TO_TICKS(at::defaultBufferTimeoutMs.count()))) {
|
|
LOG_DEBUG("DLC message buffer full!");
|
|
result.code = at::Result::Code::FULL_MSG_BUFFER;
|
|
}
|
|
}
|
|
else if (pvCallback != nullptr) {
|
|
std::string receivedData = cellularResult->getDataAsString();
|
|
pvCallback(receivedData);
|
|
}
|
|
else {
|
|
result.code = at::Result::Code::DATA_NOT_USED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool DLCChannel::evaluateEstablishResponse(bsp::cellular::CellularResult &response) const
|
|
{
|
|
auto frame = CellularMuxFrame{response.getData()};
|
|
return (frame.getFrameDLCI() == DLCI &&
|
|
(frame.getFrame().Control == (static_cast<uint8_t>(TypeOfFrame_e::UA) & ~(1 << 4))));
|
|
}
|