diff --git a/include/com/sequencer.h b/include/com/sequencer.h index 4b98e08..b094c76 100644 --- a/include/com/sequencer.h +++ b/include/com/sequencer.h @@ -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 expect_end (const script_t& script, size_t step) { + while ((++step < Steps) && (script[step].control == control_t::OR_EXPECT)) ; + return step; + } + + template + size_t detect_end (const script_t& 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); diff --git a/include/drv/cli_device.h b/include/drv/cli_device.h index 11772f8..e228492 100644 --- a/include/drv/cli_device.h +++ b/include/drv/cli_device.h @@ -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 + template std::pair 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 - 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_ (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 + 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_ (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("AT+CREG?\r\n", "\r\n+CREG: 0,%\r\n\r\nOK\r\n", 0, &status); + * cli.command("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("AT+CREG?\r\n", "\r\n+CREG: 0,%\r\n%%", 1000, &status); + * cli.command("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("AT+CREG?\r\n", "", 100000); - * cli.command("", "%", 1000); - * cli.command("", "%%", 1000, str); - * cli.command("", "OK\r\n", 1000); + * cli.command("AT+CREG?\r\n", "", 100000); + * cli.command("", "%", 1000); + * cli.command("", "%%", 1000, str); + * cli.command("", "OK\r\n", 1000); * \endcode */ - template + template bool command (const string_view cmd, const string_view expected, clock_t timeout, Ts* ...values) { constexpr size_t Nr = sizeof...(Ts); front>* 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_(expected, timeout, vargs, Nr); + return response(expected, timeout, vargs, Nr); } /*!