0

我有点新手,但我有一个旧应用程序,它使用 ttyACM0 从设备读取 64 字节的 AES 加密数据。我现在需要读取 128 个字节。听起来很简单;增加缓冲区的大小等。但无论我尝试什么,我仍然只能读取 64 个字节。之后它只是挂起。我使用终端和 cdc-acm 驱动程序验证了 Windows 中的通信。设备不使用流量控制。我无法上传代码,因为它是专有的,但以下是一些片段:

初始化:CACS_RefID::Initialise() { int iRet = 1; 结构 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

这是您的代码可能存在的一个问题;这可能不是导致您仅获得 64 个字节的原因,但它可以解释您所看到的内容。假设您使用 128 字节的缓冲区调用函数 Readport_Refid()。换句话说,您的调用类似于:

char buffer[128];

Readport_Refid(128, buffer);

无论出于何种原因,假设第一次调用 select() 得到的返回值为 1(因为设置了一个位)。您的代码只设置了一位,因此您可以开始阅读()

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 回答