diff --git a/CHANGELOG.md b/CHANGELOG.md index a737203e4..9500c727c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,9 @@ - UL: KeeLoq display decrypted `Hop` instead of showing encrypted as is (encrypted non byte reversed hop is still displayed in `Key` field) (by @xMasterX) - UL: BFT KeeLoq try decoding with zero seed too (by @xMasterX) - UL: KeeLoq display BFT programming mode TX (when arrow button is held) (by @xMasterX) + - UL: Signal Settings Improvements (by @Dmitry422) - Archive: Support opening and pinning ProtoPirate files from Archive (#510 by @LeeroysHub) +- OFW: API: Make `view_port_send_to_back()` public (by @loftyinclination) ### Fixed: - Sub-GHz: @@ -58,6 +60,7 @@ - UL: Fix LED not blinking at SLIX unlock (by @xMasterX) - UL: Settings: Storage settings exit scenes properly if used via favourites (by @xMasterX) - UL: UI: Some small changes (by @xMasterX) +- OFW: USB: Fix USB HID keyboard LED state reporting (by @Caballosanex) ### Removed: - Sub-GHz: diff --git a/applications/main/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h index c4c36e220..9a965d6de 100644 --- a/applications/main/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -10,6 +10,7 @@ typedef enum { SubGhzNotificationStateTx, SubGhzNotificationStateRx, SubGhzNotificationStateRxDone, + SubGhzNotificationStateTxWait, } SubGhzNotificationState; /** SubGhzTxRx state */ diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 4c1e3a0e5..95c2de162 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -167,7 +167,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) // user release OK // we switch off endless_tx - that mean protocols yield finish endless transmission, // send upload "repeat=xx" times, and after will be stoped by the tick event down in this code - subghz->state_notifications = SubGhzNotificationStateIDLE; + subghz->state_notifications = SubGhzNotificationStateTxWait; subghz_block_generic_global.endless_tx = false; return true; @@ -222,7 +222,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) notification_message(subghz->notifications, &sequence_blink_green_100); subghz->state_notifications = SubGhzNotificationStateRx; break; - case SubGhzNotificationStateIDLE: + case SubGhzNotificationStateTxWait: // we wait until hardware TX finished and after stop TX and start RX, else just blink led if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) { notification_message(subghz->notifications, &sequence_blink_magenta_10); @@ -232,6 +232,8 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) widget_reset(subghz->widget); subghz_scene_receiver_info_draw_widget(subghz); + subghz->state_notifications = SubGhzNotificationStateIDLE; + if(!scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneDecodeRAW)) { subghz_txrx_rx_start(subghz->txrx); subghz_txrx_hopper_unpause(subghz->txrx); diff --git a/applications/main/subghz/scenes/subghz_scene_signal_settings.c b/applications/main/subghz/scenes/subghz_scene_signal_settings.c index 90f99e50c..9b582d2ee 100644 --- a/applications/main/subghz/scenes/subghz_scene_signal_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_signal_settings.c @@ -65,6 +65,38 @@ void subghz_scene_signal_settings_counter_mode_changed(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, counter_mode_text[index]); counter_mode = counter_mode_value[index]; + + SubGhz* subghz = variable_item_get_context(item); + const char* file_path = furi_string_get_cstr(subghz->file_path); + + furi_assert(subghz); + furi_assert(file_path); + + // update file every time when we change mode + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); + + // check is the file available for update/insert CounterMode value + if(flipper_format_file_open_existing(fff_data_file, file_path)) { + if(flipper_format_insert_or_update_uint32(fff_data_file, "CounterMode", &counter_mode, 1)) { + FURI_LOG_D(TAG, "Successfully updated/inserted CounterMode value %li", counter_mode); + } else { + FURI_LOG_E(TAG, "Error update/insert CounterMode value"); + } + } else { + FURI_LOG_E(TAG, "Error open file %s for writing", file_path); + } + + flipper_format_file_close(fff_data_file); + flipper_format_free(fff_data_file); + furi_record_close(RECORD_STORAGE); + + // we need to reload file after editing it + if(subghz_key_load(subghz, file_path, false)) { + FURI_LOG_D(TAG, "Subghz file was successfully reloaded"); + } else { + FURI_LOG_E(TAG, "Error reloading subghz file"); + } } void subghz_scene_signal_settings_byte_input_callback(void* context) { @@ -311,40 +343,8 @@ bool subghz_scene_signal_settings_on_event(void* context, SceneManagerEvent even void subghz_scene_signal_settings_on_exit(void* context) { SubGhz* subghz = context; - const char* file_path = furi_string_get_cstr(subghz->file_path); furi_assert(subghz); - furi_assert(file_path); - - // if ConterMode was changed from 0xff then we must update or write new value to file - if(counter_mode != 0xff) { - Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - - // check is the file available for update/insert CounterMode value - if(flipper_format_file_open_existing(fff_data_file, file_path)) { - if(flipper_format_insert_or_update_uint32( - fff_data_file, "CounterMode", &counter_mode, 1)) { - FURI_LOG_D( - TAG, "Successfully updated/inserted CounterMode value %li", counter_mode); - } else { - FURI_LOG_E(TAG, "Error update/insert CounterMode value"); - } - } else { - FURI_LOG_E(TAG, "Error open file %s for writing", file_path); - } - - flipper_format_file_close(fff_data_file); - flipper_format_free(fff_data_file); - furi_record_close(RECORD_STORAGE); - - // we need to reload file after editing when we exit from Signal Settings menu. - if(subghz_key_load(subghz, file_path, false)) { - FURI_LOG_D(TAG, "Subghz file was successfully reloaded"); - } else { - FURI_LOG_E(TAG, "Error reloading subghz file"); - } - } // Clear views variable_item_list_set_selected_item(subghz->variable_item_list, 0); diff --git a/documentation/SubGHzSupportedSystems.md b/documentation/SubGHzSupportedSystems.md index f950cf150..f37fb64cb 100644 --- a/documentation/SubGHzSupportedSystems.md +++ b/documentation/SubGHzSupportedSystems.md @@ -24,7 +24,7 @@ That list is only for default SubGHz app, apps like *Weather Station* have their - AN-Motors (Alutech) AT4 `433.92MHz` `AM650` (64 bits, Pseudo-Dynamic, KeeLoq based) - Ansonic `433MHz` `FM` (12 bits, Static) - BETT `433.92MHz` `AM650` (18 bits, Static) -- Beninca ARC (TOGO2VA) `433.92MHz` `AM650` (128 bits, Dynamic AES) (button code `0` emulates `hidden button` option on the remote) +- Beninca ARC (TOGO2VA) `433.92MHz` `AM650` (128 bits, Dynamic AES128) (button code `0` emulates `hidden button` option on the remote) - BFT Mitto `433.92MHz` `AM650` (64 bits, Dynamic, KeeLoq based with Seed) - CAME Atomo `433.92MHz, 868MHz` `AM650` (62 bits, Dynamic) - CAME TWEE `433.92MHz` `AM650` (54 bits, Static) @@ -36,11 +36,11 @@ That list is only for default SubGHz app, apps like *Weather Station* have their - Dickert MAHS `AM650` (36 bits, Static) - Doitrand `AM650` (37 bits, Dynamic) - Elplast/P-11B/3BK/E.C.A `433MHz` `AM650` (18 bits, Static) -- FAAC SLH `433.92MHz, 868MHz` `AM650` (64 bits, Dynamic) +- FAAC SLH `433.92MHz, 868.35MHz` `AM650` (64 bits, Dynamic) (+ Genius KILO TX2/4 JLC) - Gate TX `433.92MHz` `AM650` (64 bits, Static) - Hormann `868MHz` `AM650` (44 bits, Static) - HCS101 `AM650` (64 bits, Simple Dynamic, KeeLoq-like) -- IDO `433MHz` `AM650` (48 bits, Dynamic) +- iDO `433MHz` `AM650` (48 bits, Dynamic) (Decode only) - KingGates Stylo 4k `433.92MHz` `AM650` (89 bits, Dynamic, KeeLoq based) - Mastercode `AM650` (36 bits, Static) - Megacode `AM650` (24 bits, Static) @@ -53,7 +53,7 @@ That list is only for default SubGHz app, apps like *Weather Station* have their - V2 Phoenix (Phox) `433.92MHz` `AM650` (52 bits, Dynamic) (receivers have option to enable Static mode, making them ignore rolling part of the key) - Marantec `433.92MHz, 868MHz` `AM650` (49 bits, Static) - Marantec24 `868MHz` `AM650` (24 bits, Static) -- Somfy Keytis `433.92MHz, 868MHz` `AM650` (80 bits, Dynamic) +- Somfy Keytis `433.42MHz, 868MHz` `AM650` (80 bits, Dynamic) - ZKTeco `430.5MHz` `AM650` (24 bits, Static - Princeton based) - (Button codes (already mapped to arrow keys): `0x30 (UP)`, `0x03 (STOP)`, `0x0C (DOWN)`) - Linear `300MHz` `AM650` (10 bits, Static) - Linear Delta3 `AM650` (8 bits, Static) @@ -110,7 +110,7 @@ The following manufacturers have KeeLoq support in Unleashed firmware: - DTM Neo - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - simple learning) - Elmes Poland - `433.92MHz` `AM650` (KeeLoq, 64 bits) (normal learning) - FAAC RC,XT - `433.92MHz, 868MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) -- Genius Bravo - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) +- Genius Bravo - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) (Genius ECHO, Genius Bravo (Button code 0xB for prog. mode)) - Gibidi - `433.92MHz` `AM650` (KeeLoq, 64 bits) - GSN - `433.92MHz` `AM650` (KeeLoq, 64 bits) (12bit serial part in Hop - normal learning) - Hormann EcoStar - `433.92MHz` `AM650` (KeeLoq, 64 bits) (normal learning) diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index a63d6a65c..3e7775b26 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -12,6 +12,9 @@ #define SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE 0xFFFFFFFFFFFFFFFF #define SUBGHZ_ALUTECH_AT_4N_RAINBOW_TABLE_SIZE_BYTES 32 +//variable used to bypass CounterMode settings if user just change Counter or Button +static bool bypass = false; + static const SubGhzBlockConst subghz_protocol_alutech_at_4n_const = { .te_short = 400, .te_long = 800, @@ -295,9 +298,13 @@ static bool subghz_protocol_alutech_at_4n_gen_data( instance->generic.serial = (uint32_t)(data >> 24) & 0xFFFFFFFF; } - if(alutech_at4n_counter_mode == 0) { + // if we change counter/button in SignalSettings menu then we must bypass counter_modes, just gen and save signal file. + if(subghz_block_generic_global.cnt_need_override) bypass = true; + + if((alutech_at4n_counter_mode == 0) || bypass) { // Check for OFEX (overflow experimental) mode - if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { + if((furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) || bypass) { + bypass = false; // standart counter mode. PULL data from subghz_block_generic_global variables if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value @@ -403,8 +410,10 @@ static bool subghz_protocol_encoder_alutech_at_4n_get_upload( btn = subghz_protocol_alutech_at_4n_get_btn_code(); // override button if we change it with signal settings button editor - if(subghz_block_generic_global_button_override_get(&btn)) + if(subghz_block_generic_global_button_override_get(&btn)) { + bypass = true; FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); + } // Gen new key if(!subghz_protocol_alutech_at_4n_gen_data(instance, btn)) { diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index 5fd5602d1..539847b14 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -11,6 +11,9 @@ #define TAG "SubGhzProtocoCameAtomo" +//variable used to bypass CounterMode settings if user just change Counter or Button +static bool bypass = false; + static const SubGhzBlockConst subghz_protocol_came_atomo_const = { .te_short = 600, .te_long = 1200, @@ -189,9 +192,15 @@ static void subghz_protocol_encoder_came_atomo_get_upload( uint8_t pack[8] = {}; - if(came_atomo_counter_mode == 0) { + // if we change counter/button in SignalSettings menu then we must bypass counter_modes, just gen and save signal file. + if(subghz_block_generic_global.cnt_need_override || + subghz_block_generic_global.btn_need_override) + bypass = true; + + if(came_atomo_counter_mode == 0 || bypass) { // Check for OFEX (overflow experimental) mode - if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { + if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF || bypass) { + bypass = false; // standart counter mode. PULL data from subghz_block_generic_global variables if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 0ea1c40ea..31a655fc6 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -15,10 +15,13 @@ #define TAG "SubGhzProtocolKeeloq" +//variable used to bypass CounterMode settings if user just change Counter or Button +static bool bypass = false; + static const SubGhzBlockConst subghz_protocol_keeloq_const = { .te_short = 400, .te_long = 800, - .te_delta = 140, + .te_delta = 180, .min_count_bit_for_found = 64, }; @@ -176,7 +179,8 @@ static bool subghz_protocol_keeloq_gen_data( } else if( (strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) || (strcmp(instance->manufacture_name, "Monarch") == 0) || - (strcmp(instance->manufacture_name, "NICE_Smilo") == 0)) { + (strcmp(instance->manufacture_name, "NICE_Smilo") == 0) || + (strcmp(instance->manufacture_name, "Genius_Bravo") == 0)) { klq_last_custom_btn = 0xB; } else if( (strcmp(instance->manufacture_name, "Novoferm") == 0) || @@ -243,9 +247,10 @@ static bool subghz_protocol_keeloq_gen_data( if(counter_up && prog_mode == PROG_MODE_OFF) { // Counter increment conditions - if(keeloq_counter_mode == 0) { + if(keeloq_counter_mode == 0 || bypass) { // Check for OFEX (overflow experimental) mode - if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { + if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF || bypass) { + bypass = false; // standart counter mode. PULL data from subghz_block_generic_global variables if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value @@ -603,7 +608,13 @@ static bool instance->encoder.size_upload = 0; size_t upindex = 0; - if(keeloq_counter_mode == 7) { + // if we change counter/button in SignalSettings menu then we must bypass counter_modes, just gen and save signal file. + if(subghz_block_generic_global.cnt_need_override || + subghz_block_generic_global.btn_need_override) + bypass = true; + + // Create mode7 upload only if counter and button was not changed by SignalSettings menu + if(keeloq_counter_mode == 7 && !bypass) { uint16_t temp_cnt = instance->generic.cnt; instance->encoder.repeat = 1; for(uint8_t i = 7; i > 0; i--) { diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index fc1d71f36..2d67caae8 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -21,6 +21,9 @@ #define SUBGHZ_NICE_FLOR_S_RAINBOW_TABLE_SIZE_BYTES 32 #define SUBGHZ_NO_NICE_FLOR_S_RAINBOW_TABLE 0 +//variable used to bypass CounterMode settings if user just change Counter or Button +static bool bypass = false; + static const SubGhzBlockConst subghz_protocol_nice_flor_s_const = { .te_short = 500, .te_long = 1000, @@ -152,8 +155,10 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload( btn = subghz_protocol_nice_flor_s_get_btn_code(); // override button if we change it with signal settings button editor - if(subghz_block_generic_global_button_override_get(&btn)) + if(subghz_block_generic_global_button_override_get(&btn)) { + bypass = true; FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); + } size_t size_upload = ((instance->generic.data_count_bit * 2) + ((37 + 2 + 2) * 2) * 16); if(size_upload > instance->encoder.size_upload) { @@ -161,9 +166,14 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload( } else { instance->encoder.size_upload = size_upload; } - if(nice_flors_counter_mode == 0) { + + // if we change counter/button in SignalSettings menu then we must bypass counter_modes, just gen and save signal file. + if(subghz_block_generic_global.cnt_need_override) bypass = true; + + if(nice_flors_counter_mode == 0 || bypass) { // Check for OFEX (overflow experimental) mode - if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { + if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF || bypass) { + bypass = false; // standart counter mode. PULL data from subghz_block_generic_global variables if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c index a64a31cbf..7e42c5bbe 100644 --- a/lib/subghz/protocols/phoenix_v2.c +++ b/lib/subghz/protocols/phoenix_v2.c @@ -10,6 +10,9 @@ #define TAG "SubGhzProtocolPhoenixV2" +//variable used to bypass CounterMode settings if user just change Counter or Button +static bool bypass = false; + static const SubGhzBlockConst subghz_protocol_phoenix_v2_const = { .te_short = 427, .te_long = 853, @@ -258,13 +261,19 @@ static bool btn = subghz_protocol_phoenix_v2_get_btn_code(); // override button if we change it with signal settings button editor - if(subghz_block_generic_global_button_override_get(&btn)) + if(subghz_block_generic_global_button_override_get(&btn)) { + bypass = true; FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn); + } // Reconstruction of the data - if(v2_phoenix_counter_mode == 0) { + // if we change counter/button in SignalSettings menu then we must bypass counter_modes, just gen and save signal file. + if(subghz_block_generic_global.cnt_need_override) bypass = true; + + if(v2_phoenix_counter_mode == 0 || bypass) { // Check for OFEX (overflow experimental) mode - if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) { + if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF || bypass) { + bypass = false; // standart counter mode. PULL data from subghz_block_generic_global variables if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) { // if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index e881adfb6..ff06eb798 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1774,7 +1774,7 @@ Function,+,gui_remove_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, Function,+,gui_remove_view_port,void,"Gui*, ViewPort*" Function,+,gui_set_lockdown,void,"Gui*, _Bool" Function,+,gui_set_lockdown_inhibit,void,"Gui*, _Bool" -Function,-,gui_view_port_send_to_back,void,"Gui*, ViewPort*" +Function,+,gui_view_port_send_to_back,void,"Gui*, ViewPort*" Function,+,gui_view_port_send_to_front,void,"Gui*, ViewPort*" Function,-,hci_send_req,int,"hci_request*, uint8_t" Function,+,hex_char_to_hex_nibble,_Bool,"char, uint8_t*" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index ba03170f8..6eb3b78bc 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -2079,7 +2079,7 @@ Function,+,gui_remove_view_port,void,"Gui*, ViewPort*" Function,+,gui_set_hide_statusbar,void,"Gui*, _Bool" Function,+,gui_set_lockdown,void,"Gui*, _Bool" Function,+,gui_set_lockdown_inhibit,void,"Gui*, _Bool" -Function,-,gui_view_port_send_to_back,void,"Gui*, ViewPort*" +Function,+,gui_view_port_send_to_back,void,"Gui*, ViewPort*" Function,+,gui_view_port_send_to_front,void,"Gui*, ViewPort*" Function,-,hci_send_req,int,"hci_request*, uint8_t" Function,+,hex_char_to_hex_nibble,_Bool,"char, uint8_t*" diff --git a/targets/f7/furi_hal/furi_hal_usb_hid.c b/targets/f7/furi_hal/furi_hal_usb_hid.c index 04f2ae400..7820ae8d2 100644 --- a/targets/f7/furi_hal/furi_hal_usb_hid.c +++ b/targets/f7/furi_hal/furi_hal_usb_hid.c @@ -7,8 +7,9 @@ #include "usb.h" #include "usb_hid.h" -#define HID_EP_IN 0x81 -#define HID_EP_SZ 0x10 +#define HID_EP_IN 0x81 +#define HID_EP_OUT 0x01 +#define HID_EP_SZ 0x10 #define HID_INTERVAL 2 @@ -16,6 +17,7 @@ struct HidIntfDescriptor { struct usb_interface_descriptor hid; struct usb_hid_descriptor hid_desc; struct usb_endpoint_descriptor hid_ep_in; + struct usb_endpoint_descriptor hid_ep_out; }; struct HidConfigDescriptor { @@ -162,7 +164,7 @@ static const struct HidConfigDescriptor hid_cfg_desc = { .bDescriptorType = USB_DTYPE_INTERFACE, .bInterfaceNumber = 0, .bAlternateSetting = 0, - .bNumEndpoints = 1, + .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_HID, .bInterfaceSubClass = USB_HID_SUBCLASS_BOOT, .bInterfaceProtocol = USB_HID_PROTO_KEYBOARD, @@ -187,6 +189,15 @@ static const struct HidConfigDescriptor hid_cfg_desc = { .wMaxPacketSize = HID_EP_SZ, .bInterval = HID_INTERVAL, }, + .hid_ep_out = + { + .bLength = sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DTYPE_ENDPOINT, + .bEndpointAddress = HID_EP_OUT, + .bmAttributes = USB_EPTYPE_INTERRUPT, + .wMaxPacketSize = HID_EP_SZ, + .bInterval = HID_INTERVAL, + }, }, }; @@ -481,13 +492,17 @@ static usbd_respond hid_ep_config(usbd_device* dev, uint8_t cfg) { switch(cfg) { case 0: /* deconfiguring device */ + usbd_ep_deconfig(dev, HID_EP_OUT); usbd_ep_deconfig(dev, HID_EP_IN); + usbd_reg_endpoint(dev, HID_EP_OUT, 0); usbd_reg_endpoint(dev, HID_EP_IN, 0); return usbd_ack; case 1: /* configuring device */ usbd_ep_config(dev, HID_EP_IN, USB_EPTYPE_INTERRUPT, HID_EP_SZ); + usbd_ep_config(dev, HID_EP_OUT, USB_EPTYPE_INTERRUPT, HID_EP_SZ); usbd_reg_endpoint(dev, HID_EP_IN, hid_txrx_ep_callback); + usbd_reg_endpoint(dev, HID_EP_OUT, hid_txrx_ep_callback); usbd_ep_write(dev, HID_EP_IN, 0, 0); boot_protocol = false; /* BIOS will SET_PROTOCOL if it wants this */ return usbd_ack;