| // Device drivers may inherit from this base class, if they wish to receive | // Device drivers may inherit from this base class, if they wish to receive | ||||
| // HID input data fully decoded by the USBHIDParser driver | // HID input data fully decoded by the USBHIDParser driver | ||||
| class USBHIDInput { | class USBHIDInput { | ||||
| public: | |||||
| USBHIDInput(); | |||||
| private: | private: | ||||
| virtual bool claim_collection(Device_t *dev, uint32_t topusage); | virtual bool claim_collection(Device_t *dev, uint32_t topusage); | ||||
| virtual void hid_input_begin(uint32_t topusage, uint32_t type, int min, int max); | |||||
| virtual void hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax); | |||||
| virtual void hid_input_data(uint32_t usage, int32_t value); | virtual void hid_input_data(uint32_t usage, int32_t value); | ||||
| virtual void hid_input_end(); | virtual void hid_input_end(); | ||||
| virtual void disconnect_collection(Device_t *dev); | virtual void disconnect_collection(Device_t *dev); | ||||
| void add_to_list(); | |||||
| USBHIDInput *next; | USBHIDInput *next; | ||||
| static USBHIDInput *list; | |||||
| friend class USBHIDParser; | friend class USBHIDParser; | ||||
| }; | }; | ||||
| class USBHIDParser : public USBDriver { | class USBHIDParser : public USBDriver { | ||||
| public: | public: | ||||
| USBHIDParser(USBHost &host) { init(); } | USBHIDParser(USBHost &host) { init(); } | ||||
| void driver_ready_for_hid_collection(USBHIDInput *driver); | |||||
| static void driver_ready_for_hid_collection(USBHIDInput *driver); | |||||
| protected: | protected: | ||||
| enum { TOPUSAGE_LIST_LEN = 4 }; | enum { TOPUSAGE_LIST_LEN = 4 }; | ||||
| enum { USAGE_LIST_LEN = 12 }; | enum { USAGE_LIST_LEN = 12 }; | ||||
| private: | private: | ||||
| Pipe_t *in_pipe; | Pipe_t *in_pipe; | ||||
| Pipe_t *out_pipe; | Pipe_t *out_pipe; | ||||
| static USBHIDInput *available_hid_drivers_list; | |||||
| //uint32_t topusage_list[TOPUSAGE_LIST_LEN]; | //uint32_t topusage_list[TOPUSAGE_LIST_LEN]; | ||||
| USBHIDInput *topusage_drivers[TOPUSAGE_LIST_LEN]; | USBHIDInput *topusage_drivers[TOPUSAGE_LIST_LEN]; | ||||
| uint16_t in_size; | uint16_t in_size; | ||||
| Transfer_t mytransfers[7] __attribute__ ((aligned(32))); | Transfer_t mytransfers[7] __attribute__ ((aligned(32))); | ||||
| }; | }; | ||||
| #if 1 | |||||
| class MouseController : public USBHIDInput { | |||||
| public: | |||||
| MouseController(USBHost &host) { USBHIDParser::driver_ready_for_hid_collection(this); } | |||||
| bool available() { return mouseEvent; } | |||||
| void mouseDataClear(); | |||||
| uint8_t getButtons() { return buttons; } | |||||
| int getMouseX() { return mouseX; } | |||||
| int getMouseY() { return mouseY; } | |||||
| int getWheel() { return wheel; } | |||||
| int getWheelH() { return wheelH; } | |||||
| protected: | |||||
| virtual bool claim_collection(Device_t *dev, uint32_t topusage); | |||||
| virtual void hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax); | |||||
| virtual void hid_input_data(uint32_t usage, int32_t value); | |||||
| virtual void hid_input_end(); | |||||
| virtual void disconnect_collection(Device_t *dev); | |||||
| private: | |||||
| Device_t *mydevice = NULL; | |||||
| uint8_t collections_claimed = 0; | |||||
| volatile bool mouseEvent = false; | |||||
| uint8_t buttons = 0; | |||||
| int mouseX = 0; | |||||
| int mouseY = 0; | |||||
| int wheel = 0; | |||||
| int wheelH = 0; | |||||
| }; | |||||
| #else | |||||
| class MouseController : public USBDriver { | class MouseController : public USBDriver { | ||||
| public: | public: | ||||
| MouseController(USBHost &host) { init(); } | MouseController(USBHost &host) { init(); } | ||||
| Pipe_t mypipes[2] __attribute__ ((aligned(32))); | Pipe_t mypipes[2] __attribute__ ((aligned(32))); | ||||
| Transfer_t mytransfers[4] __attribute__ ((aligned(32))); | Transfer_t mytransfers[4] __attribute__ ((aligned(32))); | ||||
| }; | }; | ||||
| #endif | |||||
| #endif | #endif |
| USBHub hub3(myusb); | USBHub hub3(myusb); | ||||
| KeyboardController keyboard1(myusb); | KeyboardController keyboard1(myusb); | ||||
| KeyboardController keyboard2(myusb); | KeyboardController keyboard2(myusb); | ||||
| USBHIDParser hid1(myusb); | |||||
| USBHIDParser hid2(myusb); | |||||
| USBHIDParser hid3(myusb); | |||||
| USBHIDParser hid4(myusb); | |||||
| USBHIDParser hid5(myusb); | |||||
| MouseController mouse1(myusb); | MouseController mouse1(myusb); | ||||
| void setup() | void setup() | ||||
| { | { | ||||
| while (!Serial) ; // wait for Arduino Serial Monitor | |||||
| Serial.println("USB Host Testing"); | |||||
| myusb.begin(); | |||||
| keyboard1.attachPress(OnPress); | |||||
| keyboard2.attachPress(OnPress); | |||||
| while (!Serial) ; // wait for Arduino Serial Monitor | |||||
| Serial.println("USB Host Testing"); | |||||
| myusb.begin(); | |||||
| keyboard1.attachPress(OnPress); | |||||
| keyboard2.attachPress(OnPress); | |||||
| } | } | ||||
| void loop() | void loop() | ||||
| { | { | ||||
| myusb.Task(); | |||||
| myusb.Task(); | |||||
| if(mouse1.available()) { | if(mouse1.available()) { | ||||
| Serial.print("buttons = "); | Serial.print("buttons = "); | ||||
| Serial.print(mouse1.getButtons(),DEC); | |||||
| Serial.print(", wheel = "); | |||||
| Serial.print(mouse1.getWheel(),DEC); | |||||
| Serial.print(mouse1.getButtons()); | |||||
| Serial.print(", mouseX = "); | Serial.print(", mouseX = "); | ||||
| Serial.print(mouse1.getMouseX(),DEC); | |||||
| Serial.print(mouse1.getMouseX()); | |||||
| Serial.print(", mouseY = "); | Serial.print(", mouseY = "); | ||||
| Serial.println(mouse1.getMouseY(),DEC); | |||||
| Serial.print(mouse1.getMouseY()); | |||||
| Serial.print(", wheel = "); | |||||
| Serial.print(mouse1.getWheel()); | |||||
| Serial.print(", wheelH = "); | |||||
| Serial.print(mouse1.getWheelH()); | |||||
| Serial.println(); | |||||
| mouse1.mouseDataClear(); | mouse1.mouseDataClear(); | ||||
| } | } | ||||
| delay(50); | |||||
| } | } | ||||
| // This is a list of all the drivers inherited from the USBHIDInput class. | // This is a list of all the drivers inherited from the USBHIDInput class. | ||||
| // Unlike the list of USBDriver (managed in enumeration.cpp), drivers stay | // Unlike the list of USBDriver (managed in enumeration.cpp), drivers stay | ||||
| // on this list even when they have claimed a top level collection. | // on this list even when they have claimed a top level collection. | ||||
| USBHIDInput * USBHIDInput::list = NULL; | |||||
| USBHIDInput * USBHIDParser::available_hid_drivers_list = NULL; | |||||
| USBHIDInput::USBHIDInput() | |||||
| void USBHIDParser::driver_ready_for_hid_collection(USBHIDInput *driver) | |||||
| { | { | ||||
| next = NULL; | |||||
| if (list == NULL) { | |||||
| list = this; | |||||
| driver->next = NULL; | |||||
| if (available_hid_drivers_list == NULL) { | |||||
| available_hid_drivers_list = driver; | |||||
| } else { | } else { | ||||
| USBHIDInput *last = list; | |||||
| USBHIDInput *last = available_hid_drivers_list; | |||||
| while (last->next) last = last->next; | while (last->next) last = last->next; | ||||
| last->next = this; | |||||
| last->next = driver; | |||||
| } | } | ||||
| } | } | ||||
| // collection is returned, or NULL if no driver wants it. | // collection is returned, or NULL if no driver wants it. | ||||
| USBHIDInput * USBHIDParser::find_driver(uint32_t topusage) | USBHIDInput * USBHIDParser::find_driver(uint32_t topusage) | ||||
| { | { | ||||
| USBHIDInput *driver = USBHIDInput::list; | |||||
| println("find_driver"); | |||||
| USBHIDInput *driver = available_hid_drivers_list; | |||||
| while (driver) { | while (driver) { | ||||
| println(" driver ", (uint32_t)driver, HEX); | |||||
| if (driver->claim_collection(device, topusage)) { | if (driver->claim_collection(device, topusage)) { | ||||
| return driver; | return driver; | ||||
| } | } | ||||
| uint32_t topusage = 0; | uint32_t topusage = 0; | ||||
| uint8_t topusage_index = 0; | uint8_t topusage_index = 0; | ||||
| uint8_t collection_level = 0; | uint8_t collection_level = 0; | ||||
| uint8_t usage[USAGE_LIST_LEN] = {0, 0}; | |||||
| uint16_t usage[USAGE_LIST_LEN] = {0, 0}; | |||||
| uint8_t usage_count = 0; | uint8_t usage_count = 0; | ||||
| uint8_t report_id = 0; | uint8_t report_id = 0; | ||||
| uint16_t report_size = 0; | uint16_t report_size = 0; | ||||
| p += 2; | p += 2; | ||||
| break; | break; | ||||
| case 2: val = p[1] | (p[2] << 8); | case 2: val = p[1] | (p[2] << 8); | ||||
| println("val16 = ", val, HEX); | |||||
| p += 3; | p += 3; | ||||
| break; | break; | ||||
| case 3: val = p[1] | (p[2] << 8) | (p[3] << 16) | (p[4] << 24); | case 3: val = p[1] | (p[2] << 8) | (p[3] << 16) | (p[4] << 24); |
| #include <Arduino.h> | #include <Arduino.h> | ||||
| #include "USBHost_t36.h" // Read this header first for key info | #include "USBHost_t36.h" // Read this header first for key info | ||||
| #if 1 | |||||
| bool MouseController::claim_collection(Device_t *dev, uint32_t topusage) | |||||
| { | |||||
| // only claim Desktop/Mouse | |||||
| if (topusage != 0x10002) return false; | |||||
| // only claim from one physical device | |||||
| if (mydevice != NULL && dev != mydevice) return false; | |||||
| mydevice = dev; | |||||
| collections_claimed++; | |||||
| return true; | |||||
| } | |||||
| void MouseController::disconnect_collection(Device_t *dev) | |||||
| { | |||||
| if (--collections_claimed == 0) { | |||||
| mydevice = NULL; | |||||
| } | |||||
| } | |||||
| void MouseController::hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax) | |||||
| { | |||||
| // TODO: check if absolute coordinates | |||||
| } | |||||
| void MouseController::hid_input_data(uint32_t usage, int32_t value) | |||||
| { | |||||
| //Serial.printf("Mouse: usage=%X, value=%d\n", usage, value); | |||||
| uint32_t usage_page = usage >> 16; | |||||
| usage &= 0xFFFF; | |||||
| if (usage_page == 9 && usage >= 1 && usage <= 8) { | |||||
| if (value == 0) { | |||||
| buttons &= ~(1 << (usage -1)); | |||||
| } else { | |||||
| buttons |= (1 << (usage -1)); | |||||
| } | |||||
| } else if (usage_page == 1) { | |||||
| switch (usage) { | |||||
| case 0x30: | |||||
| mouseX = value; | |||||
| break; | |||||
| case 0x31: | |||||
| mouseY = value; | |||||
| break; | |||||
| case 0x32: // Apple uses this for horizontal scroll | |||||
| wheelH = value; | |||||
| break; | |||||
| case 0x38: | |||||
| wheel = value; | |||||
| break; | |||||
| } | |||||
| } else if (usage_page == 12) { | |||||
| if (usage == 0x238) { // Microsoft uses this for horizontal scroll | |||||
| wheelH = value; | |||||
| } | |||||
| } | |||||
| } | |||||
| void MouseController::hid_input_end() | |||||
| { | |||||
| mouseEvent = true; | |||||
| } | |||||
| void MouseController::mouseDataClear() { | |||||
| mouseEvent = false; | |||||
| buttons = 0; | |||||
| mouseX = 0; | |||||
| mouseY = 0; | |||||
| wheel = 0; | |||||
| wheelH = 0; | |||||
| } | |||||
| #else | |||||
| void MouseController::init() | void MouseController::init() | ||||
| { | { | ||||
| contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | ||||
| println("descriptors[23] = ",descriptors[23]); | println("descriptors[23] = ",descriptors[23]); | ||||
| println("packet size(mouse) = ", size); | println("packet size(mouse) = ", size); | ||||
| // packey size seems to be 20 for (wireless type 2) or 6 bytes for wired | // packey size seems to be 20 for (wireless type 2) or 6 bytes for wired | ||||
| packetSize = size; | |||||
| if ((size != 20) && (size != 6)) return false; | |||||
| packetSize = size; | |||||
| if ((size != 20) && (size != 6)) return false; | |||||
| if(packetSize == 6) packetSize = 8; // Minimum packet size needed is 8 | if(packetSize == 6) packetSize = 8; // Minimum packet size needed is 8 | ||||
| uint32_t interval = descriptors[24]; | uint32_t interval = descriptors[24]; | ||||
| println("polling interval = ", interval); | println("polling interval = ", interval); | ||||
| // | // | ||||
| // Wireless Logitech mouse reports have byte 0 set to 0x02 indicating a type 2 report. | // Wireless Logitech mouse reports have byte 0 set to 0x02 indicating a type 2 report. | ||||
| // Not sure what this really means yet but all bytes of the report packet are shifted | // Not sure what this really means yet but all bytes of the report packet are shifted | ||||
| // ahead by one byte and there is a single byte that is always zero after the button | |||||
| // ahead by one byte and there is a single byte that is always zero after the button | |||||
| // report byte. | // report byte. | ||||
| if(packetSize == 20) { | if(packetSize == 20) { | ||||
| mouseY = 0; | mouseY = 0; | ||||
| wheel = 0; | wheel = 0; | ||||
| } | } | ||||
| #endif | |||||