WIP: ATmodem (renamed after BG95_base) and sequencer

This commit is contained in:
2021-09-27 17:04:46 +03:00
parent ca38dfa2f1
commit f7c904e9c2
5 changed files with 205 additions and 106 deletions
@@ -1,7 +1,7 @@
/*!
* \file utils/sequencer.h
* \file com/sequencer.h
* \brief
* A terminal-like device communication automation tool
* A script based automation tool for send/receive communications
*
* \copyright Copyright (C) 2021 Christos Choutouridis <christos@choutouridis.net>
*
@@ -28,8 +28,8 @@
* </dd></dl>
*/
#ifndef TBX_UTILS_SEQUENCER_H_
#define TBX_UTILS_SEQUENCER_H_
#ifndef TBX_COM_SEQUENCER_H_
#define TBX_COM_SEQUENCER_H_
#include <core/core.h>
@@ -147,14 +147,19 @@ class sequencer {
size_t value; //!< Used by \c GOTO to indicate the next sequencer's step.
};
//! A no_action action_t
static constexpr action_t no_action = {action_t::NO, 0};
//! A next action_t
static constexpr action_t next = {action_t::NEXT, 0};
//! A goto action_t template
template <size_t GOTO>
static constexpr action_t go_to = {action_t::GOTO, static_cast<size_t>(GOTO)};
//! An exit ok action_t
static constexpr action_t exit_ok = {action_t::EXIT, 0};
//! An exit error action_t
static constexpr action_t exit_error = {action_t::EXIT, static_cast<size_t>(-1)};
//! A generic exit action_t template
template <size_t Status>
static constexpr action_t exit = {action_t::EXIT, static_cast<size_t>(Status)};
@@ -421,6 +426,8 @@ class sequencer {
clock_t mark = clock_();
seq_status_t status{seq_status_t::CONTINUE}; do {
if (step >= Steps)
return exit_error.value;
const record_t& record = script[step]; // get reference ot current line
if (step != p_step) { // renew time marker in each step
@@ -452,7 +459,7 @@ class sequencer {
std::tie(step, status) = action_ (script, s);
break;
}
} while (script[++s].control == control_t::OR_EXPECT);
} while ((++s < Steps) && (script[s].control == control_t::OR_EXPECT));
}
if (record.timeout && (clock_() - mark) >= record.timeout)
return exit_error.value;
@@ -468,7 +475,7 @@ class sequencer {
std::tie(step, status) = action_ (script, s);
break;
}
} while (script[++s].control == control_t::OR_DETECT);
} while ((++s < Steps) && (script[s].control == control_t::OR_DETECT));
}
if (record.timeout && (clock_() - mark) >= record.timeout)
return exit_error.value;
@@ -484,4 +491,4 @@ class sequencer {
}
#endif /* TBX_UTILS_SEQUENCER_H_ */
#endif /* TBX_COM_SEQUENCER_H_ */
@@ -1,7 +1,7 @@
/*!
* \file cont/BG95_base.h
* \file drv/ATmodem.h
* \brief
* BG95 driver functionality as CRTP base class
* ATmodem driver functionality as CRTP base class
*
* \copyright Copyright (C) 2021 Christos Choutouridis <christos@choutouridis.net>
*
@@ -28,8 +28,8 @@
* </dd></dl>
*/
#ifndef TBX_DRV_BG95_base_H_
#define TBX_DRV_BG95_base_H_
#ifndef TBX_DRV_ATmodem_H_
#define TBX_DRV_ATmodem_H_
#define __cplusplus 201703L
@@ -37,7 +37,7 @@
#include <core/crtp.h>
#include <cont/equeue.h>
#include <cont/range.h>
#include <utils/sequencer.h>
#include <com/sequencer.h>
#include <cstring>
#include <cstdlib>
@@ -63,12 +63,12 @@ namespace tbx {
* \tparam Delimiter
*/
template<typename Impl_t, size_t N, char Delimiter ='\n'>
class BG95_base
: public sequencer<BG95_base<Impl_t, N, Delimiter>, char, N>{
class ATmodem
: public sequencer<ATmodem<Impl_t, N, Delimiter>, char, N>{
_CRTP_IMPL(Impl_t);
// local type dispatch
using base_type = sequencer<BG95_base, char, N>;
using base_type = sequencer<ATmodem, char, N>;
//! \name Public types
//! @{
@@ -106,10 +106,10 @@ class BG95_base
//!@{
protected:
//!< \brief A default constructor from derived only
BG95_base() = default;
~BG95_base () = default; //!< \brief Allow destructor from derived only
BG95_base(const BG95_base&) = delete; //!< No copies
BG95_base& operator= (const BG95_base&) = delete; //!< No copy assignments
ATmodem() noexcept = default;
~ATmodem () = default; //!< \brief Allow destructor from derived only
ATmodem(const ATmodem&) = delete; //!< No copies
ATmodem& operator= (const ATmodem&) = delete; //!< No copy assignments
//!@}
//! \name Sequencer interface requirements
@@ -139,6 +139,28 @@ class BG95_base
//! \name Private functionality
//! @{
private:
template <typename... Ts>
struct typelist {
using type = typelist; //!< act as identity
};
template <typename L>
struct front_impl {
using type = void;
};
template <typename Head, typename... Tail>
struct front_impl<typelist<Head, Tail...>> {
using type = Head;
};
//! Return the first element in \c meta::typelist \c List.
//!
//! Complexity \f$ O(1) \f$.
template <typename List>
using front = typename front_impl<List>::type;
template<typename T>
void extract (const char* str, T* value) {
static_assert (
@@ -154,6 +176,9 @@ class BG95_base
std::strcpy(value, str);
}
}
void extract (const char* str, void* value) {
(void)*str; (void)value;
}
template <char Marker = '%'>
std::pair<size_t, bool> parse (const char* expected, const string_view buffer, char* token) {
@@ -253,29 +278,45 @@ class BG95_base
* if (done && status == 1)
* std::cout << "Connected to home network\n"
* \endcode
* element_type (&arr)[N]
*/
template <typename T, char Marker = '%'>
bool command (const string_view cmd, const string_view expected, T* value, clock_t timeout =0) {
char buffer[N];
char token[N];
template<char Marker = '%', typename ...Ts>
bool command (const string_view cmd, const string_view expected, clock_t timeout, Ts* ...values) {
transmit(cmd.data()); // send command
constexpr size_t Nr = sizeof...(Ts);
front<typelist<Ts...>>* vargs[Nr] = {values...};
if constexpr (Nr == 0) { (void)vargs; }
char buffer[N], token[N];
size_t v =0;
transmit(cmd.data()); // send command
for (auto ex = expected.begin() ; ex != expected.end() ; ) {
clock_t mark = clock(); // load the answer with timeout
clock_t mark = clock(); // load the answer with timeout
size_t sz =0;
do {
sz = receive(buffer);
if ((timeout != 0 )&& ((clock() - mark) >= timeout))
return false;
} while (!sz);
bool redo = false; do {
do {
sz = receive(buffer);
if ((timeout != 0 )&& ((clock() - mark) >= timeout))
return false;
} while (!sz);
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;
}
redo = false; // have faith to parse successfully
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) {
redo = true; // fail to parse, reload and retry
break;
}
if constexpr (Nr > 0) {
if (marker && v< Nr)
extract(token, vargs[v++]);
}
i += step;
}
} while (redo);
}
return true;
}
@@ -324,4 +365,4 @@ class BG95_base
} // namespace tbx;
#endif /* TBX_DRV_BG95_base_H_ */
#endif /* #ifndef TBX_DRV_ATmodem_H_ */