关于ubuntu 下LIBUSB 出现 LIBUSB_ERROR_OVERFLOW的问题

还是书接上文,我列举了一个程序,表达如何在ubuntu 下通过LIBUSB 读取下位机数据(通过BLUK)传输方式,一般采用这种方式都是进行大数量传输的,我的程序也是这样,但是我发现了一个问题,如果每次读取比较大的数据块时候,好像问题不是很大,但是如果读取一个字节,或者比较小的数据块时会出现 LIBUSB_ERROR_OVERFLOW ,这个倒霉名字让我认为我的程序出错了,一直在调试我的程序,根本不管用,后来查阅了LIBUSB 有关于这个问题的描述才知道对这个问题的官方解释

  • Problems may occur if the device attempts to send more data than can fit in
  • the buffer. libusb reports LIBUSB_TRANSFER_OVERFLOW for this condition but
  • other behaviour is largely undefined: actual_length may or may not be
  • accurate, the chunk of data that can fit in the buffer (before overflow)
  • may or may not have been transferred.
    意思说,如果下位机需要试图传输比你要求数据更多的数据时,会产生这个问题,比如说一次BULK传输,下位机需要传输给你1000个字节,但是你使用了
    recv= readbuffer(buffer,50) 你只需要传输50个字节,这时LIBUSB 会读取50个字节,但不会返回正确读取了50个字节而是出现LIBUSB_TRANSFER_OVERFLOW 的错误,因为还有1000-50 个字节没有读取成功,因为你开的buffer 太小了,不足以填充1000个字节,意思说,我没错,错误在你,谁让你开这么小的缓存,来完成本次的BLUK 传输,其实我有一个BULK 的buffer 挺大的,分手吧,你不适合我。这个跟我们对文件操作的认知是刚好相反的。
    当然这个可以解决,比较粗暴的方法是
    recv= readbuffer(buffer,1024*1024。。。。)基本就成功了,就是读取要求很大,但是返回可以是实际读取的大小了,也许是10 也许是100 或者某一个大约0 的数字,而且要不停地读取,才能保证只要有BLUK 传输 就不会丢包。貌似这个问题合理的解释过去了,但是同样带来一个问题,说如果我的客户端真的每次读取一个int,然后处理,岂不是很快就错位或者出现了LIBUSB_TRANSFER_OVERFLOW 吗?,读取会出现丢包,或者错位。想了想,还是Windows好,真完善,我想读多大就读多大,归根到底是Windows 驱动写了一个缓存,以便用户可以随便读取任何字节打下,对于windows驱动来说,仍然是靠大buffer读取,但是驱动建立了一个缓存,以便用户可以用任何大小读取,我安装这个思想做了一个缓冲区,让用户也可以用任何字节读取,而不再考虑出现LIBUSB_TRANSFER_OVERFLOW的错误,思想是用一个大Buffer 读取USB 然后把他放到一个队列里面,当然队列也应该比较大,当读取的时候,读取队列中的数据,这样就可以任意读取了,当然这种操作,有赖于要不停地写入和不停地读出。
在这里插入代码片




unit buffercheck;
// 主要用于Linux 下usb通讯 让他看起来很像windows 下的访问
 {$mode ObjFPC}{$H+}
interface

uses
  SysUtils, Classes, SyncObjs{$IFDEF MSWINDOWS} ,windows{$endif};

// 一个追赶式的循环buffer;
const buffer_ReadTimeout = -1;
type
  Tbuffercheck = class
  private
    fCapcity: integer;
    FData: array of Byte;
    FLock: SyncObjs.TCriticalSection;

    Fwriteindex: integer;
    FReadindex: integer;
    Fisfill: boolean;

    function inc_Write_index(index: integer): integer;
    function inc_Read_index(index: integer): integer;

    function readbyte(var B: Byte): boolean;
    function writebyte(B: Byte): boolean;

//    function ReadgoforeWrite:boolean;
    function ReadBuffer(var Buffer; Len: integer): integer; overload;

  public
    constructor Create(Capcity: integer);
    destructor Destroy; override;
    function WriteBuffer(var Buffer; Len: integer): integer;
    function ReadBuffer(var Buffer; Len: integer; timeout: integer)
      : integer; overload;

    published
     property REadindex  :integer read FReadindex;
     property Writeindex :integer read FWriteindex;

  end;

implementation

{ Tbuffercheck }

function TickDelta(TickOld, TickNew: LongWord): LongWord;
begin
  // if DWord is signed type (older Deplhi),
  // then it not work properly on differencies larger then maxint!
  Result := 0;
  if TickOld <> TickNew then
  begin
    if TickNew < TickOld then
    begin
      TickNew := TickNew + LongWord(MaxInt) + 1;
      TickOld := TickOld + LongWord(MaxInt) + 1;
    end;
    Result := TickNew - TickOld;
    if TickNew < TickOld then
      if Result > 0 then
        Result := 0 - Result;
  end;
end;
{$IFNDEF MSWINDOWS}

function GetTick: LongWord;
var
  Stamp: TTimeStamp;
begin
  Stamp := DateTimeToTimeStamp(Now);
  Result := Stamp.Time;
end;
{$ELSE}

function GetTick: LongWord;
var
  tick, freq: TLargeInteger;
{$IFDEF VER100}
  x: TLargeInteger;
{$ENDIF}
begin
  if windows.QueryPerformanceFrequency(freq) then
  begin
    windows.QueryPerformanceCounter(tick);
{$IFDEF VER100}
    x.QuadPart := (tick.QuadPart / freq.QuadPart) * 1000;
    Result := x.LowPart;
{$ELSE}
    Result := Trunc((tick / freq) * 1000) and High(LongWord)
{$ENDIF}
  end
  else
    Result := windows.GetTickCount;
end;
{$ENDIF}

constructor Tbuffercheck.Create(Capcity: integer);
begin
  Fisfill := false;
  fCapcity := Capcity;
  SetLength(FData, fCapcity);
  FLock := SyncObjs.TCriticalSection.Create;

  Fwriteindex := -1; // integer;
  FReadindex := -1; // integer;
end;

destructor Tbuffercheck.Destroy;
begin
  Finalize(FData);
  FLock.Free;
  inherited;
end;

function Tbuffercheck.inc_Read_index(index: integer): integer;
begin
  index := index + 1;
  if index >= fCapcity then
  begin
    Result := 0;
  end
  else
    Result := index;
end;

function Tbuffercheck.inc_Write_index(index: integer): integer;
begin
  index := index + 1;
  if index >= fCapcity then
  begin
    Result := 0;
    Fisfill := true;
  end
  else
    Result := index;
end;

function Tbuffercheck.ReadBuffer(var Buffer; Len: integer): integer;
var
  i: integer;
 // pb: integer;
  pbuffer: pByte;
  counter:integer;
begin
FLock.Enter;
  counter:=0;
  pbuffer := @Buffer;
  for i := 0 to Len - 1 do
  begin
    if not readbyte(pbuffer^) then
      Break;
    inc(pbuffer);
    counter :=counter +1;
  end;
  Result := counter;
  FLock.Leave;
end;

function Tbuffercheck.ReadBuffer(var Buffer; Len: integer;
  timeout: integer): integer;
var
  pbuffer: pByte;
  timeount: LongWord;
  remin, read: integer;
  ti: LongWord;
begin
  remin := Len;
  pbuffer := @Buffer;
  ti := GetTick;
  repeat
    read := ReadBuffer(pbuffer^, remin);
    remin := remin - read;
    if remin <= 0 then
      Break
    else
      inc(pbuffer, read);
    timeount := timeout - integer(TickDelta(ti, GetTick));
    if timeount <= 0 then
      Break;
    //睡一会 行吗
     SysUtils.
  Sleep(10); // Sleep(100);

  until (false);
  if remin > 0 then
    Result := buffer_ReadTimeout
  else
    Result := Len;
end;

function Tbuffercheck.readbyte(var B: Byte): boolean;
var
  pb: integer;
begin
  // 如果读取到的 要覆盖 Fwriteindex 所定的数值,那一定是错误的,所以 完全不能再读取了 所以根本读不动,停下来
   Result := false;
  if  Fwriteindex = FReadindex then
    exit;

  pb := inc_Read_index(FReadindex);
  B := FData[pb];
  FReadindex := pb;
  // 如果读取到的
  Result := true;
end;

(*function Tbuffercheck.ReadgoforeWrite: boolean;
begin
 Result:= true;
 // 这里可能存在覆盖的问题导致数据错误
 if not Fisfill then
  begin
    if FReadindex <= Fwriteindex then
      begin
        Result := false;
        exit;
      end;
  end
  else
   begin
   //必须大于 Fwriteindex
{    if FReadindex >= Fwriteindex then
      begin
        Result := false;
        exit;
      end;
      }
       Result := false;
   end;
end;
  *)
function Tbuffercheck.WriteBuffer(var Buffer; Len: integer): integer;
var
  i: integer;
 // pb: integer;
  pbuffer: pByte;
begin
FLock.Enter;
  pbuffer := @Buffer;
  for i := 0 to Len - 1 do
  begin
    writebyte(pbuffer^);
    inc(pbuffer);
  end;
Result := Len;
FLock.Leave;

end;

function Tbuffercheck.writebyte(B: Byte): boolean;
var
  pb: integer;
begin
  pb := inc_Write_index(Fwriteindex);
  FData[pb] := B;
  Fwriteindex := pb;
  //如果超越了 读 那就把以前的覆盖了,所以把读取的指针也往前移动一下,保证读取的是最新的数值
  if  Fwriteindex = FReadindex then
    FReadindex := inc_Read_index(FReadindex);

   Result := true;
end;

end.

``这样终于安静了,我们在ubuntu 下获得了一个跟windows 下一样操作习惯的USB 读取方法,
最后还是说一句,不过微软有什么错误,他的操作系统还是照顾了大多数人的应用场景,Linux 从稳定性方面虽然也不差,但是这种靠草台班子组建的开发队伍,
还是有很多没有考虑到的问题,这并不是在侮辱开源精神,
而是希望更多的专业团队来从事Linux 相关领域方面的应用开发,而不是把问题交给用户,
让用户各个都成为了开发的高手,或者是解决Linux 问题的高手`




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值