无法模仿C代码中`echo`命令的动作

时间:2015-02-20 22:29:21

标签: c bash serial-port echo cat

我写了几个bash脚本文件,通过两个串口进行通信。一个脚本可以被认为是接收器而另一个可以被认为是发送器。接收脚本逐行读取和显示数据,直到它读取字符序列<break>。然后它停止收听,并将onetwo的字符序列发送回发送器。因此脚本是:

#!/bin/bash

# Read and reply bash script.

exec 3<> /dev/ttyS4
while true; do
    #cat -v /dev/ttyS4 | while read -r input; do
    while read -r -u 3 input; do
        if [ "$input" = "<break>" ]
        then
            echo "break command received."
            break
        else
            echo -e "${input}"
        fi
    done 

    echo "Sending selection"
    if [ "$selection" = "one" ]
    then
        selection="two"
    else
        selection="one"
    fi
    echo "$selection" >&3

done

发送器脚本传输一些字符数据,然后从上面的接收器脚本等待onetwo的回复:

exec 4<> /dev/ttyS0
selection="one"
while true; do
    echo "************************************" > /dev/ttyS0
    echo "       Selection: ${selection}" > /dev/ttyS0
    echo "************************************" > /dev/ttyS0
    echo "<break>" > /dev/ttyS0
    read -r -t 3 -u 4 input
    if [ -z "$input" ]
    then
        echo "Response from remote timed out."
    elif [ "$input" = "one" ]
    then
        selection=$input
    elif [ "$input" = "two" ]
    then
        selection=$input
        colour=$RED
    else
        echo "Unknown selection: $input"
    fi

    sleep 1 
done

上述两个脚本工作正常,接收者脚本正确识别<break>字符序列。

我希望用一个小的C程序替换'发送器'脚本但是我发现当我发送字符序列<break>时,接收器脚本这次 NOT 识别是'传输结束',是简单的回声<break>到标准输出,而不是break command received。我尝试过几个例子,比如添加转义字符,但Bash echo的工作方式和我在C代码中发送数据的方式显然有所不同:

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

#define TRUE 1
#define FALSE 0

int main(int argc, char *argv[]) {
    int selected_tool = DEFAULT_TOOL_SELECTION;
    FILE *ser2_fd_write, *ser2_fdrw;
    struct termios tios, tios_w;        // ser 2 termios structure
    int ser2_fd, ser2_fdw;
    char read_buffer[BUFFER_SIZE];
    struct timespec tdelay;

    bzero(&tdelay, sizeof(tdelay));
    tdelay.tv_sec = 1;
    tdelay.tv_nsec = 5000;

    if ((ser2_fd = open("/dev/ttyS0", O_RDWR)) == -1){
        printf("Unable to open ttyS0 as read-write only.\n");
        return EXIT_FAILURE;
    }

    bzero(&tios, sizeof(tios));
    cfsetispeed(&tios, B38400);
    cfsetospeed(&tios, B38400);


    tios.c_cflag = B38400 | CS8 | CLOCAL | CREAD | CRTSCTS;
    tios.c_iflag = IGNPAR;
    tios.c_oflag = 0;
    tios.c_lflag = ICANON; //0
    tios.c_cc[VTIME] = 0;
    tios.c_cc[VMIN] = 10;

    tcflush(ser2_fd, TCIFLUSH);
    if (tcsetattr(ser2_fd, TCSANOW, &tios) == -1){
        printf("Could not set ser 2 attributes.\n");
        return -1;
    }

    if ((ser2_fdrw = fdopen(ser2_fd, "awr")) == NULL){
        printf("Unable to open file descriptor.\n");
        return EXIT_FAILURE;
    }

while(1){

    push_to_ser2(ser2_fdrw, selected_tool);
    /*
     * This is where sending <break> differs from echo
     */

    //fputs("break", ser2_fdrw);
    fprintf(ser2_fdrw, "break\r\n");
    //fprintf(ser2_fdrw, "\r\n");
    //write(ser2_fd,"break\r\n", 9);
    fflush(ser2_fdrw);
    int c = 0;

    nanosleep(&tdelay, NULL);
    tcflush(ser2_fd, TCIOFLUSH);
    tcdrain(ser2_fd);
    fcntl(ser2_fd, F_SETFL, 0);

    if ( (c = read(ser2_fd, read_buffer, BUFFER_SIZE)) > 0){
        read_buffer[c] = 0;
        if (strcmp(read_buffer, "one\r\n") == 0){
            selected_tool = 1;
        } else if (strcmp(read_buffer, "two\r\n") == 0){
            selected_tool = 2;
        }
    }else{

    }
}
    return EXIT_SUCCESS;
}


/*
 * Convenience function to push data to ser 2
 * *c_data      pointer to the card data
 * *t_data      pointer to the tool data
 */
void push_to_ser2(FILE * fd, int tool){

    fprintf(fd, "**********************************************************\n");
    fprintf(fd, "*                                                        *\n");
    fprintf(fd, "*                     Tool %d Data                       *\n", tool);
    fprintf(fd, "*                                                        *\n");
    fprintf(fd, "**********************************************************\n");


    fprintf(fd,"\r\n");
    fflush(fd);
}

我也尝试过对termios结构进行各种更改,但它没有任何区别。有什么想法吗?

2 个答案:

答案 0 :(得分:1)

您的代码有几个问题需要纠正:

  • 代码bzero(&tios, sizeof(tios))代码应该调用 tcgetattr()来正确初始化结构。对于规范输入而言,这可能是一个严重的问题,因为现有代码将所有控制代码规范归零,而不是具有适当的定义。
  • 代码不是直接分配,而是应该执行逐位操作(以便保留现有设置)。见Setting Terminal Modes Properly
  • 您使用规范输入指定非规范输出,这是一种非典型组合。看起来你想要输入和输出的规范模式。
  • VMIN和VTIME仅对非规范输入有意义,不应为规范输入指定(因为它破坏了VEOF和VEOL字符规范)。
  • read(ser2_fd,...)默默地忽略错误。
  • 不要使用 fdopen() fprintf(),只需使用 write(ser2_fd,...)来简化代码,高架。缺点是你必须指定字节数并使用 sprintf()来执行整数到字符串的转换。

请参阅Serial Programming Guide for POSIX Operating Systems

答案 1 :(得分:0)

看起来好像bash脚本正在发送包含尖括号的文字字符串<break>。同时,C程序只发送break。将尖括号添加到C程序中的文字。 (这些括号对echofprintf没有任何特殊含义,因此它们只是按原样发送。)