- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在通过串行端口向设备发送(写入)字节。我正在使用 QSerialPort ( http://qt-project.org/wiki/QtSerialPort ) 模块来实例化设备 IO 支持。当我向我的 INSTEON 调制解调器(串行)发送消息时,设备会在读取我的消息后发回我的消息拷贝 + 0x06(ACK 字节),然后是状态消息。
我已经使用 DockLight ( http://www.docklight.de/ ) 测试了我的消息。我发送以下消息来查询设备的状态:
02 62 1D E9 4B 05 19 00
使用 Docklight,我收到响应:
02 62 1D E9 4B 05 19 00 06 02 50 20 CB CF 1E DA F7 21 00 FF
返回的消息完全符合我的预期,即设备已打开。如果关闭,调制解调器将在设备关闭时在最后一个字节位置发回 0x00。现在,我的问题 - 我必须没有正确设置我的函数来发送和接收响应字节。我尝试了许多不同的示例和配置,目前我正在使用以下内容:
设置信号槽连接:
QObject::connect(&thread, SIGNAL(sendResponse(QByteArray)),
this, SLOT(handleResponse(QByteArray)));
QObject::connect(&thread, SIGNAL(error(QString)),
this, SLOT(processError(QString)));
QObject::connect(&thread, SIGNAL(timeout(QString)),
this, SLOT(processTimeout(QString)));
用于遍历设备 QList 的函数。如果设备是所需的类型(“Light”),那么我们将设备 ID 格式化为预期的 QByteArray 消息结构。将消息传递给线程进行发送。 (从 QSerialPort BlockingMaster
示例修改的线程。
void Device::currentStatus(QList<Device *> * deviceList){
QString devID, updateQry;
int devStatus, updateStatus;
updateStatus=0;
QSqlQuery query;
for(int i=0; i<deviceList->size(); i++){
if(deviceList->at(i)->type == "Light"){
devStatus = deviceList->at(i)->status;
devID = deviceList->at(i)->deviceID;
QByteArray msg;
bool msgStatus;
msg.resize(8);
msg[0] = 0x02;
msg[1] = 0x62;
msg[2] = 0x00;
msg[3] = 0x00;
msg[4] = 0x00;
msg[5] = 0x05;
msg[6] = 0x19;
msg[7] = 0x00;
msg.replace(2, 3, QByteArray::fromHex( devID.toLocal8Bit() ) );
qDebug() << "Has device " << deviceList->at(i)->name << "Changed?";
//send(msg,&msgStatus, &updateStatus);
//msg.clear();
thread.setupPort("COM3",500,msg);
if(devStatus!=updateStatus){
qDebug() << deviceList->at(i)->name << " is now: " << updateStatus;
updateStatus = !updateStatus;
}
}
}
}
SetupThread
函数用于设置本地线程变量并执行(运行)线程。
void serialThread::setupPort(const QString &portName, int waitTimeout, const QByteArray &msg){
qDebug() << "Send Message " << msg.toHex();
QMutexLocker locker(&mutex);
this->portName = portName;
this->waitTimeout = waitTimeout;
this->msg = msg;
if(!isRunning())
start();
else
cond.wakeOne();
}
Run
函数 - 处理发送和接收
void serialThread::run(){
bool currentPortNameChanged = false;
qDebug() << "Thread executed";
mutex.lock();
QString currentPortName;
if(currentPortName != portName){
currentPortName = portName;
currentPortNameChanged = true;
}
int currentWaitTimeout = waitTimeout;
QByteArray sendMsg = msg;
mutex.unlock();
QSerialPort serial;
while(!quit){
if(currentPortNameChanged){
serial.close();
serial.setPortName("COM3");
if (!serial.open(QIODevice::ReadWrite)) {
emit error(tr("Can't open %1, error code %2")
.arg(portName).arg(serial.error()));
return;
}
if (!serial.setBaudRate(QSerialPort::Baud19200)) {
emit error(tr("Can't set baud rate 9600 baud to port %1, error code %2")
.arg(portName).arg(serial.error()));
return;
}
if (!serial.setDataBits(QSerialPort::Data8)) {
emit error(tr("Can't set 8 data bits to port %1, error code %2")
.arg(portName).arg(serial.error()));
return;
}
if (!serial.setParity(QSerialPort::NoParity)) {
emit error(tr("Can't set no patity to port %1, error code %2")
.arg(portName).arg(serial.error()));
return;
}
if (!serial.setStopBits(QSerialPort::OneStop)) {
emit error(tr("Can't set 1 stop bit to port %1, error code %2")
.arg(portName).arg(serial.error()));
return;
}
if (!serial.setFlowControl(QSerialPort::NoFlowControl)) {
emit error(tr("Can't set no flow control to port %1, error code %2")
.arg(portName).arg(serial.error()));
return;
}
}
//write request
serial.write(msg);
if (serial.waitForBytesWritten(waitTimeout)) {
//! [8] //! [10]
// read response
if (serial.waitForReadyRead(currentWaitTimeout)) {
QByteArray responseData = serial.readAll();
while (serial.waitForReadyRead(10)){
responseData += serial.readAll();
}
QByteArray response = responseData;
//! [12]
emit this->sendResponse(response);
//! [10] //! [11] //! [12]
} else {
emit this->timeout(tr("Wait read response timeout %1")
.arg(QTime::currentTime().toString()));
}
//! [9] //! [11]
} else {
emit timeout(tr("Wait write request timeout %1")
.arg(QTime::currentTime().toString()));
}
mutex.lock();
cond.wait(&mutex);
if (currentPortName != portName) {
currentPortName = portName;
currentPortNameChanged = true;
} else {
currentPortNameChanged = false;
}
currentWaitTimeout = waitTimeout;
sendMsg = msg;
mutex.unlock();
}
serial.close();
}
handleResponse
函数,接收响应信号的SLOT
void Device::handleResponse(const QByteArray &msg){
qDebug() << "Read: " << msg.toHex();
}
我收到以下输出:
Has device "Living Room Light" Changed?
Send Message "02621de94b051900"
Has device "Bedroom Light" Changed?
Send Message "026220cbcf051900"
Thread executed
Read: "026220cbcf05190006"
Polling for changes...
Has device "Living Room Light" Changed?
Send Message "02621de94b051900"
Has device "Bedroom Light" Changed?
Send Message "026220cbcf051900"
Read: "025020cbcf1edaf721000002621de94b05190006"
Polling for changes...
Has device "Living Room Light" Changed?
Send Message "02621de94b051900"
Has device "Bedroom Light" Changed?
Send Message "026220cbcf051900"
Read: "02501de94b1edaf72100ff02621de94b05190006"
这里有两个问题。
我从未收到关于第二个设备(卧室灯)的任何响应,这是第二个发送的消息。似乎发送被阻止了,你会如何建议我格式化我的发送,以便在收到第一次发送的响应后发送?只有 1 个 COM 端口可用于发送/接收。我相信我应该向设备 1 发送消息,接收设备 1 响应,发送到设备 2,接收设备 2。我最终会看到大量设备和使用等待条件的巨大交通拥堵吗?在执行设备 2 的通信过程之前,是否等待设备 1 的通信过程完成?
第一个读取包含接收的适当的第一半。 读取:“026220cbcf05190006”
第二个接收包含第一个响应的第二半,然后是第二个响应的第一半:读取 2 - 读取:“025020cbcf1edaf721000002621de94b05190006”
适当的完整的响应是 02621DE94B05190006 025020CBCF1EDAF72100FF
(注意 20CBCF
是完整响应示例中设备 2 的 ID)
应该对我从串行端口接收数据的方式进行哪些更正?谢谢!
最佳答案
我相信我的问题已经从这个问题的范围转移了。在 Kuzulis 的帮助下,我实现了写入/读取功能,以一致地成功发送和读取串行消息。 Kuzulis 建议使用同步阻塞通信模式,但后来决定异步非阻塞方法最适合我的应用程序。
我的实现严格遵循 QSerialPort 源文件提供的“主”示例。
我使用 CurrentStatus
遍历 Device
对象的 QList。对于设备列表中的每个灯,我设置了一条 8 字节消息的格式来查询设备的当前状态(开/关)。
void Device::currentStatus(QList<Device *> * deviceList){
QString devID, updateQry;
int devStatus, updateStatus;
updateStatus=0;
QSqlQuery query;
for(int i=0; i<deviceList->size(); i++){
if(deviceList->at(i)->type == "Light"){
devStatus = deviceList->at(i)->status;
devID = deviceList->at(i)->deviceID;
QByteArray msg;
msg.resize(8);
msg[0] = 0x02;
msg[1] = 0x62;
msg[2] = 0x00;
msg[3] = 0x00;
msg[4] = 0x00;
msg[5] = 0x05;
msg[6] = 0x19;
msg[7] = 0x00;
msg.replace(2, 3, QByteArray::fromHex( devID.toLocal8Bit() ) );
qDebug() << "Has device " << deviceList->at(i)->name << "Changed?";
emit writeRequest(msg);
if(devStatus!=updateStatus){
qDebug() << deviceList->at(i)->name << " is now: " << updateStatus;
updateStatus = !updateStatus;
}
}
}
}
在 Device 类构造函数中,我连接信号和槽:
Device::Device(){
serialTimer.setSingleShot(true);
QObject::connect(&serial, SIGNAL(readyRead()),
this, SLOT(handleResponse()));
QObject::connect(&serialTimer, SIGNAL(timeout()),
this, SLOT(processTimeout()));
QObject::connect(this, SIGNAL(writeRequest(QByteArray)),
this, SLOT(writeSerial(QByteArray)));
}
准备好要在 currentStatus
中发送的消息后,调用 emit writeRequest(msg);
。这会调度一个连接到插槽 writeRequest
的信号。 writeRequest 用于设置并将消息实际写入串行端口。
void Device::writeSerial(const QByteArray &msg){
if (serial.portName() != "COM3") {
serial.close();
serial.setPortName("COM3");
if (!serial.open(QIODevice::ReadWrite)) {
processError(tr("Can't open %1, error code %2")
.arg(serial.portName()).arg(serial.error()));
return;
}
if (!serial.setBaudRate(QSerialPort::Baud19200)) {
processError(tr("Can't set rate 19200 baud to port %1, error code %2")
.arg(serial.portName()).arg(serial.error()));
return;
}
if (!serial.setDataBits(QSerialPort::Data8)) {
processError(tr("Can't set 8 data bits to port %1, error code %2")
.arg(serial.portName()).arg(serial.error()));
return;
}
if (!serial.setParity(QSerialPort::NoParity)) {
processError(tr("Can't set no patity to port %1, error code %2")
.arg(serial.portName()).arg(serial.error()));
return;
}
if (!serial.setStopBits(QSerialPort::OneStop)) {
processError(tr("Can't set 1 stop bit to port %1, error code %2")
.arg(serial.portName()).arg(serial.error()));
return;
}
if (!serial.setFlowControl(QSerialPort::NoFlowControl)) {
processError(tr("Can't set no flow control to port %1, error code %2")
.arg(serial.portName()).arg(serial.error()));
return;
}
}
qDebug() << "Message written";
this->msgRequest = msg;
serial.write(msgRequest);
serialTimer.start(400);
}
设置串口后,我将当前消息保存到msgRequest
。如果出现错误,可能必须使用它来重新发送消息。在调用 serial.write()
之后,我设置了一个 400 毫秒的计时器。一旦这个计时器到期,我检查从串行端口读取的内容。
handleResponse()
是每次 QSerialPort 发出 readyRead()
信号时调用的槽。 readyRead()
将任何可用数据附加到 QByteArray response
。
void Device::handleResponse(){
response.append(serial.readAll());
}
400 毫秒后,serialTimer(单次定时器)将发出一个timeout()
信号。 serialTimer
在将我们请求的消息写入串行端口后立即启动。 processTimeout()
是我们在发送消息后最终检查从 PowerLinc 调制解调器收到的响应的地方。当消息发送到 INSTEON PowerLinc 调制解调器 (PLM) 时,PLM 回显消息并附加 0x06(肯定 ACK)或 0x15(NACK)。在 processTimeout()
中,我检查以确保收到的最后一个字节是 ACK 字节,如果不是 - 重新发送我们最初请求的消息。
void Device::processTimeout(){
qDebug() << "Read: " << response.toHex();
int msgLength = this->msgRequest.length();
if(response.at(msgLength)!=0x06){
qDebug() << "Error, resend.";
emit writeRequest(msgRequest);
}
response.clear();
}
我使用串行端口监视器 4.0(Eltima 软件)来验证串行端口上的写入和读取事务。下面,您可以看到 1 个示例事务的日志打印输出。
20:44:30:666 STATUS_SUCCESS 02 62 1d e9 4b 05 19 00 <--- Send
20:44:30:669 STATUS_SUCCESS 02 62 1d e9 4b 05 19 00 06 <--- Receive
20:44:30:875 STATUS_SUCCESS 02 <--- Receive
20:44:30:881 STATUS_SUCCESS 50 1d e9 4b 1e da f7 21 00 ff <--- Receive
对于 20 次发送,我收到了相同的响应。因此,我可以肯定地说我的数据到达不一致问题已经解决。现在我正在努力处理多个写请求,但我相信这是一个需要调查的单独问题。感谢大家的支持。
关于c++ - Qt Serial Port - 一致读取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15103599/
初学者 android 问题。好的,我已经成功写入文件。例如。 //获取文件名 String filename = getResources().getString(R.string.filename
我已经将相同的图像保存到/data/data/mypackage/img/中,现在我想显示这个全屏,我曾尝试使用 ACTION_VIEW 来显示 android 标准程序,但它不是从/data/dat
我正在使用Xcode 9,Swift 4。 我正在尝试使用以下代码从URL在ImageView中显示图像: func getImageFromUrl(sourceUrl: String) -> UII
我的 Ubuntu 安装 genymotion 有问题。主要是我无法调试我的数据库,因为通过 eclipse 中的 DBMS 和 shell 中的 adb 我无法查看/data/文件夹的内容。没有显示
我正在尝试用 PHP 发布一些 JSON 数据。但是出了点问题。 这是我的 html -- {% for x in sets %}
我观察到两种方法的结果不同。为什么是这样?我知道 lm 上发生了什么,但无法弄清楚 tslm 上发生了什么。 > library(forecast) > set.seed(2) > tts lm(t
我不确定为什么会这样!我有一个由 spring data elasticsearch 和 spring data jpa 使用的类,但是当我尝试运行我的应用程序时出现错误。 Error creatin
在 this vega 图表,如果我下载并转换 flare-dependencies.json使用以下 jq 到 csv命令, jq -r '(map(keys) | add | unique) as
我正在提交一个项目,我必须在其中创建一个带有表的 mysql 数据库。一切都在我这边进行,所以我只想检查如何将我所有的压缩文件发送给使用不同计算机的人。基本上,我如何为另一台计算机创建我的数据库文件,
我有一个应用程序可以将文本文件写入内部存储。我想仔细看看我的电脑。 我运行了 Toast.makeText 来显示路径,它说:/数据/数据/我的包 但是当我转到 Android Studio 的 An
我喜欢使用 Genymotion 模拟器以如此出色的速度加载 Android。它有非常好的速度,但仍然有一些不稳定的性能。 如何从 Eclipse 中的文件资源管理器访问 Genymotion 模拟器
我需要更改 Silverlight 中文本框的格式。数据通过 MVVM 绑定(bind)。 例如,有一个 int 属性,我将 1 添加到 setter 中的值并调用 OnPropertyChanged
我想向 Youtube Data API 提出请求,但我不需要访问任何用户信息。我只想浏览公共(public)视频并根据搜索词显示视频。 我可以在未经授权的情况下这样做吗? 最佳答案 YouTube
我已经设置了一个 Twilio 应用程序,我想向人们发送更新,但我不想回复单个文本。我只是想让他们在有问题时打电话。我一切正常,但我想在发送文本时显示传入文本,以确保我不会错过任何问题。我正在使用 p
我有一个带有表单的网站(目前它是纯 HTML,但我们正在切换到 JQuery)。流程是这样的: 接受用户的输入 --- 5 个整数 通过 REST 调用网络服务 在服务器端运行一些计算...并生成一个
假设我们有一个名为 configuration.js 的文件,当我们查看内部时,我们会看到: 'use strict'; var profile = { "project": "%Projec
这部分是对 Previous Question 的扩展我的: 我现在可以从我的 CI Controller 成功返回 JSON 数据,它返回: {"results":[{"id":"1","Sourc
有什么有效的方法可以删除 ios 中 CBL 的所有文档存储?我对此有疑问,或者,如果有人知道如何从本质上使该应用程序像刚刚安装一样,那也会非常有帮助。我们正在努力确保我们的注销实际上将应用程序设置为
我有一个 Rails 应用程序,它与其他 Rails 应用程序通信以进行数据插入。我使用 jQuery $.post 方法进行数据插入。对于插入,我的其他 Rails 应用程序显示 200 OK。但在
我正在为服务于发布请求的 API 调用运行单元测试。我正在传递请求正文,并且必须将响应作为帐户数据返回。但我只收到断言错误 注意:数据是从 Azure 中获取的 spec.js const accou
我是一名优秀的程序员,十分优秀!