String buffers - Devices contribute buffersmain
| @@ -56,7 +56,7 @@ | |||
| // your best effort to read chapter 4 before asking USB questions! | |||
| #define USBHOST_PRINT_DEBUG | |||
| //#define USBHOST_PRINT_DEBUG | |||
| /************************************************/ | |||
| /* Data Types */ | |||
| @@ -140,13 +140,22 @@ typedef union { | |||
| }; | |||
| } setup_t; | |||
| typedef struct { | |||
| enum {STRING_BUF_SIZE=50}; | |||
| enum {STR_ID_MAN=0, STR_ID_PROD, STR_ID_SERIAL, STR_ID_CNT}; | |||
| uint8_t iStrings[STR_ID_CNT]; // Index into array for the three indexes | |||
| uint8_t buffer[STRING_BUF_SIZE]; | |||
| } strbuf_t; | |||
| #define DEVICE_STRUCT_STRING_BUF_SIZE 50 | |||
| // Device_t holds all the information about a USB device | |||
| #define DEVICE_STRUCT_STRING_BUF_SIZE 48 | |||
| struct Device_struct { | |||
| Pipe_t *control_pipe; | |||
| Pipe_t *data_pipes; | |||
| Device_t *next; | |||
| USBDriver *drivers; | |||
| strbuf_t *strbuf; | |||
| uint8_t speed; // 0=12, 1=1.5, 2=480 Mbit/sec | |||
| uint8_t address; | |||
| uint8_t hub_address; | |||
| @@ -160,8 +169,6 @@ struct Device_struct { | |||
| uint16_t idVendor; | |||
| uint16_t idProduct; | |||
| uint16_t LanguageID; | |||
| uint8_t string_buf[DEVICE_STRUCT_STRING_BUF_SIZE]; // Probably want a place to allocate fewer of these... | |||
| uint8_t iStrings[3]; // 3 indexes - vendor string, product string, serial number. | |||
| }; | |||
| // Pipe_t holes all information about each USB endpoint/pipe | |||
| @@ -248,6 +255,7 @@ protected: | |||
| static void contribute_Devices(Device_t *devices, uint32_t num); | |||
| static void contribute_Pipes(Pipe_t *pipes, uint32_t num); | |||
| static void contribute_Transfers(Transfer_t *transfers, uint32_t num); | |||
| static void contribute_String_Buffers(strbuf_t *strbuf, uint32_t num); | |||
| static volatile bool enumeration_busy; | |||
| private: | |||
| static void isr(); | |||
| @@ -263,6 +271,8 @@ private: | |||
| static void free_Pipe(Pipe_t *q); | |||
| static Transfer_t * allocate_Transfer(void); | |||
| static void free_Transfer(Transfer_t *q); | |||
| static strbuf_t * allocate_string_buffer(void); | |||
| static void free_string_buffer(strbuf_t *strbuf); | |||
| static bool allocate_interrupt_pipe_bandwidth(Pipe_t *pipe, | |||
| uint32_t maxlen, uint32_t interval); | |||
| static void add_qh_to_periodic_schedule(Pipe_t *pipe); | |||
| @@ -356,9 +366,12 @@ public: | |||
| uint16_t idVendor() { return (device != nullptr) ? device->idVendor : 0; } | |||
| uint16_t idProduct() { return (device != nullptr) ? device->idProduct : 0; } | |||
| const uint8_t *manufacturer() { return (device != nullptr) ? &(device->string_buf[device->iStrings[0]]) : nullptr; } | |||
| const uint8_t *product() { return (device != nullptr) ? &(device->string_buf[device->iStrings[1]]) : nullptr; } | |||
| const uint8_t *serialNumber() { return (device != nullptr) ? &(device->string_buf[device->iStrings[2]]) : nullptr; } | |||
| const uint8_t *manufacturer() | |||
| { return ((device == nullptr) || (device->strbuf == nullptr)) ? nullptr : &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_MAN]]; } | |||
| const uint8_t *product() | |||
| { return ((device == nullptr) || (device->strbuf == nullptr)) ? nullptr : &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_PROD]]; } | |||
| const uint8_t *serialNumber() | |||
| { return ((device == nullptr) || (device->strbuf == nullptr)) ? nullptr : &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]]; } | |||
| // TODO: user-level functions | |||
| // check if device is bound/active/online | |||
| @@ -415,7 +428,6 @@ protected: | |||
| // wish to claim any device or interface (eg, if getting data | |||
| // from the HID parser). | |||
| Device_t *device; | |||
| friend class USBHost; | |||
| }; | |||
| @@ -445,6 +457,13 @@ public: | |||
| operator bool() { return (mydevice != nullptr); } | |||
| uint16_t idVendor() { return (mydevice != nullptr) ? mydevice->idVendor : 0; } | |||
| uint16_t idProduct() { return (mydevice != nullptr) ? mydevice->idProduct : 0; } | |||
| const uint8_t *manufacturer() | |||
| { return ((mydevice == nullptr) || (mydevice->strbuf == nullptr)) ? nullptr : &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_MAN]]; } | |||
| const uint8_t *product() | |||
| { return ((mydevice == nullptr) || (mydevice->strbuf == nullptr)) ? nullptr : &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_PROD]]; } | |||
| const uint8_t *serialNumber() | |||
| { return ((mydevice == nullptr) || (mydevice->strbuf == nullptr)) ? nullptr : &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]]; } | |||
| private: | |||
| 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); | |||
| @@ -508,6 +527,7 @@ private: | |||
| Device_t mydevices[MAXPORTS]; | |||
| Pipe_t mypipes[2] __attribute__ ((aligned(32))); | |||
| Transfer_t mytransfers[4] __attribute__ ((aligned(32))); | |||
| strbuf_t mystring_bufs[1]; | |||
| USBDriverTimer debouncetimer; | |||
| USBDriverTimer resettimer; | |||
| setup_t setup; | |||
| @@ -572,6 +592,7 @@ private: | |||
| bool use_report_id; | |||
| Pipe_t mypipes[3] __attribute__ ((aligned(32))); | |||
| Transfer_t mytransfers[4] __attribute__ ((aligned(32))); | |||
| strbuf_t mystring_bufs[1]; | |||
| }; | |||
| @@ -634,6 +655,7 @@ private: | |||
| bool processing_new_data_ = false; | |||
| Pipe_t mypipes[2] __attribute__ ((aligned(32))); | |||
| Transfer_t mytransfers[4] __attribute__ ((aligned(32))); | |||
| strbuf_t mystring_bufs[1]; | |||
| }; | |||
| class MIDIDevice : public USBDriver { | |||
| @@ -777,6 +799,7 @@ private: | |||
| void (*handleTimeCodeQuarterFrame)(uint16_t data); | |||
| Pipe_t mypipes[3] __attribute__ ((aligned(32))); | |||
| Transfer_t mytransfers[7] __attribute__ ((aligned(32))); | |||
| strbuf_t mystring_bufs[1]; | |||
| }; | |||
| @@ -810,6 +833,7 @@ private: | |||
| private: | |||
| Pipe_t mypipes[3] __attribute__ ((aligned(32))); | |||
| Transfer_t mytransfers[7] __attribute__ ((aligned(32))); | |||
| strbuf_t mystring_bufs[1]; | |||
| USBDriverTimer txtimer; | |||
| uint32_t bigbuffer[(BUFFER_SIZE+3)/4]; | |||
| setup_t setup; | |||
| @@ -858,6 +882,7 @@ private: | |||
| private: | |||
| Pipe_t mypipes[2] __attribute__ ((aligned(32))); | |||
| Transfer_t mytransfers[3] __attribute__ ((aligned(32))); | |||
| strbuf_t mystring_bufs[1]; | |||
| //USBDriverTimer txtimer; | |||
| USBDriverTimer updatetimer; | |||
| Pipe_t *rxpipe; | |||
| @@ -53,6 +53,7 @@ void AntPlus::init() | |||
| { | |||
| contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | |||
| contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | |||
| contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); | |||
| driver_ready_for_device(this); | |||
| callbackFunc = NULL; | |||
| } | |||
| @@ -119,6 +119,7 @@ Device_t * USBHost::new_Device(uint32_t speed, uint32_t hub_addr, uint32_t hub_p | |||
| free_Device(dev); | |||
| return NULL; | |||
| } | |||
| dev->strbuf = allocate_string_buffer(); // try to allocate a string buffer; | |||
| dev->control_pipe->callback_function = &enumeration; | |||
| dev->control_pipe->direction = 1; // 1=IN | |||
| // Here is where the enumeration process officially begins. | |||
| @@ -203,10 +204,6 @@ void USBHost::enumeration(const Transfer_t *transfer) | |||
| dev->enum_state = 4; | |||
| return; | |||
| case 4: // parse Language ID | |||
| dev->iStrings[0] = 0; // Set indexes into string buffer to say not there... | |||
| dev->iStrings[1] = 0; | |||
| dev->iStrings[2] = 0; | |||
| dev->string_buf[0] = 0; // have trailing NULL.. | |||
| if (enumbuf[4] < 4 || enumbuf[5] != 3) { | |||
| dev->enum_state = 11; | |||
| } else { | |||
| @@ -294,28 +291,31 @@ void USBHost::enumeration(const Transfer_t *transfer) | |||
| } | |||
| void USBHost::convertStringDescriptorToASCIIString(uint8_t string_index, Device_t *dev, const Transfer_t *transfer) { | |||
| strbuf_t *strbuf = dev->strbuf; | |||
| if (!strbuf) return; // don't have a buffer | |||
| uint8_t *buffer = (uint8_t*)transfer->buffer; | |||
| uint8_t buf_index = string_index? dev->iStrings[string_index]+1 : 0; | |||
| uint8_t buf_index = string_index? strbuf->iStrings[string_index]+1 : 0; | |||
| // Try to verify - The first byte should be length and the 2nd byte should be 0x3 | |||
| if (!buffer || (buffer[1] != 0x3)) { | |||
| return; // No string so can simply return | |||
| } | |||
| dev->iStrings[string_index] = buf_index; // remember our starting positio | |||
| strbuf->iStrings[string_index] = buf_index; // remember our starting positio | |||
| uint8_t count_bytes_returned = buffer[0]; | |||
| if ((buf_index + count_bytes_returned/2) >= DEVICE_STRUCT_STRING_BUF_SIZE) | |||
| count_bytes_returned = (DEVICE_STRUCT_STRING_BUF_SIZE - buf_index) * 2; | |||
| // Now copy into our storage buffer. | |||
| for (uint8_t i = 2; (i < count_bytes_returned) && (buf_index < (DEVICE_STRUCT_STRING_BUF_SIZE -1)); i += 2) { | |||
| dev->string_buf[buf_index++] = buffer[i]; | |||
| strbuf->buffer[buf_index++] = buffer[i]; | |||
| } | |||
| dev->string_buf[buf_index] = 0; // null terminate. | |||
| strbuf->buffer[buf_index] = 0; // null terminate. | |||
| // Update other indexes to point to null character | |||
| while (++string_index < 3) { | |||
| dev->iStrings[string_index] = buf_index; // point to trailing NULL character | |||
| strbuf->iStrings[string_index] = buf_index; // point to trailing NULL character | |||
| } | |||
| } | |||
| @@ -461,6 +461,9 @@ void USBHost::disconnect_Device(Device_t *dev) | |||
| prev_dev->next = p->next; | |||
| } | |||
| println("removed Device_t from devlist"); | |||
| if (p->strbuf != nullptr ) { | |||
| free_string_buffer(p->strbuf); | |||
| } | |||
| free_Device(p); | |||
| break; | |||
| } | |||
| @@ -8,6 +8,7 @@ USBHost myusb; | |||
| USBHub hub1(myusb); | |||
| USBHub hub2(myusb); | |||
| USBHub hub3(myusb); | |||
| USBHub hub4(myusb); | |||
| KeyboardController keyboard1(myusb); | |||
| KeyboardController keyboard2(myusb); | |||
| KeyboardHIDExtrasController hidextras(myusb); | |||
| @@ -19,15 +20,23 @@ USBHIDParser hid5(myusb); | |||
| MouseController mouse1(myusb); | |||
| JoystickController joystick1(myusb); | |||
| USBDriver *drivers[] = {&hub1, &hub2, &hub3, &keyboard1, &keyboard2, &hid1, &hid2, &hid3, &hid4, &hid5}; | |||
| #define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[1])) | |||
| const char * driver_names[CNT_DEVICES] = {"Hub1","Hub2","Hub3", "KB1", "KB2", "HID1", "HID2", "HID3", "HID4", "HID5" }; | |||
| USBDriver *drivers[] = {&hub1, &hub2, &hub3, &hub4, &keyboard1, &keyboard2, &hid1, &hid2, &hid3, &hid4, &hid5}; | |||
| #define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0])) | |||
| const char * driver_names[CNT_DEVICES] = {"Hub1","Hub2", "Hub3", "Hub4" "KB1", "KB2", "HID1", "HID2", "HID3", "HID4", "HID5" }; | |||
| bool driver_active[CNT_DEVICES] = {false, false, false, false}; | |||
| // Lets also look at HID Input devices | |||
| USBHIDInput *hiddrivers[] = {&mouse1, &joystick1}; | |||
| #define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0])) | |||
| const char * hid_driver_names[CNT_DEVICES] = {"Mouse1","Joystick1"}; | |||
| bool hid_driver_active[CNT_DEVICES] = {false, false}; | |||
| void setup() | |||
| { | |||
| while (!Serial) ; // wait for Arduino Serial Monitor | |||
| Serial.println("\n\nUSB Host Testing"); | |||
| Serial.println(sizeof(USBHub), DEC); | |||
| myusb.begin(); | |||
| keyboard1.attachPress(OnPress); | |||
| keyboard2.attachPress(OnPress); | |||
| @@ -59,6 +68,27 @@ void loop() | |||
| } | |||
| } | |||
| for (uint8_t i = 0; i < CNT_HIDDEVICES; i++) { | |||
| if (*hiddrivers[i] != hid_driver_active[i]) { | |||
| if (hid_driver_active[i]) { | |||
| Serial.printf("*** HID Device %s - disconnected ***\n", hid_driver_names[i]); | |||
| hid_driver_active[i] = false; | |||
| } else { | |||
| Serial.printf("*** HID Device %s %x:%x - connected ***\n", hid_driver_names[i], hiddrivers[i]->idVendor(), hiddrivers[i]->idProduct()); | |||
| hid_driver_active[i] = true; | |||
| const uint8_t *psz = hiddrivers[i]->manufacturer(); | |||
| if (psz && *psz) Serial.printf(" manufacturer: %s\n", psz); | |||
| psz = hiddrivers[i]->product(); | |||
| if (psz && *psz) Serial.printf(" product: %s\n", psz); | |||
| psz = hiddrivers[i]->serialNumber(); | |||
| if (psz && *psz) Serial.printf(" Serial: %s\n", psz); | |||
| } | |||
| } | |||
| } | |||
| if(mouse1.available()) { | |||
| Serial.print("Mouse: buttons = "); | |||
| Serial.print(mouse1.getButtons()); | |||
| @@ -39,6 +39,7 @@ void USBHIDParser::init() | |||
| { | |||
| contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | |||
| contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | |||
| contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); | |||
| driver_ready_for_device(this); | |||
| } | |||
| @@ -37,6 +37,7 @@ void USBHub::init() | |||
| contribute_Devices(mydevices, sizeof(mydevices)/sizeof(Device_t)); | |||
| contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | |||
| contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | |||
| contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); | |||
| driver_ready_for_device(this); | |||
| } | |||
| @@ -96,6 +96,7 @@ void KeyboardController::init() | |||
| { | |||
| contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | |||
| contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | |||
| contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); | |||
| driver_ready_for_device(this); | |||
| } | |||
| @@ -53,7 +53,7 @@ | |||
| static Device_t * free_Device_list = NULL; | |||
| static Pipe_t * free_Pipe_list = NULL; | |||
| static Transfer_t * free_Transfer_list = NULL; | |||
| static strbuf_t * free_strbuf_list = NULL; | |||
| // A small amount of non-driver memory, just to get things started | |||
| // TODO: is this really necessary? Can these be eliminated, so we | |||
| // use only memory from the drivers? | |||
| @@ -107,6 +107,25 @@ void USBHost::free_Transfer(Transfer_t *transfer) | |||
| free_Transfer_list = transfer; | |||
| } | |||
| strbuf_t * USBHost::allocate_string_buffer(void) | |||
| { | |||
| strbuf_t *strbuf = free_strbuf_list; | |||
| if (strbuf) { | |||
| free_strbuf_list = *(strbuf_t **)strbuf; | |||
| strbuf->iStrings[strbuf_t::STR_ID_MAN] = 0; // Set indexes into string buffer to say not there... | |||
| strbuf->iStrings[strbuf_t::STR_ID_PROD] = 0; | |||
| strbuf->iStrings[strbuf_t::STR_ID_SERIAL] = 0; | |||
| strbuf->buffer[0] = 0; // have trailing NULL.. | |||
| } | |||
| return strbuf; | |||
| } | |||
| void USBHost::free_string_buffer(strbuf_t *strbuf) | |||
| { | |||
| *(strbuf_t **)strbuf = free_strbuf_list; | |||
| free_strbuf_list = strbuf; | |||
| } | |||
| void USBHost::contribute_Devices(Device_t *devices, uint32_t num) | |||
| { | |||
| Device_t *end = devices + num; | |||
| @@ -132,3 +151,12 @@ void USBHost::contribute_Transfers(Transfer_t *transfers, uint32_t num) | |||
| } | |||
| } | |||
| void USBHost::contribute_String_Buffers(strbuf_t *strbufs, uint32_t num) | |||
| { | |||
| strbuf_t *end = strbufs + num; | |||
| for (strbuf_t *str = strbufs ; str < end; str++) { | |||
| free_string_buffer(str); | |||
| } | |||
| } | |||
| @@ -31,6 +31,7 @@ void MIDIDevice::init() | |||
| { | |||
| contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | |||
| contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | |||
| contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); | |||
| handleNoteOff = NULL; | |||
| handleNoteOn = NULL; | |||
| handleVelocityChange = NULL; | |||
| @@ -35,6 +35,7 @@ void USBSerial::init() | |||
| { | |||
| contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | |||
| contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); | |||
| contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); | |||
| driver_ready_for_device(this); | |||
| } | |||