nikryd
Posts: 8
Joined: Wed May 05, 2021 9:03 pm

PICO HID examples C/C++

Wed May 05, 2021 9:30 pm

Hi I trying to learn c/c++ and my project is to make a Shortcut USB Keyboard from a pico.
I have made it in CircuitPython and that was no problem as there is a lot of examples to find and there where a easy and well documented lib to use. But in c/c++ I have not found anything. There are some examples in the SDK but I can't figuring out how to use them and they are to complex and without any usable explanation. Where should I look for examples or if there are any libs that will help me, I really like to do it in c/c++?

tannewt
Posts: 59
Joined: Tue Nov 17, 2020 1:14 am

Re: PICO HID examples C/C++

Fri May 07, 2021 5:12 pm

The SDK uses TinyUSB so I'd suggest looking at the TinyUSB examples: https://github.com/hathach/tinyusb/tree ... les/device

dshadoff
Posts: 45
Joined: Wed Apr 28, 2021 3:12 am

Re: PICO HID examples C/C++

Fri May 07, 2021 7:45 pm

The example for keyboard here is OK:
Within, "pico-examples/usb/host/host_hid/"

However, there seems to be a problem with tinyusb at the moment, when using certain devices - such as Logitech unifying receiver.
A simple, wired keyboard (or mouse) seems to work OK.

Tinyusb looks like it will be updated substantially in the next release of pico-sdk (1.2.0), which - according to the GitHub logs - appears as though it should be available in the next 1-2 weeks.

dshadoff
Posts: 45
Joined: Wed Apr 28, 2021 3:12 am

Re: PICO HID examples C/C++

Fri May 07, 2021 7:50 pm

Oh, sorry - my example (and indeed, the issue with tinyusb) is with regard to using the Pico to host a USB device.

If you are instead using it to *be* a keyboard from a computer's point of view, the examples would be different, and will follow the tinyusb examples as part of the same pico-sdk update.

nikryd
Posts: 8
Joined: Wed May 05, 2021 9:03 pm

Re: PICO HID examples C/C++

Fri May 07, 2021 9:23 pm

Thanks tannewt and dshadoff for your fast response

What I really want is a easy library like https://learn.adafruit.com/circuitpyth ... -and-mouse but i know it's to much to hope for.
The only examples I find is how to poll data from existing key board/mouse or other things that for me at my level is to complicated and I don't understand it.
I can't find any examples on how to send a keyboard command to windows/Linux from the sdk or TinyUSB examples. If you know what example to use please link it and I will try to understand how to use it, but now I can't see which example to look at.
None of the tinyusb examles in the pico-sdk seems to do what I want.
dshadoff do you think that the update will provide me with examples that I need.

dshadoff
Posts: 45
Joined: Wed Apr 28, 2021 3:12 am

Re: PICO HID examples C/C++

Fri May 07, 2021 9:54 pm

I think the answer is yea and no.

Yes, the update will give better answers than it does now; the current solution is here:
https://github.com/raspberrypi/pico-exa ... _composite

compare with the 'upstream' tinyusb example here:
https://github.com/hathach/tinyusb/tree ... _composite
(The upstream version has some more information in its example.).

But also no, the 'C' implementation is built for size and speed, and thus you need to know some implementation details which are hidden from you by micropython. So it's certainly less easy to use, but that's basically because USB is not as simple as we would all like it to be.

kilograham
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 626
Joined: Fri Apr 12, 2019 11:00 am
Location: austin tx

Re: PICO HID examples C/C++

Fri May 07, 2021 11:55 pm

the next pico-sdk/pico-examples release will also build all the upstream examples rather than having a subset o stale ones copied.

nikryd
Posts: 8
Joined: Wed May 05, 2021 9:03 pm

Re: PICO HID examples C/C++

Sat May 08, 2021 6:28 am

nice to hear kilograham.
dshadoff I start looking at those examples to see if I can figure out how to use them.
I will look forward to the next pico-sdk version.

dairequinlan
Posts: 30
Joined: Tue Feb 23, 2021 3:18 pm

Re: PICO HID examples C/C++

Sun May 09, 2021 10:51 am

I have a complete keyboard firmware implementation here if it's of interest
https://github.com/dairequinlan/mechware/tree/pico

The USB setup is probably the most complicated bit, but only because I enabled the HID endpoint as well as the USB Serial endpoint, which required some mixing of different examples, i.e. the desc_configuration in usb_descriptors.c. If you're JUST interested in the HID case then the USB/device/composite example in the pico examples has everything you need in terms of setup.

Once you have it all setup, the https://github.com/dairequinlan/mechwar ... andler.cpp is how I handle the actual keypresses. I'm probably doing something wrong there, but it essentially maintains the state of the 6 keys sent in the HID report, along with the modifiers, and adds/removes as appropriate, sending the report if able, and shelving the report for a subsequent timed update if tud_hid_ready is false.

Very minimalistic implementation at the moment, there are other callbacks in that HID example that I haven't implemented for example. Should be enough to get you up and running though.

nikryd
Posts: 8
Joined: Wed May 05, 2021 9:03 pm

Re: PICO HID examples C/C++

Sun May 09, 2021 7:57 pm

Hi
I have successfully reported a key :D but I can't find any way to release the key so now it print aaa... infinitive until I disconnect the board. The composite example do the same thing (aaa... infinitive). I have used the composite example and look at dairequinlan examples and tried to modified my code but nothing helps.

Code: Select all

  void callback(button btn){   //This will be called one time every time a key is pressed (catch and release)
    for (size_t i = 0; i <= 4; i++)
    {
        buttons[i].led_off();
    }
    btn.led_on();
    const uint32_t interval_ms = 10;
    static uint32_t start_ms = 0;

    if (board_millis() - start_ms < interval_ms) return; // not enough time
    start_ms += interval_ms;

     if (tud_suspended()) {
        // Wake up host if we are in suspend mode
        // and REMOTE_WAKEUP feature is enabled by host
        tud_remote_wakeup();
    }
    uint8_t keycode[6] = {0};
    if (tud_hid_ready()) {
         keycode[0] = HID_KEY_A;
        tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode);   
    }
    //sleep_ms(20);   
    if (tud_hid_ready()) {
        keycode[0] = HID_KEY_NONE;
        tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode);
        //tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL); 
    }
    btn.led_off();

}

dairequinlan
Posts: 30
Joined: Tue Feb 23, 2021 3:18 pm

Re: PICO HID examples C/C++

Mon May 10, 2021 9:13 am

If that _is_ actually only being called once, then I'd say the culprit is that the 2nd tud_hid_keyboard_report is not being called, because tud_hid_ready is false. There's not a lot of bandwidth for this stuff, and it seems to block pretty readily, and not buffer. I haven't looked into the bowels of the TUSB HID code, but I suspect if you want to buffer it's up to you. Anyhow, what happens if you do the second call a few MS later ? I.E. catch the key up from your device and do it then.

hippy
Posts: 9945
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: PICO HID examples C/C++

Mon May 10, 2021 9:50 am

dairequinlan wrote:
Sun May 09, 2021 10:51 am
I have a complete keyboard firmware implementation here if it's of interest
https://github.com/dairequinlan/mechware/tree/pico

The USB setup is probably the most complicated bit, but only because I enabled the HID endpoint as well as the USB Serial endpoint, which required some mixing of different examples, i.e. the desc_configuration in usb_descriptors.c.
That is the hard part for those of us who don't understand TinyUSB, don't understand USB descriptors, endpoints, composite devices, etc. That's made doubly difficult for the MicroPython RP2 port which uses different file names and renaming 'usb_descriptors.c' as 'tusb_port.c' hasn't always worked for me.

However, in this case it just worked. So I now have a MicroPython build which at least presents itself as CDC, Keyboard and Mouse, even if callbacks for HID and the rest hasn't been integrated yet - So many thanks for that; it's a huge leap forward for getting HID integrated into MicroPython alongside CDC. It may even help when it comes to adding RNDIS alongside CDC to support networking over USB.

It would be great if there were some utility code which could auto-generate the various 'tusb_*.*' and 'usb_*.*' files, create callback skeletons to be filled in from what one wants. Adafruit / Tannewt have a USB descriptor generator but I haven't managed to figure that out yet -

https://github.com/adafruit/usb_descriptor

dairequinlan
Posts: 30
Joined: Tue Feb 23, 2021 3:18 pm

Re: PICO HID examples C/C++

Mon May 10, 2021 12:36 pm

hippy wrote:
Mon May 10, 2021 9:50 am
That is the hard part for those of us who don't understand TinyUSB, don't understand USB descriptors, endpoints, composite devices, etc. That's made doubly difficult for the MicroPython RP2 port which uses different file names and renaming 'usb_descriptors.c' as 'tusb_port.c' hasn't always worked for me.
Yes it was one of those 'documentation by example' trial and error jobs. Gradually you start understanding how it hangs together as you get it working. Not ideal, but I think anyone who codes for a living is used to it :-)

hippy
Posts: 9945
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: PICO HID examples C/C++

Mon May 10, 2021 3:29 pm

dairequinlan wrote:
Mon May 10, 2021 12:36 pm
Gradually you start understanding how it hangs together as you get it working.
I'll agree with that. I am slowly getting there, a hurdle at a time. I expect it will all be crystal clear once I grasp the big picture.

I can see what examples are doing, in that I can understand what they are saying per definition, it's just not so clear on how it should be and affects things under the hood, so it's a bit of a struggle figuring out how to add 'more of the same'. So I'm also walking that 'try it then tweak it' path until it falls into place.

Everyone seems to code their descriptors differently, some with named constants, enums or magic numbers, for indexes and values, so merging isn't as easy as it could be. Still, I have managed to get three CDC devices appearing alongside HID so I guess I am getting there.

hippy
Posts: 9945
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: PICO HID examples C/C++

Wed May 12, 2021 4:52 pm

dairequinlan wrote:
Mon May 10, 2021 12:36 pm
Gradually you start understanding how it hangs together as you get it working.
I seem to be getting there so a very big thank you for your example which helped me over a few hurdles, greatly assisted my understanding of USB.

I now have a generator for USB descriptors so I need do no more than "genusb CDC=3 NET HID" to get a build supporting multiple interfaces -

Code: Select all

[  269.684728] usb 1-1.4: new full-speed USB device number 13 using dwc_otg
[  269.849782] usb 1-1.4: New USB device found, idVendor=2e8a, idProduct=c113, bcdDevice= 1.00
[  269.849797] usb 1-1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  269.849806] usb 1-1.4: Product: GenUsb-NH-3C
[  269.849814] usb 1-1.4: Manufacturer: GenUsb
[  269.849821] usb 1-1.4: SerialNumber: E660081007307531
[  269.853759] cdc_acm 1-1.4:1.0: ttyACM0: USB ACM device
[  269.860297] cdc_acm 1-1.4:1.2: ttyACM1: USB ACM device
[  269.865680] cdc_acm 1-1.4:1.4: ttyACM2: USB ACM device
[  269.905872] rndis_host 1-1.4:1.6 usb0: register 'rndis_host' at usb-3f980000.usb-1.4, RNDIS device, 26:8d:5a:ca:28:49
[  269.909132] input: GenUsb GenUsb-NH-3C Keyboard as /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.8/0003:2E8A:C113.0006/input/input8
[  269.985503] input: GenUsb GenUsb-NH-3C Mouse as /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.8/0003:2E8A:C113.0006/input/input9
[  269.985818] hid-generic 0003:2E8A:C113.0006: input,hidraw2: USB HID v1.11 Keyboard [GenUsb GenUsb-NH-3C] on usb-3f980000.usb-1.4/input8

nikryd
Posts: 8
Joined: Wed May 05, 2021 9:03 pm

Re: PICO HID examples C/C++

Sun May 16, 2021 6:17 am

Thanks for all the help.
I get it finally to work as I want it. The solution for me was that I missing to call the tud_task() between the reports. I also find that use NULL to stop sending the key report did not work for me. The timing issue is very important if you use to long sleep it will print two characters and if it's to short then it won't release the key at all. There are probably better C way to do this but it works.

Code: Select all

//This will be called one time every time a key is pressed (catch and release)
void hid_callback(button btn){       
    sleep_ms(20);  
    if (tud_suspended()) {
        // Wake up host if we are in suspend mode
        // and REMOTE_WAKEUP feature is enabled by host
        tud_remote_wakeup();
    }
    uint8_t keycode[6] = {0,0,0,0,0,0};
  
    if (tud_hid_ready()) {
        // add modify keys. This link was helpful for me: 
        // http://forum.flirc.tv/index.php?/topic/2209-usb-hid-codes-keys-and-modifier-keys-for-flirc_util-record_api-x-y/
        uint8_t modifiers= 0;
        if(btn.key_ctrl){
            modifiers =modifiers + 1;
        }
        if(btn.key_shift){
              modifiers =modifiers + 2;
        }
        if(btn.key_alt) {
           modifiers =modifiers + 4;
        }
         if(btn.key_win) {
           modifiers =modifiers + 8;
        } 
        // add HID keys as for now it only support two keys.       
        keycode[0] = btn.HidArray[0];
        keycode[1] =btn.HidArray[1];    
        tud_hid_keyboard_report(REPORT_ID_KEYBOARD,modifiers, keycode);   
        sleep_ms(10);    
        tud_task();// this has to bee called before releasing the keys
        sleep_ms(5);   
        uint8_t keycode2[6] = {0,0,0,0,0,0};
        tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode2);
        // NULL did not work for me :
        //tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL); 
}

Return to “General”