尝试通过创建模拟串行设备来测试C代码

时间:2016-08-15 16:26:49

标签: c linux serial-port termios

我希望以前没有问过这个问题,我有一张支票,偶然发现this,但它对我正在尝试的自动化测试没有任何帮助。

我想创建一个简单的测试脚本,它可以创建一个串行设备,让我能够回复" w' >装置"并从中获取值X.

手动使用socat来创建多个点并不是真正有用,因为我的代码只能查看一个端口,而不是从属/主模式。

我已经加入了与串口交互的功能,并与实际的物理硬件配合使用!

int interactWithPort(char* portID, char BW, char* offOn){

  speed_t baud = B9600; // baud rate
  int fd = open(portID, (BW == 'B') ? O_RDWR : O_WRONLY); //Open the port with the correct RW settings

  struct termios settings; // structure for the settings that will be used for the port 
  tcgetattr(fd, &settings);

  cfsetospeed(&settings, baud); // baud rate 
  settings.c_cflag &= ~PARENB; // no parity 
  settings.c_cflag &= ~CSTOPB; // 1 stop bit 
  settings.c_cflag &= ~CSIZE;
  settings.c_cflag |= CS8 | CLOCAL; // 8 bits 
  settings.c_lflag = ICANON; // canonical mode 
  settings.c_oflag &= ~OPOST; // raw output 
  tcsetattr(fd, TCSANOW, &settings); // apply the settings 
  tcflush(fd, TCOFLUSH);
  fcntl(fd, F_SETFL, 0); // apply file control operations 

  // Initialize file descriptor sets
  fd_set read_fds, write_fds, except_fds;
  FD_ZERO(&read_fds);
  FD_ZERO(&write_fds);
  FD_ZERO(&except_fds);
  FD_SET(fd, &read_fds);

  // Set timeout to 1.0 seconds
  struct timeval timeout;
  timeout.tv_sec = 3; // Read timeout of around 3 seconds, any more than this and something has went wrong
  timeout.tv_usec = 1;

  int w = 0;
  if(BW == 'W'){
    w = (int) write(fd, offOn, 1); 
  }else{
    w = (int) write(fd, "w", 1); // writes to the port a w or a 1/0 depending on function 
  }

  //If theres an error in writing to the scales then tell us!
  if(w < 0)
    fprintf(stderr, "Error writting to device: %s\n", portID);

  //If we flip switch to water then return as it's worked
  if(BW == 'W') return w;


  // Wait for input to become ready or until the time out; the first parameter is
  // 1 more than the largest file descriptor in any of the sets
  if (select(fd + 1, &read_fds, &write_fds, &except_fds, &timeout) == 1) {

    //This buffer holds the data from the serial port
    char buffer[32]; //Could reduce this to around 18 in length but better to have more buffering room

    // fd is ready for reading
    u_short n = (u_short) read(fd, buffer, sizeof(buffer));  //Reads the length of the serial data

    buffer[n] = 0;

    char * result = deblank(buffer);

    close(fd); // close the connection

    return atoi(result); // convert the result to a number and cast to be short
  }
  else
    fprintf(stderr, "Timeout error\n");
  return 0; // timeout or error
}

我玩过一些python脚本但它仍然存在奴隶/主人的相同问题,并且无法从所需的地址读取,但可以写入它没问题。

我玩过类似这个python脚本的东西,但它仍然有奴隶/主设置,对我来说不起作用:

import os
import pty
import serial
import time

master, slave = pty.openpty()
s_name = os.ttyname(slave)
ser = serial.Serial(s_name, baudrate=9600)

print(os.ttyname(slave))
print(os.ttyname(master))


# Create a symbolic link for the C program to use!
src = s_name
dst = "/home/nathan/test"
# This creates a symbolic link on python in tmp directory
os.symlink(src, dst)


# To Write to the device to get a reading
# ser.write('w'.encode('ascii'))

# To read from the device
while(True):
    if "w" in str(os.read(master, 1000)):
        ser.write("100".encode('ascii'))

        print("worked")
        break
    time.sleep(1)


print(os.read(slave, 1000))
# Clean up by deleting the temp link that we used
os.unlink(dst)

1 个答案:

答案 0 :(得分:0)

  

...它仍然有奴隶/主的相同问题,无法从所需的地址读取,但可以写入它没问题。

您的代码缺少显着的初始化。

应指定输入波特率:

cfsetispeed(&settings, baud);

启用接收器需要CREAD标志:

settings.c_cflag |= CREAD;

将串行端口指定为非控制终端也很常见:

fd = open(portID, O_RDWR | O_NOCTTY);

为了保持一致的逻辑(即匹配其他测试),条件应为

fd = open(portID, (BW == 'W' ? : O_WRONLY : O_RDWR) | O_NOCTTY);

write() select()之间,tcdrain操作(等待所有写入的输出都被传输)是合适的:

tcdrain(fd);

总体情况并不明显,但看起来你正在打开,初始化和关闭串口只是为了写和读一次;即只有一个程序中的所有内容 这应该通常被分成程序的至少三个部分以用于模块化。

您似乎使用阻止规范模式,但只输出一个字节(即行终止符在哪里?)。

总的来说,您的代码无法检查系统调用的返回代码是否存在错误情况。由于您的程序没有按预期运行,您可能忽略了显着的信息。