just use device/host examples direct from tinyusb
This commit is contained in:
		
							parent
							
								
									7e4e3290d5
								
							
						
					
					
						commit
						40b07ac921
					
				| @ -1,4 +1,6 @@ | |||||||
| add_subdirectory(dev_audio_headset) | set(FAMILY rp2040) | ||||||
| add_subdirectory(dev_hid_composite) | set(BOARD pico_sdk) | ||||||
| add_subdirectory(dev_hid_generic_inout) | set(TINYUSB_FAMILY_PROJECT_NAME_PREFIX "tinyusb_dev_") | ||||||
|  | add_subdirectory(${PICO_TINYUSB_PATH}/examples/device tinyusb_device_examples) | ||||||
|  | 
 | ||||||
| add_subdirectory(dev_lowlevel) | add_subdirectory(dev_lowlevel) | ||||||
|  | |||||||
| @ -1,14 +0,0 @@ | |||||||
| set(CMAKE_C_FLAGS_DEBUG "-O0 -g") |  | ||||||
| 
 |  | ||||||
| add_executable(dev_audio_headset |  | ||||||
|         dev_audio_headset.c |  | ||||||
|         usb_descriptors.c |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
| target_include_directories(dev_audio_headset PRIVATE ${CMAKE_CURRENT_LIST_DIR}) |  | ||||||
| 
 |  | ||||||
| target_link_libraries(dev_audio_headset PRIVATE pico_stdlib tinyusb_device tinyusb_board) |  | ||||||
| pico_add_extra_outputs(dev_audio_headset) |  | ||||||
| 
 |  | ||||||
| # add url via pico_set_program_url |  | ||||||
| example_auto_set_url(dev_audio_headset) |  | ||||||
| @ -1,358 +0,0 @@ | |||||||
| /* 
 |  | ||||||
|  * The MIT License (MIT) |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2020 Jerzy Kasenberg |  | ||||||
|  * |  | ||||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
|  * of this software and associated documentation files (the "Software"), to deal |  | ||||||
|  * in the Software without restriction, including without limitation the rights |  | ||||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
|  * copies of the Software, and to permit persons to whom the Software is |  | ||||||
|  * furnished to do so, subject to the following conditions: |  | ||||||
|  * |  | ||||||
|  * The above copyright notice and this permission notice shall be included in |  | ||||||
|  * all copies or substantial portions of the Software. |  | ||||||
|  * |  | ||||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |  | ||||||
|  * THE SOFTWARE. |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <string.h> |  | ||||||
| 
 |  | ||||||
| #include "bsp/board.h" |  | ||||||
| #include "tusb.h" |  | ||||||
| #include "usb_descriptors.h" |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // MACRO CONSTANT TYPEDEF PROTOTYPES
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| /* Blink pattern
 |  | ||||||
|  * - 25 ms   : streaming data |  | ||||||
|  * - 250 ms  : device not mounted |  | ||||||
|  * - 1000 ms : device mounted |  | ||||||
|  * - 2500 ms : device is suspended |  | ||||||
|  */ |  | ||||||
| enum { |  | ||||||
|     BLINK_STREAMING = 25, |  | ||||||
|     BLINK_NOT_MOUNTED = 250, |  | ||||||
|     BLINK_MOUNTED = 1000, |  | ||||||
|     BLINK_SUSPENDED = 2500, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| enum { |  | ||||||
|     VOLUME_CTRL_0_DB = 0, |  | ||||||
|     VOLUME_CTRL_10_DB = 2560, |  | ||||||
|     VOLUME_CTRL_20_DB = 5120, |  | ||||||
|     VOLUME_CTRL_30_DB = 7680, |  | ||||||
|     VOLUME_CTRL_40_DB = 10240, |  | ||||||
|     VOLUME_CTRL_50_DB = 12800, |  | ||||||
|     VOLUME_CTRL_60_DB = 15360, |  | ||||||
|     VOLUME_CTRL_70_DB = 17920, |  | ||||||
|     VOLUME_CTRL_80_DB = 20480, |  | ||||||
|     VOLUME_CTRL_90_DB = 23040, |  | ||||||
|     VOLUME_CTRL_100_DB = 25600, |  | ||||||
|     VOLUME_CTRL_SILENCE = 0x8000, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; |  | ||||||
| 
 |  | ||||||
| // Audio controls
 |  | ||||||
| // Current states
 |  | ||||||
| int8_t mute[CFG_TUD_AUDIO_N_CHANNELS_TX + 1];       // +1 for master channel 0
 |  | ||||||
| int16_t volume[CFG_TUD_AUDIO_N_CHANNELS_TX + 1];    // +1 for master channel 0
 |  | ||||||
| 
 |  | ||||||
| // Buffer for microphone data
 |  | ||||||
| int16_t mic_buf[1000]; |  | ||||||
| // Buffer for speaker data
 |  | ||||||
| int16_t spk_buf[1000]; |  | ||||||
| // Speaker data size received in the last frame
 |  | ||||||
| int spk_data_size; |  | ||||||
| 
 |  | ||||||
| void led_blinking_task(void); |  | ||||||
| void audio_task(void); |  | ||||||
| 
 |  | ||||||
| /*------------- MAIN -------------*/ |  | ||||||
| int main(void) { |  | ||||||
|     board_init(); |  | ||||||
| 
 |  | ||||||
|     tusb_init(); |  | ||||||
| 
 |  | ||||||
|     TU_LOG1("Headset running\r\n"); |  | ||||||
| 
 |  | ||||||
|     while (1) { |  | ||||||
|         tud_task(); // TinyUSB device task
 |  | ||||||
|         audio_task(); |  | ||||||
|         led_blinking_task(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // Device callbacks
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| // Invoked when device is mounted
 |  | ||||||
| void tud_mount_cb(void) { |  | ||||||
|     blink_interval_ms = BLINK_MOUNTED; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Invoked when device is unmounted
 |  | ||||||
| void tud_umount_cb(void) { |  | ||||||
|     blink_interval_ms = BLINK_NOT_MOUNTED; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Invoked when usb bus is suspended
 |  | ||||||
| // remote_wakeup_en : if host allow us  to perform remote wakeup
 |  | ||||||
| // Within 7ms, device must draw an average of current less than 2.5 mA from bus
 |  | ||||||
| void tud_suspend_cb(bool remote_wakeup_en) { |  | ||||||
|     (void) remote_wakeup_en; |  | ||||||
|     blink_interval_ms = BLINK_SUSPENDED; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Invoked when usb bus is resumed
 |  | ||||||
| void tud_resume_cb(void) { |  | ||||||
|     blink_interval_ms = BLINK_MOUNTED; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| typedef struct TU_ATTR_PACKED { |  | ||||||
|     union { |  | ||||||
|         struct TU_ATTR_PACKED { |  | ||||||
|             uint8_t recipient: 5; ///< Recipient type tusb_request_recipient_t.
 |  | ||||||
|             uint8_t type: 2; ///< Request type tusb_request_type_t.
 |  | ||||||
|             uint8_t direction: 1; ///< Direction type. tusb_dir_t
 |  | ||||||
|         } bmRequestType_bit; |  | ||||||
| 
 |  | ||||||
|         uint8_t bmRequestType; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     audio_cs_req_t bRequest; |  | ||||||
|     uint8_t bChannelNumber; |  | ||||||
|     uint8_t bControlSelector; |  | ||||||
|     union { |  | ||||||
|         uint8_t bInterface; |  | ||||||
|         uint8_t bEndpoint; |  | ||||||
|     }; |  | ||||||
|     uint8_t bEntityID; |  | ||||||
|     uint16_t wLength; |  | ||||||
| } audio_control_request_t; |  | ||||||
| 
 |  | ||||||
| // Helper for clock get requests
 |  | ||||||
| static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t const *request) { |  | ||||||
|     TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK); |  | ||||||
| 
 |  | ||||||
|     // Example supports only single frequency, same value will be used for current value and range
 |  | ||||||
|     if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ) { |  | ||||||
|         if (request->bRequest == AUDIO_CS_REQ_CUR) { |  | ||||||
|             TU_LOG2("Clock get current freq %u\r\n", AUDIO_SAMPLE_RATE); |  | ||||||
| 
 |  | ||||||
|             audio_control_cur_4_t curf = {tu_htole32(AUDIO_SAMPLE_RATE)}; |  | ||||||
|             return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &curf, |  | ||||||
|                                                               sizeof(curf)); |  | ||||||
|         } else if (request->bRequest == AUDIO_CS_REQ_RANGE) { |  | ||||||
|             audio_control_range_4_n_t(1) rangef = |  | ||||||
|                     { |  | ||||||
|                             .wNumSubRanges = tu_htole16(1), |  | ||||||
|                             .subrange[0] = {tu_htole32(AUDIO_SAMPLE_RATE), tu_htole32(AUDIO_SAMPLE_RATE), 0} |  | ||||||
|                     }; |  | ||||||
|             TU_LOG2("Clock get freq range (%d, %d, %d)\r\n", (int) rangef.subrange[0].bMin, |  | ||||||
|                     (int) rangef.subrange[0].bMax, (int) rangef.subrange[0].bRes); |  | ||||||
|             return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &rangef, |  | ||||||
|                                                               sizeof(rangef)); |  | ||||||
|         } |  | ||||||
|     } else if (request->bControlSelector == AUDIO_CS_CTRL_CLK_VALID && |  | ||||||
|                request->bRequest == AUDIO_CS_REQ_CUR) { |  | ||||||
|         audio_control_cur_1_t cur_valid = {.bCur = 1}; |  | ||||||
|         TU_LOG2("Clock get is valid %u\r\n", cur_valid.bCur); |  | ||||||
|         return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &cur_valid, |  | ||||||
|                                                           sizeof(cur_valid)); |  | ||||||
|     } |  | ||||||
|     TU_LOG1("Clock get request not supported, entity = %u, selector = %u, request = %u\r\n", |  | ||||||
|             request->bEntityID, request->bControlSelector, request->bRequest); |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Helper for feature unit get requests
 |  | ||||||
| static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_request_t const *request) { |  | ||||||
|     TU_ASSERT(request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT); |  | ||||||
| 
 |  | ||||||
|     if (request->bControlSelector == AUDIO_FU_CTRL_MUTE && request->bRequest == AUDIO_CS_REQ_CUR) { |  | ||||||
|         audio_control_cur_1_t mute1 = {.bCur = mute[request->bChannelNumber]}; |  | ||||||
|         TU_LOG2("Get channel %u mute %d\r\n", request->bChannelNumber, mute1.bCur); |  | ||||||
|         return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &mute1, |  | ||||||
|                                                           sizeof(mute1)); |  | ||||||
|     } else if (UAC2_ENTITY_SPK_FEATURE_UNIT && request->bControlSelector == AUDIO_FU_CTRL_VOLUME) { |  | ||||||
|         if (request->bRequest == AUDIO_CS_REQ_RANGE) { |  | ||||||
|             audio_control_range_2_n_t(1) range_vol = { |  | ||||||
|                     .wNumSubRanges = tu_htole16(1), |  | ||||||
|                     .subrange[0] = {.bMin = tu_htole16(-VOLUME_CTRL_50_DB), tu_htole16(VOLUME_CTRL_0_DB), |  | ||||||
|                                                                             tu_htole16(256)} |  | ||||||
|             }; |  | ||||||
|             TU_LOG2("Get channel %u volume range (%d, %d, %u) dB\r\n", request->bChannelNumber, |  | ||||||
|                     range_vol.subrange[0].bMin / 256, range_vol.subrange[0].bMax / 256, |  | ||||||
|                     range_vol.subrange[0].bRes / 256); |  | ||||||
|             return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, |  | ||||||
|                                                               &range_vol, sizeof(range_vol)); |  | ||||||
|         } else if (request->bRequest == AUDIO_CS_REQ_CUR) { |  | ||||||
|             audio_control_cur_2_t cur_vol = {.bCur = tu_htole16(volume[request->bChannelNumber])}; |  | ||||||
|             TU_LOG2("Get channel %u volume %u dB\r\n", request->bChannelNumber, cur_vol.bCur); |  | ||||||
|             return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, |  | ||||||
|                                                               &cur_vol, sizeof(cur_vol)); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     TU_LOG1("Feature unit get request not supported, entity = %u, selector = %u, request = %u\r\n", |  | ||||||
|             request->bEntityID, request->bControlSelector, request->bRequest); |  | ||||||
| 
 |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Helper for feature unit set requests
 |  | ||||||
| static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio_control_request_t const *request, |  | ||||||
|                                                uint8_t const *buf) { |  | ||||||
|     (void) rhport; |  | ||||||
| 
 |  | ||||||
|     TU_ASSERT(request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT); |  | ||||||
|     TU_VERIFY(request->bRequest == AUDIO_CS_REQ_CUR); |  | ||||||
| 
 |  | ||||||
|     if (request->bControlSelector == AUDIO_FU_CTRL_MUTE) { |  | ||||||
|         TU_VERIFY(request->wLength == sizeof(audio_control_cur_1_t)); |  | ||||||
| 
 |  | ||||||
|         mute[request->bChannelNumber] = ((audio_control_cur_1_t *) buf)->bCur; |  | ||||||
| 
 |  | ||||||
|         TU_LOG2("Set channel %d Mute: %d\r\n", request->bChannelNumber, mute[request->bChannelNumber]); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } else if (request->bControlSelector == AUDIO_FU_CTRL_VOLUME) { |  | ||||||
|         TU_VERIFY(request->wLength == sizeof(audio_control_cur_2_t)); |  | ||||||
| 
 |  | ||||||
|         volume[request->bChannelNumber] = ((audio_control_cur_2_t const *) buf)->bCur; |  | ||||||
| 
 |  | ||||||
|         TU_LOG2("Set channel %d volume: %d dB\r\n", request->bChannelNumber, volume[request->bChannelNumber] / 256); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } else { |  | ||||||
|         TU_LOG1("Feature unit set request not supported, entity = %u, selector = %u, request = %u\r\n", |  | ||||||
|                 request->bEntityID, request->bControlSelector, request->bRequest); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // Application Callback API Implementations
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| // Invoked when audio class specific get request received for an entity
 |  | ||||||
| bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) { |  | ||||||
|     audio_control_request_t *request = (audio_control_request_t *) p_request; |  | ||||||
| 
 |  | ||||||
|     if (request->bEntityID == UAC2_ENTITY_CLOCK) |  | ||||||
|         return tud_audio_clock_get_request(rhport, request); |  | ||||||
|     if (request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT) |  | ||||||
|         return tud_audio_feature_unit_get_request(rhport, request); |  | ||||||
|     else { |  | ||||||
|         TU_LOG1("Get request not handled, entity = %d, selector = %d, request = %d\r\n", |  | ||||||
|                 request->bEntityID, request->bControlSelector, request->bRequest); |  | ||||||
|     } |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Invoked when audio class specific set request received for an entity
 |  | ||||||
| bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *buf) { |  | ||||||
|     audio_control_request_t const *request = (audio_control_request_t const *) p_request; |  | ||||||
| 
 |  | ||||||
|     if (request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT) |  | ||||||
|         return tud_audio_feature_unit_set_request(rhport, request, buf); |  | ||||||
| 
 |  | ||||||
|     TU_LOG1("Set request not handled, entity = %d, selector = %d, request = %d\r\n", |  | ||||||
|             request->bEntityID, request->bControlSelector, request->bRequest); |  | ||||||
| 
 |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const *p_request) { |  | ||||||
|     (void) rhport; |  | ||||||
| 
 |  | ||||||
|     uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex)); |  | ||||||
|     uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue)); |  | ||||||
| 
 |  | ||||||
|     if (ITF_NUM_AUDIO_STREAMING_SPK == itf && alt == 0) |  | ||||||
|         blink_interval_ms = BLINK_MOUNTED; |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request) { |  | ||||||
|     (void) rhport; |  | ||||||
|     uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex)); |  | ||||||
|     uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue)); |  | ||||||
| 
 |  | ||||||
|     TU_LOG2("Set interface %d alt %d\r\n", itf, alt); |  | ||||||
|     if (ITF_NUM_AUDIO_STREAMING_SPK == itf && alt != 0) |  | ||||||
|         blink_interval_ms = BLINK_STREAMING; |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool tud_audio_rx_done_cb(uint8_t rhport, uint8_t *buffer, uint16_t buf_size) { |  | ||||||
|     (void) rhport; |  | ||||||
| 
 |  | ||||||
|     spk_data_size = buf_size; |  | ||||||
|     memcpy(spk_buf, buffer, buf_size); |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting) { |  | ||||||
|     (void) rhport; |  | ||||||
|     (void) itf; |  | ||||||
|     (void) ep_in; |  | ||||||
|     (void) cur_alt_setting; |  | ||||||
| 
 |  | ||||||
|     // This callback could be used to fill microphone data separately
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // AUDIO Task
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| void audio_task(void) { |  | ||||||
|     // When new data arrived, copy data from speaker buffer, to microphone buffer
 |  | ||||||
|     // and send it over
 |  | ||||||
|     if (spk_data_size) { |  | ||||||
|         int16_t *src = spk_buf; |  | ||||||
|         int16_t *limit = spk_buf + spk_data_size / 2; |  | ||||||
|         int16_t *dst = mic_buf; |  | ||||||
|         while (src < limit) { |  | ||||||
|             // Combine two channels into one
 |  | ||||||
|             int32_t left = *src++; |  | ||||||
|             int32_t right = *src++; |  | ||||||
|             *dst++ = (int16_t) ((left + right) / 2); |  | ||||||
|         } |  | ||||||
|         tud_audio_write((uint8_t *) mic_buf, spk_data_size / 2); |  | ||||||
|         spk_data_size = 0; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // BLINKING TASK
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| void led_blinking_task(void) { |  | ||||||
|     static uint32_t start_ms = 0; |  | ||||||
|     static bool led_state = false; |  | ||||||
| 
 |  | ||||||
|     // Blink every interval ms
 |  | ||||||
|     if (board_millis() - start_ms < blink_interval_ms) return; |  | ||||||
|     start_ms += blink_interval_ms; |  | ||||||
| 
 |  | ||||||
|     board_led_write(led_state); |  | ||||||
|     led_state = 1 - led_state; |  | ||||||
| } |  | ||||||
| @ -1,132 +0,0 @@ | |||||||
| /*
 |  | ||||||
|  * The MIT License (MIT) |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2020 Ha Thach (tinyusb.org) |  | ||||||
|  * Copyright (c) 2020 Jerzy Kasenberg |  | ||||||
|  * |  | ||||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
|  * of this software and associated documentation files (the "Software"), to deal |  | ||||||
|  * in the Software without restriction, including without limitation the rights |  | ||||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
|  * copies of the Software, and to permit persons to whom the Software is |  | ||||||
|  * furnished to do so, subject to the following conditions: |  | ||||||
|  * |  | ||||||
|  * The above copyright notice and this permission notice shall be included in |  | ||||||
|  * all copies or substantial portions of the Software. |  | ||||||
|  * |  | ||||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |  | ||||||
|  * THE SOFTWARE. |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #ifndef _TUSB_CONFIG_H_ |  | ||||||
| #define _TUSB_CONFIG_H_ |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| extern "C" { |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| // COMMON CONFIGURATION
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| 
 |  | ||||||
| // defined by compiler flags for flexibility
 |  | ||||||
| #ifndef CFG_TUSB_MCU |  | ||||||
| #error CFG_TUSB_MCU must be defined |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX |  | ||||||
| #define CFG_TUSB_RHPORT0_MODE       (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED) |  | ||||||
| #else |  | ||||||
| #define CFG_TUSB_RHPORT0_MODE       OPT_MODE_DEVICE |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifndef CFG_TUSB_DEBUG |  | ||||||
| // Can be set during compilation i.e.: make LOG=<value for CFG_TUSB_DEBUG> BOARD=<bsp>
 |  | ||||||
| // Keep in mind that enabling logs when data is streaming can disrupt data flow.
 |  | ||||||
| // It can be very helpful though when audio unit requests are tested/debugged.
 |  | ||||||
| #define CFG_TUSB_DEBUG              2 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| /* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
 |  | ||||||
|  * Tinyusb use follows macros to declare transferring memory so that they can be put |  | ||||||
|  * into those specific section. |  | ||||||
|  * e.g |  | ||||||
|  * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) |  | ||||||
|  * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4))) |  | ||||||
|  */ |  | ||||||
| #ifndef CFG_TUSB_MEM_SECTION |  | ||||||
| #define CFG_TUSB_MEM_SECTION |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifndef CFG_TUSB_MEM_ALIGN |  | ||||||
| #define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4))) |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| // DEVICE CONFIGURATION
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| 
 |  | ||||||
| #ifndef CFG_TUD_ENDPOINT0_SIZE |  | ||||||
| #define CFG_TUD_ENDPOINT0_SIZE    64 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| //------------- CLASS -------------//
 |  | ||||||
| #define CFG_TUD_CDC               0 |  | ||||||
| #define CFG_TUD_MSC               0 |  | ||||||
| #define CFG_TUD_HID               0 |  | ||||||
| #define CFG_TUD_MIDI              0 |  | ||||||
| #define CFG_TUD_AUDIO             1 |  | ||||||
| #define CFG_TUD_VENDOR            0 |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| // AUDIO CLASS DRIVER CONFIGURATION
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| 
 |  | ||||||
| #ifndef AUDIO_SAMPLE_RATE |  | ||||||
| #define AUDIO_SAMPLE_RATE                   48000 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #define CFG_TUD_AUDIO_IN_PATH               (CFG_TUD_AUDIO) |  | ||||||
| #define CFG_TUD_AUDIO_OUT_PATH              (CFG_TUD_AUDIO) |  | ||||||
| 
 |  | ||||||
| // Audio format type
 |  | ||||||
| #define CFG_TUD_AUDIO_FORMAT_TYPE_TX        AUDIO_FORMAT_TYPE_I |  | ||||||
| #define CFG_TUD_AUDIO_FORMAT_TYPE_RX        AUDIO_FORMAT_TYPE_I |  | ||||||
| 
 |  | ||||||
| // Audio format type I specifications
 |  | ||||||
| #define CFG_TUD_AUDIO_FORMAT_TYPE_I_TX      AUDIO_DATA_FORMAT_TYPE_I_PCM |  | ||||||
| #define CFG_TUD_AUDIO_FORMAT_TYPE_I_RX      AUDIO_DATA_FORMAT_TYPE_I_PCM |  | ||||||
| #define CFG_TUD_AUDIO_N_CHANNELS_TX         1 |  | ||||||
| #define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2 |  | ||||||
| #define CFG_TUD_AUDIO_N_CHANNELS_RX         2 |  | ||||||
| #define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 2 |  | ||||||
| #define CFG_TUD_AUDIO_RX_ITEMSIZE           2 |  | ||||||
| #define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP    0 |  | ||||||
| 
 |  | ||||||
| // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
 |  | ||||||
| #define CFG_TUD_AUDIO_EPSIZE_IN           (CFG_TUD_AUDIO_IN_PATH * (48 + 1) * (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX) * (CFG_TUD_AUDIO_N_CHANNELS_TX)) // 48 Samples (48 kHz) x 2 Bytes/Sample x n Channels
 |  | ||||||
| #define CFG_TUD_AUDIO_TX_FIFO_COUNT       (CFG_TUD_AUDIO_IN_PATH * 1) |  | ||||||
| #define CFG_TUD_AUDIO_TX_FIFO_SIZE        (CFG_TUD_AUDIO_IN_PATH ? ((CFG_TUD_AUDIO_EPSIZE_IN)) : 0) |  | ||||||
| 
 |  | ||||||
| // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
 |  | ||||||
| #define CFG_TUD_AUDIO_EPSIZE_OUT          (CFG_TUD_AUDIO_OUT_PATH * ((48 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX) * (CFG_TUD_AUDIO_N_CHANNELS_RX))) // N Samples (N kHz) x 2 Bytes/Sample x n Channels
 |  | ||||||
| #define CFG_TUD_AUDIO_RX_FIFO_COUNT       (CFG_TUD_AUDIO_OUT_PATH * 1) |  | ||||||
| #define CFG_TUD_AUDIO_RX_FIFO_SIZE        (CFG_TUD_AUDIO_OUT_PATH ? (3 * (CFG_TUD_AUDIO_EPSIZE_OUT / CFG_TUD_AUDIO_RX_FIFO_COUNT)) : 0) |  | ||||||
| 
 |  | ||||||
| // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
 |  | ||||||
| #define CFG_TUD_AUDIO_N_AS_INT                    1 |  | ||||||
| 
 |  | ||||||
| // Size of control request buffer
 |  | ||||||
| #define CFG_TUD_AUDIO_CTRL_BUF_SIZE                64 |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #endif /* _TUSB_CONFIG_H_ */ |  | ||||||
| @ -1,159 +0,0 @@ | |||||||
| /* 
 |  | ||||||
|  * The MIT License (MIT) |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2020 Ha Thach (tinyusb.org) |  | ||||||
|  * Copyright (c) 2020 Jerzy Kasenberg |  | ||||||
|  * |  | ||||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
|  * of this software and associated documentation files (the "Software"), to deal |  | ||||||
|  * in the Software without restriction, including without limitation the rights |  | ||||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
|  * copies of the Software, and to permit persons to whom the Software is |  | ||||||
|  * furnished to do so, subject to the following conditions: |  | ||||||
|  * |  | ||||||
|  * The above copyright notice and this permission notice shall be included in |  | ||||||
|  * all copies or substantial portions of the Software. |  | ||||||
|  * |  | ||||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |  | ||||||
|  * THE SOFTWARE. |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #include "tusb.h" |  | ||||||
| #include "usb_descriptors.h" |  | ||||||
| 
 |  | ||||||
| /* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
 |  | ||||||
|  * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. |  | ||||||
|  * |  | ||||||
|  * Auto ProductID layout's Bitmap: |  | ||||||
|  *   [MSB]     AUDIO | MIDI | HID | MSC | CDC          [LSB] |  | ||||||
|  */ |  | ||||||
| #define _PID_MAP(itf, n)  ( (CFG_TUD_##itf) << (n) ) |  | ||||||
| #define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ |  | ||||||
|     _PID_MAP(MIDI, 3) | _PID_MAP(AUDIO, 4) | _PID_MAP(VENDOR, 5) ) |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // Device Descriptors
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| tusb_desc_device_t const desc_device = |  | ||||||
|         { |  | ||||||
|                 .bLength            = sizeof(tusb_desc_device_t), |  | ||||||
|                 .bDescriptorType    = TUSB_DESC_DEVICE, |  | ||||||
|                 .bcdUSB             = 0x0200, |  | ||||||
| 
 |  | ||||||
|                 // Use Interface Association Descriptor (IAD) for CDC
 |  | ||||||
|                 // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
 |  | ||||||
|                 .bDeviceClass       = TUSB_CLASS_MISC, |  | ||||||
|                 .bDeviceSubClass    = MISC_SUBCLASS_COMMON, |  | ||||||
|                 .bDeviceProtocol    = MISC_PROTOCOL_IAD, |  | ||||||
|                 .bMaxPacketSize0    = CFG_TUD_ENDPOINT0_SIZE, |  | ||||||
| 
 |  | ||||||
|                 .idVendor           = 0xCafe, |  | ||||||
|                 .idProduct          = USB_PID, |  | ||||||
|                 .bcdDevice          = 0x0100, |  | ||||||
| 
 |  | ||||||
|                 .iManufacturer      = 0x01, |  | ||||||
|                 .iProduct           = 0x02, |  | ||||||
|                 .iSerialNumber      = 0x03, |  | ||||||
| 
 |  | ||||||
|                 .bNumConfigurations = 0x01 |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
| // Invoked when received GET DEVICE DESCRIPTOR
 |  | ||||||
| // Application return pointer to descriptor
 |  | ||||||
| uint8_t const *tud_descriptor_device_cb(void) { |  | ||||||
|     return (uint8_t const *) &desc_device; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // Configuration Descriptor
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| #define CONFIG_TOTAL_LEN        (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_HEADSET_STEREO_DESC_LEN) |  | ||||||
| 
 |  | ||||||
| #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX |  | ||||||
| // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
 |  | ||||||
| // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
 |  | ||||||
| #define EPNUM_AUDIO   0x03 |  | ||||||
| #elif CFG_TUSB_MCU == OPT_MCU_NRF5X |  | ||||||
| // ISO endpoints for NRF5x are fixed to 0x08 (0x88)
 |  | ||||||
| #define EPNUM_AUDIO   0x08 |  | ||||||
| #else |  | ||||||
| #define EPNUM_AUDIO   0x01 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| // These variables are required by the audio driver in audio_device.c
 |  | ||||||
| 
 |  | ||||||
| // List of audio descriptor lengths which is required by audio driver - you need as many entries as CFG_TUD_AUDIO
 |  | ||||||
| const uint16_t tud_audio_desc_lengths[] = {TUD_AUDIO_HEADSET_STEREO_DESC_LEN}; |  | ||||||
| 
 |  | ||||||
| uint8_t const desc_configuration[] = |  | ||||||
|         { |  | ||||||
|                 // Interface count, string index, total length, attribute, power in mA
 |  | ||||||
|                 TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), |  | ||||||
| 
 |  | ||||||
|                 // Interface number, string index, EP Out & EP In address, EP size
 |  | ||||||
|                 TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(2, 2, 16, EPNUM_AUDIO, CFG_TUD_AUDIO_EPSIZE_OUT, EPNUM_AUDIO | 0x80, |  | ||||||
|                                                     CFG_TUD_AUDIO_EPSIZE_IN) |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
| // Invoked when received GET CONFIGURATION DESCRIPTOR
 |  | ||||||
| // Application return pointer to descriptor
 |  | ||||||
| // Descriptor contents must exist long enough for transfer to complete
 |  | ||||||
| uint8_t const *tud_descriptor_configuration_cb(uint8_t index) { |  | ||||||
|     (void) index; // for multiple configurations
 |  | ||||||
|     return desc_configuration; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // String Descriptors
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| // array of pointer to string descriptors
 |  | ||||||
| char const *string_desc_arr[] = |  | ||||||
|         { |  | ||||||
|                 (const char[]) {0x09, 0x04},  // 0: is supported language is English (0x0409)
 |  | ||||||
|                 "TinyUSB",                      // 1: Manufacturer
 |  | ||||||
|                 "TinyUSB headset",              // 2: Product
 |  | ||||||
|                 "000001",                       // 3: Serials, should use chip ID
 |  | ||||||
|                 "TinyUSB Speakers",             // 4: Audio Interface
 |  | ||||||
|                 "TinyUSB Microphone",           // 5: Audio Interface
 |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
| static uint16_t _desc_str[32]; |  | ||||||
| 
 |  | ||||||
| // Invoked when received GET STRING DESCRIPTOR request
 |  | ||||||
| // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
 |  | ||||||
| uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { |  | ||||||
|     (void) langid; |  | ||||||
| 
 |  | ||||||
|     uint8_t chr_count; |  | ||||||
| 
 |  | ||||||
|     if (index == 0) { |  | ||||||
|         memcpy(&_desc_str[1], string_desc_arr[0], 2); |  | ||||||
|         chr_count = 1; |  | ||||||
|     } else { |  | ||||||
|         // Convert ASCII string into UTF-16
 |  | ||||||
| 
 |  | ||||||
|         if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0]))) return NULL; |  | ||||||
| 
 |  | ||||||
|         const char *str = string_desc_arr[index]; |  | ||||||
| 
 |  | ||||||
|         // Cap at max char
 |  | ||||||
|         chr_count = strlen(str); |  | ||||||
|         if (chr_count > 31) chr_count = 31; |  | ||||||
| 
 |  | ||||||
|         for (uint8_t i = 0; i < chr_count; i++) { |  | ||||||
|             _desc_str[1 + i] = str[i]; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // first byte is length (including header), second byte is string type
 |  | ||||||
|     _desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2); |  | ||||||
| 
 |  | ||||||
|     return _desc_str; |  | ||||||
| } |  | ||||||
| @ -1,119 +0,0 @@ | |||||||
| /* 
 |  | ||||||
|  * The MIT License (MIT) |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2020 Jerzy Kasenbreg |  | ||||||
|  * |  | ||||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
|  * of this software and associated documentation files (the "Software"), to deal |  | ||||||
|  * in the Software without restriction, including without limitation the rights |  | ||||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
|  * copies of the Software, and to permit persons to whom the Software is |  | ||||||
|  * furnished to do so, subject to the following conditions: |  | ||||||
|  * |  | ||||||
|  * The above copyright notice and this permission notice shall be included in |  | ||||||
|  * all copies or substantial portions of the Software. |  | ||||||
|  * |  | ||||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |  | ||||||
|  * THE SOFTWARE. |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #ifndef _USB_DESCRIPTORS_H_ |  | ||||||
| #define _USB_DESCRIPTORS_H_ |  | ||||||
| 
 |  | ||||||
| #include "tusb.h" |  | ||||||
| 
 |  | ||||||
| // Unit numbers are arbitrary selected
 |  | ||||||
| #define UAC2_ENTITY_CLOCK               0x04 |  | ||||||
| // Speaker path
 |  | ||||||
| #define UAC2_ENTITY_SPK_INPUT_TERMINAL  0x01 |  | ||||||
| #define UAC2_ENTITY_SPK_FEATURE_UNIT    0x02 |  | ||||||
| #define UAC2_ENTITY_SPK_OUTPUT_TERMINAL 0x03 |  | ||||||
| // Microphone path
 |  | ||||||
| #define UAC2_ENTITY_MIC_INPUT_TERMINAL  0x11 |  | ||||||
| #define UAC2_ENTITY_MIC_OUTPUT_TERMINAL 0x13 |  | ||||||
| 
 |  | ||||||
| enum { |  | ||||||
|     ITF_NUM_AUDIO_CONTROL = 0, |  | ||||||
|     ITF_NUM_AUDIO_STREAMING_SPK, |  | ||||||
|     ITF_NUM_AUDIO_STREAMING_MIC, |  | ||||||
|     ITF_NUM_TOTAL |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| #define TUD_AUDIO_HEADSET_STEREO_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_STD_AC_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_CS_AC_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_CLK_SRC_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_INPUT_TERM_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_INPUT_TERM_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_STD_AS_INT_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_STD_AS_INT_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_CS_AS_INT_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_STD_AS_INT_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_STD_AS_INT_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_CS_AS_INT_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ |  | ||||||
|     + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| #define TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(_stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epoutsize, _epin, _epinsize) \ |  | ||||||
|     /* Standard Interface Association Descriptor (IAD) */\ |  | ||||||
|     TUD_AUDIO_DESC_IAD(/*_firstitfs*/ ITF_NUM_AUDIO_CONTROL, /*_nitfs*/ ITF_NUM_TOTAL, /*_stridx*/ 0x00),\ |  | ||||||
|     /* Standard AC Interface Descriptor(4.7.1) */\ |  | ||||||
|     TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ |  | ||||||
|     /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ |  | ||||||
|     TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ |  | ||||||
|     /* Clock Source Descriptor(4.7.2.1) */\ |  | ||||||
|     TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ UAC2_ENTITY_CLOCK, /*_attr*/ 3, /*_ctrl*/ 5, /*_assocTerm*/ 0x00,  /*_stridx*/ 0x00),    \ |  | ||||||
|     /* Input Terminal Descriptor(4.7.2.4) */\ |  | ||||||
|     TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ |  | ||||||
|     /* Feature Unit Descriptor(4.7.2.8) */\ |  | ||||||
|     TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrlch0master*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch2*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_stridx*/ 0x00),\ |  | ||||||
|     /* Output Terminal Descriptor(4.7.2.5) */\ |  | ||||||
|     TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_GENERIC_SPEAKER, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ |  | ||||||
|     /* Input Terminal Descriptor(4.7.2.4) */\ |  | ||||||
|     TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ |  | ||||||
|     /* Output Terminal Descriptor(4.7.2.5) */\ |  | ||||||
|     TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ |  | ||||||
|     /* Standard AS Interface Descriptor(4.9.1) */\ |  | ||||||
|     /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ |  | ||||||
|     TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x05),\ |  | ||||||
|     /* Standard AS Interface Descriptor(4.9.1) */\ |  | ||||||
|     /* Interface 1, Alternate 1 - alternate interface for data streaming */\ |  | ||||||
|     TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x05),\ |  | ||||||
|     /* Class-Specific AS Interface Descriptor(4.9.2) */\ |  | ||||||
|     TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ |  | ||||||
|     /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ |  | ||||||
|     TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ |  | ||||||
|     /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ |  | ||||||
|     TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epoutsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\ |  | ||||||
|     /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ |  | ||||||
|     TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\ |  | ||||||
|     /* Standard AS Interface Descriptor(4.9.1) */\ |  | ||||||
|     /* Interface 2, Alternate 0 - default alternate setting with 0 bandwidth */\ |  | ||||||
|     TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x04),\ |  | ||||||
|     /* Standard AS Interface Descriptor(4.9.1) */\ |  | ||||||
|     /* Interface 1, Alternate 1 - alternate interface for data streaming */\ |  | ||||||
|     TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x04),\ |  | ||||||
|     /* Class-Specific AS Interface Descriptor(4.9.2) */\ |  | ||||||
|     TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ |  | ||||||
|     /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ |  | ||||||
|     TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ |  | ||||||
|     /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ |  | ||||||
|     TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epinsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\ |  | ||||||
|     /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ |  | ||||||
|     TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)\ |  | ||||||
| 
 |  | ||||||
| #endif |  | ||||||
| @ -1,12 +0,0 @@ | |||||||
| add_executable(dev_hid_composite |  | ||||||
|         dev_hid_composite.c |  | ||||||
|         usb_descriptors.c |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
| target_include_directories(dev_hid_composite PRIVATE ${CMAKE_CURRENT_LIST_DIR}) |  | ||||||
| 
 |  | ||||||
| target_link_libraries(dev_hid_composite PRIVATE pico_stdlib tinyusb_device tinyusb_board) |  | ||||||
| pico_add_extra_outputs(dev_hid_composite) |  | ||||||
| 
 |  | ||||||
| # add url via pico_set_program_url |  | ||||||
| example_auto_set_url(dev_hid_composite) |  | ||||||
| @ -1,189 +0,0 @@ | |||||||
| /* 
 |  | ||||||
|  * The MIT License (MIT) |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) |  | ||||||
|  * |  | ||||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
|  * of this software and associated documentation files (the "Software"), to deal |  | ||||||
|  * in the Software without restriction, including without limitation the rights |  | ||||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
|  * copies of the Software, and to permit persons to whom the Software is |  | ||||||
|  * furnished to do so, subject to the following conditions: |  | ||||||
|  * |  | ||||||
|  * The above copyright notice and this permission notice shall be included in |  | ||||||
|  * all copies or substantial portions of the Software. |  | ||||||
|  * |  | ||||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |  | ||||||
|  * THE SOFTWARE. |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <string.h> |  | ||||||
| 
 |  | ||||||
| #include "bsp/board.h" |  | ||||||
| #include "tusb.h" |  | ||||||
| 
 |  | ||||||
| #include "usb_descriptors.h" |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // MACRO CONSTANT TYPEDEF PROTYPES
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| /* Blink pattern
 |  | ||||||
|  * - 250 ms  : device not mounted |  | ||||||
|  * - 1000 ms : device mounted |  | ||||||
|  * - 2500 ms : device is suspended |  | ||||||
|  */ |  | ||||||
| enum { |  | ||||||
|     BLINK_NOT_MOUNTED = 250, |  | ||||||
|     BLINK_MOUNTED = 1000, |  | ||||||
|     BLINK_SUSPENDED = 2500, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; |  | ||||||
| 
 |  | ||||||
| void led_blinking_task(void); |  | ||||||
| void hid_task(void); |  | ||||||
| 
 |  | ||||||
| /*------------- MAIN -------------*/ |  | ||||||
| int main(void) { |  | ||||||
|     board_init(); |  | ||||||
|     tusb_init(); |  | ||||||
| 
 |  | ||||||
|     while (1) { |  | ||||||
|         tud_task(); // tinyusb device task
 |  | ||||||
|         led_blinking_task(); |  | ||||||
| 
 |  | ||||||
|         hid_task(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // Device callbacks
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| // Invoked when device is mounted
 |  | ||||||
| void tud_mount_cb(void) { |  | ||||||
|     blink_interval_ms = BLINK_MOUNTED; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Invoked when device is unmounted
 |  | ||||||
| void tud_umount_cb(void) { |  | ||||||
|     blink_interval_ms = BLINK_NOT_MOUNTED; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Invoked when usb bus is suspended
 |  | ||||||
| // remote_wakeup_en : if host allow us  to perform remote wakeup
 |  | ||||||
| // Within 7ms, device must draw an average of current less than 2.5 mA from bus
 |  | ||||||
| void tud_suspend_cb(bool remote_wakeup_en) { |  | ||||||
|     (void) remote_wakeup_en; |  | ||||||
|     blink_interval_ms = BLINK_SUSPENDED; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Invoked when usb bus is resumed
 |  | ||||||
| void tud_resume_cb(void) { |  | ||||||
|     blink_interval_ms = BLINK_MOUNTED; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // USB HID
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| void hid_task(void) { |  | ||||||
|     // Poll every 10ms
 |  | ||||||
|     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; |  | ||||||
| 
 |  | ||||||
|     uint32_t const btn = 1; |  | ||||||
| 
 |  | ||||||
|     // Remote wakeup
 |  | ||||||
|     if (tud_suspended() && btn) { |  | ||||||
|         // Wake up host if we are in suspend mode
 |  | ||||||
|         // and REMOTE_WAKEUP feature is enabled by host
 |  | ||||||
|         tud_remote_wakeup(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /*------------- Mouse -------------*/ |  | ||||||
|     if (tud_hid_ready()) { |  | ||||||
|         if (btn) { |  | ||||||
|             int8_t const delta = 5; |  | ||||||
| 
 |  | ||||||
|             // no button, right + down, no scroll pan
 |  | ||||||
|             tud_hid_mouse_report(REPORT_ID_MOUSE, 0x00, delta, delta, 0, 0); |  | ||||||
| 
 |  | ||||||
|             // delay a bit before attempt to send keyboard report
 |  | ||||||
|             board_delay(10); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /*------------- Keyboard -------------*/ |  | ||||||
|     if (tud_hid_ready()) { |  | ||||||
|         // use to avoid send multiple consecutive zero report for keyboard
 |  | ||||||
|         static bool has_key = false; |  | ||||||
| 
 |  | ||||||
|         static bool toggle = false; |  | ||||||
|         if ((toggle = !toggle)) { |  | ||||||
|             uint8_t keycode[6] = {0}; |  | ||||||
|             keycode[0] = HID_KEY_A; |  | ||||||
| 
 |  | ||||||
|             tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode); |  | ||||||
| 
 |  | ||||||
|             has_key = true; |  | ||||||
|         } else { |  | ||||||
|             // send empty key report if previously has key pressed
 |  | ||||||
|             if (has_key) tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL); |  | ||||||
|             has_key = false; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // Invoked when received GET_REPORT control request
 |  | ||||||
| // Application must fill buffer report's content and return its length.
 |  | ||||||
| // Return zero will cause the stack to STALL request
 |  | ||||||
| uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { |  | ||||||
|     // TODO not Implemented
 |  | ||||||
|     (void) report_id; |  | ||||||
|     (void) report_type; |  | ||||||
|     (void) buffer; |  | ||||||
|     (void) reqlen; |  | ||||||
| 
 |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Invoked when received SET_REPORT control request or
 |  | ||||||
| // received data on OUT endpoint ( Report ID = 0, Type = 0 )
 |  | ||||||
| void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) { |  | ||||||
|     // TODO set LED based on CAPLOCK, NUMLOCK etc...
 |  | ||||||
|     (void) report_id; |  | ||||||
|     (void) report_type; |  | ||||||
|     (void) buffer; |  | ||||||
|     (void) bufsize; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // BLINKING TASK
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| void led_blinking_task(void) { |  | ||||||
|     static uint32_t start_ms = 0; |  | ||||||
|     static bool led_state = false; |  | ||||||
| 
 |  | ||||||
|     // Blink every interval ms
 |  | ||||||
|     if (board_millis() - start_ms < blink_interval_ms) return; // not enough time
 |  | ||||||
|     start_ms += blink_interval_ms; |  | ||||||
| 
 |  | ||||||
|     board_led_write(led_state); |  | ||||||
|     led_state = 1 - led_state; // toggle
 |  | ||||||
| } |  | ||||||
| @ -1,93 +0,0 @@ | |||||||
| /*
 |  | ||||||
|  * The MIT License (MIT) |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) |  | ||||||
|  * |  | ||||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
|  * of this software and associated documentation files (the "Software"), to deal |  | ||||||
|  * in the Software without restriction, including without limitation the rights |  | ||||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
|  * copies of the Software, and to permit persons to whom the Software is |  | ||||||
|  * furnished to do so, subject to the following conditions: |  | ||||||
|  * |  | ||||||
|  * The above copyright notice and this permission notice shall be included in |  | ||||||
|  * all copies or substantial portions of the Software. |  | ||||||
|  * |  | ||||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |  | ||||||
|  * THE SOFTWARE. |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #ifndef _TUSB_CONFIG_H_ |  | ||||||
| #define _TUSB_CONFIG_H_ |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| extern "C" { |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| // COMMON CONFIGURATION
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| 
 |  | ||||||
| // defined by compiler flags for flexibility
 |  | ||||||
| #ifndef CFG_TUSB_MCU |  | ||||||
| #error CFG_TUSB_MCU must be defined |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \ |  | ||||||
|     CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 |  | ||||||
| #define CFG_TUSB_RHPORT0_MODE     (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED) |  | ||||||
| #else |  | ||||||
| #define CFG_TUSB_RHPORT0_MODE     OPT_MODE_DEVICE |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifndef CFG_TUSB_OS |  | ||||||
| #define CFG_TUSB_OS                 OPT_OS_PICO |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| // CFG_TUSB_DEBUG is defined by compiler in DEBUG build
 |  | ||||||
| // #define CFG_TUSB_DEBUG           0
 |  | ||||||
| 
 |  | ||||||
| /* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
 |  | ||||||
|  * Tinyusb use follows macros to declare transferring memory so that they can be put |  | ||||||
|  * into those specific section. |  | ||||||
|  * e.g |  | ||||||
|  * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) |  | ||||||
|  * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4))) |  | ||||||
|  */ |  | ||||||
| #ifndef CFG_TUSB_MEM_SECTION |  | ||||||
| #define CFG_TUSB_MEM_SECTION |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifndef CFG_TUSB_MEM_ALIGN |  | ||||||
| #define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4))) |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| // DEVICE CONFIGURATION
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| 
 |  | ||||||
| #ifndef CFG_TUD_ENDPOINT0_SIZE |  | ||||||
| #define CFG_TUD_ENDPOINT0_SIZE    64 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| //------------- CLASS -------------//
 |  | ||||||
| #define CFG_TUD_HID             1 |  | ||||||
| #define CFG_TUD_CDC             0 |  | ||||||
| #define CFG_TUD_MSC             0 |  | ||||||
| #define CFG_TUD_MIDI            0 |  | ||||||
| #define CFG_TUD_VENDOR          0 |  | ||||||
| 
 |  | ||||||
| // HID buffer size Should be sufficient to hold ID (if any) + Data
 |  | ||||||
| #define CFG_TUD_HID_BUFSIZE     16 |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #endif /* _TUSB_CONFIG_H_ */ |  | ||||||
| @ -1,162 +0,0 @@ | |||||||
| /* 
 |  | ||||||
|  * The MIT License (MIT) |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) |  | ||||||
|  * |  | ||||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
|  * of this software and associated documentation files (the "Software"), to deal |  | ||||||
|  * in the Software without restriction, including without limitation the rights |  | ||||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
|  * copies of the Software, and to permit persons to whom the Software is |  | ||||||
|  * furnished to do so, subject to the following conditions: |  | ||||||
|  * |  | ||||||
|  * The above copyright notice and this permission notice shall be included in |  | ||||||
|  * all copies or substantial portions of the Software. |  | ||||||
|  * |  | ||||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |  | ||||||
|  * THE SOFTWARE. |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #include "tusb.h" |  | ||||||
| #include "usb_descriptors.h" |  | ||||||
| 
 |  | ||||||
| /* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
 |  | ||||||
|  * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. |  | ||||||
|  * |  | ||||||
|  * Auto ProductID layout's Bitmap: |  | ||||||
|  *   [MSB]         HID | MSC | CDC          [LSB] |  | ||||||
|  */ |  | ||||||
| #define _PID_MAP(itf, n)  ( (CFG_TUD_##itf) << (n) ) |  | ||||||
| #define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ |  | ||||||
|                            _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // Device Descriptors
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| tusb_desc_device_t const desc_device = |  | ||||||
|         { |  | ||||||
|                 .bLength            = sizeof(tusb_desc_device_t), |  | ||||||
|                 .bDescriptorType    = TUSB_DESC_DEVICE, |  | ||||||
|                 .bcdUSB             = 0x0200, |  | ||||||
|                 .bDeviceClass       = 0x00, |  | ||||||
|                 .bDeviceSubClass    = 0x00, |  | ||||||
|                 .bDeviceProtocol    = 0x00, |  | ||||||
|                 .bMaxPacketSize0    = CFG_TUD_ENDPOINT0_SIZE, |  | ||||||
| 
 |  | ||||||
|                 .idVendor           = 0xCafe, |  | ||||||
|                 .idProduct          = USB_PID, |  | ||||||
|                 .bcdDevice          = 0x0100, |  | ||||||
| 
 |  | ||||||
|                 .iManufacturer      = 0x01, |  | ||||||
|                 .iProduct           = 0x02, |  | ||||||
|                 .iSerialNumber      = 0x03, |  | ||||||
| 
 |  | ||||||
|                 .bNumConfigurations = 0x01 |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
| // Invoked when received GET DEVICE DESCRIPTOR
 |  | ||||||
| // Application return pointer to descriptor
 |  | ||||||
| uint8_t const *tud_descriptor_device_cb(void) { |  | ||||||
|     return (uint8_t const *) &desc_device; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // HID Report Descriptor
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| uint8_t const desc_hid_report[] = |  | ||||||
|         { |  | ||||||
|                 TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(REPORT_ID_KEYBOARD)), |  | ||||||
|                 TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(REPORT_ID_MOUSE)) |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
| // Invoked when received GET HID REPORT DESCRIPTOR
 |  | ||||||
| // Application return pointer to descriptor
 |  | ||||||
| // Descriptor contents must exist long enough for transfer to complete
 |  | ||||||
| uint8_t const *tud_hid_descriptor_report_cb(void) { |  | ||||||
|     return desc_hid_report; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // Configuration Descriptor
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| enum { |  | ||||||
|     ITF_NUM_HID, |  | ||||||
|     ITF_NUM_TOTAL |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| #define  CONFIG_TOTAL_LEN  (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN) |  | ||||||
| 
 |  | ||||||
| #define EPNUM_HID   0x81 |  | ||||||
| 
 |  | ||||||
| uint8_t const desc_configuration[] = |  | ||||||
|         { |  | ||||||
|                 // Config number, interface count, string index, total length, attribute, power in mA
 |  | ||||||
|                 TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), |  | ||||||
| 
 |  | ||||||
|                 // Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
 |  | ||||||
|                 TUD_HID_DESCRIPTOR(ITF_NUM_HID, 0, HID_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, |  | ||||||
|                                    CFG_TUD_HID_BUFSIZE, 10) |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
| // Invoked when received GET CONFIGURATION DESCRIPTOR
 |  | ||||||
| // Application return pointer to descriptor
 |  | ||||||
| // Descriptor contents must exist long enough for transfer to complete
 |  | ||||||
| uint8_t const *tud_descriptor_configuration_cb(uint8_t index) { |  | ||||||
|     (void) index; // for multiple configurations
 |  | ||||||
|     return desc_configuration; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // String Descriptors
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| // array of pointer to string descriptors
 |  | ||||||
| char const *string_desc_arr[] = |  | ||||||
|         { |  | ||||||
|                 (const char[]) {0x09, 0x04}, // 0: is supported language is English (0x0409)
 |  | ||||||
|                 "TinyUSB",                     // 1: Manufacturer
 |  | ||||||
|                 "TinyUSB Device",              // 2: Product
 |  | ||||||
|                 "123456",                      // 3: Serials, should use chip ID
 |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
| static uint16_t _desc_str[32]; |  | ||||||
| 
 |  | ||||||
| // Invoked when received GET STRING DESCRIPTOR request
 |  | ||||||
| // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
 |  | ||||||
| uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { |  | ||||||
|     (void) langid; |  | ||||||
| 
 |  | ||||||
|     uint8_t chr_count; |  | ||||||
| 
 |  | ||||||
|     if (index == 0) { |  | ||||||
|         memcpy(&_desc_str[1], string_desc_arr[0], 2); |  | ||||||
|         chr_count = 1; |  | ||||||
|     } else { |  | ||||||
|         // Convert ASCII string into UTF-16
 |  | ||||||
| 
 |  | ||||||
|         if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0]))) return NULL; |  | ||||||
| 
 |  | ||||||
|         const char *str = string_desc_arr[index]; |  | ||||||
| 
 |  | ||||||
|         // Cap at max char
 |  | ||||||
|         chr_count = strlen(str); |  | ||||||
|         if (chr_count > 31) chr_count = 31; |  | ||||||
| 
 |  | ||||||
|         for (uint8_t i = 0; i < chr_count; i++) { |  | ||||||
|             _desc_str[1 + i] = str[i]; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // first byte is length (including header), second byte is string type
 |  | ||||||
|     _desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2); |  | ||||||
| 
 |  | ||||||
|     return _desc_str; |  | ||||||
| } |  | ||||||
| @ -1,33 +0,0 @@ | |||||||
| /* 
 |  | ||||||
|  * The MIT License (MIT) |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) |  | ||||||
|  * |  | ||||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
|  * of this software and associated documentation files (the "Software"), to deal |  | ||||||
|  * in the Software without restriction, including without limitation the rights |  | ||||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
|  * copies of the Software, and to permit persons to whom the Software is |  | ||||||
|  * furnished to do so, subject to the following conditions: |  | ||||||
|  * |  | ||||||
|  * The above copyright notice and this permission notice shall be included in |  | ||||||
|  * all copies or substantial portions of the Software. |  | ||||||
|  * |  | ||||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |  | ||||||
|  * THE SOFTWARE. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #ifndef USB_DESCRIPTORS_H_ |  | ||||||
| #define USB_DESCRIPTORS_H_ |  | ||||||
| 
 |  | ||||||
| enum { |  | ||||||
|     REPORT_ID_KEYBOARD = 1, |  | ||||||
|     REPORT_ID_MOUSE |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| #endif /* USB_DESCRIPTORS_H_ */ |  | ||||||
| @ -1,12 +0,0 @@ | |||||||
| add_executable(dev_hid_generic_inout |  | ||||||
|         dev_hid_generic_inout.c |  | ||||||
|         usb_descriptors.c |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
| target_include_directories(dev_hid_generic_inout PRIVATE ${CMAKE_CURRENT_LIST_DIR}) |  | ||||||
| 
 |  | ||||||
| target_link_libraries(dev_hid_generic_inout PRIVATE pico_stdlib tinyusb_device tinyusb_board) |  | ||||||
| pico_add_extra_outputs(dev_hid_generic_inout) |  | ||||||
| 
 |  | ||||||
| # add url via pico_set_program_url |  | ||||||
| example_auto_set_url(dev_hid_generic_inout) |  | ||||||
| @ -1,152 +0,0 @@ | |||||||
| /* 
 |  | ||||||
|  * The MIT License (MIT) |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) |  | ||||||
|  * |  | ||||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
|  * of this software and associated documentation files (the "Software"), to deal |  | ||||||
|  * in the Software without restriction, including without limitation the rights |  | ||||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
|  * copies of the Software, and to permit persons to whom the Software is |  | ||||||
|  * furnished to do so, subject to the following conditions: |  | ||||||
|  * |  | ||||||
|  * The above copyright notice and this permission notice shall be included in |  | ||||||
|  * all copies or substantial portions of the Software. |  | ||||||
|  * |  | ||||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |  | ||||||
|  * THE SOFTWARE. |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <string.h> |  | ||||||
| 
 |  | ||||||
| #include "bsp/board.h" |  | ||||||
| #include "tusb.h" |  | ||||||
| 
 |  | ||||||
| /* This example demonstrate HID Generic raw Input & Output.
 |  | ||||||
|  * It will receive data from Host (In endpoint) and echo back (Out endpoint). |  | ||||||
|  * HID Report descriptor use vendor for usage page (using template TUD_HID_REPORT_DESC_GENERIC_INOUT) |  | ||||||
|  * |  | ||||||
|  * There are 2 ways to test the sketch |  | ||||||
|  * 1. Using nodejs |  | ||||||
|  *    - Install nodejs and npm to your PC |  | ||||||
|  *    - Install excellent node-hid (https://github.com/node-hid/node-hid) by
 |  | ||||||
|  *      $ npm install node-hid |  | ||||||
|  *    - Run provided hid test script |  | ||||||
|  *      $ node hid_test.js |  | ||||||
|  * |  | ||||||
|  * 2. Using python hidRun |  | ||||||
|  *    - Python and `hid` package is required, for installation please follow https://pypi.org/project/hid/
 |  | ||||||
|  *    - Run provided hid test script to send and receive data to this device. |  | ||||||
|  *      $ python3 hid_test.py |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // MACRO CONSTANT TYPEDEF PROTYPES
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| /* Blink pattern
 |  | ||||||
|  * - 250 ms  : device not mounted |  | ||||||
|  * - 1000 ms : device mounted |  | ||||||
|  * - 2500 ms : device is suspended |  | ||||||
|  */ |  | ||||||
| enum { |  | ||||||
|     BLINK_NOT_MOUNTED = 250, |  | ||||||
|     BLINK_MOUNTED = 1000, |  | ||||||
|     BLINK_SUSPENDED = 2500, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; |  | ||||||
| 
 |  | ||||||
| void led_blinking_task(void); |  | ||||||
| 
 |  | ||||||
| /*------------- MAIN -------------*/ |  | ||||||
| int main(void) { |  | ||||||
|     board_init(); |  | ||||||
| 
 |  | ||||||
|     tusb_init(); |  | ||||||
| 
 |  | ||||||
|     while (1) { |  | ||||||
|         tud_task(); // tinyusb device task
 |  | ||||||
|         led_blinking_task(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // Device callbacks
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| // Invoked when device is mounted
 |  | ||||||
| void tud_mount_cb(void) { |  | ||||||
|     blink_interval_ms = BLINK_MOUNTED; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Invoked when device is unmounted
 |  | ||||||
| void tud_umount_cb(void) { |  | ||||||
|     blink_interval_ms = BLINK_NOT_MOUNTED; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Invoked when usb bus is suspended
 |  | ||||||
| // remote_wakeup_en : if host allow us  to perform remote wakeup
 |  | ||||||
| // Within 7ms, device must draw an average of current less than 2.5 mA from bus
 |  | ||||||
| void tud_suspend_cb(bool remote_wakeup_en) { |  | ||||||
|     (void) remote_wakeup_en; |  | ||||||
|     blink_interval_ms = BLINK_SUSPENDED; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Invoked when usb bus is resumed
 |  | ||||||
| void tud_resume_cb(void) { |  | ||||||
|     blink_interval_ms = BLINK_MOUNTED; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // USB HID
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| // Invoked when received GET_REPORT control request
 |  | ||||||
| // Application must fill buffer report's content and return its length.
 |  | ||||||
| // Return zero will cause the stack to STALL request
 |  | ||||||
| uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { |  | ||||||
|     // TODO not Implemented
 |  | ||||||
|     (void) report_id; |  | ||||||
|     (void) report_type; |  | ||||||
|     (void) buffer; |  | ||||||
|     (void) reqlen; |  | ||||||
| 
 |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Invoked when received SET_REPORT control request or
 |  | ||||||
| // received data on OUT endpoint ( Report ID = 0, Type = 0 )
 |  | ||||||
| void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) { |  | ||||||
|     // This example doesn't use multiple report and report ID
 |  | ||||||
|     (void) report_id; |  | ||||||
|     (void) report_type; |  | ||||||
| 
 |  | ||||||
|     // echo back anything we received from host
 |  | ||||||
|     tud_hid_report(0, buffer, bufsize); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // BLINKING TASK
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| void led_blinking_task(void) { |  | ||||||
|     static uint32_t start_ms = 0; |  | ||||||
|     static bool led_state = false; |  | ||||||
| 
 |  | ||||||
|     // Blink every interval ms
 |  | ||||||
|     if (board_millis() - start_ms < blink_interval_ms) return; // not enough time
 |  | ||||||
|     start_ms += blink_interval_ms; |  | ||||||
| 
 |  | ||||||
|     board_led_write(led_state); |  | ||||||
|     led_state = 1 - led_state; // toggle
 |  | ||||||
| } |  | ||||||
| @ -1,93 +0,0 @@ | |||||||
| /*
 |  | ||||||
|  * The MIT License (MIT) |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) |  | ||||||
|  * |  | ||||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
|  * of this software and associated documentation files (the "Software"), to deal |  | ||||||
|  * in the Software without restriction, including without limitation the rights |  | ||||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
|  * copies of the Software, and to permit persons to whom the Software is |  | ||||||
|  * furnished to do so, subject to the following conditions: |  | ||||||
|  * |  | ||||||
|  * The above copyright notice and this permission notice shall be included in |  | ||||||
|  * all copies or substantial portions of the Software. |  | ||||||
|  * |  | ||||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |  | ||||||
|  * THE SOFTWARE. |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #ifndef _TUSB_CONFIG_H_ |  | ||||||
| #define _TUSB_CONFIG_H_ |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| extern "C" { |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| // COMMON CONFIGURATION
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| 
 |  | ||||||
| // defined by compiler flags for flexibility
 |  | ||||||
| #ifndef CFG_TUSB_MCU |  | ||||||
| #error CFG_TUSB_MCU must be defined |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \ |  | ||||||
|     CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 |  | ||||||
| #define CFG_TUSB_RHPORT0_MODE     (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED) |  | ||||||
| #else |  | ||||||
| #define CFG_TUSB_RHPORT0_MODE     OPT_MODE_DEVICE |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifndef CFG_TUSB_OS |  | ||||||
| #define CFG_TUSB_OS                 OPT_OS_PICO |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| // CFG_TUSB_DEBUG is defined by compiler in DEBUG build
 |  | ||||||
| // #define CFG_TUSB_DEBUG           0
 |  | ||||||
| 
 |  | ||||||
| /* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
 |  | ||||||
|  * Tinyusb use follows macros to declare transferring memory so that they can be put |  | ||||||
|  * into those specific section. |  | ||||||
|  * e.g |  | ||||||
|  * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) |  | ||||||
|  * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4))) |  | ||||||
|  */ |  | ||||||
| #ifndef CFG_TUSB_MEM_SECTION |  | ||||||
| #define CFG_TUSB_MEM_SECTION |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifndef CFG_TUSB_MEM_ALIGN |  | ||||||
| #define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4))) |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| // DEVICE CONFIGURATION
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| 
 |  | ||||||
| #ifndef CFG_TUD_ENDPOINT0_SIZE |  | ||||||
| #define CFG_TUD_ENDPOINT0_SIZE    64 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| //------------- CLASS -------------//
 |  | ||||||
| #define CFG_TUD_CDC             0 |  | ||||||
| #define CFG_TUD_MSC             0 |  | ||||||
| #define CFG_TUD_HID             1 |  | ||||||
| #define CFG_TUD_MIDI            0 |  | ||||||
| #define CFG_TUD_VENDOR          0 |  | ||||||
| 
 |  | ||||||
| // HID buffer size Should be sufficient to hold ID (if any) + Data
 |  | ||||||
| #define CFG_TUD_HID_BUFSIZE     64 |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #endif /* _TUSB_CONFIG_H_ */ |  | ||||||
| @ -1,160 +0,0 @@ | |||||||
| /* 
 |  | ||||||
|  * The MIT License (MIT) |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) |  | ||||||
|  * |  | ||||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
|  * of this software and associated documentation files (the "Software"), to deal |  | ||||||
|  * in the Software without restriction, including without limitation the rights |  | ||||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
|  * copies of the Software, and to permit persons to whom the Software is |  | ||||||
|  * furnished to do so, subject to the following conditions: |  | ||||||
|  * |  | ||||||
|  * The above copyright notice and this permission notice shall be included in |  | ||||||
|  * all copies or substantial portions of the Software. |  | ||||||
|  * |  | ||||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |  | ||||||
|  * THE SOFTWARE. |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #include "tusb.h" |  | ||||||
| 
 |  | ||||||
| /* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
 |  | ||||||
|  * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. |  | ||||||
|  * |  | ||||||
|  * Auto ProductID layout's Bitmap: |  | ||||||
|  *   [MSB]         HID | MSC | CDC          [LSB] |  | ||||||
|  */ |  | ||||||
| #define _PID_MAP(itf, n)  ( (CFG_TUD_##itf) << (n) ) |  | ||||||
| #define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ |  | ||||||
|                            _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // Device Descriptors
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| tusb_desc_device_t const desc_device = |  | ||||||
|         { |  | ||||||
|                 .bLength            = sizeof(tusb_desc_device_t), |  | ||||||
|                 .bDescriptorType    = TUSB_DESC_DEVICE, |  | ||||||
|                 .bcdUSB             = 0x0200, |  | ||||||
|                 .bDeviceClass       = 0x00, |  | ||||||
|                 .bDeviceSubClass    = 0x00, |  | ||||||
|                 .bDeviceProtocol    = 0x00, |  | ||||||
|                 .bMaxPacketSize0    = CFG_TUD_ENDPOINT0_SIZE, |  | ||||||
| 
 |  | ||||||
|                 .idVendor           = 0xCafe, |  | ||||||
|                 .idProduct          = USB_PID, |  | ||||||
|                 .bcdDevice          = 0x0100, |  | ||||||
| 
 |  | ||||||
|                 .iManufacturer      = 0x01, |  | ||||||
|                 .iProduct           = 0x02, |  | ||||||
|                 .iSerialNumber      = 0x03, |  | ||||||
| 
 |  | ||||||
|                 .bNumConfigurations = 0x01 |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
| // Invoked when received GET DEVICE DESCRIPTOR
 |  | ||||||
| // Application return pointer to descriptor
 |  | ||||||
| uint8_t const *tud_descriptor_device_cb(void) { |  | ||||||
|     return (uint8_t const *) &desc_device; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // HID Report Descriptor
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| uint8_t const desc_hid_report[] = |  | ||||||
|         { |  | ||||||
|                 TUD_HID_REPORT_DESC_GENERIC_INOUT(CFG_TUD_HID_BUFSIZE) |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
| // Invoked when received GET HID REPORT DESCRIPTOR
 |  | ||||||
| // Application return pointer to descriptor
 |  | ||||||
| // Descriptor contents must exist long enough for transfer to complete
 |  | ||||||
| uint8_t const *tud_hid_descriptor_report_cb(void) { |  | ||||||
|     return desc_hid_report; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // Configuration Descriptor
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| enum { |  | ||||||
|     ITF_NUM_HID, |  | ||||||
|     ITF_NUM_TOTAL |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| #define  CONFIG_TOTAL_LEN  (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN) |  | ||||||
| 
 |  | ||||||
| #define EPNUM_HID   0x01 |  | ||||||
| 
 |  | ||||||
| uint8_t const desc_configuration[] = |  | ||||||
|         { |  | ||||||
|                 // Config number, interface count, string index, total length, attribute, power in mA
 |  | ||||||
|                 TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), |  | ||||||
| 
 |  | ||||||
|                 // Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
 |  | ||||||
|                 TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID, 0, HID_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, |  | ||||||
|                                          0x80 | EPNUM_HID, CFG_TUD_HID_BUFSIZE, 10) |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
| // Invoked when received GET CONFIGURATION DESCRIPTOR
 |  | ||||||
| // Application return pointer to descriptor
 |  | ||||||
| // Descriptor contents must exist long enough for transfer to complete
 |  | ||||||
| uint8_t const *tud_descriptor_configuration_cb(uint8_t index) { |  | ||||||
|     (void) index; // for multiple configurations
 |  | ||||||
|     return desc_configuration; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // String Descriptors
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| 
 |  | ||||||
| // array of pointer to string descriptors
 |  | ||||||
| char const *string_desc_arr[] = |  | ||||||
|         { |  | ||||||
|                 (const char[]) {0x09, 0x04}, // 0: is supported language is English (0x0409)
 |  | ||||||
|                 "TinyUSB",                     // 1: Manufacturer
 |  | ||||||
|                 "TinyUSB Device",              // 2: Product
 |  | ||||||
|                 "123456",                      // 3: Serials, should use chip ID
 |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
| static uint16_t _desc_str[32]; |  | ||||||
| 
 |  | ||||||
| // Invoked when received GET STRING DESCRIPTOR request
 |  | ||||||
| // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
 |  | ||||||
| uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { |  | ||||||
|     (void) langid; |  | ||||||
| 
 |  | ||||||
|     uint8_t chr_count; |  | ||||||
| 
 |  | ||||||
|     if (index == 0) { |  | ||||||
|         memcpy(&_desc_str[1], string_desc_arr[0], 2); |  | ||||||
|         chr_count = 1; |  | ||||||
|     } else { |  | ||||||
|         // Convert ASCII string into UTF-16
 |  | ||||||
| 
 |  | ||||||
|         if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0]))) return NULL; |  | ||||||
| 
 |  | ||||||
|         const char *str = string_desc_arr[index]; |  | ||||||
| 
 |  | ||||||
|         // Cap at max char
 |  | ||||||
|         chr_count = strlen(str); |  | ||||||
|         if (chr_count > 31) chr_count = 31; |  | ||||||
| 
 |  | ||||||
|         for (uint8_t i = 0; i < chr_count; i++) { |  | ||||||
|             _desc_str[1 + i] = str[i]; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // first byte is length (including header), second byte is string type
 |  | ||||||
|     _desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2); |  | ||||||
| 
 |  | ||||||
|     return _desc_str; |  | ||||||
| } |  | ||||||
| @ -1 +1,4 @@ | |||||||
| add_subdirectory(host_hid) | set(FAMILY rp2040) | ||||||
|  | set(BOARD pico_sdk) | ||||||
|  | set(TINYUSB_FAMILY_PROJECT_NAME_PREFIX "tinyusb_host_") | ||||||
|  | add_subdirectory(${PICO_TINYUSB_PATH}/examples/host tinyusb_host_examples) | ||||||
|  | |||||||
| @ -1,10 +0,0 @@ | |||||||
| add_executable(host_hid |  | ||||||
|         host_hid.c |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
| target_include_directories(host_hid PRIVATE ${CMAKE_CURRENT_LIST_DIR}) |  | ||||||
| target_link_libraries(host_hid PRIVATE pico_stdlib tinyusb_host tinyusb_board) |  | ||||||
| pico_add_extra_outputs(host_hid) |  | ||||||
| 
 |  | ||||||
| # add url via pico_set_program_url |  | ||||||
| example_auto_set_url(host_hid) |  | ||||||
| @ -1,228 +0,0 @@ | |||||||
| /* 
 |  | ||||||
|  * The MIT License (MIT) |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) |  | ||||||
|  * |  | ||||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
|  * of this software and associated documentation files (the "Software"), to deal |  | ||||||
|  * in the Software without restriction, including without limitation the rights |  | ||||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
|  * copies of the Software, and to permit persons to whom the Software is |  | ||||||
|  * furnished to do so, subject to the following conditions: |  | ||||||
|  * |  | ||||||
|  * The above copyright notice and this permission notice shall be included in |  | ||||||
|  * all copies or substantial portions of the Software. |  | ||||||
|  * |  | ||||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |  | ||||||
|  * THE SOFTWARE. |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <string.h> |  | ||||||
| 
 |  | ||||||
| #include "bsp/board.h" |  | ||||||
| #include "tusb.h" |  | ||||||
| 
 |  | ||||||
| void print_greeting(void); |  | ||||||
| void led_blinking_task(void); |  | ||||||
| extern void hid_task(void); |  | ||||||
| 
 |  | ||||||
| int main(void) { |  | ||||||
|     board_init(); |  | ||||||
|     print_greeting(); |  | ||||||
| 
 |  | ||||||
|     tusb_init(); |  | ||||||
| 
 |  | ||||||
|     while (1) { |  | ||||||
|         // tinyusb host task
 |  | ||||||
|         tuh_task(); |  | ||||||
|         led_blinking_task(); |  | ||||||
| 
 |  | ||||||
| #if CFG_TUH_HID_KEYBOARD || CFG_TUH_HID_MOUSE |  | ||||||
|         hid_task(); |  | ||||||
| #endif |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // USB HID
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| #if CFG_TUH_HID_KEYBOARD |  | ||||||
| 
 |  | ||||||
| CFG_TUSB_MEM_SECTION static hid_keyboard_report_t usb_keyboard_report; |  | ||||||
| uint8_t const keycode2ascii[128][2] = {HID_KEYCODE_TO_ASCII}; |  | ||||||
| 
 |  | ||||||
| // look up new key in previous keys
 |  | ||||||
| static inline bool find_key_in_report(hid_keyboard_report_t const *p_report, uint8_t keycode) { |  | ||||||
|     for (uint8_t i = 0; i < 6; i++) { |  | ||||||
|         if (p_report->keycode[i] == keycode) return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline void process_kbd_report(hid_keyboard_report_t const *p_new_report) { |  | ||||||
|     static hid_keyboard_report_t prev_report = {0, 0, {0}}; // previous report to check key released
 |  | ||||||
| 
 |  | ||||||
|     //------------- example code ignore control (non-printable) key affects -------------//
 |  | ||||||
|     for (uint8_t i = 0; i < 6; i++) { |  | ||||||
|         if (p_new_report->keycode[i]) { |  | ||||||
|             if (find_key_in_report(&prev_report, p_new_report->keycode[i])) { |  | ||||||
|                 // exist in previous report means the current key is holding
 |  | ||||||
|             } else { |  | ||||||
|                 // not existed in previous report means the current key is pressed
 |  | ||||||
|                 bool const is_shift = |  | ||||||
|                         p_new_report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT); |  | ||||||
|                 uint8_t ch = keycode2ascii[p_new_report->keycode[i]][is_shift ? 1 : 0]; |  | ||||||
|                 putchar(ch); |  | ||||||
|                 if (ch == '\r') putchar('\n'); // added new line for enter key
 |  | ||||||
| 
 |  | ||||||
|                 fflush(stdout); // flush right away, else nanolib will wait for newline
 |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         // TODO example skips key released
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     prev_report = *p_new_report; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void tuh_hid_keyboard_mounted_cb(uint8_t dev_addr) { |  | ||||||
|     // application set-up
 |  | ||||||
|     printf("A Keyboard device (address %d) is mounted\r\n", dev_addr); |  | ||||||
| 
 |  | ||||||
|     tuh_hid_keyboard_get_report(dev_addr, &usb_keyboard_report); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void tuh_hid_keyboard_unmounted_cb(uint8_t dev_addr) { |  | ||||||
|     // application tear-down
 |  | ||||||
|     printf("A Keyboard device (address %d) is unmounted\r\n", dev_addr); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // invoked ISR context
 |  | ||||||
| void tuh_hid_keyboard_isr(uint8_t dev_addr, xfer_result_t event) { |  | ||||||
|     (void) dev_addr; |  | ||||||
|     (void) event; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if CFG_TUH_HID_MOUSE |  | ||||||
| 
 |  | ||||||
| CFG_TUSB_MEM_SECTION static hid_mouse_report_t usb_mouse_report; |  | ||||||
| 
 |  | ||||||
| void cursor_movement(int8_t x, int8_t y, int8_t wheel) { |  | ||||||
|     //------------- X -------------//
 |  | ||||||
|     if (x < 0) { |  | ||||||
|         printf(ANSI_CURSOR_BACKWARD(%d), (-x)); // move left
 |  | ||||||
|     } else if (x > 0) { |  | ||||||
|         printf(ANSI_CURSOR_FORWARD(%d), x); // move right
 |  | ||||||
|     } else {} |  | ||||||
| 
 |  | ||||||
|     //------------- Y -------------//
 |  | ||||||
|     if (y < 0) { |  | ||||||
|         printf(ANSI_CURSOR_UP(%d), (-y)); // move up
 |  | ||||||
|     } else if (y > 0) { |  | ||||||
|         printf(ANSI_CURSOR_DOWN(%d), y); // move down
 |  | ||||||
|     } else {} |  | ||||||
| 
 |  | ||||||
|     //------------- wheel -------------//
 |  | ||||||
|     if (wheel < 0) { |  | ||||||
|         printf(ANSI_SCROLL_UP(%d), (-wheel)); // scroll up
 |  | ||||||
|     } else if (wheel > 0) { |  | ||||||
|         printf(ANSI_SCROLL_DOWN(%d), wheel); // scroll down
 |  | ||||||
|     } else {} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline void process_mouse_report(hid_mouse_report_t const *p_report) { |  | ||||||
|     static hid_mouse_report_t prev_report = {0}; |  | ||||||
| 
 |  | ||||||
|     //------------- button state  -------------//
 |  | ||||||
|     uint8_t button_changed_mask = p_report->buttons ^prev_report.buttons; |  | ||||||
|     if (button_changed_mask & p_report->buttons) { |  | ||||||
|         printf(" %c%c%c ", |  | ||||||
|                p_report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-', |  | ||||||
|                p_report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-', |  | ||||||
|                p_report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-'); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     //------------- cursor movement -------------//
 |  | ||||||
|     cursor_movement(p_report->x, p_report->y, p_report->wheel); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| void tuh_hid_mouse_mounted_cb(uint8_t dev_addr) { |  | ||||||
|     // application set-up
 |  | ||||||
|     printf("A Mouse device (address %d) is mounted\r\n", dev_addr); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void tuh_hid_mouse_unmounted_cb(uint8_t dev_addr) { |  | ||||||
|     // application tear-down
 |  | ||||||
|     printf("A Mouse device (address %d) is unmounted\r\n", dev_addr); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // invoked ISR context
 |  | ||||||
| void tuh_hid_mouse_isr(uint8_t dev_addr, xfer_result_t event) { |  | ||||||
|     (void) dev_addr; |  | ||||||
|     (void) event; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| void hid_task(void) { |  | ||||||
|     uint8_t const addr = 1; |  | ||||||
| 
 |  | ||||||
| #if CFG_TUH_HID_KEYBOARD |  | ||||||
|     if (tuh_hid_keyboard_is_mounted(addr)) { |  | ||||||
|         if (!tuh_hid_keyboard_is_busy(addr)) { |  | ||||||
|             process_kbd_report(&usb_keyboard_report); |  | ||||||
|             tuh_hid_keyboard_get_report(addr, &usb_keyboard_report); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if CFG_TUH_HID_MOUSE |  | ||||||
|     if (tuh_hid_mouse_is_mounted(addr)) { |  | ||||||
|         if (!tuh_hid_mouse_is_busy(addr)) { |  | ||||||
|             process_mouse_report(&usb_mouse_report); |  | ||||||
|             tuh_hid_mouse_get_report(addr, &usb_mouse_report); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // BLINKING TASK
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| void led_blinking_task(void) { |  | ||||||
|     const uint32_t interval_ms = 250; |  | ||||||
|     static uint32_t start_ms = 0; |  | ||||||
| 
 |  | ||||||
|     static bool led_state = false; |  | ||||||
| 
 |  | ||||||
|     // Blink every interval ms
 |  | ||||||
|     if (board_millis() - start_ms < interval_ms) return; // not enough time
 |  | ||||||
|     start_ms += interval_ms; |  | ||||||
| 
 |  | ||||||
|     board_led_write(led_state); |  | ||||||
|     led_state = 1 - led_state; // toggle
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| // HELPER FUNCTION
 |  | ||||||
| //--------------------------------------------------------------------+
 |  | ||||||
| void print_greeting(void) { |  | ||||||
|     printf("This Host demo is configured to support:\n"); |  | ||||||
|     if (CFG_TUH_HID_KEYBOARD) puts("  - HID Keyboard"); |  | ||||||
|     if (CFG_TUH_HID_MOUSE) puts("  - HID Mouse"); |  | ||||||
| } |  | ||||||
| @ -1,73 +0,0 @@ | |||||||
| /* 
 |  | ||||||
|  * The MIT License (MIT) |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) |  | ||||||
|  * |  | ||||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
|  * of this software and associated documentation files (the "Software"), to deal |  | ||||||
|  * in the Software without restriction, including without limitation the rights |  | ||||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
|  * copies of the Software, and to permit persons to whom the Software is |  | ||||||
|  * furnished to do so, subject to the following conditions: |  | ||||||
|  * |  | ||||||
|  * The above copyright notice and this permission notice shall be included in |  | ||||||
|  * all copies or substantial portions of the Software. |  | ||||||
|  * |  | ||||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |  | ||||||
|  * THE SOFTWARE. |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #ifndef _TUSB_CONFIG_H_ |  | ||||||
| #define _TUSB_CONFIG_H_ |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| extern "C" { |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| // COMMON CONFIGURATION
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| 
 |  | ||||||
| // defined by compiler flags for flexibility
 |  | ||||||
| #ifndef CFG_TUSB_MCU |  | ||||||
| #error CFG_TUSB_MCU must be defined |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX |  | ||||||
| #define CFG_TUSB_RHPORT0_MODE       (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED) |  | ||||||
| #else |  | ||||||
| #define CFG_TUSB_RHPORT0_MODE       OPT_MODE_HOST |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifndef CFG_TUSB_MEM_SECTION |  | ||||||
| #define CFG_TUSB_MEM_SECTION |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifndef CFG_TUSB_MEM_ALIGN |  | ||||||
| #define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4))) |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| // CONFIGURATION
 |  | ||||||
| //--------------------------------------------------------------------
 |  | ||||||
| 
 |  | ||||||
| #define CFG_TUH_HUB                 1 |  | ||||||
| #define CFG_TUH_HID_KEYBOARD        1 |  | ||||||
| #define CFG_TUH_HID_MOUSE           1 |  | ||||||
| #define CFG_TUSB_HOST_HID_GENERIC   0 // (not yet supported)
 |  | ||||||
| #define CFG_TUH_MSC                 0 |  | ||||||
| #define CFG_TUH_CDC                 0 |  | ||||||
| 
 |  | ||||||
| #define CFG_TUSB_HOST_DEVICE_MAX    (CFG_TUH_HUB ? 5 : 1) // normal hub has 4 ports
 |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #endif /* _TUSB_CONFIG_H_ */ |  | ||||||
		Reference in New Issue
	
	Block a user