Browse Source

DEV: contains() data path added to sequencer (as else) and to cli_device

master
parent
commit
fce49ee963
2 changed files with 105 additions and 70 deletions
  1. +40
    -9
      include/com/sequencer.h
  2. +65
    -61
      include/drv/cli_device.h

+ 40
- 9
include/com/sequencer.h View File

@@ -115,8 +115,9 @@ class sequencer {
EXPECT, //!< Expects data from implementation via get()
OR_EXPECT, //!< Expects data from implementation via get() in conjunction with previous EXPECT
DETECT, //!< Detects data into rx buffer without receiving them via contents()
OR_DETECT //!< Detects data into rx buffer without receiving them via contents() in conjunction with
OR_DETECT, //!< Detects data into rx buffer without receiving them via contents() in conjunction with
//!< previous DETECT
OTHERWISE //!< An "else" path if the EXPECT[, OR_EXPECT[, OR_EXPECT ... ]] block timesout.
//! \note
//! The \c DETECT extra incoming channel serve the purpose of sneak into receive
@@ -346,6 +347,7 @@ class sequencer {
case control_t::OR_EXPECT: skip_while = control_t::OR_EXPECT; break;
case control_t::DETECT:
case control_t::OR_DETECT: skip_while = control_t::OR_DETECT; break;
case control_t::OTHERWISE: skip_while = control_t::OTHERWISE; break;
}
s = step;
while (script[++s].control == skip_while)
@@ -357,6 +359,17 @@ class sequencer {
}
}
template <size_t Steps>
size_t expect_end (const script_t<Steps>& script, size_t step) {
while ((++step < Steps) && (script[step].control == control_t::OR_EXPECT)) ;
return step;
}
template <size_t Steps>
size_t detect_end (const script_t<Steps>& script, size_t step) {
while ((++step < Steps) && (script[step].control == control_t::OR_DETECT)) ;
return step;
}
//! @}
@@ -452,34 +465,52 @@ class sequencer {
case control_t::OR_EXPECT:
resp_size = get_(buffer);
if (resp_size) {
size_t s = step ; do{
for (size_t s = step ; s < expect_end(script, step) ; ++s) {
if (script[s].match != nullptr && script[s].match({buffer, resp_size}, script[s].token)) {
handle_ (script[s].handler, {buffer, resp_size});
std::tie(step, status) = action_ (script, s);
break;
}
} while ((++s < Steps) && (script[s].control == control_t::OR_EXPECT));
}
}
if (record.timeout && (clock_() - mark) >= record.timeout) {
size_t s = expect_end(script, step);
if ((s < Steps) && (script[s].control == control_t::OTHERWISE)) {
handle_ (script[s].handler, {buffer, resp_size});
std::tie(step, status) = action_ (script, s);
} else {
return exit_error.value;
}
}
if (record.timeout && (clock_() - mark) >= record.timeout)
return exit_error.value;
break;
case control_t::DETECT:
case control_t::OR_DETECT:
resp_size = contents_(buffer);
if (resp_size) {
size_t s = step ; do {
for (size_t s = step ; s < detect_end(script, step) ; ++s) {
if (script[s].match != nullptr && script[s].match({buffer, resp_size}, script[s].token)) {
handle_ (script[s].handler, {buffer, resp_size});
std::tie(step, status) = action_ (script, s);
break;
}
} while ((++s < Steps) && (script[s].control == control_t::OR_DETECT));
}
}
if (record.timeout && (clock_() - mark) >= record.timeout) {
size_t s = detect_end(script, step);
if ((s < Steps) && (script[s].control == control_t::OTHERWISE)) {
handle_ (script[s].handler, {buffer, resp_size});
std::tie(step, status) = action_ (script, s);
} else {
return exit_error.value;
}
}
if (record.timeout && (clock_() - mark) >= record.timeout)
return exit_error.value;
break;
case control_t::OTHERWISE:
handle_ (script[step].handler, {buffer, resp_size});
std::tie(step, status) = action_ (script, step);
break;
} // switch (record.control)
} while ( status == seq_status_t::CONTINUE);


+ 65
- 61
include/drv/cli_device.h View File

@@ -124,7 +124,8 @@ class cli_device
//! Publish delimiter
constexpr static char delimiter = Delimiter;
enum flush_type { keep =0, flush };
enum Flush_t { Keep =0, Flush };
enum Receive_t { Get =0, Detect };
//! Required types for inetd async handler operation
//! @{
@@ -247,7 +248,7 @@ class cli_device
* \param token Pointer to store the parsed tokens
* \return A (number of characters parsed, marker found) pair
*/
template <char Marker = '%'>
template <char Marker>
std::pair<size_t, bool> parse_ (const char* expected, const string_view buffer, char* token) {
do {
if (*expected == Marker) {
@@ -273,53 +274,22 @@ class cli_device
return std::make_pair(0, false);
}
/*!
* Analyze the response of a command based on \c expected.
*
* Tries to receive data with timeout and match them against expected string_view.
* For each Marker inside the expected string the value gets extracted, converted and
* copied to \c vargs pointer array.
*
* \param expected The expected string view
* \param timeout the timeout in CPU time
* \param vargs Pointer to variable arguments array
* \param nargs Size of variable arguments array
* \return
*/
template<char Marker = '%', typename T>
bool response_ (const string_view expected, clock_t timeout, T* vargs, size_t nargs) {
char buffer[N], token[N], *pbuffer = buffer;
size_t v =0, sz =0;
for (auto ex = expected.begin() ; ex != expected.end() ; ) {
clock_t mark = clock(); // mark the time
while (sz <= 0) { // if buffer is empty get buffer with timeout
sz = receive(buffer);
pbuffer = buffer;
if ((timeout != 0 )&& ((clock() - mark) >= timeout))
return false;
}
// try to parse
auto [step, marker] = parse_<Marker> (ex, {pbuffer, sz}, token);
if (!step)
return false; // discard buffer and fail
if (marker && v < nargs)
extract_(token, vargs[v++]);
pbuffer += step;
sz -= (step <= sz) ? step: sz;
++ex;
}
return true;
}
//! @}
//! \name public functionality
//! @{
public:
//! Clears the incoming data buffer
void clear () noexcept {
rx_q.clear();
}
//! \return Returns the size of the incoming data buffer
size_t size() noexcept {
return rx_q.size();
}
/*!
* \brief
* Transmit data to modem
@@ -370,14 +340,48 @@ class cli_device
return 0;
}
//! Clears the incoming data buffer
void clear () noexcept {
rx_q.clear();
}
/*!
* Analyze the response of a command based on \c expected.
*
* Tries to receive data via get() path with timeout and match them against expected string_view.
* For each Marker inside the expected string the value gets extracted, converted and
* copied to \c vargs pointer array.
*
* \param expected The expected string view
* \param timeout the timeout in CPU time
* \param vargs Pointer to variable arguments array
* \param nargs Size of variable arguments array
* \return
*/
template<Receive_t Recv, char Marker, typename T>
bool response (const string_view expected, clock_t timeout, T* vargs, size_t nargs) {
char buffer[N], token[N], *pbuffer = buffer;
//! \return Returns the size of the incoming data buffer
size_t size() noexcept {
return rx_q.size();
size_t v =0, sz =0;
for (auto ex = expected.begin() ; ex != expected.end() ; ) {
clock_t mark = clock(); // mark the time
while (sz <= 0) { // if buffer is empty get buffer with timeout
if constexpr (Recv == Get)
sz = receive(buffer);
else
sz = contents(buffer);
pbuffer = buffer;
if ((timeout != 0 )&& ((clock() - mark) >= timeout))
return false;
}
// try to parse
auto [step, marker] = parse_<Marker> (ex, {pbuffer, sz}, token);
if (!step)
return false; // discard buffer and fail
if (marker && v < nargs)
extract_(token, vargs[v++]);
pbuffer += step;
sz -= (step <= sz) ? step: sz;
++ex;
}
return true;
}
/*!
@@ -387,7 +391,7 @@ class cli_device
* This function executes 3 steps.
* - Clears the incoming buffer if requested by template parameter
* - Sends the command to device
* - Waits to get the response and parse it accordingly to \c expected \see response_()
* - Waits to get the response and parse it accordingly to \c expected \see response()
*
* The user can mark spots inside the expected string using the \c Marker ['%'] character.
* These spots will be extracted to tokens upon parsing. If the user passes \c values parameters,
@@ -399,7 +403,7 @@ class cli_device
* \param timeout The timeout in CPU time (leave it for 0 - no timeout)
* \param values The value pointer arguments to get the converted tokens
*
* \tparam Flush Flag to indicate if we flush the buffer before command or not
* \tparam Flush Flag to indicate if we Flush the buffer before command or not
* \tparam Marker The marker character
* \tparam Ts The type of the values to read from response marked with \c Marker
* \warning The types MUST be the same
@@ -416,31 +420,31 @@ class cli_device
* cli.command("AT+CREG?\r\n", "%%%OK\r\n", 1000);
*
* // extract a number from response without timeout (blocking)
* cli.command<flush>("AT+CREG?\r\n", "\r\n+CREG: 0,%\r\n\r\nOK\r\n", 0, &status);
* cli.command<Flush>("AT+CREG?\r\n", "\r\n+CREG: 0,%\r\n\r\nOK\r\n", 0, &status);
*
* // extract a number and discard the last 2 lines
* cli.command<flush>("AT+CREG?\r\n", "\r\n+CREG: 0,%\r\n%%", 1000, &status);
* cli.command<Flush>("AT+CREG?\r\n", "\r\n+CREG: 0,%\r\n%%", 1000, &status);
*
* // discard first line, read the 2nd to str, discard the 3rd line.
* // expect the last to be "OK\r\n"
* cli.command<flush>("AT+CREG?\r\n", "", 100000);
* cli.command<keep>("", "%", 1000);
* cli.command<keep>("", "%%", 1000, str);
* cli.command<keep>("", "OK\r\n", 1000);
* cli.command<Flush>("AT+CREG?\r\n", "", 100000);
* cli.command<Keep>("", "%", 1000);
* cli.command<Keep>("", "%%", 1000, str);
* cli.command<Keep>("", "OK\r\n", 1000);
* \endcode
*/
template<flush_type Flush =flush, char Marker = '%', typename ...Ts>
template<Receive_t Recv =Get, Flush_t Flsh =Flush, char Marker = '%', typename ...Ts>
bool command (const string_view cmd, const string_view expected, clock_t timeout, Ts* ...values) {
constexpr size_t Nr = sizeof...(Ts);
front<typelist<Ts...>>* vargs[Nr] = {values...}; // read all args to local buffer
if constexpr (Flush == flush) {
if constexpr (Flsh == Flush) {
clear ();
}
if (transmit(cmd.data(), cmd.size()) != cmd.size()) // send command
return false;
// parse the response and return the status
return response_<Marker>(expected, timeout, vargs, Nr);
return response<Recv, Marker>(expected, timeout, vargs, Nr);
}
/*!


Loading…
Cancel
Save