DEV: contains() data path added to sequencer (as else) and to cli_device
This commit is contained in:
parent
887bbf391e
commit
fce49ee963
@ -115,8 +115,9 @@ class sequencer {
|
|||||||
EXPECT, //!< Expects data from implementation via get()
|
EXPECT, //!< Expects data from implementation via get()
|
||||||
OR_EXPECT, //!< Expects data from implementation via get() in conjunction with previous EXPECT
|
OR_EXPECT, //!< Expects data from implementation via get() in conjunction with previous EXPECT
|
||||||
DETECT, //!< Detects data into rx buffer without receiving them via contents()
|
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
|
//!< previous DETECT
|
||||||
|
OTHERWISE //!< An "else" path if the EXPECT[, OR_EXPECT[, OR_EXPECT ... ]] block timesout.
|
||||||
|
|
||||||
//! \note
|
//! \note
|
||||||
//! The \c DETECT extra incoming channel serve the purpose of sneak into receive
|
//! 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::OR_EXPECT: skip_while = control_t::OR_EXPECT; break;
|
||||||
case control_t::DETECT:
|
case control_t::DETECT:
|
||||||
case control_t::OR_DETECT: skip_while = control_t::OR_DETECT; break;
|
case control_t::OR_DETECT: skip_while = control_t::OR_DETECT; break;
|
||||||
|
case control_t::OTHERWISE: skip_while = control_t::OTHERWISE; break;
|
||||||
}
|
}
|
||||||
s = step;
|
s = step;
|
||||||
while (script[++s].control == skip_while)
|
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:
|
case control_t::OR_EXPECT:
|
||||||
resp_size = get_(buffer);
|
resp_size = get_(buffer);
|
||||||
if (resp_size) {
|
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)) {
|
if (script[s].match != nullptr && script[s].match({buffer, resp_size}, script[s].token)) {
|
||||||
handle_ (script[s].handler, {buffer, resp_size});
|
handle_ (script[s].handler, {buffer, resp_size});
|
||||||
std::tie(step, status) = action_ (script, s);
|
std::tie(step, status) = action_ (script, s);
|
||||||
break;
|
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;
|
break;
|
||||||
|
|
||||||
case control_t::DETECT:
|
case control_t::DETECT:
|
||||||
case control_t::OR_DETECT:
|
case control_t::OR_DETECT:
|
||||||
resp_size = contents_(buffer);
|
resp_size = contents_(buffer);
|
||||||
if (resp_size) {
|
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)) {
|
if (script[s].match != nullptr && script[s].match({buffer, resp_size}, script[s].token)) {
|
||||||
handle_ (script[s].handler, {buffer, resp_size});
|
handle_ (script[s].handler, {buffer, resp_size});
|
||||||
std::tie(step, status) = action_ (script, s);
|
std::tie(step, status) = action_ (script, s);
|
||||||
break;
|
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;
|
break;
|
||||||
|
|
||||||
|
case control_t::OTHERWISE:
|
||||||
|
handle_ (script[step].handler, {buffer, resp_size});
|
||||||
|
std::tie(step, status) = action_ (script, step);
|
||||||
|
break;
|
||||||
} // switch (record.control)
|
} // switch (record.control)
|
||||||
|
|
||||||
} while ( status == seq_status_t::CONTINUE);
|
} while ( status == seq_status_t::CONTINUE);
|
||||||
|
@ -124,7 +124,8 @@ class cli_device
|
|||||||
//! Publish delimiter
|
//! Publish delimiter
|
||||||
constexpr static char delimiter = 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
|
//! Required types for inetd async handler operation
|
||||||
//! @{
|
//! @{
|
||||||
@ -247,7 +248,7 @@ class cli_device
|
|||||||
* \param token Pointer to store the parsed tokens
|
* \param token Pointer to store the parsed tokens
|
||||||
* \return A (number of characters parsed, marker found) pair
|
* \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) {
|
std::pair<size_t, bool> parse_ (const char* expected, const string_view buffer, char* token) {
|
||||||
do {
|
do {
|
||||||
if (*expected == Marker) {
|
if (*expected == Marker) {
|
||||||
@ -273,53 +274,22 @@ class cli_device
|
|||||||
return std::make_pair(0, false);
|
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
|
//! \name public functionality
|
||||||
//! @{
|
//! @{
|
||||||
public:
|
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
|
* \brief
|
||||||
* Transmit data to modem
|
* Transmit data to modem
|
||||||
@ -370,14 +340,48 @@ class cli_device
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Clears the incoming data buffer
|
/*!
|
||||||
void clear () noexcept {
|
* Analyze the response of a command based on \c expected.
|
||||||
rx_q.clear();
|
*
|
||||||
}
|
* 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 v =0, sz =0;
|
||||||
size_t size() noexcept {
|
for (auto ex = expected.begin() ; ex != expected.end() ; ) {
|
||||||
return rx_q.size();
|
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.
|
* This function executes 3 steps.
|
||||||
* - Clears the incoming buffer if requested by template parameter
|
* - Clears the incoming buffer if requested by template parameter
|
||||||
* - Sends the command to device
|
* - 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.
|
* 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,
|
* 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 timeout The timeout in CPU time (leave it for 0 - no timeout)
|
||||||
* \param values The value pointer arguments to get the converted tokens
|
* \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 Marker The marker character
|
||||||
* \tparam Ts The type of the values to read from response marked with \c Marker
|
* \tparam Ts The type of the values to read from response marked with \c Marker
|
||||||
* \warning The types MUST be the same
|
* \warning The types MUST be the same
|
||||||
@ -416,31 +420,31 @@ class cli_device
|
|||||||
* cli.command("AT+CREG?\r\n", "%%%OK\r\n", 1000);
|
* cli.command("AT+CREG?\r\n", "%%%OK\r\n", 1000);
|
||||||
*
|
*
|
||||||
* // extract a number from response without timeout (blocking)
|
* // 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
|
* // 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.
|
* // discard first line, read the 2nd to str, discard the 3rd line.
|
||||||
* // expect the last to be "OK\r\n"
|
* // expect the last to be "OK\r\n"
|
||||||
* cli.command<flush>("AT+CREG?\r\n", "", 100000);
|
* cli.command<Flush>("AT+CREG?\r\n", "", 100000);
|
||||||
* cli.command<keep>("", "%", 1000);
|
* cli.command<Keep>("", "%", 1000);
|
||||||
* cli.command<keep>("", "%%", 1000, str);
|
* cli.command<Keep>("", "%%", 1000, str);
|
||||||
* cli.command<keep>("", "OK\r\n", 1000);
|
* cli.command<Keep>("", "OK\r\n", 1000);
|
||||||
* \endcode
|
* \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) {
|
bool command (const string_view cmd, const string_view expected, clock_t timeout, Ts* ...values) {
|
||||||
constexpr size_t Nr = sizeof...(Ts);
|
constexpr size_t Nr = sizeof...(Ts);
|
||||||
|
|
||||||
front<typelist<Ts...>>* vargs[Nr] = {values...}; // read all args to local buffer
|
front<typelist<Ts...>>* vargs[Nr] = {values...}; // read all args to local buffer
|
||||||
if constexpr (Flush == flush) {
|
if constexpr (Flsh == Flush) {
|
||||||
clear ();
|
clear ();
|
||||||
}
|
}
|
||||||
if (transmit(cmd.data(), cmd.size()) != cmd.size()) // send command
|
if (transmit(cmd.data(), cmd.size()) != cmd.size()) // send command
|
||||||
return false;
|
return false;
|
||||||
// parse the response and return the status
|
// parse the response and return the status
|
||||||
return response_<Marker>(expected, timeout, vargs, Nr);
|
return response<Recv, Marker>(expected, timeout, vargs, Nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
Loading…
x
Reference in New Issue
Block a user