2009-07-07 11 views
2

cのunistd.h Linux関数を使用してMAC OSX上のBluetoothデバイスに書き込もうとしています。私はうまく接続し、成功の最初の数バイトを書いています。私はそれに他のコマンドを書き込もうとすると(書き込みバッファに15msごとに追加されたバイトがあります)、write()関数が1を返しても(書き込み成功)、結果は表示されません。cのunistd.hを使用してMAC OSXのシリアルポートに書き込む際の問題

書き込みを開始して別の書き込みを開始しようとするまでに完了しない場合(非ブロックなので)、最初の書き込みが失敗する可能性がありますか? (もしそうなら、書き込みが完了したかどうかを確認する方法はありますか?)書き込みがかなり頻繁に行われ、最初の2つが正常に送信されたので、これが私が考えることができる唯一のものです。

単に出力配列にバイトを追加し、その長さをインクリメント()

qwbyte

オープンポート機能:

BAMid = -1; 
struct termios options; 
struct termios originalTTYAttrs; 

// Open the serial port read/write, nonblocking, with no controlling terminal, and don't wait for a connection. 
BAMid = open(strPath, O_RDWR | O_NOCTTY | O_NONBLOCK); 
if (BAMid == -1) 
{ 
    printf("Error opening serial port %s - %s(%d).\n", 
      strPath, strerror(errno), errno); 
    goto error; 
} 

// Issue TIOCEXCL ioctl to prevent additional opens except by root-owned processes. 
if (ioctl(BAMid, TIOCEXCL) == -1) 
{ 
    printf("Error setting TIOCEXCL on %s - %s(%d).\n", 
    strPath, strerror(errno), errno); 
    goto error; 
} 

// Get the current options and save them so we can restore the default settings later. 
if (tcgetattr(BAMid, &originalTTYAttrs) == -1) 
{ 
    printf("Error getting tty attributes %s - %s(%d).\n", 
    strPath, strerror(errno), errno); 
    goto error; 
} 

// The serial port attributes such as timeouts and baud rate are set by modifying the termios 
// structure and then calling tcsetattr() to cause the changes to take effect. Note that the 
// changes will not become effective without the tcsetattr() call. 

options = originalTTYAttrs; 

// Set raw input (non-canonical) mode, with reads blocking until either a single character 
// has been received or a one second timeout expires. [should be moot since we are leaving it as nonblocking] 

cfmakeraw(&options); 
options.c_cc[VMIN] = 1; 
options.c_cc[VTIME] = 10; 
cfsetspeed(&options, B57600); // Set 57600 baud  
options.c_cflag |= CS8; // Use 8 bit words 

// Cause the new options to take effect immediately. 
if (tcsetattr(BAMid, TCSANOW, &options) == -1) 
{ 
    printf("Error setting tty attributes %s - %s(%d).\n", 
    strPath, strerror(errno), errno); 
    goto error; 
} 



//flush old transmissions 
if (tcflush(BAMid,TCIOFLUSH) == -1) { 
    printf("Error flushing BAM serial port - %s(%d).\n", 
    strerror(errno), errno); 
} 

oBufLength = 0; 

// Ask it to start 
if (! qwbyte(CmdStart)) { 
    goto error; 
} 

if (! qwbyte(CmdFull)) { 
    goto error; 
} 
//this transmit works 
txbytes(); 

printf("success opening port!"); 
return -1; 
    // Failure path 
error: 
if (BAMid != -1) { 
     close(BAMid); 
    } 
printf("returning an error--%d",errno); 
    return errno; 
} 

書き込み機能(txbytes):

int i, bufSize, numBytes; 

if(oBufLength != 0) { //if the output array isn't empty 

     //duplicating the output array and its size so it can 
     //be overwritten while this write is occuring 
     printf("about to transmit: "); 
    for(i = 0; i < oBufLength; i++) { 
    printf(" %u",oBuf[i]); 
    tempBuf[i] = oBuf[i]; 
    } 
    printf("\n"); 




bufSize = oBufLength; 
oBufLength = 0; 

numBytes = write(BAMid, &tempBuf, bufSize); 

printf("bytes written = %d\n",numBytes); 

if (numBytes == -1) { 
    printf("Error writing to port - %s(%d).\n", strerror(errno), errno); 
} 

return (numBytes > 0); 
} 
else { 
    return 0; 
} 

答えて

1

非ブロッキング書き込みは、あなたがそれらを期待している方法では動作しません。

書込みがすぐに完了できない場合は、write()がコードに戻りますが、は、がバックグラウンドでデータを送信しようとしていません。それは "私は現時点では書き込めません - 後でやり直してください"と言います。それは-1を返すことによってこれを行います。errnoがEAGAINに設定されています。

また、成功した場合、write()は、のバイト数を返します。に成功しました。したがって、2バイトの書き込みを要求したときに1の戻り値を取得した場合、それは部分的にしか成功しなかったことを意味し、2番目のバイトのためにwrite()を再度呼び出す必要があります。

基本的に、非ブロッキングIOを使用している場合、txbytes()関数は、バッファが空であるか-1を返すまでループ内でwrite()を呼び出す必要があります。 -1を返した場合は、errnoをチェックする必要があります.EAGAINの場合、もう一度write()を呼び出さなければなりません。他の何かはおそらく本当の誤りです。

ssize_t written = 0; 

while (oBufLength > 0 && written > -1) 
{ 
    size_t i; 

    printf("about to transmit %d bytes: ", oBufLength); 
    for(i = 0; i < oBufLength; i++) { 
      printf(" %u",oBuf[i]); 
    } 
    printf("\n"); 

    written = write(BAMid, oBuf, oBufLength); 

    printf("Write returned %d\n", written); 

    if (written > 0) 
    { 
     /* The first "written" number of bytes in the buffer have now been sent, so 
     * we discard them and move up the remaining bytes (if any) to the start of 
     * the buffer */ 

     oBufLength -= written; 
     memmove(oBuf, oBuf + written, oBufLength); 

     printf("Now have %d bytes left to send.\n", oBufLength); 
    } 
} 

if (written > -1 || errno == EAGAIN) 
{ 
    /* No fatal errors... */ 
    return 0; 
} else 
    /* error left in errno for caller to inspect */ 
    return -1; 
} 

write()はコードと並行して何もしないので、バッファを複製する必要はありません。バイトが書かれていると言うと、それ以上あなたのバッファは必要ありません。希望が助けてくれる!

+0

残念ながら、それは私の問題を解決しませんが、機能の構造に関する良いアドバイスありがとう。 write()関数から返された書き込み用のバイト数を常に取得しており、送信されたすべてのバイトを正常に書き込んだことを示しています。 –

+0

OK、write()が送信するよう要求したバイト数に等しい正の数を返す場合、write()に問題はありません - OSはあなたからのバイトを受け入れ、カーネルにはそれらを送信する仕事。 問題は、カーネルが最初の数バイト後にそれをしないことです。これは、フロー制御の問題のように聞こえる - デバイスがtcsetattr()で設定しているのと同じフロー制御設定を使用していることを確認する必要があります。 暗闇の中で刺すように、options.c_cflagでCRTSCTSの設定を解除したり、CLOCALを設定したりすることができます。 – caf

関連する問題