Let's take a look at parts of the actual source code that HIDmaker FS has generated for our Varty16 sample project. You will notice that HIDmaker's USB Advisor tends to leave helpful notes at various places in the generated source code, to aid your understanding and to suggest places where you might want to put code for certain important operations.
This page shows what the generated code for PICBASIC PRO looks like:
Test value declarations
HIDmaker cannot know what I/O pins your device is going to use. So, to give you maximum flexibility, HIDmaker's generated code does no hardware dependent I/O other than USB. The generated code will compile and run and send data back and forth between the PC and the PIC device, but the generated code only sends test values: numeric contstants.
Toward the top of your PICBASIC PRO program, you will see place where these test value constants are declared in your project:
' Test values for Endpoint 1 IN Variables:
' =======================================
TEST_IN9BIT con 106
TEST_IN16BITARRAY_0 con 0
TEST_IN16BITARRAY_1 con 1
TEST_IN16BITARRAY_2 con 2
TEST_IN16BITARRAY_3 con 3
TEST_IN16BITARRAY_4 con 4
TEST_IN16BITARRAY_5 con 5
TEST_IN16BITARRAY_6 con 6
TEST_IN16BITARRAY_7 con 7
TEST_IN16BITARRAY_8 con 8
TEST_IN16BITARRAY_9 con 9
TEST_IN16BITARRAY_10 con 10
TEST_IN16BITARRAY_11 con 11
TEST_IN16BITARRAY_12 con 12
TEST_IN16BITARRAY_13 con 13
TEST_IN16BITARRAY_14 con 14
TEST_IN13BIT con 1476
TEST_IN8BIT con 240
TEST_IN5BIT con 10
TEST_IN8BITARRAY_0 con 0
TEST_IN8BITARRAY_1 con 1
and so on, for all the data items and array elements in your project.
Data item declararations
Since HIDmaker FS works on a Principle of Direct Transfer of Variables , for every data item that you define in HIDmaker's Visual Data Designer , you will see a variable declared in the generated source code on both sides.
Recall that this project uses a mixture of odd-sized data items:
Input Report A :
In8bit - 8 bit simple variable
In9bit - 9 bit simple variable
In16bitArray - array variable, 15 elements, each 16 bits long
In13bit - 13 bit simple variable
In5bit - 5 bit simple variable
In8bitArray - array variable, 63 elements, each 8 bits long
Output Report B :
Out8bitArray - array variable, 6 elements, each 8 bits long
Out7bit - 7 bit simple variable
Here are the actual declarations for these variables in PICBASIC PRO, as generated for this specific project by HIDmaker FS :
' ************************************************************************
' Report Variables, which you defined in HIDmaker's Visual Data Designer ,
' to be sent to/from PC via USB:
' ************************************************************************
'
' For your convenience, multi-bit data items are declared as byte or word
' size variables, even if only a few bits are needed. Single-bit data items
' are declared as bit variables. Subroutines like UnPackData and PackData
' are created by HIDmaker to pack this data into the small packets needed for
' USB transmission.
' Declare the actual storage for the Report variables
' Endpoint 1 IN variables:
' ========================
In9bit var word
In16bitArray var word[15]
In13bit var word
In8bit var byte
In5bit var byte
In8bitArray var byte[63]
' Endpoint 1 OUT variables:
' =========================
Out8bitArray var byte[6]
Out7bit var byte
Initializing USB variables
HIDmaker creates a special routine where you can initialize your USB data items if you need to. (It is especially important for you to initialize any bi-directional Feature Report variables that your project may have.)
' ************************************************************************
' InitUSBVars:
' Initializes all data items that will be transferred over USB. This is
' especially important for Feature items, that can be read and written
' by the PC.
'
' HIDmaker will automatically initialize certain variables here, if needed.
' You may add other initialization code here if you choose.
' ************************************************************************
InitUSBVars:
USB_Enum_Complete = 0
return
' ************************************************************************
' USB Init Code:
' ************************************************************************
start:
gosub InitUSBVars
I/O Pin declarations
HIDmaker FS has no way of knowing what I/O pins you plan to use in your project, which ones will be digital, which will be analog, or whether some pins will be dedicated for use by PIC modules such as the USART, PWM, or whatever.
As a convenience to you, HIDmaker's generated PICBASIC PRO code provides, in commented out form, some lines initialization codes for the PIC registers that set these choices:
start:
gosub InitUSBVars
' USB Advisor: You may wish to initialize some things here, before the
' USB initialization happens. Initialization code placed here is sure
' to run, even if the USB initialization fails (perhaps because the
' device was never connected to a USB cable).
' For example:
' The following 5 lines initialize real I/O on a Pic Proto USB board
' INTCON2.7 = 0 ' Enable PortB Pullups
' TRISB = %11111100 ' PORTB to all inputs except LED1 and LED2
' TRISA = %11111111 ' PORTA to all inputs, esp POT1 and POT2
' ADCON0 = 0
' ADCON1 = %00001101 ' Only A/D channels 0 and 1 are enabled
These lines are placed close to the beginning of the executable part of the PICBASIC PRO program, as shown above. Simply uncomment these lines and modify them according to the needs of your project.
Sending and Using Data with HIDmaker's USB Variables
Remember that HIDmaker's USB variables are transfer variables, each one being sort of like a shipping create with a label on it, showing the variable's name.
This is just like the situation when you receive a package containing the copy of HIDmaker FS that you ordered. You can't DO much with it until you actually take it out of the package and use it: install it on your PC and run it.
That's the way it is with HIDmaker's USB variables. A HID class Report (an Input Report, an Output Report, or a Feature Report) is like a truckload of packages that you send or receive. Each HIDmaker variable is like one of the packages. If a truckload of packages arrives, you want to open each package and use whatever was inside.
If an Output Report arrives, you want to make use of whatever data was contained in each of the USB variables in that Output Report. HIDmaker FS makes that really simple.
Suppose one of the data items in an Output Report (of a different HIDmaker project) is a 1-bit variable that is supposed to turn on an LED on your board. We'll call that data item LED1 in HIDmaker's Visual Data Item. For our project, we expect that when the PC sets LED1 = 1 and sends it to our peripheral, the peripheral is supposed to turn the LED on. Sending LED1 = 0 should turn off the LED on our board.
If the LED on your board is connected to pin RB0 or PORTB.0, all you need to do to turn the LED on or off is to assign the value in transfer variable LED1 to the I/O pin, like this:
PORTB.0 = LED1
That copies the 1 or 0 value from the LED1 transfer variable to the digital pin connected to the LED on your board, turning it on or off.
Over time, if you haven't looked at your project software for a few months, you may find it hard to remember just what PORTB.0 is connected to. As a suggestion to make your code easier to read and maintain, HIDmaker FS creates a commented section for defining variables that you may want to use help:
' ************************************************************************
' Declare other variables you will need HERE:
' ************************************************************************
' USB Advisor: This would be a good place to define app-specific variables
' for your particular device. For example:
' Defines for "Real I/O" on a Pic Proto USB board
'realLED1 var PORTB.0
'realLED2 var PORTB.1
'realButton1 var PORTB.4
'realButton2 var PORTB.5
The variable realLED1 is the same as PORTB.0, but a lot more helpful in telling us what it actually DOES. Then, our assignment statement that turns the LED on or off becomes
realLED1 = LED1
which is a little easier to read and understand.
This comment block shown above is just placed in the generated code as a suggestion for your optional use. Just add some similar lines if you want to make your code more readable and maintainable.
Main loop
The Developers Guide to USB HID Peripherals, in the HIDmaker FS Users Guide, shows that HIDmaker's peripheral side code can be set up to operate in several different Operating Models. The code that is generated by HIDmaker FS uses Peripheral Model, which assumes that the device is powered by, and always connected to, the USB cable. (Other operating models are explained in the Developers Guide, such as the Data Logger Operating Model, for devices that are self powered and only connected to the USB occasionally. The Developers Guide to USB HID Peripherals shows you how to convert HIDmaker's generated peripheral code to these other operating models.)
The main loop of HIDmaker's generated PICBASIC PRO code is where the USB I/O occurs.
' ************************************************************************
' Main loop:
' This code is structured so that it looks for data to receive, or send,
' without getting stuck on any one of the endpoints until a report
' from or to the PC has been started.
' ************************************************************************
MainLoop:
USBService ; Must service USB regularly
' This is a NORMAL or "simple" device. It has a single
' USB Configuration, which contains a single USB Interface .
' Look for USB data coming to PIC
' If a Report is coming to us via Endpoint 1 Out, get it all...
'
HandleEp1Rcv = FALSE
Where you handle Output Variables
For a device that only has a single USB Interface , the top half of the main loop contains code that:
- receives an Output Report from the PC whenever one is sent,
- unpacks it to the individual HIDmaker USB transfer variables you have defined for your project,
- and provides a well marked area for you to handle the data that has just arrived.
Here is how that well-marked area looks in PICBASIC PRO for our Varty16 project:
DoHandleEp1Rcv:
HandleEp1Rcv = TRUE ' Indicate that we have data to handle
' --------------- ADD USER "EP1 RCV" CODE HERE: ------------------
' Add code here to handle the newly-received data from Endpoint 1 Out
' C1 I0
' USB Advisor: Here is where you add code to make use of the data that
' has arrived from the PC.
' For example:
' The following 2 lines provide real I/O for a PicProto USB board
' realLED1 = LED1 ' Light the LEDs
' realLED2 = LED2
' --------------- END USER "EP1 RCV" CODE: ------------------
HandleEp1Rcv = FALSE ' Indicate that received EP1 data has been handled now
This is where you add your own code to USE all the variables that have just been sent to your peripheral device in the Output Report.
Example: How to light an LED
Our Varty16 project doesn't have a variable called LED1, but if it did, this is where we would place a line of code to use it to light up an LED on our board. If we also had defined a local variable realLED1 that sets which I/O pin is actually connected to our hardware LED, as discussed above, we could just use the same code as shown in the comment, like so:
' --------------- ADD USER "EP1 RCV" CODE HERE: ------------------
' Add code here to handle the newly-received data from Endpoint 1 Out
' C1 I0
' USB Advisor: Here is where you add code to make use of the data that
' has arrived from the PC.
' For example:
' The following 2 lines provide real I/O for a PicProto USB board
' realLED1 = LED1 ' Light the LEDs
' realLED2 = LED2
realLED1 = LED1 ' Light the LED on our board
' --------------- END USER "EP1 RCV" CODE: ------------------
It's that simple in HIDmaker FS !
Where you prepare Input Variables
In a HIDmaker FS project that has a single USB Interface , the bottom half of the main loop contains code that
- prepares data,
- and then packs it together and sends it to the PC in an Input Report.
"Preparing data" is done by you: it is where you would add your own code to read buttons on your board, or read A/D channels, read sensors, or do whatever you need to do to get a fresh set of data to send to the PC. There is a clearly marked section in the generated main look, where you should add this code:
' --------------- ADD USER "EP1 XMT" CODE HERE: ------------------
' C1 I0
' Add code here to generate data to transmit to PC via Endpoint 1 In
' This code should:
' set flag EP1XmtDataReady = TRUE if there is new data to send out, or
' set flag EP1XmtDataReady = FALSE if data has NOT changed
' USB Advisor: This is where you add code to generate data that gets
' send to the PC over the USB. Use the variables you defined in HIDmaker's
' Visual Data Designer . Variables having the correct names and convenient
' sizes (e.g. word, byte, bit) have been allocated for your use.
' Here is an example:
'
' The following lines provide real I/O for a PicProto USB board
' ADCIN 0, POT1 ' Read the pots
' ADCIN 1, POT2
' Button1 = ~ realButton1 ' Read the buttons (pullup R, so invert)
' Button2 = ~ realButton2
' Test values for EP1 In (In to PC host):
In9bit = TEST_IN9BIT
In16bitArray[0] = TEST_IN16BITARRAY_0
In16bitArray[1] = TEST_IN16BITARRAY_1
In16bitArray[2] = TEST_IN16BITARRAY_2
In16bitArray[3] = TEST_IN16BITARRAY_3
In16bitArray[4] = TEST_IN16BITARRAY_4
In16bitArray[5] = TEST_IN16BITARRAY_5
In16bitArray[6] = TEST_IN16BITARRAY_6
In16bitArray[7] = TEST_IN16BITARRAY_7
In16bitArray[8] = TEST_IN16BITARRAY_8
In16bitArray[9] = TEST_IN16BITARRAY_9
In16bitArray[10] = TEST_IN16BITARRAY_10
In16bitArray[11] = TEST_IN16BITARRAY_11
In16bitArray[12] = TEST_IN16BITARRAY_12
In16bitArray[13] = TEST_IN16BITARRAY_13
In16bitArray[14] = TEST_IN16BITARRAY_14
In13bit = TEST_IN13BIT
In8bit = TEST_IN8BIT
In5bit = TEST_IN5BIT
In8bitArray[0] = TEST_IN8BITARRAY_0
In8bitArray[1] = TEST_IN8BITARRAY_1
In8bitArray[2] = TEST_IN8BITARRAY_2
In8bitArray[3] = TEST_IN8BITARRAY_3
' etc . . .
In8bitArray[59] = TEST_IN8BITARRAY_59
In8bitArray[60] = TEST_IN8BITARRAY_60
In8bitArray[61] = TEST_IN8BITARRAY_61
In8bitArray[62] = TEST_IN8BITARRAY_62
EP1XmtDataReady = TRUE
' --------------- END USER "EP1 XMT" CODE ------------------
Since HIDmaker FS cannot know what real I/O resources your project will use, the generated code only sends those test values we saw defined above.
You should replace these test value assignments with your own "real I/O" code, that reads data from the sensors used by your own hardware.
Example: How to read a pot and a button
If your USB project contained a pot and a button that you wanted to read and send to the PC, you could use the sort of code that is shown in the comment block:
' --------------- ADD USER "EP1 XMT" CODE HERE: ------------------
' C1 I0
' Add code here to generate data to transmit to PC via Endpoint 1 In
' This code should:
' set flag EP1XmtDataReady = TRUE if there is new data to send out, or
' set flag EP1XmtDataReady = FALSE if data has NOT changed
' USB Advisor: This is where you add code to generate data that gets
' send to the PC over the USB. Use the variables you defined in HIDmaker's
' Visual Data Designer . Variables having the correct names and convenient
' sizes (e.g. word, byte, bit) have been allocated for your use.
' Here is an example:
'
' The following lines provide real I/O for a PicProto USB board
' ADCIN 0, POT1 ' Read the pots
' ADCIN 1, POT2
' Button1 = ~ realButton1 ' Read the buttons (pullup R, so invert)
' Button2 = ~ realButton2
ADCIN 0, POT1 ' Read the pot on YOUR board
Button1 = ~ realButton1 ' Read the buttons on YOUR board (pullup R, so invert)
EP1XmtDataReady = TRUE
' --------------- END USER "EP1 XMT" CODE ------------------
Feature Reports
USB Human Interface Device (or USB HID ) class defines 3 different types of data report:
- Output Reports only send data items OUT from the PC, toward your device.
- Input Reports only send data items IN to the PC, from your device
- Feature Reports can send the data items in either direction
In HIDmaker FS , you set the direction of each data item (Input, Output, or Feature) when you define the data item in the HIDmaker's Visual Data Designer .
Then the collection of all Output data items becomes the Output Report, and so on for Input and Feature Reports.
HIDmaker's data items are identified to the PC in the Report Descriptor, so a data item's direction cannot be changed on the fly.
You almost never see support for bidirectional Feature Reports in those demo programs you find on the web, or from semiconductor manufacturers or compiler makers.
HIDmaker FS supports Feature Reports fully, and can pack and unpack Feature Reports that have any mixture of odd sized data items, and which can span multiple packets.
When your HIDmaker FS project uses Feature Reports (which our Varty16 example project does not), it generates some special functions to handle them. These functions contain specially marked sections, similar to the ones shown above for Output Reports and Input Reports, where you handle Feature Report data sent from the PC, and where you send data to the PC.
Feature Reports are often used for parameter settings like a volume control, that you want to occasionally check and maybe send a new value from the PC.