- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我必须更新连接到串行端口的设备上的固件和设置。
由于这是由一系列命令完成的,因此我发送一个命令并等待我收到答复。在 answere (多行)中,我搜索指示操作是否成功完成的字符串。
Serial->write(“boot”, 1000);
Serial->waitForKeyword(“boot successful”);
Serial->sendFile(“image.dat”);
…
bool waitForKeyword(const QString &keyword)
{
QString str;
// read all lines
while(serial->readLines(10000))
{
// check each line
while((str = serial->getLine()) != "")
{
// found!
if(str.contains(keyword))
return true;
}
}
// timeout
return false;
}
bool SerialPort::readLines(int waitTimeout)
{
if(!waitForReadyRead(waitTimeout))
{
qDebug() << "Timeout reading" << endl;
return false;
}
QByteArray data = readAll();
while (waitForReadyRead(100))
data += readAll();
char* begin = data.data();
char* ptr = strstr(data, "\r\n");
while(ptr != NULL)
{
ptr+=2;
buffer.append(begin, ptr - begin);
emit readyReadLine(buffer);
lineBuffer.append(QString(buffer)); // store line in Qstringlist
buffer.clear();
begin = ptr;
ptr = strstr(begin, "\r\n");
}
// rest
buffer.append(begin, -1);
return true;
}
最佳答案
让我们使用 QStateMachine
来简化这个过程。让我们回想一下您希望这样的代码看起来如何:
Serial->write("boot", 1000);
Serial->waitForKeyword("boot successful");
Serial->sendFile("image.dat");
让我们把它放在一个类中,该类具有程序员可能处于的每个状态的显式状态成员。我们还将有 Action 生成器
send
、
expect
等,将给定的 Action 附加到状态。
// https://github.com/KubaO/stackoverflown/tree/master/questions/comm-commands-32486198
#include <QtWidgets>
#include <private/qringbuffer_p.h>
#include <type_traits>
[...]
class Programmer : public StatefulObject {
Q_OBJECT
AppPipe m_port { nullptr, QIODevice::ReadWrite, this };
State s_boot { &m_mach, "s_boot" },
s_send { &m_mach, "s_send" };
FinalState s_ok { &m_mach, "s_ok" },
s_failed { &m_mach, "s_failed" };
public:
Programmer(QObject * parent = 0) : StatefulObject(parent) {
connectSignals();
m_mach.setInitialState(&s_boot);
send (&s_boot, &m_port, "boot\n");
expect(&s_boot, &m_port, "boot successful", &s_send, 1000, &s_failed);
send (&s_send, &m_port, ":HULLOTHERE\n:00000001FF\n");
expect(&s_send, &m_port, "load successful", &s_ok, 1000, &s_failed);
}
AppPipe & pipe() { return m_port; }
};
这是功能齐全、完整的程序员代码!完全异步、非阻塞,并且它也处理超时。
AppPipe
是一个简单的进程内双向管道,可用作真正串行端口的替代品:
// See http://stackoverflow.com/a/32317276/1329652
/// A simple point-to-point intra-process pipe. The other endpoint can live in any
/// thread.
class AppPipe : public QIODevice {
[...]
};
StatefulObject
包含一个状态机、一些用于监控状态机进程的基本信号,以及用于将信号与状态连接的
connectSignals
方法:
class StatefulObject : public QObject {
Q_OBJECT
Q_PROPERTY (bool running READ isRunning NOTIFY runningChanged)
protected:
QStateMachine m_mach { this };
StatefulObject(QObject * parent = 0) : QObject(parent) {}
void connectSignals() {
connect(&m_mach, &QStateMachine::runningChanged, this, &StatefulObject::runningChanged);
for (auto state : m_mach.findChildren<QAbstractState*>())
QObject::connect(state, &QState::entered, this, [this, state]{
emit stateChanged(state->objectName());
});
}
public:
Q_SLOT void start() { m_mach.start(); }
Q_SIGNAL void runningChanged(bool);
Q_SIGNAL void stateChanged(const QString &);
bool isRunning() const { return m_mach.isRunning(); }
};
State
和
FinalState
是 Qt 3 风格的简单命名状态包装器。它们允许我们一次性声明状态并为其命名。
template <class S> struct NamedState : S {
NamedState(QState * parent, const char * name) : S(parent) {
this->setObjectName(QLatin1String(name));
}
};
typedef NamedState<QState> State;
typedef NamedState<QFinalState> FinalState;
Action 生成器也很简单。 Action 生成器的意思是“在进入给定状态时做某事”。要执行的状态始终作为第一个参数给出。第二个和后续参数特定于给定的操作。有时,一个 Action 也可能需要一个目标状态,例如如果成功或失败。
void send(QAbstractState * src, QIODevice * dev, const QByteArray & data) {
QObject::connect(src, &QState::entered, dev, [dev, data]{
dev->write(data);
});
}
QTimer * delay(QState * src, int ms, QAbstractState * dst) {
auto timer = new QTimer(src);
timer->setSingleShot(true);
timer->setInterval(ms);
QObject::connect(src, &QState::entered, timer, static_cast<void (QTimer::*)()>(&QTimer::start));
QObject::connect(src, &QState::exited, timer, &QTimer::stop);
src->addTransition(timer, SIGNAL(timeout()), dst);
return timer;
}
void expect(QState * src, QIODevice * dev, const QByteArray & data, QAbstractState * dst,
int timeout = 0, QAbstractState * dstTimeout = nullptr)
{
addTransition(src, dst, dev, SIGNAL(readyRead()), [dev, data]{
return hasLine(dev, data);
});
if (timeout) delay(src, timeout, dstTimeout);
}
hasLine
测试只是检查可以从设备读取的所有行以获取给定的针。这适用于这个简单的通信协议(protocol)。如果您的通信涉及更多,您将需要更复杂的机器。有必要阅读所有的行,即使你找到了你的针。这是因为该测试是从
readyRead
信号调用的,在该信号中,您必须读取满足所选标准的所有数据。这里,标准是数据形成整条线。
static bool hasLine(QIODevice * dev, const QByteArray & needle) {
auto result = false;
while (dev->canReadLine()) {
auto line = dev->readLine();
if (line.contains(needle)) result = true;
}
return result;
}
使用默认 API 向状态添加 protected 转换有点麻烦,因此我们将对其进行包装以使其更易于使用,并保持上面的 Action 生成器的可读性:
template <typename F>
class GuardedSignalTransition : public QSignalTransition {
F m_guard;
protected:
bool eventTest(QEvent * ev) Q_DECL_OVERRIDE {
return QSignalTransition::eventTest(ev) && m_guard();
}
public:
GuardedSignalTransition(const QObject * sender, const char * signal, F && guard) :
QSignalTransition(sender, signal), m_guard(std::move(guard)) {}
GuardedSignalTransition(const QObject * sender, const char * signal, const F & guard) :
QSignalTransition(sender, signal), m_guard(guard) {}
};
template <typename F> static GuardedSignalTransition<F> *
addTransition(QState * src, QAbstractState *target,
const QObject * sender, const char * signal, F && guard) {
auto t = new GuardedSignalTransition<typename std::decay<F>::type>
(sender, signal, std::forward<F>(guard));
t->setTargetState(target);
src->addTransition(t);
return t;
}
就是这样 - 如果你有一个真正的设备,那就是你所需要的。由于我没有你的设备,我将创建另一个
StatefulObject
来模拟假定的设备行为:
class Device : public StatefulObject {
Q_OBJECT
AppPipe m_dev { nullptr, QIODevice::ReadWrite, this };
State s_init { &m_mach, "s_init" },
s_booting { &m_mach, "s_booting" },
s_firmware { &m_mach, "s_firmware" };
FinalState s_loaded { &m_mach, "s_loaded" };
public:
Device(QObject * parent = 0) : StatefulObject(parent) {
connectSignals();
m_mach.setInitialState(&s_init);
expect(&s_init, &m_dev, "boot", &s_booting);
delay (&s_booting, 500, &s_firmware);
send (&s_firmware, &m_dev, "boot successful\n");
expect(&s_firmware, &m_dev, ":00000001FF", &s_loaded);
send (&s_loaded, &m_dev, "load successful\n");
}
Q_SLOT void stop() { m_mach.stop(); }
AppPipe & pipe() { return m_dev; }
};
现在让我们把这一切都很好地可视化。我们将有一个带有文本浏览器的窗口,显示通信内容。下面是启动/停止编程器或设备的按钮,以及指示仿真设备和编程器状态的标签:
int main(int argc, char ** argv) {
using Q = QObject;
QApplication app{argc, argv};
Device dev;
Programmer prog;
QWidget w;
QGridLayout grid{&w};
QTextBrowser comms;
QPushButton devStart{"Start Device"}, devStop{"Stop Device"},
progStart{"Start Programmer"};
QLabel devState, progState;
grid.addWidget(&comms, 0, 0, 1, 3);
grid.addWidget(&devState, 1, 0, 1, 2);
grid.addWidget(&progState, 1, 2);
grid.addWidget(&devStart, 2, 0);
grid.addWidget(&devStop, 2, 1);
grid.addWidget(&progStart, 2, 2);
devStop.setDisabled(true);
w.show();
我们将连接设备和程序员的
AppPipe
s。我们还将可视化程序员正在发送和接收的内容:
dev.pipe().addOther(&prog.pipe());
prog.pipe().addOther(&dev.pipe());
Q::connect(&prog.pipe(), &AppPipe::hasOutgoing, &comms, [&](const QByteArray & data){
comms.append(formatData(">", "blue", data));
});
Q::connect(&prog.pipe(), &AppPipe::hasIncoming, &comms, [&](const QByteArray & data){
comms.append(formatData("<", "green", data));
});
最后,我们将连接按钮和标签:
Q::connect(&devStart, &QPushButton::clicked, &dev, &Device::start);
Q::connect(&devStop, &QPushButton::clicked, &dev, &Device::stop);
Q::connect(&dev, &Device::runningChanged, &devStart, &QPushButton::setDisabled);
Q::connect(&dev, &Device::runningChanged, &devStop, &QPushButton::setEnabled);
Q::connect(&dev, &Device::stateChanged, &devState, &QLabel::setText);
Q::connect(&progStart, &QPushButton::clicked, &prog, &Programmer::start);
Q::connect(&prog, &Programmer::runningChanged, &progStart, &QPushButton::setDisabled);
Q::connect(&prog, &Programmer::stateChanged, &progState, &QLabel::setText);
return app.exec();
}
#include "main.moc"
Programmer
和
Device
可以存在于任何线程中。我将它们留在主线程中,因为没有理由将它们移出,但是您可以将它们都放入专用线程中,或者将每个放入自己的线程中,或者放入与其他对象共享的线程中,等等。自
AppPipe
以来它是完全透明的支持跨线程通信。如果使用
QSerialPort
而不是
AppPipe
也会出现这种情况。重要的是
QIODevice
的每个实例仅在一个线程中使用。其他一切都通过信号/插槽连接发生。
Programmer
存在于专用线程中,则可以在
main
的某处添加以下内容:
// fix QThread brokenness
struct Thread : QThread { ~Thread() { quit(); wait(); } };
Thread progThread;
prog.moveToThread(&progThread);
progThread.start();
一个小助手格式化数据以使其更易于阅读:
static QString formatData(const char * prefix, const char * color, const QByteArray & data) {
auto text = QString::fromLatin1(data).toHtmlEscaped();
if (text.endsWith('\n')) text.truncate(text.size() - 1);
text.replace(QLatin1Char('\n'), QString::fromLatin1("<br/>%1 ").arg(QLatin1String(prefix)));
return QString::fromLatin1("<font color=\"%1\">%2 %3</font><br/>")
.arg(QLatin1String(color)).arg(QLatin1String(prefix)).arg(text);
}
关于c++ - 发送一系列命令并等待响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32486198/
我正在使用 voip 推送通知制作 ios 应用程序。 我想从 Node js 发送 voip 推送通知,但不是很好。 我阅读了本教程 CallKit iOS Swift Tutorial for V
我编写了一个服务器,当浏览器尝试连接到某些站点时,它会检查黑名单并发回 404,但是当我调用 send() 时没有错误,但消息不会出现在网络上浏览器,除非我关闭连接? 有什么建议吗? 接受来自浏览器的
#include int main() { char c = getchar(); //EOF (ctrl + d ) while( ( c = getchar() ) != '?'
我正在尝试使用MailMessage对象通过PowerShell发送电子邮件。该脚本使用Import-CSV来使用文件,然后在电子邮件正文中使用ConvertTo-HTML。由于我要发送的电子邮件客户
我需要创建一个脚本,每 30 秒对网络流量进行一次采样并存储发送/接收的字节。该数据随后用于绘制图形。我编写了一个在 Windows 2012 上完美运行的程序,但我意识到某些 cmdlet 在以前的
我正在运行“autoit3.chm”文件。当它运行时,我想发送一个向下键箭头,但它不起作用: $file = FileGetShortName("C:\Users\PHSD100-SIC\Deskto
当我使用网络浏览器测试我的程序时,我可以很好地写入套接字/FD,所以我决定循环它并在连接中途切断连接,我发现了一个问题。 send() 能够在套接字不可用时关闭整个程序。我认为问题在于该程序陷入了第
我正在运行“autoit3.chm”文件。当它运行时,我想发送一个向下键箭头,但它不起作用: $file = FileGetShortName("C:\Users\PHSD100-SIC\Deskto
所以我试图向自己发送数据并接收数据然后打印它,现在我已经测试了一段时间,我注意到它没有发送任何东西,事实上,也许它是,但我没有正确接收它,我需要这方面的帮助。 这就是我用来发送数据的
问题:开发人员创建自己的序列化格式有多常见?具体来说,我使用 java 本质上将对象作为一个巨大的字符串发送,并用标记来分隔变量。 我的逻辑:我选择这个是因为它几乎消除了语言依赖性(忽略java的修改
我必须在 Linux 上编写一个应用程序,该应用程序需要与具有自定义以太网类型的设备进行通信。甚至在如何编写这样的应用程序中也有很多解决方案。一个缺点是需要 root 访问权限(AFAIK)。之后释放
我有一个包含三个单选按钮选项的表单。我需要将表单数据提交到另一个文件,但由于某种原因,发送的数据包含所选单选按钮的值“on”,而不是 value 属性的值。 我尝试通过 post() 函数手动操作和发
基本上我想实现这样的目标: Process 1 Thread 1 Receive X from process 2 Thread 2 Receive Y from proces
我目前正在 Google App Engine 上开发一个系统,对它还很陌生,我正在使用 Java 平台进行开发。我在 servlet 之间发送 session 对象时遇到问题。我已经在 appeng
当我尝试将“this”(触发的元素)作为参数发送给函数时,函数收到“Object[Document build.php]”作为参数,而不是触发的元素。请让我知道我的错误: function set(a
我正在寻找让我的应用响应联系人 > 发送的魔法咒语。我希望能够接收联系人的 URI 以便检索联系人。谁有 list 过滤器/代码 fragment 吗? 最佳答案 我没有睾丸,但您可以尝试基于 ACT
关于我心爱的套接字的另一个问题。我先解释一下我的情况。之后我会告诉你是什么困扰着我。 我有一个客户端和一个服务器。这两个应用程序都是用 C++ 编写的,实现了 winsock2。连接通过 TCP 和
我看到了这篇文章 http://www.eskimo.com/~scs/cclass/int/sx5.html 但这部分让我感到困惑:如果我们已经使用 send_array 或 send_array_
我对这行代码有疑问。我必须将一个数据包带到一个端口并重新发送到接口(interface)(例如:eth0)。我的程序成功地从端口获取数据包,但是当我重新发送(使用 send())到接口(interfa
我正在尝试编写一个 X11 输入驱动程序,它可以使用我的 Android 手机上的触摸屏来移动和单击鼠标。我可以正常移动鼠标,但我无法让应用程序正确识别点击。我当前的代码位于 https://gist
我是一名优秀的程序员,十分优秀!