I was trying to use the similar way that Kuba has done in post here. Basically I want to construct a overridden StatefulObject programatically using
void Command::buildStatefulCommands(DeviceComm* dev, COMMAND_TYPE cmdtype, const QAbstractProxyModel* entries)
{
// according to cmdtype and number of entries, build the transition mapping dynamically
....
switch (cmdtype) {
case CMDUploadEntries: {
connectSignals(); // the same as in example
send (&s_start, dev, QByteArray::fromHex(entries.at(index,0))); // 'dev' changed to use my own DeviceComm for communication,
expect(&s_start, dev, QByteArray::fromHex(entries.at(index,1)), &s_ok_01, 3000, &s_failed);
expect(&s_start, dev, QByteArray::fromHex(entries.at(index,2)), &s_ok_02, 3000, &s_failed);
....
}
The state transition building process of StatefulObject will be called everytime a button is clicked (because the data to send might be changed)
void MainWindow::on_btnSend_clicked(){
....
// the cmdtype is used for different tasks
Command* cmd = Command::getCommand(cmdtype);
cmd->buildStatefulCommands(m_commDev, cmdtype, getDatabase());
if (cmd->isRunning())
cmd->stop();
cmd->start();
}
Question 1. As the setup of statemachine is done multiple times, how to disconnect the old signal/slot pair? I guess every time 'send' invocation will cause a new lambda anonymous functor be created due to the capture.
void send(QAbstractState * src, QIODevice * dev, const QByteArray & data) {
// how to disconnect the previous connect?
conn =
QObject::connect(src, &QState::entered, dev, [dev, data]{
dev->write(data);
});
}
The second related question, instead of using 'readyRead' signal as in original 'expect' while adding transition
void expect(QState * src, QIODevice * dev, const QByteArray & pattern, QAbstractState * dst,
int timeout = 0, QAbstractState * dstTimeout = nullptr)
{
addTransition(src, dst, dev, SIGNAL(readyRead()), [dev, pattern]{
return hasLine(dev, data);
});
if (timeout) delay(src, timeout, dstTimeout);
}
how can I use a signal 'responsePosted' that has argument (say, 'payload') to be connected with lambda that still has capture list (i.e. the pattern to check with)? I tried to use auto to cast into function pointer, but not supported with capture in it.
Q_SIGNALS: // 'dev' signals
void responsePosted(const QByteArray& payload);
....
// I want to have different pattern to check with while building the state transition table
addTransition(src, dst, dev, SIGNAL(responsePosted()), [dev, pattern](const QByteArray& payload){
return dev->matching(payload, pattern);
});
The template functor in GuardedSignalTransition for 'eventTest' does not seem to take any argument. How to wrap it with argument?
template <typename F>
class GuardedSignalTransition : public QSignalTransition {
F m_guard;
QByteArray m_pattern; // << I want to store the pattern here
protected:
bool eventTest(QEvent * ev) Q_DECL_OVERRIDE {
return QSignalTransition::eventTest(ev) && m_guard(); // <<<< I guess 'ev' has the passed-in argument ?
}
template <typename F> static GuardedSignalTransition<F> *
addTransition(QState * src, QAbstractState *target,
const QObject * sender, const char * signal, F && guard) { // What function type will F be?
auto t = new GuardedSignalTransition<typename std::decay<F>::type>
(sender, signal, std::forward<F>(guard)); // what should I put here ?
t->setTargetState(target);
src->addTransition(t);
return t;
}
The std::forward, std::move, && annotation and std::decay are difficult to understand.