HIDKeyboard
This simple program demonstrates the use of a USB equipped PIC, such as the 18F4550, as a HID Keyboard device.
The program was designed using the PICDEM FS USB board, and using the FSUSB Bootloader program.
Once running it will enumerate with a connected PC as a "HID Keyboard Device". After a few seconds it will open a Wordpad window and begin typing by itself. If you press the CapsLock key on your keyboard you should notice it also change to reflect the current status on LED D4.
The program works by sending a HID packet with the required keypresses. The keypress code table can be found in the "KeyboardDefs.bas" file. Six individual keypresses can be sent simultaneously by using the KeyArray 0 - 5 bytes. The key will keep repeating unless either a blank packet is sent (indicating the key has been lifted), or another keypress combination is sent.
The shift, alt, ctrl and GUI(windows) keys are special modifier keys and are not sent in the same way (and do not count for the 6 keypresses). These are sent in the leading Modifier byte, coded as individual bits within the byte. As such multiple modifier bytes can be sent by ORing the bits together eg.
LeftShift = %00000010, LeftAlt = %00000100,
Setting the Modifier byte to %00000110 would send both a left shift and a left alt keypress.
The hid_rpt01 descriptor array is taken from the microchip hid keyboard demo program.
Demo Program
{ ***************************************************************************** * Name : USB Keyboard demo.bas * * Author : Nathan Herbert * * Notice : Copyright (c) 2008 * * : All Rights Reserved * * Date : 03/02/2009 * * Version : 1.1 * * Notes : 1.0 First Revision * * : 1.1 Updated to read back LED status * * : 1.2 Now opens own wordpad window to show possibile uses * ***************************************************************************** } { Up to 6 individual simultaneous keys can be pressed by using Keyarray 1 through 5 Alts, shift, ctrls etc are handled though modifer bytes. These can be combined by ORing the required bytes together. } Device = 18F4550 Clock = 48 // 20Mhz crystal, 48Mhz internal (FS USB) Config PLLDIV = 5, CPUDIV = OSC1_PLL2, USBDIV = 2, FOSC = HSPLL_HS, VREGEN = ON #option HID_BUFFER_SIZE = 8 #option USB_DESCRIPTOR = "HIDKeyboardDesc.bas" // Use with FSUSB Bootloader #option org_reset = $0800 Include "usbhid.bas" Include "keyboarddefs.bas" // Keyboard HID buffer Structure TKeyReport Modifier As Byte // Modifer Byte Reserved As Byte // Reserved KeyArray0 As Byte // Buttons Pushed KeyArray1 As Byte KeyArray2 As Byte KeyArray3 As Byte KeyArray4 As Byte KeyArray5 As Byte End Structure Dim KeyReport As TKeyReport Absolute TXReportRAM // Status LED structure Structure TLedsReport _byte As Byte NumLock As _byte.0 CapsLock As _byte.1 ScrollLock As _byte.2 Compose As _byte.3 Kana As _byte.4 Const1 As _byte.5 Const2 As _byte.6 Const3 As _byte.7 End Structure Dim LedsReport As TLedsReport Absolute RXReportRAM Dim LED0 As PORTD.0, LED1 As PORTD.1, LED3 As PORTD.3 { ******************************************************************************** * Name : SendKey * * Purpose : Sends Key Report * ******************************************************************************** } Sub SendKey(pKey As Byte, pModifier As Byte = $00) // Send desired key KeyReport.Modifier = pModifier KeyReport.Reserved = 0 KeyReport.KeyArray0 = pKey KeyReport.KeyArray1 = 0 KeyReport.KeyArray2 = 0 KeyReport.KeyArray3 = 0 KeyReport.KeyArray4 = 0 KeyReport.KeyArray5 = 0 WriteReport // Send Key Release KeyReport.Modifier = 0 KeyReport.Reserved = 0 KeyReport.KeyArray0 = 0 KeyReport.KeyArray1 = 0 KeyReport.KeyArray2 = 0 KeyReport.KeyArray3 = 0 KeyReport.KeyArray4 = 0 KeyReport.KeyArray5 = 0 WriteReport End Sub { ******************************************************************************** * Name : Main * * Purpose : Main Routine * ******************************************************************************** } Sub Main() Dim Key As Byte Dim UpperCase As Boolean Dim pModifier As Byte // Open a Wordpad Window by sending GUI + R to open the run dialog SendKey(r, LeftGUI) // Wait a little DelayMS(100) // Write Wordpad.exe SendKey(w, LeftShift) SendKey(o) SendKey(r) SendKey(d) SendKey(p) SendKey(a) SendKey(d) SendKey(period) SendKey(e) SendKey(x) SendKey(e) SendKey(enter) // Wait a little to load DelayMS(1000) // Write Welcome Message SendKey(b, LeftCtrl) SendKey(s, LeftShift) SendKey(w) SendKey(o) SendKey(r) SendKey(d) SendKey(f) SendKey(i) SendKey(s) SendKey(h) SendKey(b, LeftCtrl) SendKey(spacebar) SendKey(u, LeftShift) SendKey(s, LeftShift) SendKey(b, LeftShift) SendKey(spacebar) SendKey(d) SendKey(e) SendKey(m) SendKey(o) SendKey(enter) SendKey(enter) SendKey(enter) Uppercase = true // Let the Keyboard type away! While true // Modifer byte controls Shift, Alts, Ctrls If Uppercase = true Then pModifier = None Uppercase = false Else pModifier = LeftShift Uppercase = true EndIf // Cycle throught A-Z, 1-0 For key = 4 To 40 // Activity LED Toggle(LED1) // Send the Key SendKey(key, pmodifier) DelayMS(500) // Read LED status If HID.DataAvailable Then // Bring Report into structure ReadReport // Set LED 3 to show caps lock status LED3 = LedsReport.CapsLock EndIf Next Wend End Sub { ******************************************************************************** * Name : Program Start * * Purpose : * ******************************************************************************** } Low(LED0) Low(LED1) Low(LED3) // Wait for USB attach Repeat Until HID.Attached // Attached High(LED0) // Let PC finish enumerating DelayMS(5000) Main
HID Descriptors
{ ***************************************************************************** * Name : HIDKeyboardDesc.bas * * Author : David John Barker * * Notice : Copyright (c) 2007 Mecanique * * : All Rights Reserved * * Date : 10/01/2007 * * Version : 1.0 * * Notes : EasyHID USB HID descriptor module * ***************************************************************************** } Module HIDDescriptor // EasyHID options... #option USB_HAVE_SERIAL_STRING = false #option USB_VID = 6017 #option USB_PID = 2000 #option HID_EP_OUT_POLLING_MS = $0A #option HID_EP_IN_POLLING_MS = $0A #option USB_BUS_POWER = $FA #option HID_REPORT_BYTES_IN = $08 #option HID_REPORT_BYTES_OUT = $08 #option USB_SERVICE = true // import modules... Include "usbconfig.bas" Include "usbdefs.bas" // Device Descriptor Public Const device_dsc(18) As Byte = ( SizeOf(USB_DEV_DSC), // bLength - size of this descriptor IN bytes DSC_DEV, // bDescriptorType - device descriptor type $00, // bcdUSB (low byte) - USB Spec Release Number IN BCD format (2.0) $02, // bcdUSB (high byte) - USB Spec Release Number IN BCD format (2.0) $00, // bDeviceClass - class Code $00, // bDeviceSubClass - subclass code $00, // bDeviceProtocol - protocol code USB_EP0_BUFF_SIZE, // bMaxPacketSize - max packet size for EP0 USB_VID And $00FF, // idVendor (low byte) USB_VID >> 8, // idVendor (high byte) USB_PID And $00FF, // idProduct (low byte) USB_PID >> 8, // idProduct (high byte) USB_DEVICE_VERSION And $00FF, // bcdDevice (low byte) - device release number IN BCD format USB_DEVICE_VERSION >> 8, // bcdDevice (high byte) - device release number IN BCD format USB_MANUFACTURER_INDEX, // iManufacturer - manufacturer string index USB_PRODUCT_INDEX, // iProduct - product string index USB_SERIAL_INDEX, // iSerialNumber - device serial number string index $01 // bNumConfigurations - mumber of possible configurations ) // Configuration 1 Descriptor Public Const cfg01(41) As Byte = ( // configuration Descriptor (cd01) SizeOf(USB_CFG_DSC), // Size of this descriptor in bytes DSC_CFG, // CONFIGURATION descriptor type 41, // sizeof(cfg01) - Total length of data for this cfg 0, // HIGH BYTE 1, // Number of interfaces in this cfg 1, // Index value of this configuration 0, // Configuration string index _DEFAULT Or _RWU, // Attributes, see usbdefs_std_dsc.h USB_BUS_POWER, // Max power consumption (2X mA) // interface descriptor (i00a00) SizeOf(USB_INTF_DSC), // Size of this descriptor in bytes DSC_INTF, // INTERFACE descriptor type 0, // Interface Number 0, // Alternate Setting Number 2, // Number of endpoints in this intf HID_INTF, // Class code BOOT_INTF_SUBCLASS, // Subclass code HID_PROTOCOL_KEYBOAD, // Protocol code // Spelling mistake in SF lib 0, // Interface string index // HID class-specific descriptor (hid_i00a00) SizeOf(USB_HID_DSC), // Size of this descriptor in bytes DSC_HID, // HID descriptor type $10, // HID Spec Release Number in BCD format (Low) $01, // HID Spec Release Number in BCD format (High) $00, // Country Code ($00 for Not supported) HID_NUM_OF_DSC, // Number of class descriptors, see usbcfg.h DSC_RPT, // Report descriptor type 63, // sizeof(hid_rpt01) - Size of the report descriptor // Now hardcoded here 0, // HIGH BYTE // endpoint descriptor (IN) (ep01i_i00a00) SizeOf(USB_EP_DSC), // Size of this descriptor in bytes DSC_EP, // Endpoint descriptor type _EP01_IN, // Endpoint 1 IN _INT, // Interrupt transfers HID_INT_IN_EP_SIZE, // Maximum packet size $00, // high byte HID_EP_IN_POLLING_MS, // Polling interval (milliseconds) // enpoint descriptor (OUT) (ep01o_i00a00) SizeOf(USB_EP_DSC), // Size of this descriptor in bytes DSC_EP, // Endpoint descriptor type _EP01_OUT, // Endpoint 1 OUT _INT, // Interrupt transfers HID_INT_OUT_EP_SIZE, // Maximum packet size $00, // high byte HID_EP_OUT_POLLING_MS // Polling interval (milliseconds) ) // language string - unicode format... Public Const sd000(4) As Byte = ( 4, // Size of this descriptor in bytes DSC_STR, // DescriptorType $09, // language ID - low byte $04 // language ID - high byte ) // manufacturer string - unicode format... Public Const sd001(20) As Byte = ( 20, DSC_STR, "S", 0, "w", 0, "o", 0, "r", 0, "d", 0, "F", 0, "i", 0, "s", 0, "h", 0 ) // product string - unicode format... Public Const sd002(26) As Byte = ( 26, DSC_STR, "K", 0, "e", 0, "y", 0, "b", 0, "o", 0, "a", 0, "r", 0, "d", 0, "D", 0, "e", 0, "m", 0, "o", 0 ) // product serial number... #if USB_HAVE_SERIAL_STRING // no serial string #endif (* This example report descriptor for a "generic HID" defines one report of each type. Each report contains two bytes of data with a vendor-defined Usage. HID_RPT01_SIZE is defined in usbcfg.h and must equal the number of bytes in the report descriptor. *) Public Const hid_rpt01(63) As Byte = ( // Hard coded size $05, $01, // USAGE_PAGE (Generic Desktop) $09, $06, // USAGE (Keyboard) $a1, $01, // COLLECTION (Application) $05, $07, // USAGE_PAGE (Keyboard) $19, $e0, // USAGE_MINIMUM (Keyboard LeftControl) $29, $e7, // USAGE_MAXIMUM (Keyboard Right GUI) $15, $00, // LOGICAL_MINIMUM (0) $25, $01, // LOGICAL_MAXIMUM (1) $75, $01, // REPORT_SIZE (1) $95, $08, // REPORT_COUNT (8) $81, $02, // INPUT (Data,Var,Abs) $95, $01, // REPORT_COUNT (1) $75, $08, // REPORT_SIZE (8) $81, $03, // INPUT (Cnst,Var,Abs) $95, $05, // REPORT_COUNT (5) $75, $01, // REPORT_SIZE (1) $05, $08, // USAGE_PAGE (LEDs) $19, $01, // USAGE_MINIMUM (Num Lock) $29, $05, // USAGE_MAXIMUM (Kana) $91, $02, // OUTPUT (Data,Var,Abs) $95, $01, // REPORT_COUNT (1) $75, $03, // REPORT_SIZE (3) $91, $03, // OUTPUT (Cnst,Var,Abs) $95, $06, // REPORT_COUNT (6) $75, $08, // REPORT_SIZE (8) $15, $00, // LOGICAL_MINIMUM (0) $25, $65, // LOGICAL_MAXIMUM (101) $05, $07, // USAGE_PAGE (Keyboard) $19, $00, // USAGE_MINIMUM (Reserved (no event indicated)) $29, $65, // USAGE_MAXIMUM (Keyboard Application) $81, $00, // INPUT (Data,Ary,Abs) $c0 )
KeyBoard definitions
{ ***************************************************************************** * Name : KeyboardDefs.BAS * * Author : Nathan Herbert * * Notice : Copyright (c) 2009 * * : All Rights Reserved * * Date : 02/02/2009 * * Version : 1.0 * * Notes : * * : * ***************************************************************************** } Module KeyDefs //*Definitions*/ Public Const a = 4, b = 5, c = 6, d = 7, e = 8, f = 9, g = 10, h = 11, i = 12, j = 13, k = 14, l = 15, m = 16, n = 17, o = 18, p = 19, q = 20, r = 21, s = 22, t = 23, u = 24, v = 25, w = 26, x = 27, y = 28, z = 29, one = 30, two = 31, three = 32, four = 33, five = 34, six = 35, seven = 36, eight = 37, nine = 38, zero = 39, enter = 40, escape = 41, backspace = 42, tab = 43, spacebar = 44, underscore = 45, equals = 46, leftbrace = 47, rightbrace = 48, backslash = 49, hash = 50, semicolon = 51, comma = 54, period = 55, slash = 56, capslock = 57, f1 = 58, f2 = 59, f3 = 60, f4 = 61, f5 = 62, f6 = 63, f7 = 64, f8 = 65, f9 = 66, f10 = 67, f11 = 68, f12 = 69, home = 74, pageup = 75, delete = 76, pagedown = 78, rightarrow = 79, leftarrow = 80, downarrow = 81, uparrow = 82, // add numpad keys for mouse keys? // Modifier bytes None = %00000000, LeftCtrl = %00000001, LeftShift = %00000010, LeftAlt = %00000100, LeftGUI = %00001000, RightCtrl = %00010000, RightShift = %00100000, RightAlt = %01000000, RightGUI = %10000000