2016-08-15 11 views
0

나는이 질문이 전에 물어 보지 않았 으면 좋겠다. 나는 확인을했고 this을 우연히 만났지만 실제로 시도하고있는 자동화 된 테스트에는 도움이되지 않는다. 해야 할 것.시뮬레이트 된 시리얼 장치를 생성하여 C 코드를 테스트하려고 시도합니다.

직렬 장치를 만들 수있는 간단한 테스트 스크립트를 만들고 싶습니다. "장치를 반향"하고 값 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 
} 

좀 파이썬 스크립팅과 주위 연주했지만 여전히 노예/주인 같은 문제가 원하는 주소에서 읽을 수 있지만 문제는 쓸 수 없습니다.

나는이 파이썬 스크립트 같은 것을 주위에 연주했지만 여전히 나를 위해 작동하지 않는 슬레이브/마스터 설정이 있습니다

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) 
+0

골동품 : 왜'w = (int) write (fd, offOn, 1);의'(int)'인가? – chux

+1

'buffer [n] = 0'은'u_short n = (u_short) read (fd, buffer, sizeof (buffer))에서 잘못되었습니다; 버퍼 [n] = 0;'. 'buffer []'의 밖에 쓸 수 있습니다. 아마도'int n = read (fd, buffer, sizeof buffer - 1); if (n <0) Handle_Error()'('-1'을 더한다.) – chux

+0

@chux 컴파일러 경고를 고치는 데 그 캐스트를 사용해야했습니다. – Csharpest

답변

0

은 ... 여전히 같은 문제가를 슬레이브/마스터와 원하는 주소에서 읽을 수 없지만 아무 문제가 그것에 쓸 수 있습니다.

코드에 현저한 초기화가 없습니다.

가 입력 전송 속도가 지정되어야한다

CREAD 플래그가 상기 수신기를 사용하는 데 필요한
cfsetispeed(&settings, baud); 

:

settings.c_cflag |= CREAD; 

그것은 비 제어 단자로 직렬 포트를 지정하는 것이 일반적이다 :

fd = open(portID, O_RDWR | O_NOCTTY); 

일관된 로직 (즉, 다른 테스트와 일치)을 위해 조건부는 할 것을 쓰기 사이

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

()선택 적절할 것 같다()하는 tcdrain 작업은 (전송 된 기록 된 모든 출력이 될 때까지 대기) :

tcdrain(fd); 

큰 그림은 분명하지 않지만 직렬 포트를 열어 초기화하고 닫으면 한 번만 쓰고 읽을 수 있습니다. 즉 모두 하나의 절차에 불과합니다.
이것은 일반적으로 모듈성을 위해 프로그램의 적어도 세 섹션으로 분리되어야합니다.

차단 표준 모드를 ​​사용하는 것 같지만 1 바이트 만 출력합니다 (즉, 줄 종결 자의 위치는 어디입니까?).

전체 코드가 오류 조건에 대한 syscalls의 반환 코드를 확인하지 못합니다. 프로그램이 예상대로 작동하지 않으므로 중요한 정보를 무시할 수 있습니다.

+0

줄이 맞지 않습니다 : cfsetispeed (& settings, baud); 보오율 설정 기능 시작시 9600으로 표시 했습니까? – Csharpest

+0

이 정보를 제공해 주셔서 감사합니다. 정말 도움이 되겠지만 제 질문은 어떻게이 코드를 테스트 할 수있는 시리얼 장치를 시뮬레이트하기위한 스크립트를 작성할 수 있습니까? – Csharpest

+0

* "회선이 아닙니다 : cfsetispeed (& settings, baud); 전송 속도 설정"* - 코드는 cfsetospeed() ** 만 호출합니다. 그 함수 이름의 'o'는 "output"을위한 것이고 출력 baudrate 만 설정됩니다. 이식성 (예 : POSIX 준수)을 위해 입력 통신 속도를 설정하거나 결합 된 기능 ** cfsetspeed() **를 사용해야합니다. http://www.gnu.org/software/libc/manual/html_node/Line-Speed.html을 참조하십시오. 일반적인 구현에는 일반적인 보오 레이트 생성기 만 있지만 8250 UART는 서로 다른 전송 속도를 가질 수 있습니다. – sawdust