2021-05-13 07:28:05 +02:00
|
|
|
#include <memory>
|
|
|
|
#include <future>
|
|
|
|
#include <cstring>
|
|
|
|
#include "LoopbackTerm.h"
|
|
|
|
|
|
|
|
void LoopbackTerm::start()
|
|
|
|
{
|
|
|
|
status = status_t::STARTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoopbackTerm::stop()
|
|
|
|
{
|
|
|
|
status = status_t::STOPPED;
|
|
|
|
}
|
|
|
|
|
|
|
|
int LoopbackTerm::write(uint8_t *data, size_t len)
|
|
|
|
{
|
2022-06-06 15:05:38 +02:00
|
|
|
if (inject_by) { // injection test: ignore what we write, but respond with injected data
|
|
|
|
auto ret = std::async(&LoopbackTerm::batch_read, this);
|
|
|
|
return len;
|
|
|
|
}
|
2021-06-01 10:21:51 +02:00
|
|
|
if (len > 2 && (data[len - 1] == '\r' || data[len - 1] == '+') ) { // Simple AT responder
|
|
|
|
std::string command((char *)data, len);
|
2021-05-13 07:28:05 +02:00
|
|
|
std::string response;
|
|
|
|
if (command == "+++") {
|
|
|
|
response = "NO CARRIER\r\n";
|
|
|
|
} else if (command == "ATE1\r" || command == "ATE0\r") {
|
2022-06-10 18:04:10 +02:00
|
|
|
response = "OK\r\n ";
|
2021-05-13 07:28:05 +02:00
|
|
|
} else if (command == "ATO\r") {
|
|
|
|
response = "ERROR\r\n";
|
|
|
|
} else if (command.find("ATD") != std::string::npos) {
|
|
|
|
response = "CONNECT\r\n";
|
|
|
|
} else if (command.find("AT+CSQ\r") != std::string::npos) {
|
|
|
|
response = "+CSQ: 123,456\n\r\nOK\r\n";
|
2021-11-25 16:24:49 +01:00
|
|
|
} else if (command.find("AT+CGMM\r") != std::string::npos) {
|
|
|
|
response = "0G Dummy Model\n\r\nOK\r\n";
|
2022-07-11 21:03:55 +02:00
|
|
|
} else if (command.find("AT+COPS?\r") != std::string::npos) {
|
|
|
|
response = "+COPS: 0,0,\"OperatorName\",5\n\r\nOK\r\n";
|
2021-05-13 07:28:05 +02:00
|
|
|
} else if (command.find("AT+CBC\r") != std::string::npos) {
|
2021-12-06 11:16:38 +01:00
|
|
|
response = is_bg96 ? "+CBC: 1,20,123456\r\r\n\r\nOK\r\n\n\r\n" :
|
2021-06-01 10:21:51 +02:00
|
|
|
"+CBC: 123.456V\r\r\n\r\nOK\r\n\n\r\n";
|
2021-05-13 07:28:05 +02:00
|
|
|
} else if (command.find("AT+CPIN=1234\r") != std::string::npos) {
|
|
|
|
response = "OK\r\n";
|
|
|
|
pin_ok = true;
|
|
|
|
} else if (command.find("AT+CPIN?\r") != std::string::npos) {
|
2021-06-01 10:21:51 +02:00
|
|
|
response = pin_ok ? "+CPIN: READY\r\nOK\r\n" : "+CPIN: SIM PIN\r\nOK\r\n";
|
2021-05-13 07:28:05 +02:00
|
|
|
} else if (command.find("AT") != std::string::npos) {
|
2022-06-10 18:04:10 +02:00
|
|
|
if (command.length() > 4) {
|
|
|
|
response = command;
|
|
|
|
response[0] = 'O';
|
|
|
|
response[1] = 'K';
|
|
|
|
response[2] = '\r';
|
|
|
|
response[3] = '\n';
|
|
|
|
} else {
|
|
|
|
response = "OK\r\n";
|
|
|
|
}
|
|
|
|
|
2021-05-13 07:28:05 +02:00
|
|
|
}
|
|
|
|
if (!response.empty()) {
|
|
|
|
data_len = response.length();
|
|
|
|
loopback_data.resize(data_len);
|
|
|
|
memcpy(&loopback_data[0], &response[0], data_len);
|
2021-05-26 14:45:14 +02:00
|
|
|
auto ret = std::async(on_read, nullptr, data_len);
|
2021-05-13 07:28:05 +02:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (len > 2 && data[0] == 0xf9) { // Simple CMUX responder
|
|
|
|
// turn the request into a reply -> implements CMUX loopback
|
2022-06-10 18:04:10 +02:00
|
|
|
if (data[2] == 0x3f || data[2] == 0x53) { // SABM command
|
2021-05-13 07:28:05 +02:00
|
|
|
data[2] = 0x73;
|
2021-06-01 10:21:51 +02:00
|
|
|
} else if (data[2] == 0xef) { // Generic request
|
2021-05-13 07:28:05 +02:00
|
|
|
data[2] = 0xff; // generic reply
|
|
|
|
}
|
|
|
|
}
|
|
|
|
loopback_data.resize(data_len + len);
|
|
|
|
memcpy(&loopback_data[data_len], data, len);
|
|
|
|
data_len += len;
|
2021-05-26 14:45:14 +02:00
|
|
|
auto ret = std::async(on_read, nullptr, data_len);
|
2021-05-13 07:28:05 +02:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
int LoopbackTerm::read(uint8_t *data, size_t len)
|
|
|
|
{
|
|
|
|
size_t read_len = std::min(data_len, len);
|
2022-06-06 15:05:38 +02:00
|
|
|
if (inject_by && read_len > inject_by)
|
|
|
|
read_len = inject_by;
|
2021-05-13 07:28:05 +02:00
|
|
|
if (read_len) {
|
2021-06-01 10:21:51 +02:00
|
|
|
if (loopback_data.capacity() < len) {
|
2021-05-13 07:28:05 +02:00
|
|
|
loopback_data.reserve(len);
|
2021-06-01 10:21:51 +02:00
|
|
|
}
|
2021-05-13 07:28:05 +02:00
|
|
|
memcpy(data, &loopback_data[0], read_len);
|
|
|
|
loopback_data.erase(loopback_data.begin(), loopback_data.begin() + read_len);
|
|
|
|
data_len -= read_len;
|
|
|
|
}
|
|
|
|
return read_len;
|
|
|
|
}
|
|
|
|
|
2022-06-06 15:05:38 +02:00
|
|
|
LoopbackTerm::LoopbackTerm(bool is_bg96): loopback_data(), data_len(0), pin_ok(false), is_bg96(is_bg96), inject_by(0) {}
|
|
|
|
|
|
|
|
LoopbackTerm::LoopbackTerm(): loopback_data(), data_len(0), pin_ok(false), is_bg96(false), inject_by(0) {}
|
|
|
|
|
|
|
|
int LoopbackTerm::inject(uint8_t *data, size_t len, size_t injected_by)
|
|
|
|
{
|
|
|
|
if (data == nullptr) {
|
|
|
|
inject_by = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
2021-05-13 07:28:05 +02:00
|
|
|
|
2022-06-06 15:05:38 +02:00
|
|
|
loopback_data.resize(len);
|
|
|
|
memcpy(&loopback_data[0], data, len);
|
|
|
|
data_len = len;
|
|
|
|
inject_by = injected_by;
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoopbackTerm::batch_read()
|
|
|
|
{
|
|
|
|
while (data_len > 0) {
|
|
|
|
on_read(nullptr, std::min(inject_by, data_len));
|
|
|
|
Task::Delay(1);
|
|
|
|
}
|
|
|
|
}
|
2021-05-13 07:28:05 +02:00
|
|
|
|
|
|
|
LoopbackTerm::~LoopbackTerm() = default;
|