Updated RawHID with new, more intuitive API
This commit is contained in:
parent
626be84137
commit
c197491272
3 changed files with 98 additions and 124 deletions
|
|
@ -7,11 +7,7 @@
|
|||
Shows how to send bytes via RawHID.
|
||||
Press a button to send some example values.
|
||||
|
||||
Every received data is mirrored to the host.
|
||||
The use of the RawHIDEvent() function is shown too.
|
||||
|
||||
This sketch only tries to show the possiblities
|
||||
and is not perfect.You might want to use RawHID differently.
|
||||
Every received data is mirrored to the host via Serial.
|
||||
|
||||
See HID Project documentation for more information.
|
||||
https://github.com/NicoHood/HID/wiki/RawHID-API
|
||||
|
|
@ -22,14 +18,22 @@
|
|||
const int pinLed = LED_BUILTIN;
|
||||
const int pinButton = 2;
|
||||
|
||||
uint8_t data[255];
|
||||
volatile size_t len = 0;
|
||||
// Buffer to hold RawHID data.
|
||||
// If host tries to send more data than this,
|
||||
// it will respond with an error.
|
||||
// If the data is not read until the host sends the next data
|
||||
// it will also respond with an error and the data will be lost.
|
||||
uint8_t rawhidData[255];
|
||||
|
||||
void setup() {
|
||||
pinMode(pinLed, OUTPUT);
|
||||
pinMode(pinButton, INPUT_PULLUP);
|
||||
|
||||
// No begin/end function required for RawHID
|
||||
Serial.begin(115200);
|
||||
|
||||
// Set the RawHID OUT report array.
|
||||
// Feature reports are also (parallel) possible, see the other example for this.
|
||||
RawHID.begin(rawhidData, sizeof(rawhidData));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
|
@ -50,54 +54,18 @@ void loop() {
|
|||
}
|
||||
|
||||
|
||||
// This will miss longer RawHID data transmissions
|
||||
// and return an error to the host if data was missed.
|
||||
// Only use this for non changing/less important data.
|
||||
// Or you can use this if the event aborted on a full buffer.
|
||||
// Please note, that all data after this full buffer is missed anyways.
|
||||
// Check if there is new data from the RawHID device
|
||||
auto bytesAvailable = RawHID.available();
|
||||
while (bytesAvailable--) {
|
||||
if (len < sizeof(data)) {
|
||||
data[len++] = RawHID.read();
|
||||
}
|
||||
}
|
||||
|
||||
// Process data from the host
|
||||
if (len) {
|
||||
if (bytesAvailable)
|
||||
{
|
||||
digitalWrite(pinLed, HIGH);
|
||||
|
||||
// Disable interrupts while processing the data
|
||||
uint8_t oldSREG = SREG;
|
||||
cli();
|
||||
// Mirror data via Serial
|
||||
while (bytesAvailable--) {
|
||||
Serial.println(RawHID.read());
|
||||
}
|
||||
|
||||
// Mirror the incoming data from the host back
|
||||
RawHID.write(data, len);
|
||||
len = 0;
|
||||
|
||||
SREG = oldSREG;
|
||||
|
||||
// Simple debounce for led
|
||||
delay(300);
|
||||
digitalWrite(pinLed, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void RawHIDEvent(uint8_t num) {
|
||||
// This event is called via interrupt.
|
||||
// Do not use print inside, or other long function calls!
|
||||
// If you not use this event function,
|
||||
// you might miss some data in the loop,
|
||||
// if the host sends too fast or too much data at once.
|
||||
|
||||
auto bytesAvailable = RawHID.available();
|
||||
while (bytesAvailable--) {
|
||||
// Only add data to the buffer if its not full.
|
||||
// If it is, no more event will occur
|
||||
// and the data should be discarded
|
||||
// or read (as shown) in the loop above.
|
||||
if (len < sizeof(data)) {
|
||||
data[len++] = RawHID.read();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,13 +47,7 @@ static const uint8_t _hidReportDescriptorRawHID[] PROGMEM = {
|
|||
0xC0 /* end collection */
|
||||
};
|
||||
|
||||
// Weak implementation of the Event function
|
||||
void RawHIDEvent(uint8_t num) __attribute__ ((weak));
|
||||
void RawHIDEvent(uint8_t num){
|
||||
// Empty
|
||||
}
|
||||
|
||||
RawHID_::RawHID_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1), dataLength(0)
|
||||
RawHID_::RawHID_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1), dataLength(0), dataAvailable(0), featureReport(NULL), featureLength(0)
|
||||
{
|
||||
epType[0] = EP_TYPE_INTERRUPT_IN;
|
||||
PluggableUSB().plug(this);
|
||||
|
|
@ -120,51 +114,36 @@ bool RawHID_::setup(USBSetup& setup)
|
|||
}
|
||||
if (request == HID_SET_REPORT)
|
||||
{
|
||||
// Get the data length information and the corresponding bytes
|
||||
// Check if data has the correct length afterwards
|
||||
int length = setup.wLength;
|
||||
uint8_t num = 0;
|
||||
while(length)
|
||||
{
|
||||
// Dont receive more than the USB EP has to offer
|
||||
// TODO use fixed 64 because control EP always have 64 bytes even on 16 u2. Test!
|
||||
auto recvLength = length;
|
||||
if(recvLength > USB_EP_SIZE){
|
||||
recvLength = USB_EP_SIZE;
|
||||
}
|
||||
if(recvLength > int(sizeof(data))){
|
||||
recvLength = int(sizeof(data));
|
||||
}
|
||||
length -= recvLength;
|
||||
|
||||
// Only receive data if the last one was read fully.
|
||||
// Discard data if it wasnt read yet.
|
||||
// To not miss any data you can use the (weak) event function.
|
||||
if(!dataLength)
|
||||
{
|
||||
// Write data to fit to the end (not the beginning) of the array
|
||||
USB_RecvControl(data + (sizeof(data) - recvLength), recvLength);
|
||||
dataLength = recvLength;
|
||||
RawHIDEvent(num++);
|
||||
}
|
||||
// Do not read the data, flag an error to the USB Host
|
||||
// TODO always return no error, even if data was discarded? -> use break then
|
||||
else{
|
||||
return false;
|
||||
|
||||
// Feature (set feature report)
|
||||
if(setup.wValueH == HID_REPORT_TYPE_FEATURE){
|
||||
// No need to check for negative featureLength values,
|
||||
// except the host tries to send more then 32k bytes.
|
||||
// We dont have that much ram anyways.
|
||||
if (length == featureLength) {
|
||||
USB_RecvControl(featureReport, featureLength);
|
||||
|
||||
// Block until data is read (make length negative)
|
||||
disableFeatureReport();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Output (set out report)
|
||||
else if(setup.wValueH == HID_REPORT_TYPE_OUTPUT){
|
||||
if(!dataAvailable && length <= dataLength){
|
||||
// Write data to fit to the end (not the beginning) of the array
|
||||
USB_RecvControl(data + dataLength - length, length);
|
||||
dataAvailable = length;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Flag no error
|
||||
// TODO this is required to get hyperion working
|
||||
// however this blocks the CDC serial!?
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void RawHID_::SendReport(void* data, int length){
|
||||
USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, length);
|
||||
}
|
||||
|
||||
RawHID_ RawHID;
|
||||
|
|
|
|||
|
|
@ -73,32 +73,73 @@ class RawHID_ : public PluggableUSBModule, public Stream
|
|||
public:
|
||||
RawHID_(void);
|
||||
|
||||
void begin(void){
|
||||
// empty
|
||||
void setFeatureReport(void* report, int length){
|
||||
if(length > 0){
|
||||
featureReport = (uint8_t*)report;
|
||||
featureLength = length;
|
||||
|
||||
// Disable feature report by default
|
||||
disableFeatureReport();
|
||||
}
|
||||
}
|
||||
|
||||
int availableFeatureReport(void){
|
||||
if(featureLength < 0){
|
||||
return featureLength & ~0x8000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void enableFeatureReport(void){
|
||||
featureLength &= ~0x8000;
|
||||
}
|
||||
|
||||
void disableFeatureReport(void){
|
||||
featureLength |= 0x8000;
|
||||
}
|
||||
|
||||
void begin(void* report, int length){
|
||||
if(length > 0){
|
||||
data = (uint8_t*)report;
|
||||
dataLength = length;
|
||||
dataAvailable = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void end(void){
|
||||
// empty
|
||||
disable();
|
||||
dataLength = 0;
|
||||
}
|
||||
|
||||
void enable(void){
|
||||
dataAvailable = 0;
|
||||
}
|
||||
|
||||
void disable(void){
|
||||
dataAvailable = -1;
|
||||
}
|
||||
|
||||
virtual int available(void){
|
||||
return dataLength;
|
||||
if(dataAvailable < 0){
|
||||
return 0;
|
||||
}
|
||||
return dataAvailable;
|
||||
}
|
||||
|
||||
virtual int read(){
|
||||
// Check if we have data available
|
||||
if(dataLength)
|
||||
if(dataAvailable > 0)
|
||||
{
|
||||
// Get next data byte (from the start to the end)
|
||||
return data[sizeof(data) - dataLength--];
|
||||
return data[dataLength - dataAvailable--];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual int peek(){
|
||||
// Check if we have data available
|
||||
if(dataLength){
|
||||
return data[sizeof(data) - dataLength];
|
||||
if(dataAvailable > 0){
|
||||
return data[dataLength - dataAvailable];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -114,27 +155,9 @@ public:
|
|||
}
|
||||
|
||||
virtual size_t write(uint8_t *buffer, size_t size){
|
||||
// TODO this will split the data into proper USB_EP_SIZE packets already
|
||||
SendReport(buffer, size);
|
||||
return size;
|
||||
|
||||
size_t bytesleft = size;
|
||||
// First work through the buffer thats already there
|
||||
while (bytesleft >= RAWHID_TX_SIZE){
|
||||
SendReport(&buffer[size - bytesleft], RAWHID_TX_SIZE);
|
||||
bytesleft -= RAWHID_TX_SIZE;
|
||||
}
|
||||
|
||||
// Write down the leftover bytes and fill with zeros
|
||||
if (bytesleft){
|
||||
SendReport(&buffer[size - bytesleft], bytesleft);
|
||||
}
|
||||
|
||||
return size;
|
||||
return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, buffer, size);
|
||||
}
|
||||
|
||||
void SendReport(void* data, int length);
|
||||
|
||||
protected:
|
||||
// Implementation of the PUSBListNode
|
||||
int getInterface(uint8_t* interfaceCount);
|
||||
|
|
@ -147,7 +170,11 @@ protected:
|
|||
|
||||
// Buffer pointers to hold the received data
|
||||
int dataLength;
|
||||
uint8_t data[RAWHID_RX_SIZE];
|
||||
int dataAvailable;
|
||||
uint8_t* data;
|
||||
|
||||
uint8_t* featureReport;
|
||||
int featureLength;
|
||||
};
|
||||
extern RawHID_ RawHID;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue