- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我为armv7体系结构制作了一个简单的c ++程序(使用raspi rootfs与linaro gnueabihf编译),该程序接受具有波特率,数据,串行端口等的参数,并将其发送到选定的串行端口并接收响应。至少那是它的目标。
我目前正在使用它来发送命令,以通过UART端口禁用/启用工业屏幕上的背光。屏幕将接受一个以crlf结尾的简单文本命令,并返回响应。屏幕的规格说明它使用9600波特,无奇偶校验,8个数据位和1个停止位进行通讯,因此非常标准。
尽管发送过程完美无瑕-我似乎找不到能够正确接收响应的方法。我尝试以多种不同方式配置termios端口结构(禁用硬件控制,使用cfmakeraw
,配置VMIN
和VTIME
值),但是没有运气。
第一件事是,我按字节接收所有输入(因此,每个read()
调用都恰好返回1个字节..),但这不是问题。
当使用不带select()
的非阻塞模式时,我正在接收所有字节,但是我不知道何时停止接收(并且我希望它是通用的,因此我发送命令,期望得到简单的响应,如果没有更多响应数据,然后退出)。自上一条消息以来,我做了一个时间计数器,因此,如果在过去约500毫秒内什么都没收到,那么我认为不会再有其他消息了。但这有时会丢失一些字节的响应,我不知道为什么。
使用阻塞模式时,我接收到正确的字节(虽然仍然是逐字节),但是我不知道何时停止,对read()
的最后一次调用使程序挂起,因为输入中没有其他内容。
将select()
添加到阻塞调用中时,要查看输入是否可读,我会遇到非常频繁的数据丢失(有时仅接收一些字节)的情况,有时select
返回1,但read()
会阻塞,左挂。
当我不做任何读取就发送数据,并使用cat -v < /dev/ttyS3
查看输入时,实际上我一直都能在串行端口上看到正确的输入,但是当我同时将cat和程序作为接收器运行时,它们中只有一个数据(或cat
接收一些字节,而我的程序接收一些),这表明我有一些东西在尝试读取时以相同的方式“窃取”我的字节,但可能是什么,为什么呢?那?
我当前的代码(使用无阻塞读取+ 500ms超时),仍然会不时丢失一些字节:
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
int open_port(char* portname)
{
int fd; // file description for the serial port
fd = open(portname, O_RDWR | O_NOCTTY | O_NDELAY);
if(fd == -1) // if open is unsucessful
{
printf("Error: open_port: Unable to open %s. \n", portname);
}
else
{
//fcntl(fd, F_SETFL, 0);
fcntl(fd, F_SETFL, FNDELAY);
}
return(fd);
}
int configure_port(int fd, int baud_rate)
{
struct termios port_settings;
tcgetattr(fd, &port_settings);
cfsetispeed(&port_settings, baud_rate); // set baud rates
cfsetospeed(&port_settings, baud_rate);
cfmakeraw(&port_settings);
port_settings.c_cflag &= ~PARENB; // no parity
port_settings.c_cflag &= ~CSTOPB; // 1 stop bit
port_settings.c_cflag &= ~CSIZE;
port_settings.c_cflag |= CS8; // 8 data bits
tcsetattr(fd, TCSANOW, &port_settings); // apply the settings to the port
return(fd);
}
/**
* Convert int baud rate to actual baud rate from termios
*/
int get_baud(int baud)
{
switch (baud) {
case 9600:
return B9600;
case 19200:
return B19200;
case 38400:
return B38400;
case 57600:
return B57600;
case 115200:
return B115200;
case 230400:
return B230400;
case 460800:
return B460800;
case 500000:
return B500000;
case 576000:
return B576000;
case 921600:
return B921600;
case 1000000:
return B1000000;
case 1152000:
return B1152000;
case 1500000:
return B1500000;
case 2000000:
return B2000000;
case 2500000:
return B2500000;
case 3000000:
return B3000000;
case 3500000:
return B3500000;
case 4000000:
return B4000000;
default:
return -1;
}
}
unsigned char* datahex(char* string) {
if(string == NULL)
return NULL;
size_t slength = strlen(string);
if((slength % 2) != 0) // must be even
return NULL;
size_t dlength = slength / 2;
unsigned char* data = (unsigned char*)malloc(dlength);
memset(data, 0, dlength);
size_t index = 0;
while (index < slength) {
char c = string[index];
int value = 0;
if(c >= '0' && c <= '9')
value = (c - '0');
else if (c >= 'A' && c <= 'F')
value = (10 + (c - 'A'));
else if (c >= 'a' && c <= 'f')
value = (10 + (c - 'a'));
else {
free(data);
return NULL;
}
data[(index/2)] += value << (((index + 1) % 2) * 4);
index++;
}
return data;
}
int main(int argc, char **argv) {
int baud_rate = B9600;
baud_rate = get_baud(atoi(argv[1]));
if(baud_rate == -1) {
printf("Error: Cannot convert baud rate %s, using 9600\n", argv[1]);
baud_rate = B9600;
}
bool convertHex = false;
char portName[24] = "/dev/ttyS0";
bool debug = false;
bool noreply = false;
for(int i = 3; i < argc; i++) {
if(!strcmp(argv[i], "hex"))
convertHex = true;
else if(strstr(argv[i], "/dev/") != NULL)
strncpy(portName, argv[i], sizeof(portName));
else if(!strcmp(argv[i], "debug"))
debug = true;
else if(!strcmp(argv[i], "no-reply"))
noreply = true;
}
unsigned char* data = nullptr;
size_t len = 0;
if(convertHex) {
data = datahex(argv[2]);
if((int)data == (int)NULL) {
convertHex = false;
printf("Error: Couldn't convert hex value! Needs to be even length (2 chars per byte)\n");
}
else
len = strlen(argv[2])/2;
}
if(!convertHex) {
data = (unsigned char*)argv[2];
len = strlen(argv[2]);
}
int fd = open_port(portName);
if(fd == -1) {
printf("Error: Couldn't open port %s\n", portName);
if(convertHex)
free(data);
return 0;
}
configure_port(fd, baud_rate);
if(debug) {
printf("Sending data (raw): ");
for(int i =0; i< len; i++) {
printf("%02X", data[i]);
}
printf("\n");
}
size_t writelen = write(fd, data, len);
if(debug)
printf("Sent %d/%d bytes\n", writelen, len);
if(writelen != len)
printf("Error: not all bytes were sent (%d/%d)\n", writelen, len);
else if(noreply)
printf("WRITE OK");
if(!noreply) {
unsigned char ibuff[512] = {0};
int curlen = 0; // full length
clock_t begin_time = clock();
while(( float(clock() - begin_time) / CLOCKS_PER_SEC) < 0.5 && curlen < sizeof(ibuff)) {
int ret = read(fd, ibuff+curlen, sizeof(ibuff)-curlen-1);
if(ret < 0) {
ret = 1;
continue;
}
if(ret > 0) {
curlen += ret;
begin_time = clock();
}
}
if(curlen > 0) {
ibuff[curlen] = 0; // null terminator
printf("RESPONSE: %s", ibuff);
}
}
if(fd)
close(fd);
if(convertHex)
free(data);
return 0;
}
./rs232 9600 [hex string] hex debug
之类的程序
#BLIGHT_ON!OK
的响应,但有时我会收到例如
#BLI_ON!O
最佳答案
首先是,我逐字节接收所有输入(因此每个输入
read()调用恰好返回1个字节。)[...]
这不足为奇。响应以9600波特的速度返回,这可能比循环所需的一次迭代慢得多。它也将直接由串行驱动程序的某些配置引起。应该可以通过操作VMIN
和VTIME
来对此进行调整,但是请注意,这需要禁用规范模式(无论如何,您可能都想这样做;请参见下文)。
当使用不带select()的非阻塞模式时,我将接收所有字节,
但我不知道什么时候停止接收(我希望它成为
通用,所以我发送命令,希望得到简单的响应,如果有
没有更多数据,然后退出)。自上次以来我做了一个时间计数器
消息,所以如果在过去〜500ms内什么都没收到,那么我认为
没有其他东西了。但这有时会丢失一些字节
反应,我不知道为什么。
这一切都在细节中,您没有针对该案例进行介绍。因此,我们无法谈谈您的特定数据丢失。
一般而言,如果没有流控制,那么必须确保在下一个字节到达之前平均读取每个字节,否则很快,新字节将覆盖以前接收的字节。 VMIN
和VTIME
可以帮助解决此问题,或者可以尝试其他方法来调整读取定时,但是请注意,9600波特响应将以超过每毫秒1个的速率传送字节,因此两次读取之间的延迟为500毫秒太长了。假设您尝试读取的特定响应相对较短,但是,这不能解释数据丢失的原因。
使用阻止模式时,我收到正确的字节(仍然逐字节
虽然),但我不知道何时停止以及对read()的最后一次调用
使程序挂起,因为输入中没有其他内容。
因此要求该命令以CRLF终止,但是不能依靠响应来同样终止吗?您正在使用多么粗鲁的设备。如果它以与终止命令相同的方式终止其响应,则您可能可以在规范模式下工作,并且您肯定会注意终止符是否能够识别传输结束。
将select()添加到阻塞调用时,查看输入是否为
可读性强,我经常丢失数据(有时只是收到一个
几个字节),有时select返回1,但read()块使我
左挂。
在没有任何相关代码可供分析的情况下,我无法提出问题所在,但是您实际上不需要select()
。
当我不做任何阅读就发送数据并查看输入时
使用cat -v
一直都有串口
这是一个很好的测试。
但是,当我同时运行cat和我的程序时
作为接收者,只有其中一个接收数据(或者猫接收到一些
字节和我的程序一些),
这正是我所期望的。一旦程序从端口读取了一个字节,其他任何程序都将无法再读取该字节。因此,如果多个程序试图同时读取同一端口,则可用数据将以某种未指定且不一定一致的方式在它们之间进行分区。
这表明我有些事情是
尝试读取字节时以相同的方式“窃取”我的字节,但是可以
是的,为什么会这样?
考虑到cat
单独运行时不会受到相同的影响,(报告)您自己程序的某些版本,这似乎不太可能。
首先,如果设备支持流控制,那么我将启用它。如果两者都可行,则硬件流控制优先于软件流控制。但是,这主要是故障保护功能-我看不出任何理由认为,如果程序编写得当,流控制实际上可能会触发。
然后,除了设置串行线路参数(8 / n / 1)外,您还应该
禁用规范模式。这是必需的,因为(显然)您(显然)不能依赖于由行终止符终止的响应。
禁用回声。
避免在文件上启用非阻止模式。
(可选)使用VMIN == 1
和VTIME == 0
读取第一个响应字节;这允许设备开始发送响应之前的任意延迟。另外,如果您愿意等待设备开始发送响应的时间有一个可靠的上限,则可以在下一个中使用合适的VTIME
来跳过此步骤。或者对于第一个字节使用较大的VTIME
来适应传输开始之前的延迟,但是如果设备无法响应,则不会挂起。
请使用VTIME == 1
(或更大)和VMIN == 0
读取其余的响应字节。这可能会在一个调用中让您获得整个响应的其余部分,但是请重复read()
直到返回0(或负数)。返回值0表示所有可用字节均已传输,并且在VTIME
的十分之一秒内没有收到新的字节,这比9600波特传输的字符间时间还要长得多,即使对于VTIME == 1
。请注意,VTIME
越大,设备发送其响应的最后一个字节与检测传输结束的程序之间的延迟就越长。
在连续的读取尝试之间不要实施任何人为的延迟。
您不需要在fcntl级别使用非阻塞模式,也不需要select()
。您可能还可以使用其他termios设置来更好地调整串行链接另一端的特定设备的程序,但是以上内容对于仅具有ASCII数据且无控制权的单命令/单响应对就足够了除回车符和换行符外的其他字符。
关于c++ - 写入uart串行端口并接收响应,使用非阻塞模式时会丢失字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59106619/
我有一个存储结构向量的应用程序。这些结构保存有关系统上每个 GPU 的信息,如内存和 giga-flop/s。每个系统上有不同数量的 GPU。 我有一个程序可以同时在多台机器上运行,我需要收集这些数据
我很好奇 MPI 中缺少此功能: MPI_Isendrecv( ... ); 即,非阻塞发送和接收,谁能告诉我其省略背后的基本原理? 最佳答案 我的看法是 MPI_SENDRECV存在是为了方便那些想
当我用以下方法监听TCP或UDP套接字时 ssize_t recv(int sockfd, void *buf, size_t len, int flags); 或者 ssize_t recvfrom
SUM:如何在 azure 事件网格中推迟事件触发或事件接收? 我设计的系统需要对低频对象状态(创建、启动、检查长时间启动状态、结束)使用react。它看起来像是事件处理的候选者。我想用azure函数
我正在 MPI 中实现一个程序,其中主进程(等级 = 0)应该能够接收来自其他进程的请求,这些进程要求只有根才知道的变量值。如果我按等级 0 进行 MPI_Recv(...),我必须指定向根发送请求的
我正在学习DX12,并在此过程中学习“旧版Win32”。 我在退出主循环时遇到问题,这似乎与我没有收到WM_CLOSE消息有关。 在C++,Windows 10控制台应用程序中。 #include
SUM:如何在 azure 事件网格中推迟事件触发或事件接收? 我设计的系统需要对低频对象状态(创建、启动、检查长时间启动状态、结束)使用react。它看起来像是事件处理的候选者。我想用azure函数
我想编写方法来通过号码发送短信并使用编辑文本字段中的文本。发送消息后,我想收到一些声音或其他东西来提醒我收到短信。我怎样才能做到这一点?先感谢您,狼。 最佳答案 这个网站似乎对两者都有很好的描述:ht
所以我正在用 Java 编写一个程序,在 DatagramSocket 和 DatagramPacket 的帮助下发送和接收数据。问题是,在我发送数据/接收数据之间的某个时间 - 我发送数据的程序中的
我是 Android 编程新手,我正在用 Java 编写一个应用程序,该应用程序可以打开相机拍照并保存。我通过 Intents 做到了,但看不到 onActivityResult 正在运行。 我已经在
我有一个套接字服务器和一个套接字客户端。客户端只有一个套接字。我必须使用线程在客户端发送/接收数据。 static int sock = -1; static std::mutex mutex; vo
我正在尝试使用 c 中的套接字实现 TCP 服务器/客户端。我以这样的方式编写程序,即我们在客户端发送的任何内容都逐行显示在服务器中,直到键入退出。该程序可以运行,但数据最后一起显示在服务器中。有人可
我正在使用微 Controller 与 SIM808 模块通信,我想发送和接收 AT 命令。 现在的问题是,对于某些命令,我只收到了我应该收到的答案的一部分,但对于其他一些命令,我收到了我应该
我用c设计了一个消息传递接口(interface),用于在我的系统中运行的不同进程之间提供通信。该接口(interface)为此目的创建 10-12 个线程,并使用 TCP 套接字提供通信。 它工作正
我需要澄清一下在套接字程序中使用多个发送/接收。我的客户端程序如下所示(使用 TCP SOCK_STREAM)。 send(sockfd,"Messgfromlient",15,0);
我正在构建一个真正的基本代理服务器到我现有的HTTP服务器中。将传入连接添加到队列中,并将信号发送到另一个等待线程队列中的一个线程。此线程从队列中获取传入连接并对其进行处理。 问题是代理程序真的很慢。
我正在使用 $routeProvider 设置一条类似 的路线 when('/grab/:param1/:param2', { controller: 'someController',
我在欧洲有通过 HLS 流式传输的商业流媒体服务器。http://europe.server/stream1/index.m3u8现在我在美国的客户由于距离而遇到一些网络问题。 所以我在美国部署了新服
我有一个长期运行的 celery 任务,该任务遍历一系列项目并执行一些操作。 任务应该以某种方式报告当前正在处理的项目,以便最终用户知道任务的进度。 目前,我的django应用程序和celery一起坐
我需要将音频文件从浏览器发送到 python Controller 。我是这样做的: var xmlHttp = new XMLHttpRequest(); xmlHttp.open( "POST",
我是一名优秀的程序员,十分优秀!