Linux上正确的串行端口初始化问题

问题描述

我想将RFID阅读器附加到我的android应用程序上,但是我陷入了termios错误的初始化代码!读取器在Windows上的工作速度为19200 br / 8个数据位/ N(o奇偶校验)/ 1个停止位。 当将我的测试控制台应用程序运行到带有ubuntu 20.04的WSL环境中时,它始终运行良好!但是,当我在真实PC(或android)上的Ubuntu 20.04上运行它时,它在read()上返回损坏的数据,但似乎读取器始终接受未损坏的命令,但我不确定。我想知道我做错了什么吗?在同一台PC上,在netcore 3.1上重写为system.io.serialports的示例效果很好!因此,似乎只有我的代码问题! (我只了解带有一些认值的Windows初始化序列,而且似乎没有将所有系统调用代理到winapi)

#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <errno.h>

#define SOH 0x01
#define STX 0x02
#define ETX 0x03
#define EOT 0x04
#define ENQ 0x05
#define ACK 0x06
#define NAK 0x15
#define CAN 0x18


static speed_t getBaudrate(int baudrate)
{
    switch (baudrate) {
    case 0: return B0;
    case 50: return B50;
    case 75: return B75;
    case 110: return B110;
    case 134: return B134;
    case 150: return B150;
    case 200: return B200;
    case 300: return B300;
    case 600: return B600;
    case 1200: return B1200;
    case 1800: return B1800;
    case 2400: return B2400;
    case 4800: return B4800;
    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;
    }
}

char bcc(char* buffer,int size)
{
    char result = SOH;
    while (size-->0)result ^= *buffer++;
    return result;
}

void test(int fd)
{
    char cmd_buffer[] = { 0x01,0x43,0x31,0x02,0x03,0x42 };
    char response_buffer[256];
    char dump_buffer[1025];
    int bytes_available;
    char response;
    char enq = ENQ;

    ioctl(fd,FIONREAD,&bytes_available);
    read(fd,response_buffer,bytes_available);

    memset(response_buffer,sizeof(response_buffer));
    memset(dump_buffer,sizeof(dump_buffer));
    if (fd < 0)
        printf("Bad file descriptor!\n");
    write(fd,cmd_buffer,sizeof(cmd_buffer));
    bytes_available = 0;

    while (!bytes_available)
    {
        ioctl(fd,&bytes_available);
        usleep(100000);
    }
    read(fd,&response,1);

    if (response == ACK)
    {
        //printf("OK! ACK was recieved!\n");
        write(fd,&enq,1);
        bytes_available = 0;
        while (bytes_available<14)
        {
            ioctl(fd,&bytes_available);
            usleep(100000);
        }
        ioctl(fd,&bytes_available);
        int read_count = read(fd,bytes_available);
        for (int i = 0; i < read_count; i++)
        {
            sprintf(dump_buffer + strlen(dump_buffer),"%02X ",(0xff & response_buffer[i]));
        }

        printf("%s - BCC: %02X,BCC[-1]: %02X\n",dump_buffer,0xff&bcc(response_buffer,read_count),0xff & bcc(response_buffer,read_count-1));
    }
    else
        printf("ACK was not recieved!\n");
}

int configTTY2(int fd,int baudrate)
{
    if (ioctl(fd,TIOCEXCL)) {
        printf("configTTY2 open: error setting TIOCEXCL: errno=%d\n",errno);
        return -1;
    }
    speed_t speed = getBaudrate(baudrate);
    struct termios newtio;
    memset(&newtio,sizeof(newtio));
    printf("configTTY2: getting attributes\n");
    if (tcgetattr(fd,&newtio) == -1) {
        printf("configTTY2: tcgetattr Failed: errno=%d\n",errno);
        return -2;
    }

    newtio.c_cflag |= (CLOCAL | CREAD);
    newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG | IEXTEN);
    newtio.c_oflag &= ~OPOST;
    newtio.c_iflag = IGNBRK;
    newtio.c_cflag &= ~CSIZE;
    newtio.c_cflag |= CS8;
    newtio.c_cflag &= ~CSTOPB;
    newtio.c_iflag &= ~(INPCK | ISTRIP | IGNPAR | PARMRK);
    newtio.c_cflag &= ~(PARENB | PARODD);
#ifdef HAVE_TERMIOS_CMSPAR
    newtio.c_cflag &= ~CMSPAR;
#endif
    //newtio.c_iflag |= INPCK;
    newtio.c_cflag &= ~CRTSCTS;
    newtio.c_iflag &= ~(IXON | IXOFF | IXANY);
    newtio.c_cc[VMIN] = 0;
    newtio.c_cc[VTIME] = 0;
    //cfmakeraw(&newtio);

    if (cfsetospeed(&newtio,speed) < 0 ||  cfsetispeed(&newtio,speed) < 0)
    {
        printf("error to set speed!\n");
        return -4;
    }
    if (tcsetattr(fd,TCSADRAIN,&newtio) < 0) {
        printf("setproperties: setting attributes Failed: errno=%d\n",errno);
        return -5;
    }
    //printf("setting attributes done\n");

    fsync(fd);

    // Get the baudrate and compare with what we set
    tcgetattr(fd,&newtio);
    if (cfgetispeed(&newtio) != speed ||
        cfgetospeed(&newtio) != speed) {
        printf("baudrate mismatch. ispeed ret=%d set=%d; ospeed ret=%d set=%d",cfgetispeed(&newtio),speed,cfgetospeed(&newtio),speed);
        // For some reason the baudrate was not set to what we had asked.
        return -6;
    }
    return 0;
}

int main( int argc,char** argv)
{
    if (argc < 2)
    {
        printf("\n%s /dev/ttyS0 for select com1\n",argv[0]);
        return 0;
    }
    int fd = open(argv[1],O_RDWR | O_NOCTTY | O_SYNC );
    if (fd < 0 )
    {
        printf("Cannot open port!\n");
        return -1;
    }
    if (configTTY2(fd,19200) < 0)
        return -1;
    for (int i = 0; i < 30; i++)
    {
        printf("%d: ",i);
        test(fd);
    }
    close(fd);
    return 0;
}

与ubuntu的WSL通信转储: 循环发送获取版本命令给阅读器,它总是返回正确的响应 [SOH]'c''1''1'[STX] [P] [STATUS] V 2。 0 2 [ETX] [BCC]

./wsl_serial_test /dev/ttyS4
configTTY2: getting attributes
0: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
1: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
2: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
3: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
4: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
5: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
6: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
7: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
8: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
9: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
10: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
11: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
12: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
13: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
14: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
15: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
16: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
17: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
18: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
19: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
20: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
21: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
22: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
23: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
24: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
25: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
26: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
27: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
28: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
29: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A

使用ubuntu在PC上进行通讯转储:

 ./wsl_serial_test /dev/ttyS0
configTTY2: getting attributes
0: 01 43 31 39 02 D0 00 56 32 2E 30 32 03 5A  - BCC: 88,BCC[-1]: D2
1: 01 43 31 31 02 50 00 56 32 2E 30 32 83 5A  - BCC: 80,BCC[-1]: DA
2: 01 43 31 31 02 58 00 56 32 2E 30 32 03 5A  - BCC: 08,BCC[-1]: 52
3: 01 43 31 71 02 50 00 56 32 2E 30 32 03 5A  - BCC: 40,BCC[-1]: 1A
4: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
5: 01 43 B1 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 80,BCC[-1]: DA
6: 01 53 31 31 82 50 00 56 32 2E 60 32 03 5B  - BCC: C1,BCC[-1]: 9A
7: 01 43 31 99 02 50 00 5E 32 2E 30 32 03 AE  - BCC: 54,BCC[-1]: FA
8: 01 43 31 31 02 A0 00 56 32 2E 30 9A 03 5A  - BCC: 58,BCC[-1]: 02
9: ACK was not recieved!
10: 01 43 31 31 02 B0 00 F6 32 2E 30 32 83 5A  - BCC: C0,BCC[-1]: 9A
11: ACK was not recieved!
12: 01 43 31 31 02 50 02 56 32 2E 30 32 03 5A  - BCC: 02,BCC[-1]: 58
13: ACK was not recieved!
14: 01 43 31 31 02 B0 00 56 32 2E 30 32 03 BA  - BCC: 00,BCC[-1]: BA
15: 01 43 31 31 02 50 00 56 32 2E 30 32 43 5A  - BCC: 40,BCC[-1]: 1A
16: 81 43 31 71 02 50 00 56 32 2E 30 32 03 5A  - BCC: C0,BCC[-1]: 9A
17: ACK was not recieved!
18: 81 43 31 31 82 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
19: ACK was not recieved!
20: 01 43 31 31 82 50 00 56 32 2E 30 32 03 5A  - BCC: 80,BCC[-1]: DA
21: 01 43 31 31 02 50 00 56 32 2E 30 32 03 5A  - BCC: 00,BCC[-1]: 5A
22: 01 43 D9 CC 81 D0 00 56 B2 2E 30 36 03 5A  - BCC: 92,BCC[-1]: C8
23: ACK was not recieved!
24: 81 A3 31 31 02 50 00 56 32 2E 31 9A 03 5A  - BCC: C9,BCC[-1]: 93
25: 01 63 31 35 02 A8 80 AE 32 2E 38 32 03 5A  - BCC: AC,BCC[-1]: F6
26: 01 C3 31 31 02 50 00 56 9A 2E 30 32 03 5A  - BCC: 28,BCC[-1]: 72
27: 01 43 31 63 02 50 01 56 32 2E 30 32 03 5A  - BCC: 53,BCC[-1]: 09
28: ACK was not recieved!
29: 81 43 31 33 02 50 00 56 32 AE 30 32 03 5A  - BCC: 02,BCC[-1]: 58

在同一台ubuntu PC上进行dotnet测试:

~/test_net$ dotnet run --port:/dev/ttyS0
Ack was received,send ENQ
Respose:
01-43-31-31-02-50-00-56-32-2E-30-32-03-5A

~/test_net$ dotnet run --port:/dev/ttyS0
Ack was received,send ENQ
Respose:
01-43-31-31-02-50-00-56-32-2E-30-32-03-5A

/test_net$ cat Program.cs

using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace core_serial_test
{
    class Program
    {
        static byte ACK = 0x06;
        static byte ENQ = 0x05;
        class Anchor { };
        static void Main(string[] args)
        {
            string portName=null;
            foreach(var arg in args)
            {
                var kv = arg.Split(new char[] { ':' });
                if(kv.Length==2)
                {
                    switch(kv[0])
                    {
                        case "--port":
                            portName = kv[1];
                            break;
                    }
                }
            }
            if(portName==null)
            {
                Console.WriteLine("{0} --port:[comport name]",System.IO.Path.GetFileName(new Anchor().GetType().Assembly.Location));
                string[] ports = SerialPort.GetPortNames();
                                foreach(var port in ports) Console.WriteLine(port);
                return;
            }
            SerialPort serialPort = new SerialPort(portName,19200,Parity.None,8,StopBits.One);
            serialPort.open();
            byte[] cmd = new byte[] { 0x01,0x42 };
            byte[] response = new byte[200];
            serialPort.Write(cmd,cmd.Length);
            Thread.Sleep(200);
            serialPort.Read(response,1);
            if (response[0] == ACK)
                serialPort.Write(new byte[] { ENQ },1);
            else
                return;
            Console.WriteLine("Ack was received,send ENQ");
            Thread.Sleep(200);
            int size = 0;
            if (serialPort.BytesToRead > 0)
            {
                size = serialPort.Read(response,serialPort.BytesToRead);
            }
            serialPort.Close();
            Array.Resize<byte>(ref response,size);
            Console.WriteLine("Respose: ");
            Console.WriteLine(BitConverter.ToString(response,response.Length));
            Console.ReadLine();
        }
    }
}

今天更新,我正在尝试以下代码示例:

int open_tty(char* ttyname,int baudrate)
{
    int USB = open(ttyname,O_RDWR | O_NOCTTY);
    struct termios tty;
    struct termios tty_old;
    memset(&tty,sizeof(tty));
    if (tcgetattr(USB,&tty) != 0) {
        std::cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << std::endl;
        return -1;
    }
    tty_old = tty;
    cfsetospeed(&tty,(speed_t)baudrate);
    cfsetispeed(&tty,(speed_t)baudrate);
    tty.c_cflag &= ~PARENB;            // Make 8n1
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;
    tty.c_cflag &= ~CRTSCTS;           // no flow control
    tty.c_cc[VMIN] = 1;                  // read doesn't block
    tty.c_cc[VTIME] = 0;                  
    tty.c_cflag |= CREAD | CLOCAL;     // turn on READ & ignore ctrl lines
    cfmakeraw(&tty);
    tcflush(USB,TCIFLUSH);
    tcflush(USB,TCOFLUSH);
    if (tcsetattr(USB,TCSANow,&tty) != 0) {
        std::cout << "Error " << errno << " from tcsetattr" << std::endl;
        return -1;
    }
    return USB;
} 

char bcc(char* buffer,int size)
{
    char result = SOH;
    while (size-- > 0)result ^= *buffer++;
    return result;
}

void test(int fd)
{
    char cmd_buffer[] = { 0x01,0x42 };
    char response_buffer[256];
    char dump_buffer[1025];
    char response;
    char enq = ENQ;

    memset(response_buffer,sizeof(cmd_buffer));
    usleep(50000);
    while(1!=read(fd,1))
        usleep(10000);
    if (response == ACK)
    {
        write(fd,1);
        usleep(2000);
        int read_count = 0;
        while (read_count < 14)
        {
            read_count+=read(fd,response_buffer + read_count,1);
            usleep(1000);
        }
        if (read_count > 7)
        {
            for (int i = 0; i < read_count; i++)
            {
                sprintf(dump_buffer + strlen(dump_buffer),(0xff & response_buffer[i]));
            }

            printf("%s - BCC: %02X,read_count - 1));
        }
        else
        {
            tcflush(fd,TCIFLUSH);  
            tcflush(fd,TCOFLUSH);  
            printf("read result is %d\n",read_count);
        }
    }
    else
    {
            printf("ACK was not recieved [%02X] !\n",0xff & response);
            tcflush(fd,TCOFLUSH);  
    }
}

在main()内部进行更改

int main(int argc,char** argv)
{
if (argc == 2 && argv[1][0] == '4')
        {
            int fd = open_tty("/dev/ttyUSB0",B1200);
            int n = 0,spot = 0;
            char buf = '\0';

            /* Whole response*/
            char response[1024];
            memset(response,sizeof response);
            usleep(10000);
            do {
                n = read(fd,&buf,1);
                if (n)
                {
                    sprintf(&response[spot],"%c",buf);
                    printf("%c - %02X\n",buf,buf & 0xff);
                    spot += n;
                }
            } while (buf != '\r' && n > 0);

            if (n < 0) {
                std::cout << "Error reading: " << strerror(errno) << std::endl;
            }
            else if (n == 0) {
                std::cout << "Read nothing!" << std::endl;
            }
            else {
                std::cout << "Response: " << response << std::endl;
            }
            close(fd);
        }
        else
        if (argc == 2 && argv[1][0] == '5')
        {
            int fd = open_tty("/dev/ttyS0",B19200);
            test(fd);
            close(fd);
        }

}

对于串行初始化,结果从另一台设备读取的文本可以正常工作,读取器的响应仍然看起来不正常!

从重量终端模拟器(位于/ dev / ttyUSB0上)读取文本

./wsl_serial_test 4
P - 50
+ - 2B
  - 20
1 - 31
2 - 32
1 - 31
0 - 30
0 - 30
 - 0D
Response: P+ 12100
./wsl_serial_test 4
P - 50
+ - 2B
  - 20
1 - 31
2 - 32
1 - 31
0 - 30
0 - 30
 - 0D
Response: P+ 12100
./wsl_serial_test 4
P - 50
+ - 2B
  - 20
1 - 31
2 - 32
1 - 31
0 - 30
0 - 30
 - 0D
Response: P+ 12100

./wsl_serial_test 5
01 43 D9 CC 81 50 00 56 32 2E B0 32 03 5A  - BCC: 16,BCC[-1]: 4C
./wsl_serial_test 5
01 43 31 31 82 50 00 56 32 2E 30 32 23 5A  - BCC: A0,BCC[-1]: FA
./wsl_serial_test 5
01 43 31 35 02 50 00 D6 32 AE 30 32 03 5A  - BCC: 04,BCC[-1]: 5E

结论从相对较慢的设备(9600 bps)读取文本可以正常工作,但在阅读器问题上仍然存在。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)