Libusb

For issues with communication ports, protocols, etc.
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: Libusb

Post by Dinosaur »

Hi All

Here a version with usb running in it's own Thread.
Worth noting that I have had usb running in it's own thread on my Industrial machines for about a year now,
and NO problems.

Code: Select all

#include once "fbthread.bi"
#include once "libusb-1.0.bi"
#Include once "usbPort.bi"
''------Compiled with--------------------------------------------------------------------
''  FreeBASIC Compiler - Version 1.05.0 (01-31-2016), built for linux-x86_64 (64bit)
''
''  Note: Comments are double '' to avoid clash with Gede debugger.
''
''This program does the following:
''  1: Initialize Libusb  
''  2: Gets List of usb devices attached
''  3: Uses 0-7 idVendor/idProduct's to find matches in list.
''  4: Opens matches found and assign's .Handle(n)
''  5: Uses .Handle(n) to check if Kernel has control, then releases it.
''  6: Uses .Handle(n) to Claim Interface & load ascii string desc to get iSerialNumber.
''  7: Uses Control Transfer to send a request 
''  8: Now .Handle(n) is available to Write & Read Control Transfers to devices attached.
''  9: WriteOnce & ReadOnce are dedicated to Ontrak ADU70 Load Cell's
'' 10: Deallocates Buffer, and closes Interface's and Libusb
''  By setting .PrintFlag to 1 detail is printed to Terminal.(Errors are always printed)
''  Fill in your own .Vendor / .Product at lines 176-183
''  This has only been tested on Linux Mint 18.3
''---------------------------------------------------------------------------------------
Sub usbInitialize
    With usbPort
        .PrintFlag = 1
        ''----First init the Lib-----
        .Found = libusb_init(0)
        If .Found = 0 Then
                .usbFlag = 1
            Else
                If .PrintFlag > 0 Then Print "libusb_Init     = Failed"
                Exit Sub
        EndIf
        If .Found = 0 Then
            For cnt = 0 to 7
                .Handle(cnt) = 0
            Next
            cnt = 0
            ''-----Get list of all usb devices (always succeeds)----------
            cnt = libusb_get_device_list(NULL, @ppList)
            If .PrintFlag > 0 Then Print "----Reading all usb devices to assign pDevice to MyDev numbers----"
            For i = 0 to cnt-1
                pDevice = ppList[i]
                ''-----Load found device one at a time------
                .RetValue = libusb_get_device_descriptor(pDevice, @desc) 
                If .PrintFlag > 0 Then Print "Load desc.;";Hex(desc.idVendor,4);":";Hex(desc.idProduct,4);" From Device";i
                ''-----Check 8 possible matches-------------
                For MyDev = 0 to 7
                    If Hex(desc.idVendor,4) = .Vendor(MyDev) And Hex(desc.idProduct,4) = .Product(MyDev) Then
                        ''----If not been selected before, assign desc to this Hd number----
                        If .Handle(MyDev) = 0 Then
                            If .PrintFlag > 0 Then Print Hex(desc.idVendor,4);":";Hex(desc.idProduct,4)
                            If .PrintFlag > 0 Then Print "Found MyDev ";MyDev;"; Device Nbr ";pdevice
                            ''----Open device(i) with .Handle(Hd)----
                            .RetValue = libusb_open(pDevice, @pHandle)
                            '---If an error opening------
                            If .RetValue < 0 Then
                                Print "dev_handle      ;"; pHandle
                                Print "Error Detail    ;";.RetValue
                                Print *(libusb_error_name(.RetValue))
                                Return
                            EndIf
                            .Handle(MyDev) = pHandle
                            pHandle = 0
                            Exit For
                        EndIf
                    End if
                Next MyDev
            Next i
            ''------Use .Handle to release from Kernel and get Serial Number----
            If .PrintFlag > 0 Then Print "----Claiming MyDev's and getting Serial Numbers----"
            For i = 0 to 7
                If .Handle(i) > 0 Then
                    .usbFlag += 1
                    .RetValue = libusb_kernel_driver_active(.Handle(i),0)          ''check if kernel has attached a driver
                    If .RetValue > 0 Then                                          ''if so
                        .RetValue = libusb_detach_kernel_driver(.Handle(i), 0)     ''detach it
                        If .PrintFlag > 0 Then Print "Detach from Kernel"
                    Endif
                    .RetValue = libusb_claim_interface(.Handle(i), 0)               ''now we can claim the interface
                    If .RetValue = 0 Then
                            .usbFlag += 1                                           ''This allows usbThread to proceed
                            If .PrintFlag > 0 Then Print "Claimed I/F ";i
                        Else
                            Print "Claim I/F Fail   "
                            Return
                    EndIf
                    ReAllocate(Buffer,64)
                    ''------value 3 in call = index of descriptor for iSerialNumber--------
                    .RetValue = libusb_get_string_descriptor_ascii(.Handle(i),3,Buffer,64)
                    MyDev = i
                    ''---RetValue = number of char's in iSerialNumber string------
                    If .RetValue > 0 Then
                            Dim Nbr as Ushort
                            If .PrintFlag > 0 Then Print "Chr's in Serial =";.RetValue
                            .SerialNbr(MyDev) = ""
                            For Nbr = 0 to .RetValue
                                .SerialNbr(MyDev) += Chr(Buffer[Nbr])
                            Next
                        Else
                            If .PrintFlag > 0 Then Print "----string_descriptor not supported on this device----"
                    EndIf
                    If .PrintFlag > 0 Then Print .SerialNbr(MyDev)                     
                EndIf
            Next
            If cnt > 0 Then libusb_free_device_list(ppList,1)
            '' If Initialize succeeded Then set EndFlag to allow usbThread to run.
            If .usbFlag > 2 Then .EndFlag= 1
        EndIf
    End With
End Sub
Sub ReadOnce
    '---------------------------------------------------------
    'This Sub reads a Control Transfer from endpoint &h81
    'as a result of the request done in WriteOnce previously
    '---------------------------------------------------------
    With usbPort
        If .Handle(MyDev) > 0 Then
            .RetValue = libusb_interrupt_transfer(.Handle(MyDev), &H81, Buffer, 64, @.RxBytes, 500 )
            If .PrintFlag > 0 Then Print "Bytes Rx = ";.RxBytes
            If .RetValue = 0 Then
                If .RxBytes = 64 Then
                    .ValString(MyDev) = ""
                    For i as Integer = 1 to .RxBytes-1             '-1 for zero terminated string
                        If (Buffer[i] > 47) And (Buffer[i] < 58) Then 'if 0-9
                            .ValString(MyDev) += Chr(Buffer[i])
                        EndIf
                        If (i > 8) and Buffer[i] = 0 Then Exit For 'dont read trailing zeroes
                    Next
                    If .PrintFlag > 0 Then 
                            Print "Value of Read of MyDev ";MyDev;" ";Val(.ValString(MyDev))
                        Else
                            Print Val(.ValString(MyDev));";";
                    EndIf
                End If
            EndIf
            If .RetValue < 0 Then 
                Print "Read Control Transfer Failed"
            EndIf            
        EndIf
    End With
End Sub
Sub WriteOnce
    ''---------------------------------------------------------
    ''This Sub writes a Control Transfer request to endpoint 1
    ''value of 8 is bytes expected, .TxBytes = actual sent.
    ''---------------------------------------------------------
    With usbPort
        ReAllocate(Buffer,64)
        Buffer[0] = &H01
        Buffer[1] = 82      '' 'R' 
        Buffer[2] = 68      '' 'D'
        If .Handle(MyDev) > 0 Then
            .RetValue = libusb_interrupt_transfer(.Handle(MyDev), &H01, Buffer, 8, @.TxBytes, 500 )
            If .RetValue < 0 Then 
                Print "Write Control Transfer Failed"
                Print "Bytes Sent = ";.TxBytes
                Return
            EndIf
            If .PrintFlag > 0 Then Print "Bytes Tx = ";.TxBytes
        EndIf
    End With
End Sub
Sub usbQuit 
    With usbPort
        Dim i as uShort
        '----First must release i/f Then close device------------
        For i = 0 To 7
            If .Handle(i) > 0 Then 
                .RetValue = libusb_release_interface(.Handle(i), 0)
                libusb_close(.Handle(i))
                If .RetValue = 0 Then
                        If .PrintFlag > 0 Then Print "I/F ";i;" Release=; Success"
                    Else
                        Print "I/F ";i;" Release=; Failed"
                EndIf
            EndIf
        Next
        Deallocate Buffer
        Print "Buffer Closed"
        Print "libusb Closed"
        Libusb_exit(0)
        Print "libusb exited"
        .EndFlag = -1
    End With
End Sub
Sub usbthread( ByVal userdata As Any Ptr )
    Buffer = Allocate(64)
    usbInitialize                                                   '' sets usbFlag if succesfull
    Sleep 100                                                       '' let things settle before
    With usbPort
        Print "usbFlag;";.usbFlag                                   '' If > 0 Then Initialize was OK
        If .usbFlag > 2 Then
            Print "usb Thread Running"
            Print "------------------"
        EndIf
        If .usbFlag < 1 Then
            print "usb Error "
            Threaddetach(ThreadHandle)
            print "?  Handle =";ThreadHandle
            ThreadHandle = 0
            .usbFlag     = 0                                         '' Tells Main to quit
            Print "Quiting Program "
            Exit Sub
        Endif
        ''----------------------------------------------------------
        '' Here write your own code to call each device using 
        '' usbPort.Handle(MyDev)
        ''----------------------------------------------------------
        While .usbFlag                                              '' Hangs here for duration of Thread
            'MyDev = 1
            'WriteOnce
            'ReadOnce
            'MyDev = 2
            'WriteOnce
            'ReadOnce
        Wend                                                        '' Main program loop cancels .usbFlag
    End With
    usbQuit                                                         '' Go release the port.
End Sub

    ThreadHandle    = ThreadCreate(@usbThread,CPtr(Any Ptr,Null))      ''Start usb I/O in another thread.
    If ThreadHandle = 0 Then 
        Print "Failure to create Thread for usb."
        End 10                                                          ''If it Failed then Quit.
    EndIf
    ''--------------------------------------------------------
    ''Main Program Loop which is independant of usbThread Loop
    ''--------------------------------------------------------
    Do
    
    
        If Inkey <> "" Then exit do
        
        
    Loop
    usbPort.usbFlag = 0                 ''usbFlag tells usbThread to quit.
    Print "Wait for Thread to Quit"
    While usbPort.EndFlag > 0           ''EndFlag tells Main that it has quit.
        ThreadWait(ThreadHandle)        ''Don't terminate program with usbThread still running.
    Wend
    Print "Gotit"   
	Sleep
And the usbPort.bi
Notice I have shifted the Vendor detail into this .bi file.

Code: Select all

Type usbPort
    Handle(0 to 7)      As Long Ptr
    Found               As Short
    usbFlag             As Short
    EndFlag             As Short
    PrintFlag           As Short
    RxBytes             As Long 
    TxBytes             As Long 
    RetValue            As Long
    ChrByte             As String * 1
    ValString(0 to 7)   As String * 24
    SerialNbr(0 to 7)   As String * 6
    Vendor (0 to 7)     As String * 4
    Product(0 to 7)     As String * 4
End Type
Dim Shared usbPort as usbPort
''-----------------------------------------------------------------------------------
''  After confirming with lsusb (in Linux Terminal) assign .Vendor / .Product Numbers
''-----------------------------------------------------------------------------------
    With usbPort
        .Vendor(0) = "0A07":.Product(0) = "0046"  'Ontrak ADU70 24 bit A2D Load Cell interface
        .Vendor(1) = "0A07":.Product(1) = "0046"  '           ditto
        .Vendor(2) = "1605":.Product(2) = "8018"  'AccesIO USB-IDIO-16L.(32 bit I/O Board)
        .Vendor(3) = "1605":.Product(3) = "8077"  'AccesIO USB-AO16-4E. (16 bit I/O + 4 bit A/O)
        .Vendor(4) = "":.Product(4) = ""  
        .Vendor(5) = "":.Product(5) = ""  
        .Vendor(6) = "":.Product(6) = ""  
        .Vendor(7) = "":.Product(7) = ""  
    End With
'------------------------------------
Dim shared Buffer As UByte Ptr 
Dim shared as Any Ptr ThreadHandle
Dim shared as libusb_device Ptr dev
dim shared as libusb_device_descriptor desc
dim shared as libusb_device_handle ptr pHandle
dim shared as libusb_device ptr pDevice
dim shared as libusb_device ptr ptr ppList
dim shared as ssize_t cnt = 0, i = 0
dim shared as short ix = 0 , MyDev = 0

declare sub usbinitialize()
declare sub WriteOnce()
declare sub ReadOnce()
declare sub usbQuit ()
I think I am done now.

Regards
Post Reply