ubuntu 下虚拟串口问题及处理方案

最近由于国产化要求,需要把原来Windows
下的程序进行修改,主要是支持Linux,其中我们有一块采集卡是核心芯片是STM32F429,通讯采用usb cdc
方式,这块卡在windows 下采用的通用驱动程序 windows 自带驱动,或者是安装ST公司的驱动(实质依然采用的是windows
自带驱动),上下位机通讯,通讯方面不能说运行十分稳定,也能说真他妈的稳定,最长记录是5年连续运行。
但是好就好在Windows以后不能在工业方面用了,所以不得不在Linux 重新写通讯程序,不干不知道还是Windows好,在Linux
上USB CDC应用有一些问题,在Linux文档中已经支持了虚拟串口通用驱动程序,就是可以把USB CDC 设备模拟成一个串口
/dev/ttyACM0 ,本来应该很完美,但好就好在好像对BULK
传输有点问题,貌似读取没问题,但是写入就运行稳定了(有时可以,有时不行,同样的程序,开关一次机,可能结果不一样),开源的东西就是不可靠,郁闷了,终于陷入了Linux
中所谓不兼容需要重新适配的问题了,我完全没有精力在看看Linux CDC ACM
驱动源码,关键是有可能看不懂,另外也不会编译内核(因为我是一个搞水电工程的),问题无解了。
但是我们水电工程方面国产化是必须的,所以只有一个办法,就是不用 CDC ACM
驱动,或者把它绕过去,直接操作USB,能够选择的方法是使用libusb 安装方法请自行百度,里面有一万篇,关于如何安装的文档,ubuntu
就十分简单了,直接APT吧libusb 1.0.0,版本好像有点低,不过好就好在它跟libusb
官网中版本一样低,直接写程序操作就好,我习惯于使用FPC ,所以使用Typhon64 写了一个简单的封装,目前libusb1.0.0
不支持windows 虽然有接口但是没有实现,只实现了一点点功能,因为在win 下压根不需要libusb ,可以使用winlibusb
或者普通的串口驱动就好,linux 生态差一点吧,我把写的一些关键代码贴出,跟大家共享。 一切开始的前提是权限问题,要使用libusb
需要进行权限设置的操作,因为USB设备用户都是root,其他用户只有读取的权利,所以使用当打开的时候会出错,网上也分享了一些如何进行权限设置的问题,我觉得最直接的方法是一句话,比如我的用户是tr
sudo usermod -a -G root tr 这样免去了很多问题 ,把tr这个用户加入root
组,这样还有一些其他问题,没准都能解决。

代码如下:(水平不高,高手斧正)

在这里插入代码片
unit MyUSBLib;

{$mode ObjFPC}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,
  ctUtils,
  LibUsbDyn, LibUsbOop, mytype;



type
  Tr8000UsbStruct = record
    Addr: byte;
    Bus: byte;
    Port: byte;
    PortPath: string;
    Speed: byte;
    DevDesc: libusb_device_descriptor;
    //DevDesc  : libusb_device_descriptor;
  end;

  Tr8000UsbTransfer = class
  private
    FActive: boolean;
    FContext: TLibUsbContext;
    FEnable: boolean;
    FTr8000DeviceExist: boolean;
    FTr8000Usb: Tr8000UsbStruct;
    FDevice: TLibUsbDevice;
    fDescrEPreadTransfer: TLibUsbBulkInEndpoint;//Endpoint
    fDescrEPsendTransfer: TLibUsbBulkOutEndpoint;//Endpoint;//Endpoint

    fLibUsbInterface: TLibUsbInterface;
    function reFoundTr8000Device: boolean;
    procedure clearAll;
  public
    constructor Create;
    destructor Destroy; override;
    function init: boolean;

    function Open: boolean;
    function Reopen: boolean;
    procedure Close;// :boolean;

    function ReadBuffer(var Buffer; Len: integer): integer;
    function WriteBuffer(var Buffer; Len: integer): integer;

  published
    property Tr8000DeviceExist: boolean read FTr8000DeviceExist;
    property Enable: boolean read FEnable;
    property Active: boolean read FActive;
  end;


function initusbLib: boolean;

function FoundTr8000Device(var _Tr8000Usb: Tr8000UsbStruct; Context: TLibUsbContext): boolean;

implementation

//uses mytype;

{const
  SpeedName: array[0..4] of string = (
    'Unknown',
    '1.5 Mbit/s (USB LowSpeed)',
    '12 Mbit/s (USB FullSpeed)',
    '480 Mbit/s (USB HighSpeed)',
    '5000 Mbit/s (USB SuperSpeed)');
 }
function FoundTr8000Device(var _Tr8000Usb: Tr8000UsbStruct; Context: TLibUsbContext): boolean;
var
 // Version: Plibusb_version;
  // Context  : TLibUsbContext;
  DevList: PPlibusb_device;
  DevCount: integer;
//  Addr: byte;
 // Bus: byte;
 // Port: byte;
  PortPath: TDynByteArray;
 // Speed: byte;
 // DevDesc: libusb_device_descriptor;
  I, J: integer;
var
  s: string;
begin
  // ...

  Result := False;
  // get library version
 // Version := TLibUsbContext.GetVersion;
  // create context
  //Context := TLibUsbContext.Create;
  try
    DevCount := ELibUsb.Check(Context.GetDeviceList(DevList), 'GetDeviceList');
    // InfoMemo.Append( 'Found ' +IntToStr( DevCount) +' devices:');

    // list all devices
    for I := 0 to DevCount - 1 do
    begin
      move(TLibUsbContext.GetDeviceDescriptor(DevList[I]), _Tr8000Usb.DevDesc, sizeof(libusb_device_descriptor));
      if (_Tr8000Usb.DevDesc.idProduct = Tr8000idProduct) and (_Tr8000Usb.DevDesc.idVendor = Tr8000idVendor) then
      begin
        _Tr8000Usb.Addr := TLibUsbContext.GetDeviceAddress(DevList[I]);
        _Tr8000Usb.Bus := TLibUsbContext.GetBusNumber(DevList[I]);
        _Tr8000Usb.Port := TLibUsbContext.GetPortNumber(DevList[I]);
        PortPath := Context.GetPortPath(DevList[I]);
        _Tr8000Usb.Speed := TLibUsbContext.GetDeviceSpeed(DevList[I]);
        //     move(TLibUsbContext.GetDeviceDescriptor( DevList[I]), _Tr8000Usb.DevDesc,sizeof  (libusb_device_descriptor)) ;
        //  _Tr8000Usb.DevDesc  := TLibUsbContext.GetDeviceDescriptor( DevList[I]);

        _Tr8000Usb.PortPath := '';
        if Length(PortPath) > 0 then
        begin
          s := ' port path from HCD: ' + #9 + IntToStr(PortPath[0]) + ' ';
          for J := 1 to Length(PortPath) - 1 do s := s + IntToStr(PortPath[J]);
          //  InfoMemo.Append( s);
        end;
        _Tr8000Usb.PortPath := s;
        Result := True;
        break;
      end;
    end;
    Context.FreeDeviceList(DevList);
  finally
    // Context.Free;
  end;

  // finalize
  //  ButtonSearch.Visible:= TRUE;

end;

function initusbLib: boolean;
begin
  Result := True;
  if USBLib_Load = False then
    Result := USBLib_Load(ctGetRuntimesCPUOSDir(True) + USBLibName);

end;

function Tr8000UsbTransfer.reFoundTr8000Device: boolean;
var
  Version: Plibusb_version;
  // Context  : TLibUsbContext;
  DevList: PPlibusb_device;
  DevCount: integer;
  Addr: byte;
  Bus: byte;
  Port: byte;
  PortPath: TDynByteArray;
  Speed: byte;
  DevDesc: libusb_device_descriptor;
  I, J: integer;
  _Tr8000Usb: Tr8000UsbStruct;
var
  s: string;
begin
  // ...

  Result := False;
  // get library version
  Version := TLibUsbContext.GetVersion;
  // create context
  if fContext <> nil then
    FreeAndNil(fContext);
  fContext := TLibUsbContext.Create;
  try
    DevCount := ELibUsb.Check(fContext.GetDeviceList(DevList), 'GetDeviceList');
    // InfoMemo.Append( 'Found ' +IntToStr( DevCount) +' devices:');

    // list all devices
    for I := 0 to DevCount - 1 do
    begin
      move(TLibUsbContext.GetDeviceDescriptor(DevList[I]), _Tr8000Usb.DevDesc, sizeof(libusb_device_descriptor));
      if (_Tr8000Usb.DevDesc.idProduct = Tr8000idProduct) and (_Tr8000Usb.DevDesc.idVendor = Tr8000idVendor) then
      begin
        _Tr8000Usb.Addr := TLibUsbContext.GetDeviceAddress(DevList[I]);
        _Tr8000Usb.Bus := TLibUsbContext.GetBusNumber(DevList[I]);
        _Tr8000Usb.Port := TLibUsbContext.GetPortNumber(DevList[I]);
        PortPath := fContext.GetPortPath(DevList[I]);
        _Tr8000Usb.Speed := TLibUsbContext.GetDeviceSpeed(DevList[I]);
        //     move(TLibUsbContext.GetDeviceDescriptor( DevList[I]), _Tr8000Usb.DevDesc,sizeof  (libusb_device_descriptor)) ;
        //  _Tr8000Usb.DevDesc  := TLibUsbContext.GetDeviceDescriptor( DevList[I]);

        _Tr8000Usb.PortPath := '';
        if Length(PortPath) > 0 then
        begin
          s := ' port path from HCD: ' + #9 + IntToStr(PortPath[0]) + ' ';
          for J := 1 to Length(PortPath) - 1 do s := s + IntToStr(PortPath[J]);
          //  InfoMemo.Append( s);
        end;
        _Tr8000Usb.PortPath := s;
        Result := True;
        break;
      end;
    end;
    fContext.FreeDeviceList(DevList);
  finally
    // Context.Free;
  end;
end;

procedure Tr8000UsbTransfer.clearAll;
begin
  if fDescrEPreadTransfer <> nil then
    FreeAndNil(fDescrEPreadTransfer);

  if fDescrEPsendTransfer <> nil then
    FreeAndNil(fDescrEPsendTransfer);

  if fLibUsbInterface <> nil then
    FreeAndNil(fLibUsbInterface);

  if FDevice <> nil then
  FreeAndNil(FDevice);
   // FDevice.Free;

end;

constructor Tr8000UsbTransfer.Create;
begin
  FTr8000DeviceExist := False;
  fLibUsbInterface := nil;//TLibUsbInterface.Create(FDevice,@fDescrIntf);
  //TLibUsbInterfaceEndpoint.Create(fLibUsbInterface,)
  fDescrEPsendTransfer := nil;//TLibUsbBulkOutEndpoint.Create (fLibUsbInterface,@fDescrEPsend);
  fDescrEPreadTransfer := nil;//TLibUsbBulkInEndpoint.Create (fLibUsbInterface,@fDescrEPread);
  FDevice := nil;
  FActive := False;
  //Freadaddr := 255;
  //FSendaddr := 255;
  FEnable := initusbLib;// then
end;

destructor Tr8000UsbTransfer.Destroy;
begin
 clearAll;
  if Assigned(FContext) then
    FreeAndNil(FContext);
  inherited Destroy;
end;

function Tr8000UsbTransfer.init: boolean;
begin
  Result := False;
  if FEnable then
  begin
    if FContext = nil then
      FContext := TLibUsbContext.Create;
    Result := FoundTr8000Device(FTr8000Usb, FContext);
    FTr8000DeviceExist := Result;
  end;

end;

function Tr8000UsbTransfer.Open: boolean;
var
  DescrDev: libusb_device_descriptor;
  NumConf: integer;
  DescrCfg: array[0..1023] of byte;
  CfgSize: word;
  CfgIdx: word;
  endtag: integer;

  EP0: TLibUsbDeviceControlEndpoint;

    fDescrConf: libusb_config_descriptor;
    // NumConf   : Byte;
    fDescrIntf: libusb_interface_descriptor;
    fDescrEP: libusb_endpoint_descriptor;
    fDescrEPread: libusb_endpoint_descriptor;
    fDescrEPsend: libusb_endpoint_descriptor;
begin
  Result := False;
  endtag := 0;
  //clearAll;
  if not FEnable then exit;
  if not FTr8000DeviceExist then exit;


  try
    FDevice := TLibUsbDevice.Create(FContext, FTr8000Usb.DevDesc.idVendor, FTr8000Usb.DevDesc.idProduct);
    EP0 := FDevice.Control;
    fDescrEPread.bEndpointAddress := 255;
    fDescrEPsend.bEndpointAddress := 255;

    if ELibUsb.Check(EP0.GetDescriptor(LIBUSB_DT_DEVICE, 0, DescrDev, LIBUSB_DT_DEVICE_SIZE), 'GetDescriptor') <> LIBUSB_DT_DEVICE_SIZE then
      raise Exception.Create('GetDescriptor: Didn''t get expected number of bytes');
    for NumConf := 0 to DescrDev.bNumConfigurations - 1 do
    begin
      CfgSize := ELibUsb.Check(EP0.GetDescriptor(LIBUSB_DT_CONFIG, 0, DescrCfg, SizeOf(DescrCfg)), 'GetDescriptor');
      CfgIdx := 0;
      while CfgIdx < CfgSize do
      begin
        if (DescrCfg[CfgIdx + 1] = LIBUSB_DT_CONFIG) and (DescrCfg[CfgIdx] = LIBUSB_DT_CONFIG_SIZE) then
          with fDescrConf do
          begin
            // copy config descriptor (inside "With" to save one level of indentation)
            Move(DescrCfg[CfgIdx], fDescrConf, DescrCfg[CfgIdx]);
            Inc(CfgIdx, fDescrConf.bLength);
          end
        else if (DescrCfg[CfgIdx + 1] = LIBUSB_DT_INTERFACE) and (DescrCfg[CfgIdx] = LIBUSB_DT_INTERFACE_SIZE) then
          with fDescrIntf do
          begin
            // copy interface descriptor (inside "With" to save one level of indentation)
            Move(DescrCfg[CfgIdx], fDescrIntf, DescrCfg[CfgIdx]);
            Inc(CfgIdx, fDescrIntf.bLength);
          end
        else if (DescrCfg[CfgIdx + 1] = LIBUSB_DT_ENDPOINT) and (DescrCfg[CfgIdx] = LIBUSB_DT_ENDPOINT_SIZE) then
          with fDescrEP do
          begin
            // copy endpoint descriptor (inside "With" to save one level of indentation)
            if endtag = 0 then
            begin
              Move(DescrCfg[CfgIdx], fDescrEP, DescrCfg[CfgIdx]);
              Inc(CfgIdx, fDescrEP.bLength);
              Inc(endtag);
            end
            else if endtag = 1 then
            begin
              Move(DescrCfg[CfgIdx], fDescrEPread, DescrCfg[CfgIdx]);
              Inc(CfgIdx, fDescrEPread.bLength);
              Inc(endtag);
            end
            else if endtag = 2 then
            begin
              Move(DescrCfg[CfgIdx], fDescrEPsend, DescrCfg[CfgIdx]);
              Inc(CfgIdx, fDescrEPsend.bLength);
              Inc(endtag);
            end;
          end
        else
          Inc(CfgIdx, DescrCfg[CfgIdx]);
      end;
    end;

    if (fDescrEPsend.bEndpointAddress <> 255) and (fDescrEPread.bEndpointAddress <> 255) then
    begin
      fLibUsbInterface := TLibUsbInterface.Create(FDevice, @fDescrIntf);
      fDescrEPsendTransfer := TLibUsbBulkOutEndpoint.Create(fLibUsbInterface, @fDescrEPread); // i do not know why but is is right
      fDescrEPreadTransfer := TLibUsbBulkInEndpoint.Create(fLibUsbInterface, @fDescrEPsend);

    //  fDescrEPsendTransfer := TLibUsbBulkOutEndpoint.Create(fLibUsbInterface, @fDescrEPsend); // i do not know why but is is right
     // fDescrEPreadTransfer := TLibUsbBulkInEndpoint.Create(fLibUsbInterface, @fDescrEPread);

      EP0.Addr := fDescrEP.bEndpointAddress;

      FActive := True;
      Result := True;
    end;
  except
    if FDevice <> nil then
      FreeAndNil(FDevice);

    FActive := False;
    exit;
  end;

end;

function Tr8000UsbTransfer.Reopen: boolean;
begin
  Result := False;
  if Enable then
  begin
    clearAll;
    FTr8000DeviceExist := reFoundTr8000Device;
    if FTr8000DeviceExist then
    begin
      fActive := Open;
      Result := True;
    end;
  end;
end;

//Result := True;




procedure Tr8000UsbTransfer.Close;
begin
  FActive := False;
  FTr8000DeviceExist := False;
  clearAll;
end;

function Tr8000UsbTransfer.ReadBuffer(var Buffer; Len: integer): integer;
begin
  Result := 0;
  if not FTr8000DeviceExist then exit;

  if not FEnable then exit;
  if not FActive then exit;
  if fDescrEPreadTransfer <> nil then
  begin
    Result := fDescrEPreadTransfer.Recv(Buffer, Len, 1000);
  end;
end;

function Tr8000UsbTransfer.WriteBuffer(var Buffer; Len: integer): integer;
//var
 // bytes: TDynByteArray;
begin
  Result := 0;
  if not FTr8000DeviceExist then exit;
  if not FEnable then exit;
  if not FActive then exit;

  if fDescrEPsendTransfer <> nil then
  begin
  //  SetLength(bytes, Len);
   // Move(Buffer, bytes[0], Len);
    Result := fDescrEPsendTransfer.Send(Buffer, len,1000);
  end;
end;

end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值