Linux串行端口 - 无法接收某些控制字符

时间:2016-11-18 13:06:19

标签: c linux serial-port uart

我有一个使用USB串行适配器连接到我的PC的开发板。从电路板上,我发送8字节的IEEE mac地址,但由于某种原因,我没有收到某些字节。

在我的电脑上,我有一个监控串口的守护进程,简单打印终端上收到的字符。

由于某种原因,未接收到值0x12(DC2(设备控制2))。我知道它是由我的开发板发送的,因为我正在嗅探串行输出,我可以看到0x12被发送。

我对linux没有足够的经验,但感觉它可能是我在C代码中初始化串口的方式(假设被跳过的字符是控制字符)。

我也尝试发送0x11(DC1),我能够成功接收。

我的代码是

serial_fd serial_open(char* serial_tty_path)
{
        //OPEN SERIAL PORT SPECIFIED BY THE ARGUMENT
        //AND RETURN HANDLE

        int32_t fd = open(serial_tty_path, O_RDONLY | O_NOCTTY);
        return (serial_fd)fd;
}

int8_t serial_setup(serial_fd fd, uint32_t serial_baud)
{
        //SET THE SPECIFIED SPEED, LENGTH, PARITY NAND STOP BIT
        //PARAMETERS FOR THE SUPPLIED SERIAL HANDLE

        struct termios serial_settings;
        uint32_t baudrate = B9600;

        switch(serial_baud)
        {
                case 2400:
                        baudrate = B2400;
                        break;
                case 4800:
                        baudrate = B4800;
                        break;
                case 9600:
                        baudrate = B9600;
                        break;
                case 115200:
                        baudrate = B115200;
                        break;
                default:
                        //invalid baudrate
                        return -1;
        };

        tcgetattr(fd, &serial_settings);

        //set the same input & output serial speed
        cfsetispeed(&serial_settings, baudrate);
        cfsetospeed(&serial_settings, baudrate);

        //seup serial for 8N1
        //no parity
        serial_settings.c_cflag &= ~PARENB;
        //stop bits = 1
        serial_settings.c_cflag &= ~CSTOPB;
        //data length = 8
        serial_settings.c_cflag &= ~CSIZE;
        serial_settings.c_cflag |= CS8;

        //set other serial control options
        //turn hardware flow control off
        serial_settings.c_cflag &= ~CRTSCTS;
        //turn software flow control off
        serial_settings.c_iflag &= ~(IXON | IXOFF | IXANY);
        //turn on the receiver on serial port
        serial_settings.c_cflag |= (CREAD | CLOCAL);

        //set the serial port mode of operation to NON CANONICAL
        //data available to program as soon as it's types
        //serial_settings.c_iflag &= ~(ICANON | ECHO | ECHO | ISIG);

        //set the minimum character to read from port to 1
        serial_settings.c_cc[VMIN] = 1;

        //set read timeout to 0.1 second (1 decisecond)
        serial_settings.c_cc[VTIME] = 2;

        //apply the settings to the serial port
        tcsetattr(fd, TCSANOW, &serial_settings);
}

int8_t serial_getc(serial_fd fd, uint8_t* c)
{
        //GET ONE CHAR FROM THE SERIAL RX BUFFER
        //RETURN -1 ON ERROR
        //ASCII CHARACTER RETURNED IN SUPPLIED CHARACTER POINTER

    uint8_t d=0;
    if(read(fd, &d, 1)<1)
    {
        perror("msg ");
        return -1;
    }
    *c = d;
    if(d == 0x12)
    {
        printf("hola !\n");
    }
    return 0;
}

    uint8_t serial_readline(serial_fd fd, uint8_t* buffer)
{
        //READ INCOMING SERIAL CHARACTERS INTO THE SPECIFIED BUFFER
        //TILL LF(\n) RECEIVED
        //RETURN : BYTES READ TILL \n (including \n)

        uint8_t read_char;
        int8_t status;
        uint32_t counter = 0;

        status = serial_getc(fd, &read_char);
        if(status != -1)
        {
                while(read_char != '\n')
                {
                        buffer[counter] = read_char;
                        counter++;

                        while(serial_getc(fd, &read_char) == -1){};
                }
                buffer[counter] = '\n';
                return counter;
        }
        return 0;
}

这是我的主要常规

while(1)
        {   

                if((l = serial_readline(serial_handle, &serial_buffer[0])) != 0)
                {
                        //ACTUAL LINE READ FROM SERIAL
                        if(serial_buffer[0] == '#')
                        {
                                printf("l = %d\n", l);
                //SENSOR MESSAGE
                printf("*** received sensor message\n-*** Sending data to backend\n");
                printf("%s\n", serial_buffer);

                for(m=1; m<=21; m++)
                {
                    printf("data : %c, %02X\n", serial_buffer[m], serial_buffer[m]);
                }

                //populate the json request buffer
                //sensor mac address (8 bytes)
                //note sprintf adds a null terminated char after its output. need to replace
                //it manually !
                sprintf(&rpc_request_buffer[87], "%02X", serial_buffer[1]);
                rpc_request_buffer[89] = ':';
                sprintf(&rpc_request_buffer[90], "%02X", serial_buffer[2]);
                rpc_request_buffer[92] = ':';
                sprintf(&rpc_request_buffer[93], "%02X", serial_buffer[3]);
                rpc_request_buffer[95] = ':';
                sprintf(&rpc_request_buffer[96], "%02X", serial_buffer[4]);
                rpc_request_buffer[98] = ':';
                sprintf(&rpc_request_buffer[99], "%02X", serial_buffer[5]);
                rpc_request_buffer[101] = ':';
                sprintf(&rpc_request_buffer[102], "%02X", serial_buffer[6]);
                rpc_request_buffer[104] = ':';
                sprintf(&rpc_request_buffer[105], "%02X", serial_buffer[7]);
                rpc_request_buffer[107] = ':';
                sprintf(&rpc_request_buffer[108], "%02X", serial_buffer[8]);
                rpc_request_buffer[110] = '\"';

                //amr readings
                sprintf(&rpc_request_buffer[136], "%05u", util_8_bit_to_16_bit_unsigned(serial_buffer[9], serial_buffer[10]));
                rpc_request_buffer[141] = '-';
                sprintf(&rpc_request_buffer[142], "%05u", util_8_bit_to_16_bit_unsigned(serial_buffer[11], serial_buffer[12]));
                rpc_request_buffer[147] = '-';
                sprintf(&rpc_request_buffer[148], "%05u", util_8_bit_to_16_bit_unsigned(serial_buffer[13], serial_buffer[14]));
                rpc_request_buffer[153] = '-';
                sprintf(&rpc_request_buffer[154], "%05u", util_8_bit_to_16_bit_unsigned(serial_buffer[15], serial_buffer[16]));
                rpc_request_buffer[159] = '-';
                sprintf(&rpc_request_buffer[160], "%05u", util_8_bit_to_16_bit_unsigned(serial_buffer[17], serial_buffer[18]));
                rpc_request_buffer[165] = '-';
                sprintf(&rpc_request_buffer[166], "%05u", util_8_bit_to_16_bit_unsigned(serial_buffer[19], serial_buffer[20]));
                rpc_request_buffer[171] = '\"';

                //occupied filed
                rpc_request_buffer[186] = serial_buffer[21] + 48;
                rpc_request_buffer[187] = '\"';

                printf("json request\n");
                printf("%s\n", rpc_request_buffer);


                                struct curl_fetch_st* curl_handle = (struct curl_fetch_st*)malloc(sizeof(struct curl_fetch_st));
                curl_send_data_get_reply(curl_handle, rpc_request_buffer, rpc_reply_buffer);

                //sensordb_add(sensordb_16From8(&serial_buffer[1]), sensordb_16From8(&serial_buffer[3]));
                                //sensordb_printSerial();
                        }
                        else
                        {
                                //DEBUG MESSAGE
                //IGNORE THE DEBUG MESSAGES FOR NOW
                                //printf("%s", serial_buffer);
                        }
        }

}

这就是我得到的

root@ankit-ThinkPad-W530:/media/ankit/work/projects/parkmon/parkmon_gateway# l = 21
*** received sensor message
-*** Sending data to backend
#
data : , 00
data : K, 4B
data : , 00
data :, 08
data : �, FB
data : $, 24
data : �, 85
data : , 00
data : z, 7A
data : , 01
data : �, F1
data :  , 09
data : �, 9F
data : , 07
data : 2, 32
data : , 06
data :, 08
data : , 06
data : �, 86
data : , 01
data : 
, 0A
json request
{"src": "5A:D6:34:5E:1C:D8","time": 1468409465,"messages": [{"type": "status?","src": "00:4B:00:08:FB:24:85:00","id": 9,"amr_reading": "31233-61705-40711-12806-02054-34305","occupied": ":"}],"auth":""}
CURL Returned: 
1,1479472678,
status,00:4B:00:08:FB:24:85:00,9,1

数据为0x00 - 0x12 - 0x4B。但是,如输出中所示,0x12完全被跳过。

不确定是什么原因造成的。

谢谢!

1 个答案:

答案 0 :(得分:0)

您是否尝试过取消名义动物提到的ICANON和IEXTEN并禁用某些控制字符?

我无法在串行端口上接收到一些字节,并且仅将VMIN保持为1即可禁用每个c_cc来解决问题。

//Right after open...
termios ios;
::tcgetattr(fd, &ios);
ios.c_lflag &= ~(ICANON | IEXTEN);
for(int i = 0; i < NCCS; i++)
{
    ios.c_cc[i] = i==VMIN ? 1 : 0;
}
::tcsetattr(fd, TCSANOW, &ios);

对于使用boost_asio的用户,将fd替换为port-> native_handle()也可以解决该问题。