0

私は少し初心者ですが、ttyACM0 を使用してデバイスから 64 バイトの AES 暗号化データを読み取るレガシー アプリを持っています。128 バイトを読み取る必要があります。シンプルに聞こえました。バッファなどのサイズを増やします。しかし、何を試しても、まだ64バイトしか読み取れません。その後、ハングするだけです。ターミナルと cdc-acm ドライバーを使用して、Windows での通信を確認しました。デバイスはフロー制御を使用しません。コードは独自のものであるためアップロードできませんが、以下にいくつかのスニペットを示します。

初期化: CACS_RefID::Initialise() { int iRet = 1; struct termios dev_settings;

    if(( m_fdRefdev = open("/dev/ttyACM0", O_RDWR))<0)
    {
        g_dbg->debug("CACS_RefID::Failed to open device\n");
        return 0;
    }


    g_dbg->debug("CACS_RefID::Initialse completed\n");
    // Configure the port
    tcgetattr(m_fdRefdev, &dev_settings);
    cfmakeraw(&dev_settings);

    //*tcflush 
    //tcflush(m_fdRefdev, TCIOFLUSH);   
     tcsetattr(m_fdRefdev, TCSANOW, &dev_settings);
    return iRet;
}

実装:

    int CACS_RefID::Readport_Refid(int ilen, char* buf)
{
    int ierr=0, iret = 0, ictr=0;
    fd_set  fdrefid;      
        struct timeval porttime_refrd;

    FD_ZERO(&fdrefid);
    FD_SET(m_fdRefdev,&fdrefid); 

    porttime_refrd.tv_sec = 1;
    porttime_refrd.tv_usec = 0; //10 Seconds wait time for read port

    do
    {
        iret = select(m_fdRefdev + 1, &fdrefid, NULL, NULL, &porttime_refrd);
        switch(iret)
        {
            case READ_TIMEOUT:
                g_dbg->debug("Refid portread: Select timeout:readlen=%d \n",ilen);
                ierr = -1;
                break;

            case READ_ERROR:
                g_dbg->debug("Refid portread: Select error:readlen=%d \n",ilen);
                ierr = -1; 
                break;

            default:
                iret = read(m_fdRefdev, buf, ilen); 
                g_dbg->debug("Refid portread: Read len(%d):%d\n",ilen,iret);
                break;
        }
    }while((ierr == 0) && (iret<ilen) );          

    //Flush terminal content at Input and Output after every read completion
//  tcflush(m_fdRefdev, TCIOFLUSH); 

    return ierr;

}

実装を実行する前に毎回初期化すると、128 バイトになりますが、データは 64 バイト後に破損します。それに取り組む前でさえ、私はたくさんの READ_ERROR を受け取ります。元の作成者は、デバイスが select() でブロックされることを期待していたようですが、そうではありません。
システムの ttyACM0 バッファ サイズに何らかの制限がありますか? ttyACM ドライバーでボーレートは重要ですか? read() は、すべてのバイトが読み取られた後に読み取りを停止しますか (最初の 64 バイトが使用可能で、次に空になり、さらにデータが増えると考えています)?

マニュアルページに注いでいますが、私は困惑しています。どんな助けでも大歓迎です。

ここに私の最新のものがあります:

   int CACS_RefID::Get_GasTest_Result(int ilen)
{
    int ierr=0, iret = 0, ictr=0, iread=0;
    fd_set  fdrefid;      
        struct timeval porttime_refrd;

    porttime_refrd.tv_sec = 5;
    porttime_refrd.tv_usec = 0; //10 Seconds wait time for read port


    if (Get_GasTest_FirstPass == 0)
    {
        g_dbg->debug("GasTest_Result_firstPass\n");
        memset(strresult, 0, sizeof(strresult));        //SLY clear out result buffer
        iread=0;
        Get_GasTest_FirstPass = 1;
    }

    do
    {
        iread = strlen(strresult);

        FD_ZERO(&fdrefid);
        FD_SET(m_fdRefdev,&fdrefid); 

        iret = select(m_fdRefdev + 1, &fdrefid, NULL, NULL, &porttime_refrd);
        switch(iret)
        {
            case READ_TIMEOUT:      //0
                g_dbg->debug("Get_GasTest_Result: Select timeout\n");
                ierr = -1;
                break;

            case READ_ERROR:        //-1
                g_dbg->debug("Get_GasTest_Result: Select error=%d %s \n", errno,strerror(errno)) ;
                ierr = -1; 
                break;

        }
        iret = read(m_fdRefdev, (&strresult[0] + iread), (ilen-iread)); 
        g_dbg->debug("Get_GasTest_Result: ilen=%d,iret=%d,iread=%d \n",ilen,iret,iread);

    }while((ierr == 0) && (iread<ilen) );


    return ierr;

注:選択エラーに関係なくデータを読み取っていますが、まだ64バイトしか取得していません。デバイス製造元に連絡しました。何か変なことが起きているに違いない。

4

2 に答える 2

1

コードで考えられる問題の 1 つを次に示します。これが原因で 64 バイトしか取得できない可能性がありますが、表示されている内容を説明できる可能性があります。関数 Readport_Refid() を 128 バイトのバッファーで呼び出すとします。言い換えれば、あなたの呼び出しは次のようなものでした:

char buffer[128];

Readport_Refid(128, buffer);

なんらかの理由で、select() の最初の呼び出しで戻り値 1 が返されたとします (1 ビットが設定されているため)。あなたのコードは1ビットしか設定していないので、離れて read()

iret = read(m_fdRefdev, buf, ilen); 
g_dbg->debug("Refid portread: Read len(%d):%d\n",ilen,iret);
break;

iret は 64 を返し (64 バイトが読み取られたことを意味します)、プログラムは適切なメッセージを出力します。 ierr はまだ 0 であり、iret (64) は ilen (128) よりも小さいため、もう一度ラウンドして select() を呼び出します。

さらにデータを取得し、select() が再び 1 を返したとします。次に、同じ ilen で同じバッファーを再度読み取り、読み取った最初の 64 バイトを上書きします。

少なくとも、次のことを行う必要があります。変更された行の下にのみ表示しました。最初に iread 変数を追加し、それを使用して、既に読み取ったデータを保持していることを確認します。次に、 iread を使用して、十分に読んだかどうかを判断します。

int CACS_RefID::Readport_Refid(int ilen, char* buf)
{
    int ierr=0, iret = 0, ictr=0, iread = 0;

    [...]
            default:
                iret = read(m_fdRefdev, buf + iread, ilen - iread); 
                if (iret > 0)
                    iread += iret;

                g_dbg->debug("Refid portread: Read len(%d):%d\n",ilen,iret);
                break;
        }
    }while((ierr == 0) && (iread<ilen) );          

    [...]

**** 2013-08-19 編集 ****

@wildplasserのコメントを繰り返したい

また、ループの各トリップで FD_SET を設定する必要があります。大漁。

新しいコードに関して、それは機能しますか、それともまだ問題がありますか?

**** 2013-08-19 再度編集 ****

EINTR を取得することは心配する必要はありません。FD_SET をリセットして再試行することを計画する必要があります。

于 2013-08-17T13:35:29.213 に答える
0

理由はわかりませんが、以前に呼び出されたにもかかわらず、実装の最初に初期化コードを呼び出すことで修正されました。もう一度呼び出すと、128 バイトで読み取ることができます。そうしないと、最大 64 バイトしか読み取れません。

于 2013-08-22T00:00:12.110 に答える