2016-08-15 5 views
0

私はこの質問が以前に尋ねられていないことを祈り、thisに遭遇しましたが、行う。シミュレートされたシリアルデバイスを作成してCコードをテストしようとしています

私はシリアルデバイスを作成し、 "echo 'w'> device"を許可して値を返すことができる簡単なテストスクリプトを作成します。

手動で複数のポイントを作成するためにsocatを使用しても、私のコードはスレーブ/マスタースタイルのポートではなく、ポートを1つだけ表示するのに役立ちます。

シリアルポートと対話し、実際の物理ハードウェアで動作する私の機能が含まれています!

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

珍しいもの:なぜw =(int)write(fd、offOn、1);の '(int)'? – chux

+1

''バッファ[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

...それはまだ同じ問題を抱えていますスレーブ/マスターと希望のアドレスから読み取ることができませんが、それに問題を書くことができます。

コードに顕著な初期化がありません。

入力ボーレートを指定する必要があります。

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); 

()選択が適切であろう()、tcdrain操作は(送信された書かれたすべての出力がされるまで待機する):

tcdrain(fd); 

全体像は明白ではありませんが、シリアルポートを開いたり、初期化したり、閉じたりして一度だけ書き込みと読み取りを行うように見えます。すなわち、すべてがただ1つの手順にある。
これは通常、モジュール性のためにプログラムの少なくとも3つのセクションに分かれていなければなりません。

ブロッキングカノニカルモードを使用しているようですが、1バイトだけを出力します(つまり、ラインターミネータはどこですか)。

全体的に、コードはエラー条件のためにsyscallsからの戻りコードをチェックすることができません。プログラムが期待どおりに動作しないため、顕著な情報を無視する可能性があります。

+0

行がありません: cfsetispeed(&settings、baud); ボーレートを設定する機能の開始時に9600と表示されましたか? – Csharpest

+0

この情報をありがとう、それは本当に有用ですが、私の本当の問題は、このコードをテストできるシリアルデバイスをシミュレートするためのスクリプトを書くことができますか? – Csharpest

+0

* "行ではありません:cfsetispeed(&settings、baud);ボーレートを設定する" * - コードはcfsetospeed()**のみを呼び出します。その関数名の 'o'は「出力」用であり、出力ボーレートのみが設定されています。移植性(POSIX準拠)のためには、入力ボーレートを設定するか、結合機能** cfsetspeed()**を使用する必要があります。 http://www.gnu.org/software/libc/manual/html_node/Line-Speed.htmlを参照してください。8250 UARTは異なるTxとRxのボーレートを持つことができますが、一般的な実装ではボーレートジェネレータは1つしかありません。 – sawdust

関連する問題