WIP: BG95_base::command parser and sequencer script representation

This commit is contained in:
2021-09-24 18:06:45 +03:00
parent bab3fd04fe
commit fd64d8726c
4 changed files with 192 additions and 215 deletions
+65 -53
View File
@@ -31,6 +31,7 @@
#ifndef TBX_DRV_BG95_base_H_
#define TBX_DRV_BG95_base_H_
#define __cplusplus 201703L
#include <core/core.h>
#include <core/crtp.h>
@@ -39,10 +40,10 @@
#include <utils/sequencer.h>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
//#include <iostream>
#include <utility>
#include <atomic>
namespace tbx {
@@ -116,7 +117,6 @@ class BG95_base
using base_type = sequencer<BG95_base, Cont_t, char, N>;
using str_view_t = typename base_type::str_view_t;
using range_t = typename Cont_t::range_t;
using status_t = typename base_type::status_t;
//! \name Public types
//! @{
@@ -124,17 +124,22 @@ class BG95_base
using action_t = typename base_type::action_t;
using control_t = typename base_type::control_t;
using match_t = typename base_type::match_t;
using handler_t = typename base_type::handler_ft;
template<size_t Nr, size_t Nh =2>
using script_t = typename base_type::template script_t<Nr, Nh>;
using handler_ft = typename base_type::handler_ft;
template<size_t Nm>
using script_t = typename base_type::template script_t<Nm>;
//! Publish delimiter
constexpr static char delimiter = Delimiter;
//! Required typenames for async operation
//! Required types for inetd async handler operation
//! @{
struct inetd_handler_t {
str_view_t token;
match_t match;
handler_ft handler;
};
template <size_t Nm>
using async_handlers = std::array<typename base_type::handle_t, Nm>;
using inetd_handlers = std::array<inetd_handler_t, Nm>;
//! @}
//! @}
@@ -176,32 +181,48 @@ class BG95_base
//! @{
private:
template<typename T>
ptrdiff_t parse (char* str, size_t n, char next, T& value) {
auto next_ptr = std::find(str, &str[n], next);
char save = *next_ptr;
*next_ptr =0;
void extract (const char* str, T* value) {
static_assert (
std::is_same_v<std::remove_cv_t<T>, int>
|| std::is_same_v<std::remove_cv_t<T>, double>
|| std::is_same_v<std::remove_cv_t<T>, char>,
"Not supported conversion type.");
if constexpr (std::is_same_v<std::remove_cv_t<T>, int>) {
sscanf(str, "%d", &value);
} else if (std::is_same_v<std::remove_cv_t<T>, float>) {
sscanf(str, "%f", &value);
*value = std::atoi(str);
} else if (std::is_same_v<std::remove_cv_t<T>, double>) {
sscanf(str, "%lf", &value);
*value = std::atof(str);
} else if (std::is_same_v<std::remove_cv_t<T>, char>) {
sscanf(str, "%c", &value);
std::strcpy(value, str);
}
*next_ptr = save;
return next_ptr - str;
}
ptrdiff_t parse (char* str, size_t n, char next, char* value) {
auto next_ptr = std::find(str, &str[n], next);
char save = *next_ptr;
*next_ptr =0;
strcpy(value, str);
*next_ptr = save;
return next_ptr - str;
template <char Marker = '%'>
std::pair<size_t, bool> parse (const char* expected, const str_view_t buffer, char* token) {
if (*expected == Marker) {
// We have Marker. Copy to token the next part of buffer, from begin up to expected[1] where
// the expected[1] character is and return the size of that part.
auto next = std::find(buffer.begin(), buffer.end(), expected[1]);
if (next == buffer.end()) {
*token =0;
return std::make_pair(0, false);
}
char* nullpos = std::copy(buffer.begin(), next, token);
*nullpos =0;
return std::make_pair(next - buffer.begin(), true);
}
else if (*expected == buffer.front()) {
// We have character match, copy the character to token and return 1 (the char size)
*token++ = buffer.front();
*token =0;
return std::make_pair(1, false);
}
else {
// Discrepancy. Return 0 (none parsed)
*token =0;
return std::make_pair(0, false);
}
}
//! @}
//! \name public functionality
@@ -248,9 +269,6 @@ class BG95_base
return 0;
}
// cmd: "AT+CREG?"
// expected: "\r\n+CREG: 0,%\r\n\r\nOK\r\n"
/*!
* \brief
* Send a command to modem and check if the response matches to
@@ -279,32 +297,26 @@ class BG95_base
* \endcode
*/
template <typename T, char Marker = '%'>
bool command (const char* cmd, const str_view_t expected, T& t, clock_t timeout =0) {
bool command (const str_view_t cmd, const str_view_t expected, T* value, clock_t timeout =0) {
char buffer[N];
char token[N];
transmit(cmd);
transmit(cmd.data()); // send command
for (size_t pos =0, i=0, j=0 ; pos < expected.size(); pos += j) {
str_view_t ex = expected.substr(pos); // get starting point of expected
for (auto ex = expected.begin() ; ex != expected.end() ; ) {
clock_t mark = clock(); // load the answer with timeout
size_t sz =0;
clock_t mark = clock();
do {
sz = receive(buffer); // load the answer with timeout
if ((timeout != 0 )&& ((clock() - mark) >= timeout)) {
sz = receive(buffer);
if ((timeout != 0 )&& ((clock() - mark) >= timeout))
return false;
}
} while (!sz);
for (i=0, j=0 ; i<sz ; ) {
if (ex[j] == Marker) {
i += parse(&buffer[i], sz, ex[j+1], t); // parse and convert
++j;
}
else if (ex[j] == buffer[i]) {
++i; // if same consume current character
++j;
}
else
return false; // Fail to parse
for (size_t i=0 ; i<sz ; ) { // parse buffer based on expected
auto [step, marker] = parse<Marker> (ex++, {&buffer[i], sz-i}, token);
if (!step) return false;
if (marker) extract(token, value);
i += step;
}
}
return true;
@@ -322,16 +334,16 @@ class BG95_base
* \param loop Flag to indicate blocking mode. If true blocking.
*/
template <size_t Nm =0>
void inetd (bool loop =true, const async_handlers<Nm>* async_handles =nullptr) {
void inetd (bool loop =true, const inetd_handlers<Nm>* inetd_handlers =nullptr) {
std::array<char, N> buffer;
size_t resp_size;
do {
if ((resp_size = get_(buffer.data())) != 0) {
// on data check for async handlers
bool match = false;
if (async_handles != nullptr) {
for (auto& h : *async_handles)
match |= base_type::check_handle (h, buffer.data());
if (inetd_handlers != nullptr) {
for (auto& h : *inetd_handlers)
match |= base_type::check_handle(h.token, h.match, h.handler, {buffer.data(), resp_size});
}
// if no match forward data to receive channel.
if (!match) {