我有点新手,但我有一个遗留应用程序,使用ttyACM0从设备读取64字节的AES加密数据。我现在需要读取128个字节。听起来很简单;增加缓冲区的大小等。但无论我尝试什么,我仍然只能读取64个字节。之后它只是挂起。我使用终端和cdc-acm驱动程序验证了Windows中的通信。设备不使用流量控制。我无法上传代码,因为它的专有但下面是一些片段:
初始化: CACS_RefID ::初始化() { 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;
注意:我现在正在读取数据,无论选择错误如何,STILL只能获得64字节。我联系了我的设备制造商。一定是奇怪的事情。
答案 0 :(得分: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)小于艾朗(128)你轮再次去调用select()。< / p>
假设您获得更多数据,而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并再次尝试。
答案 1 :(得分:0)
我不能说我知道为什么但是修复是在实现开始时调用初始化代码,即使它之前被调用过。如果我再次调用它,我可以读取128个字节。如果不这样做,我最多只能读取64个字节。