News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

VB.NET HID Application Framework to send and receive to and from PIC

Started by trastikata, Apr 11, 2021, 03:03 PM

Previous topic - Next topic

trastikata

PIC mcu with USB capabilities is only useful if we can do something with it. Therefore we need a PC host application to receive from and send information to the PIC microcontroller.

If the data transfer speed is not critical then for simple applications the HID USB protocol is proffered because of its simplicity of implementation (since WinXP, the USB HID driver is standardized in Windows.

So I am sharing one way to built HID-capable applications with VB.NET, far from being the only or the best way to do it, this is simply one possibility.

1. First download the required DLL files USB_Framework_DLL.zip and the Windows Form example USB_Framework_Solution.zip.
- The mcHID.dll needs to be in the same folder as the application's exe file

DLL.jpg

- The mcHIDinterface.dll need to be referenced in your VB.NET solution as shown here:

REF.jpg

-- 1. In the "Solution Explorer" right click on your solution and select "Properties"
-- 2. Click on "Add" and browse to "mcHIDinterface.dll" and select it to add.
-- 3. and 4. It should appear in you "References" as shown in 3 and 4

2. Make sure in your project properties, "Target CPU" is set as x86

x86.jpg

3. Design your Windows form to fit your project. This is the example Project, included in USB_Framework_Solution.zip:

VB_HID.jpg

In this example:
- The top Label is changed to "MY USB CONNECTED" and "MY USB NOT CONNECTED" when a device with the preset VID and PID is connected and disconnected from the PC respectively.
- Button "SEND" sends a simple command to the PIC MCU to turn on the LED.
- The PIC MCU switches on the LED and responds with a string saying "LED ON"
- After 1 second the PIC switches off the LED and sends a string "LED OFF"
- As idle process the PIC constantly sends the status of the button and the green/red button in the form changes color accordingly.

To set up the application correctly, make sure the VID and PID, as well as the BufferIN and BufferOUT sizes match in both, the VB.NET application and Proton.

All functions and events are commented in the VB.NET solution and how information is being handled. However how to deal with the data received and sent to the PIC MCU is entirely up to the user and there is always a rudimentary protocol required that will avoid infinity loops (i.e. waiting for data, that is never being sent) or time collisions and overflows. 

Again, there are probably many and better ways to achieve the same result, this is just a basic to start and build on.



John Lawton

Trastikata, I've been using your excellent mcHID information as a start and have been able to create a nice App for configuring my Joystick interface board design.

I followed your example code but I now want to utilise some of the other functionality available with mcHIDusb, e.g.

mcHIDusb.hidGetProductID(pHandle) which I was able to use, but I can't find the API (if that's the right term) for any other commands available, (e.g. USB Serial Number?) despite searching. Can you point me in the right direction please?

trastikata

Hello John,

this is the entire API as shown in the solution explorer:

' HID interface API declarations...
 Declare Function hidConnect Lib "mcHID.dll" Alias "Connect" (ByVal pHostWin As Integer) As Boolean
 Declare Function hidDisconnect Lib "mcHID.dll" Alias "Disconnect" () As Boolean
 Declare Function hidGetItem Lib "mcHID.dll" Alias "GetItem" (ByVal pIndex As Integer) As Integer
 Declare Function hidGetItemCount Lib "mcHID.dll" Alias "GetItemCount" () As Integer
 Declare Function hidRead Lib "mcHID.dll" Alias "Read" (ByVal pHandle As Integer, ByRef pData As Byte) As Boolean
 Declare Function hidWrite Lib "mcHID.dll" Alias "Write" (ByVal pHandle As Integer, ByRef pData As Byte) As Boolean
 Declare Function hidReadEx Lib "mcHID.dll" Alias "ReadEx" (ByVal pVendorID As Integer, ByVal pProductID As Integer, ByRef pData As Byte) As Boolean
 Declare Function hidWriteEx Lib "mcHID.dll" Alias "WriteEx" (ByVal pVendorID As Integer, ByVal pProductID As Integer, ByRef pData As Byte) As Boolean
 Declare Function hidGetHandle Lib "mcHID.dll" Alias "GetHandle" (ByVal pVendoID As Integer, ByVal pProductID As Integer) As Integer
 Declare Function hidGetVendorID Lib "mcHID.dll" Alias "GetVendorID" (ByVal pHandle As Integer) As Integer
 Declare Function hidGetProductID Lib "mcHID.dll" Alias "GetProductID" (ByVal pHandle As Integer) As Integer
 Declare Function hidGetVersion Lib "mcHID.dll" Alias "GetVersion" (ByVal pHandle As Integer) As Integer
 Declare Function hidGetVendorName Lib "mcHID.dll" Alias "GetVendorName" (ByVal pHandle As Integer, ByVal pText As String, ByVal pLen As Integer) As Integer
 Declare Function hidGetProductName Lib "mcHID.dll" Alias "GetProductName" (ByVal pHandle As Integer, ByVal pText As String, ByVal pLen As Integer) As Integer
 Declare Function hidGetSerialNumber Lib "mcHID.dll" Alias "GetSerialNumber" (ByVal pHandle As Integer, ByVal pText As String, ByVal pLen As Integer) As Integer
 Declare Function hidGetInputReportLength Lib "mcHID.dll" Alias "GetInputReportLength" (ByVal pHandle As Integer) As Integer
 Declare Function hidGetOutputReportLength Lib "mcHID.dll" Alias "GetOutputReportLength" (ByVal pHandle As Integer) As Integer
 Declare Sub hidSetReadNotify Lib "mcHID.dll" Alias "SetReadNotify" (ByVal pHandle As Integer, ByVal pValue As Boolean)
 Declare Function hidIsReadNotifyEnabled Lib "mcHID.dll" Alias "IsReadNotifyEnabled" (ByVal pHandle As Integer) As Boolean
 Declare Function hidIsAvailable Lib "mcHID.dll" Alias "IsAvailable" (ByVal pVendorID As Integer, ByVal pProductID As Integer) As Boolean

Example how to get the Product name by clicking a button:

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        'New string variable with preset lenght of 32
        Dim ProductName As String = "                                "
        'Get the product name
        mcHIDusb.hidGetProductName(pHandle1, ProductName, 20)
        'Post ProductName
        TextBox1.Text = ProductName
    End Sub
End Class

John Lawton

Thank you very much. It looks like I still have a lot to learn as it looks like I could have found this myself in Visual Studio if I had known how to... :)

John

Stephen Moss

If using Visual Studio an alternative may be to use one of the USB library packages, I have not tried them but if you go to the Project menu - Manage NuGet Package and enter USB in the search textbox there appears to be several options available.
The downside is they may produce a lot of files you need to distribute with your application (WebView2 does), but the upside may be that it is possible to use the same library to communicate with both HID and non HID devices so you won't have to use different methods for different device types.

John Lawton

Hi Stephen,

thanks for that info, but I'll stick with what's working for now...

John

DaveC

Hi Trastikata, any chance you could share your positron code.

trying to get my head round this USB stuff.

John Lawton

He has, it's in this post: https://protoncompiler.com/index.php?msg=1659

John

[edit] Sorry, I misread your post - you wanted the Positron code.

trastikata

Hello all,

This the Positron side of the USB HID framework to start you going. Open "USB_Device.bas" to start with, rest of the files have to be in the same folder. This file should start you going.

Device = 18F14K50
'Make sure your clock and fuse settings return 48Mhz system clock
Declare Xtal = 48
Include "USB_Device.inc"
'//Change VID and PID in USB_Device.Inc
'VID = 6017
'PID = 2010
'//Change Manufacturer String in USB_Device.Inc
'Manufacturer = "POSITRON USB HID"
'//Change Product String in USB_Device.Inc
'Product = "USB FRAMEWORK"
'The InBound and OutBound HID buffers are 64 bytes each

Main:
    Clear
    'Full-Speed Enable bit - requires input clock at 48 MHz
    UCFG.2 = 1
   
    'Attach UsbDevice to UsbHost
    While 1 = 1
        mUSBService()
        If tUSB_Attached = True Then Break
        DelayUS 10
    Wend   
   
    'Main Program Loop
    While 1 = 1
        'You need to fire this routine every 1 mS or so to keep the USB HID
        'connection alive, could be often than that but not much longer
        mUSBService()
        GoSub ReceiveData
        If pDataReceived = 1 Then                   'We received some data
            pDataReceived = 0                       'Clear new data arrived flag
            If bTemp1 = 10 Then                     'We got our USB data and will do something with it if needed
                GoSub DoSomething     
            ElseIf bTemp2 = 100 Then                'We got our USB data and maybe will do something else with it if needed
                GoSub DoSomethingElse                         
            EndIf
        EndIf
    Wend
   
   
ReceiveData:
    If tUSB_Attached = True Then
        If HID_DataAvailable() = True Then
            HID_ReadReport()
            'Data is received in an array called RXReport[] which is a 64 Byte array
            'Do something with my received data, for example get first byte and do something
            bTemp1 = RXReport[0]
            bTemp2 = RXReport[1]
            Clear RXReport
            pDataReceived = 1
        EndIf
    EndIf
Return

SendData:
    HID_WriteReport()
    Clear TXReport
Return   
                       
DoSomething:
    'Let's our "do something" be a respond to the Usb Host that we got our InBound data
    'Literally we send a string with a response, and then send other data as well
    TXReport = "I got your data, now get mine"
    'Send my OutBound data
    GoSub SendData
    'Now send some bytes too
    TXReport[0] = 143
    TXReport[1] = 56
    TXReport[2] = 32
    TXReport[3] = 195
    TXReport[4] = 244
    'Send my OutBound data
    GoSub SendData
Return

DoSomethingElse:
    'Read some sensor data for example and send it back
    'let bTemp3 be my sensor data from temperature
    'Send it as a string
     TXReport = "Temperature = " + Str$(Dec bTemp3) + " Degrees"
     GoSub SendData
    'Now maybe we want to send data as bytes instead of strings
     TXReport[0] = bTemp3
     GoSub SendData     
Return
                     
Config_Start
        CPUDIV = NOCLKDIV ;No CPU System Clock divide
        USBDIV = OFF ;USB clock comes directly from the OSC1/OSC2 oscillator block; no divide
        FOSC = HS ;HS oscillator
        PLLEN = On ;Oscillator multiplied by 4
        PCLKEN = On ;Primary clock enabled
        FCMEN = OFF ;Fail-Safe Clock Monitor disabled
        IESO = OFF ;Oscillator Switchover mode disabled
        PWRTEN = OFF ;PWRT disabled
        BOREN = On ;Brown-out Reset enabled and controlled by software (SBOREN is enabled)
        BORV = 19 ;VBOR set to 1.9 V nominal
        WDTEN = OFF ;WDT is controlled by SWDTEN bit of the WDTCON register
        WDTPS = 32768 ;1:32768
        HFOFST = OFF ;The system clock is held off until the HFINTOSC is stable.
        MCLRE = OFF ;RA3 input pin enabled; MCLR disabled
        STVREN = On ;Stack full/underflow will cause Reset
        LVP = OFF ;Single-Supply ICSP disabled
        BBSIZ = On ;2kW boot block size
        XINST = OFF ;Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
        Debug = OFF ;Background debugger disabled, RA0 and RA1 configured as general purpose I/O pins
        Cp0 = OFF ;Block 0 not code-protected
        CP1 = OFF ;Block 1 not code-protected
        CPB = OFF ;Boot block not code-protected
        CPD = OFF ;Data EEPROM not code-protected
        WRT0 = OFF ;Block 0 not write-protected
        WRT1 = OFF ;Block 1 not write-protected
        WRTC = On ;Configuration registers write-protected
        WRTB = On ;Boot block write-protected
        WRTD = OFF ;Data EEPROM not write-protected
        EBTR0 = OFF ;Block 0 not protected from table reads executed in other blocks
        EBTR1 = OFF ;Block 1 not protected from table reads executed in other blocks
        EBTRB = OFF ;Boot block not protected from table reads executed in other blocks
Config_End

Dim bTemp1 As Byte              'Temp Byte Variable
Dim bTemp2 As Byte              'Temp Byte Variable
Dim bTemp3 As Byte              'Temp Byte Variable
Dim pDataReceived As Bit        'Flag if new data arrived 

USB_HID.jpg