串行端口流/Bash 或 C 脚本

串行端口流/Bash 或 C 脚本

我有一个串行设备(测速雷达),每 250 毫秒输出一次数据。

这是我在设备上的信息:

1. Speed Packet Protocol
The Radar message packet consists of 7 bytes @ 1200 baud, no parity, 8 data bits, 1 start
bit. Messages are paced at 250mS intervals and are sent whether there is a target or not.
Char Description
1 <STX> Start of message
2 Status Radar status, as defined below
3 Patrol Speeds in binary from 4 to 255, Speed values below 4 are treated as
zero.
4 Target
5 Lock
6 Alt Alternate speed, as defined below
7 <ETX> End of message
1.1. Radar status byte
Bit Description/function if set
0 Low voltage error
1 Radio frequency interference error
2 Front antenna
3 Rear antenna
4 Moving mode
5 Alternate mode (fastest or slow)
6 Opposite direction mode
7 Always set (Indicated a speed packet)
Neither antenna being selected indicates standby.
Both antennae selected indicates a self-test is in progress. Test results are not sent, the
radar either returns to normal operation if successful or ceases communication in the
event of failure.
1.2. Alternate Speed
If the alternate mode bit is set, the alternate speed should be displayed. This will be
fastest if in opposite direction or slow if in same direction.
1.3. Message Receipt
Each message received should be time stamped and removed after 1 second if it has not
been replaced by a new message. The only exception is the self-test message, which
allows 8 seconds for the test to complete.
1.4. Example
Received sequence 02, 244(0xf4), 50, 99, 75, 01, 03.
Front antenna, moving mode, fastest mode, opposite direction mode, patrol speed of 50,
strongest target at 99, a locked speed of 75 and a no fastest target (since the value is
less that 4). 

使用:

minicom -b 1200 -D /dev/ttyUSB0 -8 -H -w

如果读取 0,数据如下所示:

02 c8 00 00 00 00 03

如果它读的是其他东西的话:

02 c8 00 16 00 00 03

或者

02 c8 00 0f 00 00 03

所以它可能会是这样的:

//How do I pipe the stream into the script??
"Get String Code Here"
//example string
$string=02 c8 00 16 00 00 03
//remove first part
$prefix=02 c8 00
//remove last part 
$suffix=00 00 03
//result which appears to be a hex value
$result=16 (22MPH)
//convert $result to decimal

echo $result to monitor/file/database

我还遇到了一个 C 脚本,我希望它能更好地工作:

    #include <stdio.h> /* Standard input/output definitions */
    #include <string.h> /* String function definitions */
    #include <unistd.h> /* UNIX standard function definitions */
    #include <fcntl.h> /* File control definitions */
    #include <errno.h> /* Error number definitions */
    #include <termios.h> /* POSIX terminal control definitions */



//Initialize serial port
int initport(int fd)
{
    int portstatus = 0;

    struct termios options;
    // Get the current options for the port...
    tcgetattr(fd, &options);
    // Set the baud rates to 115200...
    cfsetispeed(&options, B1200);
    cfsetospeed(&options, B1200);
    // Enable the receiver and set local mode...
    options.c_cflag |= (CLOCAL | CREAD);

    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;
    //options.c_cflag |= SerialDataBitsInterp(8);           /* CS8 - Selects 8 data bits */
    options.c_cflag &= ~CRTSCTS;                            // disable hardware flow control
    options.c_iflag &= ~(IXON | IXOFF | IXANY);           // disable XON XOFF (for transmit and receive)
    //options.c_cflag |= CRTSCTS;                     /* enable hardware flow control */


    options.c_cc[VMIN] = 0;     //min carachters to be read
    options.c_cc[VTIME] = 0;    //Time to wait for data (tenths of seconds)


    // Set the new options for the port...
    //tcsetattr(fd, TCSANOW, &options);


    //Set the new options for the port...
    tcflush(fd, TCIFLUSH);
    if (tcsetattr(fd, TCSANOW, &options)==-1)
    {
        perror("On tcsetattr:");
        portstatus = -1;
    }
    else
        portstatus = 1;


    return portstatus;
}


/*
* 'open_port()' - Open serial port 1.
*
* Returns the file descriptor on success or -1 on error.
*/
int open_port(void)
{
    int fd; /* File descriptor for the port */
    fd = open("/dev/ttyUSB0", O_RDONLY | O_NOCTTY | O_NDELAY);

    if (fd == -1)
    {
        /*
        * Could not open the port.
        */
        perror("open_port: Unable to open /dev/ttyUSB0 --- \n");
    }
    else
        fcntl(fd, F_SETFL, 0);

    return (fd);
}

int main(void)
{

    int serial_fd = open_port();

    if(serial_fd == -1)
        printf("Error opening serial port /dev/ttyUSB0 \n");
    else
    {
        printf("Serial Port /dev/ttyUSB0 is now open \n");

        // READ PORT DATA 


        if(initport(serial_fd) == -1)
        {
            printf("Error Initializing port");
            close(serial_fd);
            return 0;
        }

        sleep(.5);
        //usleep(500000);
        //printf("size of data being sent = %ld", sizeof("~ver~\n\r"));

        sleep(.5);
        //usleep(500000);

        printf("\n\nNow closing Serial Port /dev/ttyUSB0 \n\n");

        close(serial_fd);
    }


    return 0;
}

答案1

好吧,我想你所需要的只是:

"Get String Code Here"  
string="02 c8 00 16 00 00 03"  
result=$(echo ${string} | cut -w -f 3)  

但这是十六进制的,所以比较会很棘手:

decimalresult=$(printf "%d" 0x${result})  

当然,您可以在一行中完成此操作,但为了清楚起见,我这样做了。

经过修改的版本

您说您有一个连续的流,需要将其作为脚本的一部分来读取。 Shell 脚本通常按行读取,因此我们这样做:

  • 您可以使用minicom其输出并将其通过管道传输到脚本中。请务必使用该-H选项来获取十六进制输出,因为 shell 脚本不能很好地处理二进制文件。像这样:
    minicom -b 1200 -D /dev/ttyUSB0 -8 -H -w | this_script
  • 输入通过管道传输,dd将其分割成组成一条消息的块,并在末尾添加换行符。
  • 这会进入一个循环,读取每行的七个项目,忽略除第四个之外的所有项目。
  • 将十六进制转换为十进制并输出。

    dd conv=unblock cbs=21 | while read x x x hexresult x x x ; do decimalresult=$(printf "%d" 0x${hexresult}) echo ${decimalresult} done

我还没有尝试过连续流,所以你可能需要稍微调整一下。特别是,您可能需要添加obs=21参数dd(甚至可能是 20,而不是 21)。

相关内容