这个项目的开发就像当年初中的长跑一样,前几圈劲头十足信心满怀,接下来的情况我想大部分人跟我一样,慢慢地感觉有点累,再后来压力越来越大,越来越感觉大脑缺氧呼吸困难,到后来已经身心疲累。人这一生从出生开始就背负了责任,要么为责任活着要么超越责任为理想活着,所以有人活得辛苦而无趣,有人轻松而超然。有点跑题了,还是说一下前几天遇到的技术问题。
客户方有一外部设备是N年前购买的,一直用于原来的系统中,这次需要在本项目中使用此外设,关于这个外设的文档早已缺失,唯一可以参考的就是一个windows下的动态链接库源代码(不过这也是最重要的参考资料,候大侠一本书上不是也说“源码面前了无秘密”嘛),于是参考此代码写了一个windows下的测试程序很顺利地测试通过,测试代码如下:
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char **argv)
{
HANDLE h_com;
unsigned char addr = 0x01;
unsigned char buf[10];
int i;
DCB dcb;
COMMTIMEOUTS timeouts;
DWORD n;
if (argc != 2) {
printf("%s <comdev>\n", argv[0]);
return -1;
}
h_com = CreateFile(argv[1], GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (h_com == INVALID_HANDLE_VALUE) {
printf("Initialize COM device failed\n");
return -1;
}
GetCommState(h_com, &dcb);
dcb.BaudRate = 9600;
dcb.ByteSize = 8;
dcb.Parity = MARKPARITY;
dcb.StopBits = ONESTOPBIT;
SetCommState(h_com, &dcb);
GetCommTimeouts(h_com, &timeouts);
timeouts.ReadTotalTimeoutConstant = 10;
SetCommTimeouts(h_com, &timeouts);
WriteFile(h_com, &addr, sizeof(addr), &n, NULL);
Sleep(1);
dcb.Parity = SPACEPARITY;
SetCommState(h_com, &dcb);
memcpy(buf, "\x02\x85\x83\04", 4);
WriteFile(h_com, buf, 4, &n, NULL);
Sleep(2);
ReadFile(h_com, buf, sizeof(buf), &n, NULL);
printf("read %d bytes\n", n);
for (i = 0; i < n; ++i)
printf("%02x ", buf[i]);
printf("\n");
return 0;
}
由此代码可以看出通信过程大概是这样的:将串口设置为8M1发送地址,然后将串口设置更改为8S1发送请求数据,再然后接收数据,看起来还是很简单的。接下来很快地写好了linux下的测试程序,源代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
int
main(int argc, char **argv)
{
if (argc != 2) {
printf("Usage: %s <comdev>\n", argv[0]);
return -1;
}
int fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
printf("Initialize COM device failed.\n");
return -1;
}
struct termios options;
if (tcgetattr(fd, &options) == -1)
return -1;
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8 | CLOCAL | CREAD | CMSPAR | PARODD;
options.c_cflag &= CSTOPB;
options.c_iflag |= INPCK;
options.c_iflag &= ~(IXON | IXOFF | IXANY);
options.c_oflag &= ~OPOST;
options.c_lflag &= ~(ECHO | ECHOE | ICANON | ISIG);
tcflush(fd, TCIFLUSH);
printf("tcsetattr result: %d\n", tcsetattr(fd, TCSANOW, &options));
char addr = 0x01;
if (write(fd, &addr, 1) == -1)
goto failed;
usleep(1000);
options.c_cflag &= ~PARODD;
printf("tcsetattr result: %d\n", tcsetattr(fd, TCSADRAIN, &options));
usleep(1000);
unsigned char buf[10];
memcpy(buf, "\x02\x85\x83\x04", 4);
if (write(fd, buf, 4) == -1)
goto failed;
usleep(10000);
ssize_t read_n;
int i;
read_n = read(fd, buf, sizeof(buf));
printf("result: %d\n", read_n);
for (i = 0; i < read_n; ++i)
printf("%02X ", buf[i]);
printf("\n");
close(fd);
return 0;
failed:
close(fd);
return -1;
}
虽然Mark Parity和Space Parity在Posix中并未定义,但是在linux下通过CMSPAR仍然可以实现,tcsetattr的man pages可以看到对CMSPAR的描述(),可是反复尝试仍然有问题,后来一个完全不懂linux开发的同事问了我设置串口各行代码的意思,并通过tcsetattr的man pages,一个一个地组合这些标记,居然成功了!结果出人意料,且看如下代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
int
main(int argc, char **argv)
{
if (argc != 2) {
printf("Usage: %s <comdev>\n", argv[0]);
return -1;
}
int fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
printf("Initialize COM device failed.\n");
return -1;
}
struct termios options;
memset(&options, 0, sizeof(options));
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
options.c_cflag = CS8 | CLOCAL | CREAD | CSTOPB | CMSPAR;
options.c_iflag = INPCK;
options.c_oflag = 0;
options.c_lflag = 0;
tcflush(fd, TCIFLUSH);
printf("tcsetattr result: %d\n", tcsetattr(fd, TCSANOW, &options));
char addr = 0x01;
if (write(fd, &addr, 1) == -1)
goto failed;
usleep(1000);
options.c_cflag |= PARENB | PARODD;
printf("tcsetattr result: %d\n", tcsetattr(fd, TCSADRAIN, &options));
usleep(1000);
unsigned char buf[10];
memcpy(buf, "\x02\x85\x83\x04", 4);
if (write(fd, buf, 4) == -1)
goto failed;
usleep(10000);
ssize_t read_n;
int i;
read_n = read(fd, buf, sizeof(buf));
printf("result: %d\n", read_n);
for (i = 0; i < read_n; ++i)
printf("%02X ", buf[i]);
printf("\n");
close(fd);
return 0;
failed:
close(fd);
return -1;
}
想不到抛开CMSPAR不算8M1看起来是8N2,而8S1则看起来是8O2。。。
没有评论:
发表评论