From aa342b3ed9fc00fdc577bbc14fa92fb010b37c48 Mon Sep 17 00:00:00 2001 From: Lauszus Date: Tue, 19 Jan 2021 21:36:49 +0000 Subject: [PATCH] deploy: 5af56accc32fa8959717853e6109f3f71a037ccf --- _b_t_d_8cpp_source.html | 2 +- _b_t_d_8h.html | 19 +- _b_t_d_8h__dep__incl.map | 19 +- _b_t_d_8h__dep__incl.md5 | 2 +- _b_t_d_8h__dep__incl.png | Bin 19106 -> 20754 bytes _b_t_d_8h_source.html | 2 +- _b_t_h_i_d_8cpp_source.html | 4 +- _b_t_h_i_d_8h.html | 3 +- _b_t_h_i_d_8h__dep__incl.map | 3 +- _b_t_h_i_d_8h__dep__incl.md5 | 2 +- _b_t_h_i_d_8h__dep__incl.png | Bin 6746 -> 7455 bytes _b_t_h_i_d_8h_source.html | 2 +- _p_s3_b_t_8cpp_source.html | 36 +- _p_s3_b_t_8h_source.html | 6 +- _p_s3_u_s_b_8cpp_source.html | 14 +- _p_s3_u_s_b_8h_source.html | 6 +- _p_s4_parser_8cpp.html | 28 +- _p_s4_parser_8cpp_source.html | 2 +- _p_s4_parser_8h_source.html | 20 +- _p_s5_b_t_8h.html | 149 + _p_s5_b_t_8h__incl.map | 11 + _p_s5_b_t_8h__incl.md5 | 1 + _p_s5_b_t_8h__incl.png | Bin 0 -> 30714 bytes _p_s5_b_t_8h_source.html | 114 + _p_s5_parser_8cpp.html | 177 ++ _p_s5_parser_8cpp__incl.map | 6 + _p_s5_parser_8cpp__incl.md5 | 1 + _p_s5_parser_8cpp__incl.png | Bin 0 -> 10854 bytes _p_s5_parser_8cpp_source.html | 126 + _p_s5_parser_8h.html | 145 + _p_s5_parser_8h__dep__incl.map | 5 + _p_s5_parser_8h__dep__incl.md5 | 1 + _p_s5_parser_8h__dep__incl.png | Bin 0 -> 5762 bytes _p_s5_parser_8h__incl.map | 5 + _p_s5_parser_8h__incl.md5 | 1 + _p_s5_parser_8h__incl.png | Bin 0 -> 9787 bytes _p_s5_parser_8h_source.html | 165 + _p_s5_trigger_8cpp.html | 100 + _p_s5_trigger_8cpp__incl.map | 3 + _p_s5_trigger_8cpp__incl.md5 | 1 + _p_s5_trigger_8cpp__incl.png | Bin 0 -> 5379 bytes _p_s5_trigger_8cpp_source.html | 77 + _p_s5_trigger_8h.html | 120 + _p_s5_trigger_8h__dep__incl.map | 7 + _p_s5_trigger_8h__dep__incl.md5 | 1 + _p_s5_trigger_8h__dep__incl.png | Bin 0 -> 10349 bytes _p_s5_trigger_8h__incl.map | 2 + _p_s5_trigger_8h__incl.md5 | 1 + _p_s5_trigger_8h__incl.png | Bin 0 -> 2986 bytes _p_s5_trigger_8h_source.html | 82 + _p_s5_u_s_b_8h.html | 142 + _p_s5_u_s_b_8h__incl.map | 10 + _p_s5_u_s_b_8h__incl.md5 | 1 + _p_s5_u_s_b_8h__incl.png | Bin 0 -> 25117 bytes _p_s5_u_s_b_8h_source.html | 116 + _p_s_buzz_8h_source.html | 4 +- _r_e_a_d_m_e_8md_source.html | 2 +- _usb_8cpp_source.html | 6 +- _usb_8h.html | 98 +- _usb_8h__dep__incl.map | 98 +- _usb_8h__dep__incl.md5 | 2 +- _usb_8h__dep__incl.png | Bin 155656 -> 157594 bytes _wii_8cpp_source.html | 10 +- _wii_8h_source.html | 2 +- _x_b_o_x_o_l_d_8cpp_source.html | 10 +- _x_b_o_x_o_l_d_8h_source.html | 2 +- _x_b_o_x_o_n_e_8cpp_source.html | 10 +- _x_b_o_x_o_n_e_8h_source.html | 2 +- _x_b_o_x_o_n_e_s_parser_8cpp.html | 28 +- _x_b_o_x_o_n_e_s_parser_8cpp_source.html | 2 +- _x_b_o_x_o_n_e_s_parser_8h_source.html | 2 +- _x_b_o_x_r_e_c_v_8cpp_source.html | 10 +- _x_b_o_x_r_e_c_v_8h_source.html | 2 +- _x_b_o_x_u_s_b_8cpp_source.html | 10 +- _x_b_o_x_u_s_b_8h_source.html | 2 +- annotated.html | 89 +- class_b_t_h_i_d.html | 15 +- class_b_t_h_i_d__coll__graph.md5 | 2 +- class_b_t_h_i_d__inherit__graph.map | 5 +- class_b_t_h_i_d__inherit__graph.md5 | 2 +- class_b_t_h_i_d__inherit__graph.png | Bin 6556 -> 8167 bytes class_bluetooth_service.html | 11 +- class_bluetooth_service__coll__graph.md5 | 2 +- class_bluetooth_service__inherit__graph.map | 11 +- class_bluetooth_service__inherit__graph.md5 | 2 +- class_bluetooth_service__inherit__graph.png | Bin 11182 -> 12702 bytes class_h_i_d_composite.html | 7 +- class_h_i_d_composite__coll__graph.md5 | 2 +- class_h_i_d_composite__inherit__graph.map | 5 +- class_h_i_d_composite__inherit__graph.md5 | 2 +- class_h_i_d_composite__inherit__graph.png | Bin 12378 -> 13591 bytes class_h_i_d_universal.html | 7 +- class_h_i_d_universal__coll__graph.md5 | 2 +- class_h_i_d_universal__inherit__graph.map | 5 +- class_h_i_d_universal__inherit__graph.md5 | 2 +- class_h_i_d_universal__inherit__graph.png | Bin 12365 -> 13573 bytes class_p_s5_b_t-members.html | 136 + class_p_s5_b_t.html | 478 +++ class_p_s5_b_t__coll__graph.map | 12 + class_p_s5_b_t__coll__graph.md5 | 1 + class_p_s5_b_t__coll__graph.png | Bin 0 -> 22955 bytes class_p_s5_b_t__inherit__graph.map | 5 + class_p_s5_b_t__inherit__graph.md5 | 1 + class_p_s5_b_t__inherit__graph.png | Bin 0 -> 7171 bytes class_p_s5_parser-members.html | 105 + class_p_s5_parser.html | 1062 +++++++ class_p_s5_parser__coll__graph.map | 3 + class_p_s5_parser__coll__graph.md5 | 1 + class_p_s5_parser__coll__graph.png | Bin 0 -> 3689 bytes class_p_s5_parser__inherit__graph.map | 4 + class_p_s5_parser__inherit__graph.md5 | 1 + class_p_s5_parser__inherit__graph.png | Bin 0 -> 3798 bytes class_p_s5_trigger-members.html | 84 + class_p_s5_trigger.html | 375 +++ class_p_s5_u_s_b-members.html | 163 + class_p_s5_u_s_b.html | 591 ++++ class_p_s5_u_s_b__coll__graph.map | 16 + class_p_s5_u_s_b__coll__graph.md5 | 1 + class_p_s5_u_s_b__coll__graph.png | Bin 0 -> 44442 bytes class_p_s5_u_s_b__inherit__graph.map | 8 + class_p_s5_u_s_b__inherit__graph.md5 | 1 + class_p_s5_u_s_b__inherit__graph.png | Bin 0 -> 14472 bytes class_u_s_b_device_config.html | 17 +- class_u_s_b_device_config__inherit__graph.map | 15 +- class_u_s_b_device_config__inherit__graph.md5 | 2 +- class_u_s_b_device_config__inherit__graph.png | Bin 45423 -> 46642 bytes class_u_s_b_h_i_d.html | 5 +- class_u_s_b_h_i_d__coll__graph.md5 | 2 +- class_u_s_b_h_i_d__inherit__graph.map | 5 +- class_u_s_b_h_i_d__inherit__graph.md5 | 2 +- class_u_s_b_h_i_d__inherit__graph.png | Bin 14836 -> 16205 bytes class_usb_config_xtracter.html | 7 +- class_usb_config_xtracter__inherit__graph.map | 7 +- class_usb_config_xtracter__inherit__graph.md5 | 2 +- class_usb_config_xtracter__inherit__graph.png | Bin 26265 -> 27897 bytes classes.html | 83 +- controller_enums_8h.html | 62 +- controller_enums_8h__dep__incl.map | 36 +- controller_enums_8h__dep__incl.md5 | 2 +- controller_enums_8h__dep__incl.png | Bin 45011 -> 48877 bytes controller_enums_8h_source.html | 64 +- files.html | 74 +- functions_a.html | 4 + functions_b.html | 5 +- functions_c.html | 15 +- functions_d.html | 8 + functions_f.html | 3 +- functions_func.html | 1 + functions_func_c.html | 7 +- functions_func_g.html | 12 + functions_func_i.html | 1 + functions_func_o.html | 2 + functions_func_p.html | 15 + functions_func_r.html | 5 +- functions_func_s.html | 33 +- functions_func_v.html | 1 + functions_func_w.html | 2 +- functions_g.html | 16 + functions_h.html | 4 + functions_i.html | 1 + functions_l.html | 6 + functions_m.html | 12 +- functions_o.html | 2 + functions_p.html | 19 + functions_r.html | 22 +- functions_s.html | 37 + functions_t.html | 6 +- functions_u.html | 1 + functions_v.html | 3 + functions_vars_a.html | 3 + functions_vars_b.html | 5 +- functions_vars_c.html | 8 +- functions_vars_d.html | 8 + functions_vars_f.html | 3 +- functions_vars_g.html | 4 + functions_vars_h.html | 4 + functions_vars_l.html | 6 + functions_vars_m.html | 8 +- functions_vars_p.html | 4 + functions_vars_r.html | 17 +- functions_vars_s.html | 8 + functions_vars_t.html | 6 +- functions_vars_u.html | 1 + functions_vars_v.html | 2 + functions_vars_w.html | 2 +- functions_vars_x.html | 4 +- functions_vars_y.html | 3 +- functions_w.html | 4 +- functions_x.html | 4 +- functions_y.html | 3 +- globals_c.html | 9 + globals_d.html | 28 +- globals_defs_c.html | 3 + globals_defs_p.html | 14 +- globals_enum.html | 1 + globals_eval.html | 33 +- globals_m.html | 3 + globals_p.html | 9 + globals_vars.html | 2595 +--------------- globals_vars_p.html | 2669 +++++++++++++++++ globals_w.html | 6 +- globals_y.html | 6 +- hidboot_8h.html | 7 +- hidboot_8h__dep__incl.map | 7 +- hidboot_8h__dep__incl.md5 | 2 +- hidboot_8h__dep__incl.png | Bin 10116 -> 12086 bytes hidcomposite_8h.html | 13 +- hidcomposite_8h__dep__incl.map | 13 +- hidcomposite_8h__dep__incl.md5 | 2 +- hidcomposite_8h__dep__incl.png | Bin 12658 -> 14365 bytes hiduniversal_8h.html | 5 +- hiduniversal_8h__dep__incl.map | 5 +- hiduniversal_8h__dep__incl.md5 | 2 +- hiduniversal_8h__dep__incl.png | Bin 9529 -> 11174 bytes hidusagestr_8h.html | 62 +- hidusagestr_8h__dep__incl.map | 62 +- hidusagestr_8h__dep__incl.md5 | 2 +- hidusagestr_8h__dep__incl.png | Bin 66087 -> 72097 bytes hierarchy.html | 127 +- index.html | 13 +- inherit_graph_17.md5 | 2 +- inherit_graph_31.md5 | 2 +- inherit_graph_40.map | 2 +- inherit_graph_40.md5 | 2 +- inherit_graph_40.png | Bin 1562 -> 1489 bytes inherit_graph_41.map | 2 +- inherit_graph_41.md5 | 2 +- inherit_graph_41.png | Bin 1073 -> 1105 bytes inherit_graph_42.map | 2 +- inherit_graph_42.md5 | 2 +- inherit_graph_42.png | Bin 1757 -> 1275 bytes inherit_graph_43.map | 2 +- inherit_graph_43.md5 | 2 +- inherit_graph_43.png | Bin 1074 -> 1163 bytes inherit_graph_44.map | 2 +- inherit_graph_44.md5 | 2 +- inherit_graph_44.png | Bin 2240 -> 1738 bytes inherit_graph_45.map | 2 +- inherit_graph_45.md5 | 2 +- inherit_graph_45.png | Bin 1701 -> 1275 bytes inherit_graph_46.map | 2 +- inherit_graph_46.md5 | 2 +- inherit_graph_46.png | Bin 1408 -> 1562 bytes inherit_graph_47.map | 2 +- inherit_graph_47.md5 | 2 +- inherit_graph_47.png | Bin 1128 -> 1073 bytes inherit_graph_48.map | 2 +- inherit_graph_48.md5 | 2 +- inherit_graph_48.png | Bin 1372 -> 1757 bytes inherit_graph_49.map | 2 +- inherit_graph_49.md5 | 2 +- inherit_graph_49.png | Bin 2383 -> 1074 bytes inherit_graph_50.map | 2 +- inherit_graph_50.md5 | 2 +- inherit_graph_50.png | Bin 2068 -> 2240 bytes inherit_graph_51.map | 2 +- inherit_graph_51.md5 | 2 +- inherit_graph_51.png | Bin 1953 -> 1701 bytes inherit_graph_52.map | 2 +- inherit_graph_52.md5 | 2 +- inherit_graph_52.png | Bin 1708 -> 1408 bytes inherit_graph_53.map | 2 +- inherit_graph_53.md5 | 2 +- inherit_graph_53.png | Bin 2108 -> 1128 bytes inherit_graph_54.map | 2 +- inherit_graph_54.md5 | 2 +- inherit_graph_54.png | Bin 1228 -> 1372 bytes inherit_graph_55.map | 2 +- inherit_graph_55.md5 | 2 +- inherit_graph_55.png | Bin 1614 -> 2383 bytes inherit_graph_56.map | 6 +- inherit_graph_56.md5 | 2 +- inherit_graph_56.png | Bin 16219 -> 2068 bytes inherit_graph_57.map | 2 +- inherit_graph_57.md5 | 2 +- inherit_graph_57.png | Bin 1903 -> 1953 bytes inherit_graph_58.map | 2 +- inherit_graph_58.md5 | 2 +- inherit_graph_58.png | Bin 1721 -> 1708 bytes inherit_graph_59.map | 32 +- inherit_graph_59.md5 | 2 +- inherit_graph_59.png | Bin 101984 -> 2108 bytes inherit_graph_60.map | 3 + inherit_graph_60.md5 | 1 + inherit_graph_60.png | Bin 0 -> 1228 bytes inherit_graph_61.map | 3 + inherit_graph_61.md5 | 1 + inherit_graph_61.png | Bin 0 -> 1614 bytes inherit_graph_62.map | 7 + inherit_graph_62.md5 | 1 + inherit_graph_62.png | Bin 0 -> 16219 bytes inherit_graph_63.map | 3 + inherit_graph_63.md5 | 1 + inherit_graph_63.png | Bin 0 -> 1903 bytes inherit_graph_64.map | 3 + inherit_graph_64.md5 | 1 + inherit_graph_64.png | Bin 0 -> 1721 bytes inherit_graph_65.map | 36 + inherit_graph_65.md5 | 1 + inherit_graph_65.png | Bin 0 -> 108697 bytes inherits.html | 135 +- menudata.js | 3 +- search/all_1.js | 8 +- search/all_10.js | 28 +- search/all_12.js | 23 +- search/all_13.js | 25 +- search/all_14.js | 8 +- search/all_15.js | 2 +- search/all_16.js | 4 +- search/all_17.js | 6 +- search/all_18.js | 4 +- search/all_19.js | 4 +- search/all_2.js | 6 +- search/all_3.js | 12 +- search/all_4.js | 29 +- search/all_5.js | 2 +- search/all_6.js | 2 +- search/all_7.js | 27 +- search/all_8.js | 3 +- search/all_9.js | 2 +- search/all_c.js | 7 +- search/all_d.js | 6 +- search/all_f.js | 4 +- search/classes_a.js | 9 + search/defines_10.js | 2 + search/defines_3.js | 3 +- search/enums_3.js | 2 +- search/enumvalues_13.js | 2 +- search/enumvalues_15.js | 2 +- search/enumvalues_2.js | 1 + search/enumvalues_3.js | 18 +- search/enumvalues_a.js | 1 + search/files_5.js | 6 + search/functions_0.js | 2 +- search/functions_10.js | 19 +- search/functions_13.js | 2 +- search/functions_14.js | 2 +- search/functions_2.js | 3 +- search/functions_6.js | 19 +- search/functions_8.js | 2 +- search/functions_d.js | 4 +- search/functions_e.js | 10 +- search/functions_f.js | 6 +- search/variables_1.js | 6 +- search/variables_11.js | 17 +- search/variables_12.js | 6 +- search/variables_13.js | 8 +- search/variables_14.js | 2 +- search/variables_15.js | 2 +- search/variables_16.js | 2 +- search/variables_17.js | 4 +- search/variables_18.js | 2 +- search/variables_2.js | 6 +- search/variables_3.js | 8 +- search/variables_4.js | 9 +- search/variables_5.js | 2 +- search/variables_6.js | 2 +- search/variables_7.js | 8 +- search/variables_8.js | 3 +- search/variables_b.js | 7 +- search/variables_c.js | 5 +- search/variables_f.js | 4 +- struct_hub_descriptor.html | 34 +- struct_hub_event.html | 32 +- struct_p_s5_data-members.html | 91 + struct_p_s5_data.html | 351 +++ struct_p_s5_data__coll__graph.map | 4 + struct_p_s5_data__coll__graph.md5 | 1 + struct_p_s5_data__coll__graph.png | Bin 0 -> 6629 bytes struct_p_s5_output-members.html | 86 + struct_p_s5_output.html | 252 ++ struct_s_e_t_u_p___p_k_t-members.html | 4 +- struct_s_e_t_u_p___p_k_t.html | 60 +- structps5_touchpad_x_y-members.html | 82 + structps5_touchpad_x_y.html | 179 ++ union_p_s5_buttons-members.html | 95 + union_p_s5_buttons.html | 431 +++ union_p_s5_status-members.html | 84 + union_p_s5_status.html | 233 ++ union_p_s_b_u_z_z_buttons-members.html | 2 +- union_p_s_b_u_z_z_buttons.html | 30 +- union_xbox_one_s_buttons.html | 62 +- usbhid_8h.html | 58 +- usbhid_8h__dep__incl.map | 58 +- usbhid_8h__dep__incl.md5 | 2 +- usbhid_8h__dep__incl.png | Bin 59493 -> 59158 bytes 386 files changed, 10938 insertions(+), 3734 deletions(-) create mode 100644 _p_s5_b_t_8h.html create mode 100644 _p_s5_b_t_8h__incl.map create mode 100644 _p_s5_b_t_8h__incl.md5 create mode 100644 _p_s5_b_t_8h__incl.png create mode 100644 _p_s5_b_t_8h_source.html create mode 100644 _p_s5_parser_8cpp.html create mode 100644 _p_s5_parser_8cpp__incl.map create mode 100644 _p_s5_parser_8cpp__incl.md5 create mode 100644 _p_s5_parser_8cpp__incl.png create mode 100644 _p_s5_parser_8cpp_source.html create mode 100644 _p_s5_parser_8h.html create mode 100644 _p_s5_parser_8h__dep__incl.map create mode 100644 _p_s5_parser_8h__dep__incl.md5 create mode 100644 _p_s5_parser_8h__dep__incl.png create mode 100644 _p_s5_parser_8h__incl.map create mode 100644 _p_s5_parser_8h__incl.md5 create mode 100644 _p_s5_parser_8h__incl.png create mode 100644 _p_s5_parser_8h_source.html create mode 100644 _p_s5_trigger_8cpp.html create mode 100644 _p_s5_trigger_8cpp__incl.map create mode 100644 _p_s5_trigger_8cpp__incl.md5 create mode 100644 _p_s5_trigger_8cpp__incl.png create mode 100644 _p_s5_trigger_8cpp_source.html create mode 100644 _p_s5_trigger_8h.html create mode 100644 _p_s5_trigger_8h__dep__incl.map create mode 100644 _p_s5_trigger_8h__dep__incl.md5 create mode 100644 _p_s5_trigger_8h__dep__incl.png create mode 100644 _p_s5_trigger_8h__incl.map create mode 100644 _p_s5_trigger_8h__incl.md5 create mode 100644 _p_s5_trigger_8h__incl.png create mode 100644 _p_s5_trigger_8h_source.html create mode 100644 _p_s5_u_s_b_8h.html create mode 100644 _p_s5_u_s_b_8h__incl.map create mode 100644 _p_s5_u_s_b_8h__incl.md5 create mode 100644 _p_s5_u_s_b_8h__incl.png create mode 100644 _p_s5_u_s_b_8h_source.html create mode 100644 class_p_s5_b_t-members.html create mode 100644 class_p_s5_b_t.html create mode 100644 class_p_s5_b_t__coll__graph.map create mode 100644 class_p_s5_b_t__coll__graph.md5 create mode 100644 class_p_s5_b_t__coll__graph.png create mode 100644 class_p_s5_b_t__inherit__graph.map create mode 100644 class_p_s5_b_t__inherit__graph.md5 create mode 100644 class_p_s5_b_t__inherit__graph.png create mode 100644 class_p_s5_parser-members.html create mode 100644 class_p_s5_parser.html create mode 100644 class_p_s5_parser__coll__graph.map create mode 100644 class_p_s5_parser__coll__graph.md5 create mode 100644 class_p_s5_parser__coll__graph.png create mode 100644 class_p_s5_parser__inherit__graph.map create mode 100644 class_p_s5_parser__inherit__graph.md5 create mode 100644 class_p_s5_parser__inherit__graph.png create mode 100644 class_p_s5_trigger-members.html create mode 100644 class_p_s5_trigger.html create mode 100644 class_p_s5_u_s_b-members.html create mode 100644 class_p_s5_u_s_b.html create mode 100644 class_p_s5_u_s_b__coll__graph.map create mode 100644 class_p_s5_u_s_b__coll__graph.md5 create mode 100644 class_p_s5_u_s_b__coll__graph.png create mode 100644 class_p_s5_u_s_b__inherit__graph.map create mode 100644 class_p_s5_u_s_b__inherit__graph.md5 create mode 100644 class_p_s5_u_s_b__inherit__graph.png create mode 100644 globals_vars_p.html create mode 100644 inherit_graph_60.map create mode 100644 inherit_graph_60.md5 create mode 100644 inherit_graph_60.png create mode 100644 inherit_graph_61.map create mode 100644 inherit_graph_61.md5 create mode 100644 inherit_graph_61.png create mode 100644 inherit_graph_62.map create mode 100644 inherit_graph_62.md5 create mode 100644 inherit_graph_62.png create mode 100644 inherit_graph_63.map create mode 100644 inherit_graph_63.md5 create mode 100644 inherit_graph_63.png create mode 100644 inherit_graph_64.map create mode 100644 inherit_graph_64.md5 create mode 100644 inherit_graph_64.png create mode 100644 inherit_graph_65.map create mode 100644 inherit_graph_65.md5 create mode 100644 inherit_graph_65.png create mode 100644 struct_p_s5_data-members.html create mode 100644 struct_p_s5_data.html create mode 100644 struct_p_s5_data__coll__graph.map create mode 100644 struct_p_s5_data__coll__graph.md5 create mode 100644 struct_p_s5_data__coll__graph.png create mode 100644 struct_p_s5_output-members.html create mode 100644 struct_p_s5_output.html create mode 100644 structps5_touchpad_x_y-members.html create mode 100644 structps5_touchpad_x_y.html create mode 100644 union_p_s5_buttons-members.html create mode 100644 union_p_s5_buttons.html create mode 100644 union_p_s5_status-members.html create mode 100644 union_p_s5_status.html diff --git a/_b_t_d_8cpp_source.html b/_b_t_d_8cpp_source.html index 63fd5ff5..48b714dd 100644 --- a/_b_t_d_8cpp_source.html +++ b/_b_t_d_8cpp_source.html @@ -63,7 +63,7 @@ $(function() {
BTD.cpp
-Go to the documentation of this file.
1 /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
2 
3  This software may be distributed and modified under the terms of the GNU
4  General Public License version 2 (GPL2) as published by the Free Software
5  Foundation and appearing in the file GPL2.TXT included in the packaging of
6  this file. Please note that GPL2 Section 2[b] requires that all works based
7  on this software must also be made publicly available under the terms of
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Lauszus, TKJ Electronics
14  Web : http://www.tkjelectronics.com
15  e-mail : kristianl@tkjelectronics.com
16  */
17 
18 #include "BTD.h"
19 // To enable serial debugging see "settings.h"
20 //#define EXTRADEBUG // Uncomment to get even more debugging data
21 
22 const uint8_t BTD::BTD_CONTROL_PIPE = 0;
23 const uint8_t BTD::BTD_EVENT_PIPE = 1;
24 const uint8_t BTD::BTD_DATAIN_PIPE = 2;
25 const uint8_t BTD::BTD_DATAOUT_PIPE = 3;
26 
28 connectToWii(false),
29 pairWithWii(false),
30 connectToHIDDevice(false),
31 pairWithHIDDevice(false),
32 useSimplePairing(false),
33 pUsb(p), // Pointer to USB class instance - mandatory
34 bAddress(0), // Device address - mandatory
35 bNumEP(1), // If config descriptor needs to be parsed
36 qNextPollTime(0), // Reset NextPollTime
37 pollInterval(0),
38 simple_pairing_supported(false),
39 bPollEnable(false) // Don't start polling before dongle is connected
40 {
41  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
42  btService[i] = NULL;
43 
44  Initialize(); // Set all variables, endpoint structs etc. to default values
45 
46  if(pUsb) // Register in USB subsystem
47  pUsb->RegisterDeviceClass(this); // Set devConfig[] entry
48 }
49 
50 uint8_t BTD::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
51  const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
52  uint8_t buf[constBufSize];
53  USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
54  uint8_t rcode;
55  UsbDevice *p = NULL;
56  EpInfo *oldep_ptr = NULL;
57 
58  Initialize(); // Set all variables, endpoint structs etc. to default values
59 
60  AddressPool &addrPool = pUsb->GetAddressPool(); // Get memory address of USB device address pool
61 #ifdef EXTRADEBUG
62  Notify(PSTR("\r\nBTD ConfigureDevice"), 0x80);
63 #endif
64 
65  if(bAddress) { // Check if address has already been assigned to an instance
66 #ifdef DEBUG_USB_HOST
67  Notify(PSTR("\r\nAddress in use"), 0x80);
68 #endif
70  }
71 
72  p = addrPool.GetUsbDevicePtr(0); // Get pointer to pseudo device with address 0 assigned
73  if(!p) {
74 #ifdef DEBUG_USB_HOST
75  Notify(PSTR("\r\nAddress not found"), 0x80);
76 #endif
78  }
79 
80  if(!p->epinfo) {
81 #ifdef DEBUG_USB_HOST
82  Notify(PSTR("\r\nepinfo is null"), 0x80);
83 #endif
85  }
86 
87  oldep_ptr = p->epinfo; // Save old pointer to EP_RECORD of address 0
88  p->epinfo = epInfo; // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
89  p->lowspeed = lowspeed;
90  rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
91 
92  p->epinfo = oldep_ptr; // Restore p->epinfo
93 
94  if(rcode)
95  goto FailGetDevDescr;
96 
97  bAddress = addrPool.AllocAddress(parent, false, port); // Allocate new address according to device class
98 
99  if(!bAddress) {
100 #ifdef DEBUG_USB_HOST
101  Notify(PSTR("\r\nOut of address space"), 0x80);
102 #endif
104  }
105 
106  if (udd->bDeviceClass == 0x09) // Some dongles have an USB hub inside
107  goto FailHub;
108 
109  epInfo[0].maxPktSize = udd->bMaxPacketSize0; // Extract Max Packet Size from device descriptor
110  epInfo[1].epAddr = udd->bNumConfigurations; // Steal and abuse from epInfo structure to save memory
111 
112  VID = udd->idVendor;
113  PID = udd->idProduct;
114 
116 
117 FailHub:
118 #ifdef DEBUG_USB_HOST
119  Notify(PSTR("\r\nPlease create a hub instance in your code: \"USBHub Hub1(&Usb);\""), 0x80);
120 #endif
121  pUsb->setAddr(bAddress, 0, 0); // Reset address
123  Release();
124  return rcode;
125 
126 FailGetDevDescr:
127 #ifdef DEBUG_USB_HOST
128  NotifyFailGetDevDescr(rcode);
129 #endif
130  if(rcode != hrJERR)
132  Release();
133  return rcode;
134 };
135 
136 uint8_t BTD::Init(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed) {
137  uint8_t rcode;
138  uint8_t num_of_conf = epInfo[1].epAddr; // Number of configurations
139  epInfo[1].epAddr = 0;
140 
141  AddressPool &addrPool = pUsb->GetAddressPool();
142 #ifdef EXTRADEBUG
143  Notify(PSTR("\r\nBTD Init"), 0x80);
144 #endif
145  UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record
146 
147  if(!p) {
148 #ifdef DEBUG_USB_HOST
149  Notify(PSTR("\r\nAddress not found"), 0x80);
150 #endif
152  }
153 
154  delay(300); // Assign new address to the device
155 
156  rcode = pUsb->setAddr(0, 0, bAddress); // Assign new address to the device
157  if(rcode) {
158 #ifdef DEBUG_USB_HOST
159  Notify(PSTR("\r\nsetAddr: "), 0x80);
160  D_PrintHex<uint8_t > (rcode, 0x80);
161 #endif
162  p->lowspeed = false;
163  goto Fail;
164  }
165 #ifdef EXTRADEBUG
166  Notify(PSTR("\r\nAddr: "), 0x80);
167  D_PrintHex<uint8_t > (bAddress, 0x80);
168 #endif
169 
170  p->lowspeed = false;
171 
172  p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record
173  if(!p) {
174 #ifdef DEBUG_USB_HOST
175  Notify(PSTR("\r\nAddress not found"), 0x80);
176 #endif
178  }
179 
180  p->lowspeed = lowspeed;
181 
182  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); // Assign epInfo to epinfo pointer - only EP0 is known
183  if(rcode)
184  goto FailSetDevTblEntry;
185 
186  if(VID == PS3_VID && (PID == PS3_PID || PID == PS3NAVIGATION_PID || PID == PS3MOVE_PID)) {
187  delay(100);
188  rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 1); // We only need the Control endpoint, so we don't have to initialize the other endpoints of device
189  if(rcode)
190  goto FailSetConfDescr;
191 
192 #ifdef DEBUG_USB_HOST
193  if(PID == PS3_PID || PID == PS3NAVIGATION_PID) {
194  if(PID == PS3_PID)
195  Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80);
196  else // It must be a navigation controller
197  Notify(PSTR("\r\nNavigation Controller Connected"), 0x80);
198  } else // It must be a Motion controller
199  Notify(PSTR("\r\nMotion Controller Connected"), 0x80);
200 #endif
201 
202  if(my_bdaddr[0] == 0x00 && my_bdaddr[1] == 0x00 && my_bdaddr[2] == 0x00 && my_bdaddr[3] == 0x00 && my_bdaddr[4] == 0x00 && my_bdaddr[5] == 0x00) {
203 #ifdef DEBUG_USB_HOST
204  Notify(PSTR("\r\nPlease plug in the dongle before trying to pair with the PS3 Controller\r\nor set the Bluetooth address in the constructor of the PS3BT class"), 0x80);
205 #endif
206  } else {
207  if(PID == PS3_PID || PID == PS3NAVIGATION_PID)
208  setBdaddr(my_bdaddr); // Set internal Bluetooth address
209  else
210  setMoveBdaddr(my_bdaddr); // Set internal Bluetooth address
211 #ifdef DEBUG_USB_HOST
212  Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80);
213  for(int8_t i = 5; i > 0; i--) {
214  D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
215  Notify(PSTR(":"), 0x80);
216  }
217  D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
218 #endif
219  }
220 
221  pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 0); // Reset configuration value
222  pUsb->setAddr(bAddress, 0, 0); // Reset address
223  Release(); // Release device
225  } else {
226  // Check if attached device is a Bluetooth dongle and fill endpoint data structure
227  // First interface in the configuration must have Bluetooth assigned Class/Subclass/Protocol
228  // And 3 endpoints - interrupt-IN, bulk-IN, bulk-OUT, not necessarily in this order
229  for(uint8_t i = 0; i < num_of_conf; i++) {
230  if((VID == IOGEAR_GBU521_VID && PID == IOGEAR_GBU521_PID) || (VID == BELKIN_F8T065BF_VID && PID == BELKIN_F8T065BF_PID)) {
231  ConfigDescParser<USB_CLASS_VENDOR_SPECIFIC, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Workaround issue with some dongles
232  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
233  } else {
234  ConfigDescParser<USB_CLASS_WIRELESS_CTRL, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Set class id according to the specification
235  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
236  }
237  if(rcode) // Check error code
238  goto FailGetConfDescr;
239  if(bNumEP >= BTD_MAX_ENDPOINTS) // All endpoints extracted
240  break;
241  }
242 
244  goto FailUnknownDevice;
245 
246  // Assign epInfo to epinfo pointer - this time all 3 endpoins
247  rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
248  if(rcode)
249  goto FailSetDevTblEntry;
250 
251  // Set Configuration Value
252  rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bConfNum);
253  if(rcode)
254  goto FailSetConfDescr;
255 
256  hci_num_reset_loops = 100; // only loop 100 times before trying to send the hci reset command
257  hci_counter = 0;
258  hci_state = HCI_INIT_STATE;
259  waitingForConnection = false;
260  bPollEnable = true;
261 
262 #ifdef DEBUG_USB_HOST
263  Notify(PSTR("\r\nBluetooth Dongle Initialized"), 0x80);
264 #endif
265  }
266  return 0; // Successful configuration
267 
268  /* Diagnostic messages */
269 FailSetDevTblEntry:
270 #ifdef DEBUG_USB_HOST
272  goto Fail;
273 #endif
274 
275 FailGetConfDescr:
276 #ifdef DEBUG_USB_HOST
278  goto Fail;
279 #endif
280 
281 FailSetConfDescr:
282 #ifdef DEBUG_USB_HOST
284 #endif
285  goto Fail;
286 
287 FailUnknownDevice:
288 #ifdef DEBUG_USB_HOST
289  NotifyFailUnknownDevice(VID, PID);
290 #endif
291  pUsb->setAddr(bAddress, 0, 0); // Reset address
293 Fail:
294 #ifdef DEBUG_USB_HOST
295  Notify(PSTR("\r\nBTD Init Failed, error code: "), 0x80);
296  NotifyFail(rcode);
297 #endif
298  Release();
299  return rcode;
300 }
301 
302 void BTD::Initialize() {
303  uint8_t i;
304  for(i = 0; i < BTD_MAX_ENDPOINTS; i++) {
305  epInfo[i].epAddr = 0;
306  epInfo[i].maxPktSize = (i) ? 0 : 8;
307  epInfo[i].bmSndToggle = 0;
308  epInfo[i].bmRcvToggle = 0;
310  }
311  for(i = 0; i < BTD_NUM_SERVICES; i++) {
312  if(btService[i])
313  btService[i]->Reset(); // Reset all Bluetooth services
314  }
315 
316  connectToWii = false;
317  incomingWii = false;
318  connectToHIDDevice = false;
319  incomingHIDDevice = false;
320  incomingPS4 = false;
321  bAddress = 0; // Clear device address
322  bNumEP = 1; // Must have to be reset to 1
323  qNextPollTime = 0; // Reset next poll time
324  pollInterval = 0;
325  bPollEnable = false; // Don't start polling before dongle is connected
326  simple_pairing_supported = false;
327 }
328 
329 /* Extracts interrupt-IN, bulk-IN, bulk-OUT endpoint information from config descriptor */
330 void BTD::EndpointXtract(uint8_t conf, uint8_t iface __attribute__((unused)), uint8_t alt, uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR *pep) {
331  //ErrorMessage<uint8_t>(PSTR("Conf.Val"),conf);
332  //ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
333  //ErrorMessage<uint8_t>(PSTR("Alt.Set"),alt);
334 
335  if(alt) // Wrong interface - by BT spec, no alt setting
336  return;
337 
338  bConfNum = conf;
339  uint8_t index;
340 
341  if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80) { // Interrupt In endpoint found
342  index = BTD_EVENT_PIPE;
344  } else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) // Bulk endpoint found
345  index = ((pep->bEndpointAddress & 0x80) == 0x80) ? BTD_DATAIN_PIPE : BTD_DATAOUT_PIPE;
346  else
347  return;
348 
349  // Fill the rest of endpoint data structure
350  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
351  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
352 #ifdef EXTRADEBUG
354 #endif
355  if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
356  pollInterval = pep->bInterval;
357  bNumEP++;
358 }
359 
360 void BTD::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr __attribute__((unused))) {
361 #ifdef EXTRADEBUG
362  Notify(PSTR("\r\nEndpoint descriptor:"), 0x80);
363  Notify(PSTR("\r\nLength:\t\t"), 0x80);
364  D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
365  Notify(PSTR("\r\nType:\t\t"), 0x80);
366  D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
367  Notify(PSTR("\r\nAddress:\t"), 0x80);
368  D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
369  Notify(PSTR("\r\nAttributes:\t"), 0x80);
370  D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
371  Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
372  D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
373  Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
374  D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
375 #endif
376 }
377 
378 /* Performs a cleanup after failed Init() attempt */
379 uint8_t BTD::Release() {
380  Initialize(); // Set all variables, endpoint structs etc. to default values
382  return 0;
383 }
384 
385 uint8_t BTD::Poll() {
386  if(!bPollEnable)
387  return 0;
388  if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) { // Don't poll if shorter than polling interval
389  qNextPollTime = (uint32_t)millis() + pollInterval; // Set new poll time
390  HCI_event_task(); // Poll the HCI event pipe
391  HCI_task(); // HCI state machine
392  ACL_event_task(); // Poll the ACL input pipe too
393  }
394  return 0;
395 }
396 
398  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
399  if(btService[i])
400  btService[i]->disconnect();
401 };
402 
403 void BTD::HCI_event_task() {
404  uint16_t length = BULK_MAXPKTSIZE; // Request more than 16 bytes anyway, the inTransfer routine will take care of this
405  uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_EVENT_PIPE ].epAddr, &length, hcibuf, pollInterval); // Input on endpoint 1
406 
407  if(!rcode || rcode == hrNAK) { // Check for errors
408  switch(hcibuf[0]) { // Switch on event type
409  case EV_COMMAND_COMPLETE:
410  if(!hcibuf[5]) { // Check if command succeeded
411  hci_set_flag(HCI_FLAG_CMD_COMPLETE); // Set command complete flag
412  if((hcibuf[3] == 0x01) && (hcibuf[4] == 0x10)) { // Parameters from read local version information
413  hci_version = hcibuf[6]; // Used to check if it supports 2.0+EDR - see http://www.bluetooth.org/Technical/AssignedNumbers/hci.htm
414 #ifdef EXTRADEBUG
416  Notify(PSTR("\r\nHCI version: "), 0x80);
417  D_PrintHex<uint8_t > (hci_version, 0x80);
418  }
419 #endif
421  } else if((hcibuf[3] == 0x04) && (hcibuf[4] == 0x10)) { // Parameters from read local extended features
423 #ifdef EXTRADEBUG
424  Notify(PSTR("\r\nPage number: "), 0x80);
425  D_PrintHex<uint8_t > (hcibuf[6], 0x80);
426  Notify(PSTR("\r\nMaximum page number: "), 0x80);
427  D_PrintHex<uint8_t > (hcibuf[7], 0x80);
428  Notify(PSTR("\r\nExtended LMP features:"), 0x80);
429  for(uint8_t i = 0; i < 8; i++) {
430  Notify(PSTR(" "), 0x80);
431  D_PrintHex<uint8_t > (hcibuf[8 + i], 0x80);
432  }
433 #endif
434  if(hcibuf[6] == 0) { // Page 0
435 #ifdef DEBUG_USB_HOST
436  Notify(PSTR("\r\nDongle "), 0x80);
437 #endif
438  if(hcibuf[8 + 6] & (1U << 3)) {
439  simple_pairing_supported = true;
440 #ifdef DEBUG_USB_HOST
441  Notify(PSTR("supports"), 0x80);
442 #endif
443  } else {
444  simple_pairing_supported = false;
445 #ifdef DEBUG_USB_HOST
446  Notify(PSTR("does NOT support"), 0x80);
447 #endif
448  }
449 #ifdef DEBUG_USB_HOST
450  Notify(PSTR(" secure simple pairing (controller support)"), 0x80);
451 #endif
452  } else if(hcibuf[6] == 1) { // Page 1
453 #ifdef DEBUG_USB_HOST
454  Notify(PSTR("\r\nDongle "), 0x80);
455  if(hcibuf[8 + 0] & (1U << 0))
456  Notify(PSTR("supports"), 0x80);
457  else
458  Notify(PSTR("does NOT support"), 0x80);
459  Notify(PSTR(" secure simple pairing (host support)"), 0x80);
460 #endif
461  }
462  }
463 
465  } else if((hcibuf[3] == 0x09) && (hcibuf[4] == 0x10)) { // Parameters from read local bluetooth address
466  for(uint8_t i = 0; i < 6; i++)
467  my_bdaddr[i] = hcibuf[6 + i];
469  }
470  }
471  break;
472 
473  case EV_COMMAND_STATUS:
474  if(hcibuf[2]) { // Show status on serial if not OK
475 #ifdef DEBUG_USB_HOST
476  Notify(PSTR("\r\nHCI Command Failed: "), 0x80);
477  D_PrintHex<uint8_t > (hcibuf[2], 0x80);
478  Notify(PSTR("\r\nNum HCI Command Packets: "), 0x80);
479  D_PrintHex<uint8_t > (hcibuf[3], 0x80);
480  Notify(PSTR("\r\nCommand Opcode: "), 0x80);
481  D_PrintHex<uint8_t > (hcibuf[4], 0x80);
482  Notify(PSTR(" "), 0x80);
483  D_PrintHex<uint8_t > (hcibuf[5], 0x80);
484 #endif
485  }
486  break;
487 
488  case EV_INQUIRY_COMPLETE:
489  if(inquiry_counter >= 5 && (pairWithWii || pairWithHIDDevice)) {
490  inquiry_counter = 0;
491 #ifdef DEBUG_USB_HOST
492  if(pairWithWii)
493  Notify(PSTR("\r\nCouldn't find Wiimote"), 0x80);
494  else
495  Notify(PSTR("\r\nCouldn't find HID device"), 0x80);
496 #endif
497  connectToWii = false;
498  pairWithWii = false;
499  connectToHIDDevice = false;
500  pairWithHIDDevice = false;
501  hci_state = HCI_SCANNING_STATE;
502  }
503  inquiry_counter++;
504  break;
505 
506  case EV_INQUIRY_RESULT:
507  if(hcibuf[2]) { // Check that there is more than zero responses
508 #ifdef EXTRADEBUG
509  Notify(PSTR("\r\nNumber of responses: "), 0x80);
510  Notify(hcibuf[2], 0x80);
511 #endif
512  for(uint8_t i = 0; i < hcibuf[2]; i++) {
513  uint8_t offset = 8 * hcibuf[2] + 3 * i;
514 
515  for(uint8_t j = 0; j < 3; j++)
516  classOfDevice[j] = hcibuf[j + 4 + offset];
517 
518 #ifdef EXTRADEBUG
519  Notify(PSTR("\r\nClass of device: "), 0x80);
520  D_PrintHex<uint8_t > (classOfDevice[2], 0x80);
521  Notify(PSTR(" "), 0x80);
522  D_PrintHex<uint8_t > (classOfDevice[1], 0x80);
523  Notify(PSTR(" "), 0x80);
524  D_PrintHex<uint8_t > (classOfDevice[0], 0x80);
525 #endif
526 
527  if(pairWithWii && classOfDevice[2] == 0x00 && (classOfDevice[1] == 0x05) && (classOfDevice[0] & 0x0C)) { // See http://wiibrew.org/wiki/Wiimote#SDP_information
528  checkRemoteName = true; // Check remote name to distinguish between the different controllers
529 
530  for(uint8_t j = 0; j < 6; j++)
531  disc_bdaddr[j] = hcibuf[j + 3 + 6 * i];
532 
534  break;
535  } else if(pairWithHIDDevice && (classOfDevice[1] & 0x0F) == 0x05 && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad - see: http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html
536 #ifdef DEBUG_USB_HOST
537  checkRemoteName = true; // Used to print name in the serial monitor if serial debugging is enabled
538 
539  if(classOfDevice[0] & 0x80)
540  Notify(PSTR("\r\nMouse found"), 0x80);
541  if(classOfDevice[0] & 0x40)
542  Notify(PSTR("\r\nKeyboard found"), 0x80);
543  if(classOfDevice[0] & 0x08)
544  Notify(PSTR("\r\nGamepad found"), 0x80);
545 #endif
546  for(uint8_t j = 0; j < 6; j++)
547  disc_bdaddr[j] = hcibuf[j + 3 + 6 * i];
548 
550  break;
551  }
552  }
553  }
554  break;
555 
556  case EV_CONNECT_COMPLETE:
558  if(!hcibuf[2]) { // Check if connected OK
559 #ifdef EXTRADEBUG
560  Notify(PSTR("\r\nConnection established"), 0x80);
561 #endif
562  hci_handle = hcibuf[3] | ((hcibuf[4] & 0x0F) << 8); // Store the handle for the ACL connection
563  hci_set_flag(HCI_FLAG_CONNECT_COMPLETE); // Set connection complete flag
564  } else {
565  hci_state = HCI_CHECK_DEVICE_SERVICE;
566 #ifdef DEBUG_USB_HOST
567  Notify(PSTR("\r\nConnection Failed: "), 0x80);
568  D_PrintHex<uint8_t > (hcibuf[2], 0x80);
569 #endif
570  }
571  break;
572 
574  if(!hcibuf[2]) { // Check if disconnected OK
575  hci_set_flag(HCI_FLAG_DISCONNECT_COMPLETE); // Set disconnect command complete flag
576  hci_clear_flag(HCI_FLAG_CONNECT_COMPLETE); // Clear connection complete flag
577  }
578  break;
579 
581  if(!hcibuf[2]) { // Check if reading is OK
582  for(uint8_t i = 0; i < min(sizeof (remote_name), sizeof (hcibuf) - 9); i++) {
583  remote_name[i] = hcibuf[9 + i];
584  if(remote_name[i] == '\0') // End of string
585  break;
586  }
587  // TODO: Always set '\0' in remote name!
589  }
590  break;
591 
592  case EV_INCOMING_CONNECT:
593  for(uint8_t i = 0; i < 6; i++)
594  disc_bdaddr[i] = hcibuf[i + 2];
595 
596  for(uint8_t i = 0; i < 3; i++)
597  classOfDevice[i] = hcibuf[i + 8];
598 
599  if((classOfDevice[1] & 0x0F) == 0x05 && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad
600 #ifdef DEBUG_USB_HOST
601  if(classOfDevice[0] & 0x80)
602  Notify(PSTR("\r\nMouse is connecting"), 0x80);
603  if(classOfDevice[0] & 0x40)
604  Notify(PSTR("\r\nKeyboard is connecting"), 0x80);
605  if(classOfDevice[0] & 0x08)
606  Notify(PSTR("\r\nGamepad is connecting"), 0x80);
607 #endif
608  incomingHIDDevice = true;
609  }
610 
611 #ifdef EXTRADEBUG
612  Notify(PSTR("\r\nClass of device: "), 0x80);
613  D_PrintHex<uint8_t > (classOfDevice[2], 0x80);
614  Notify(PSTR(" "), 0x80);
615  D_PrintHex<uint8_t > (classOfDevice[1], 0x80);
616  Notify(PSTR(" "), 0x80);
617  D_PrintHex<uint8_t > (classOfDevice[0], 0x80);
618 #endif
620  break;
621 
622  case EV_PIN_CODE_REQUEST:
623  if(pairWithWii) {
624 #ifdef DEBUG_USB_HOST
625  Notify(PSTR("\r\nPairing with Wiimote"), 0x80);
626 #endif
628  } else if(btdPin != NULL) {
629 #ifdef DEBUG_USB_HOST
630  Notify(PSTR("\r\nBluetooth pin is set too: "), 0x80);
631  NotifyStr(btdPin, 0x80);
632 #endif
634  } else {
635 #ifdef DEBUG_USB_HOST
636  Notify(PSTR("\r\nNo pin was set"), 0x80);
637 #endif
639  }
640  break;
641 
642  case EV_LINK_KEY_REQUEST:
643 #ifdef DEBUG_USB_HOST
644  Notify(PSTR("\r\nReceived Key Request"), 0x80);
645 #endif
647  break;
648 
650  if(!hcibuf[2]) { // Check if pairing was successful
651  if(pairWithWii && !connectToWii) {
652 #ifdef DEBUG_USB_HOST
653  Notify(PSTR("\r\nPairing successful with Wiimote"), 0x80);
654 #endif
655  connectToWii = true; // Used to indicate to the Wii service, that it should connect to this device
656  } else if(pairWithHIDDevice && !connectToHIDDevice) {
657 #ifdef DEBUG_USB_HOST
658  Notify(PSTR("\r\nPairing successful with HID device"), 0x80);
659 #endif
660  connectToHIDDevice = true; // Used to indicate to the BTHID service, that it should connect to this device
661  } else {
662 #ifdef EXTRADEBUG
663  Notify(PSTR("\r\nPairing was successful"), 0x80);
664 #endif
665  }
666  } else {
667 #ifdef DEBUG_USB_HOST
668  Notify(PSTR("\r\nPairing Failed: "), 0x80);
669  D_PrintHex<uint8_t > (hcibuf[2], 0x80);
670 #endif
672  hci_state = HCI_DISCONNECT_STATE;
673  }
674  break;
675 
677 #ifdef DEBUG_USB_HOST
678  Notify(PSTR("\r\nReceived IO Capability Request"), 0x80);
679 #endif
681  break;
682 
684 #ifdef EXTRADEBUG
685  Notify(PSTR("\r\nReceived IO Capability Response: "), 0x80);
686  Notify(PSTR("\r\nIO capability: "), 0x80);
687  D_PrintHex<uint8_t > (hcibuf[8], 0x80);
688  Notify(PSTR("\r\nOOB data present: "), 0x80);
689  D_PrintHex<uint8_t > (hcibuf[9], 0x80);
690  Notify(PSTR("\r\nAuthentication request: "), 0x80);
691  D_PrintHex<uint8_t > (hcibuf[10], 0x80);
692 #endif
693  break;
694 
696 #ifdef DEBUG_USB_HOST
697  Notify(PSTR("\r\nUser confirmation Request"), 0x80);
698 #ifdef EXTRADEBUG
699  Notify(PSTR(": \r\nNumeric value: "), 0x80);
700  for(uint8_t i = 0; i < 4; i++) {
701  Notify(PSTR(" "), 0x80);
702  D_PrintHex<uint8_t > (hcibuf[8 + i], 0x80);
703  }
704 #endif
705 #endif
706  // Simply confirm the connection, as the host has no "NoInputNoOutput" capabilities
708  break;
709 
711 #ifdef EXTRADEBUG
712  if(!hcibuf[2]) { // Check if connected OK
713  Notify(PSTR("\r\nSimple Pairing succeeded"), 0x80);
714  } else {
715  Notify(PSTR("\r\nSimple Pairing failed: "), 0x80);
716  D_PrintHex<uint8_t > (hcibuf[2], 0x80);
717  }
718 #endif
719  break;
720 
721  /* We will just ignore the following events */
722  case EV_MAX_SLOTS_CHANGE:
723  case EV_NUM_COMPLETE_PKT:
724  break;
725  case EV_ROLE_CHANGED:
727  case EV_LOOPBACK_COMMAND:
734 #ifdef EXTRADEBUG
735  if(hcibuf[0] != 0x00) {
736  Notify(PSTR("\r\nIgnore HCI Event: "), 0x80);
737  D_PrintHex<uint8_t > (hcibuf[0], 0x80);
738  }
739 #endif
740  break;
741 #ifdef EXTRADEBUG
742  default:
743  if(hcibuf[0] != 0x00) {
744  Notify(PSTR("\r\nUnmanaged HCI Event: "), 0x80);
745  D_PrintHex<uint8_t > (hcibuf[0], 0x80);
746  Notify(PSTR(", data: "), 0x80);
747  for(uint16_t i = 0; i < hcibuf[1]; i++) {
748  D_PrintHex<uint8_t > (hcibuf[2 + i], 0x80);
749  Notify(PSTR(" "), 0x80);
750  }
751  }
752  break;
753 #endif
754  } // Switch
755  }
756 #ifdef EXTRADEBUG
757  else {
758  Notify(PSTR("\r\nHCI event error: "), 0x80);
759  D_PrintHex<uint8_t > (rcode, 0x80);
760  }
761 #endif
762 }
763 
764 /* Poll Bluetooth and print result */
765 void BTD::HCI_task() {
766  switch(hci_state) {
767  case HCI_INIT_STATE:
768  hci_counter++;
769  if(hci_counter > hci_num_reset_loops) { // wait until we have looped x times to clear any old events
770  hci_reset();
771  hci_state = HCI_RESET_STATE;
772  hci_counter = 0;
773  }
774  break;
775 
776  case HCI_RESET_STATE:
777  hci_counter++;
779  hci_counter = 0;
780 #ifdef DEBUG_USB_HOST
781  Notify(PSTR("\r\nHCI Reset complete"), 0x80);
782 #endif
783  hci_state = HCI_CLASS_STATE;
785  } else if(hci_counter > hci_num_reset_loops) {
786  hci_num_reset_loops *= 10;
787  if(hci_num_reset_loops > 2000)
788  hci_num_reset_loops = 2000;
789 #ifdef DEBUG_USB_HOST
790  Notify(PSTR("\r\nNo response to HCI Reset"), 0x80);
791 #endif
792  hci_state = HCI_INIT_STATE;
793  hci_counter = 0;
794  }
795  break;
796 
797  case HCI_CLASS_STATE:
799 #ifdef DEBUG_USB_HOST
800  Notify(PSTR("\r\nWrite class of device"), 0x80);
801 #endif
802  hci_state = HCI_BDADDR_STATE;
803  hci_read_bdaddr();
804  }
805  break;
806 
807  case HCI_BDADDR_STATE:
809 #ifdef DEBUG_USB_HOST
810  Notify(PSTR("\r\nLocal Bluetooth Address: "), 0x80);
811  for(int8_t i = 5; i > 0; i--) {
812  D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
813  Notify(PSTR(":"), 0x80);
814  }
815  D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
816 #endif
818  hci_state = HCI_LOCAL_VERSION_STATE;
819  }
820  break;
821 
822  case HCI_LOCAL_VERSION_STATE: // The local version is used by the PS3BT class
824  if(btdName != NULL) {
826  hci_state = HCI_WRITE_NAME_STATE;
827  } else if(useSimplePairing) {
828  hci_read_local_extended_features(0); // "Requests the normal LMP features as returned by Read_Local_Supported_Features"
829  //hci_read_local_extended_features(1); // Read page 1
831  } else
832  hci_state = HCI_CHECK_DEVICE_SERVICE;
833  }
834  break;
835 
838 #ifdef DEBUG_USB_HOST
839  Notify(PSTR("\r\nThe name was set to: "), 0x80);
840  NotifyStr(btdName, 0x80);
841 #endif
842  if(useSimplePairing) {
843  hci_read_local_extended_features(0); // "Requests the normal LMP features as returned by Read_Local_Supported_Features"
844  //hci_read_local_extended_features(1); // Read page 1
846  } else
847  hci_state = HCI_CHECK_DEVICE_SERVICE;
848  }
849  break;
850 
853  if(simple_pairing_supported) {
855  hci_state = HCI_WRITE_SIMPLE_PAIRING_STATE;
856  } else
857  hci_state = HCI_CHECK_DEVICE_SERVICE;
858  }
859  break;
860 
863 #ifdef DEBUG_USB_HOST
864  Notify(PSTR("\r\nSimple pairing was enabled"), 0x80);
865 #endif
867  hci_state = HCI_SET_EVENT_MASK_STATE;
868  }
869  break;
870 
873 #ifdef DEBUG_USB_HOST
874  Notify(PSTR("\r\nSet event mask completed"), 0x80);
875 #endif
876  hci_state = HCI_CHECK_DEVICE_SERVICE;
877  }
878  break;
879 
881  if(pairWithHIDDevice || pairWithWii) { // Check if it should try to connect to a Wiimote
882 #ifdef DEBUG_USB_HOST
883  if(pairWithWii)
884  Notify(PSTR("\r\nStarting inquiry\r\nPress 1 & 2 on the Wiimote\r\nOr press the SYNC button if you are using a Wii U Pro Controller or a Wii Balance Board"), 0x80);
885  else
886  Notify(PSTR("\r\nPlease enable discovery of your device"), 0x80);
887 #endif
888  hci_inquiry();
889  hci_state = HCI_INQUIRY_STATE;
890  } else
891  hci_state = HCI_SCANNING_STATE; // Don't try to connect to a Wiimote
892  break;
893 
894  case HCI_INQUIRY_STATE:
896  hci_inquiry_cancel(); // Stop inquiry
897 #ifdef DEBUG_USB_HOST
898  if(pairWithWii)
899  Notify(PSTR("\r\nWiimote found"), 0x80);
900  else
901  Notify(PSTR("\r\nHID device found"), 0x80);
902 
903  Notify(PSTR("\r\nNow just create the instance like so:"), 0x80);
904  if(pairWithWii)
905  Notify(PSTR("\r\nWII Wii(&Btd);"), 0x80);
906  else
907  Notify(PSTR("\r\nBTHID bthid(&Btd);"), 0x80);
908 
909  Notify(PSTR("\r\nAnd then press any button on the "), 0x80);
910  if(pairWithWii)
911  Notify(PSTR("Wiimote"), 0x80);
912  else
913  Notify(PSTR("device"), 0x80);
914 #endif
915  if(checkRemoteName) {
916  hci_remote_name(); // We need to know the name to distinguish between the Wiimote, the new Wiimote with Motion Plus inside, a Wii U Pro Controller and a Wii Balance Board
917  hci_state = HCI_REMOTE_NAME_STATE;
918  } else
919  hci_state = HCI_CONNECT_DEVICE_STATE;
920  }
921  break;
922 
925 #ifdef DEBUG_USB_HOST
926  if(pairWithWii)
927  Notify(PSTR("\r\nConnecting to Wiimote"), 0x80);
928  else
929  Notify(PSTR("\r\nConnecting to HID device"), 0x80);
930 #endif
931  checkRemoteName = false;
932  hci_connect();
933  hci_state = HCI_CONNECTED_DEVICE_STATE;
934  }
935  break;
936 
940 #ifdef DEBUG_USB_HOST
941  if(pairWithWii)
942  Notify(PSTR("\r\nConnected to Wiimote"), 0x80);
943  else
944  Notify(PSTR("\r\nConnected to HID device"), 0x80);
945 #endif
946  hci_authentication_request(); // This will start the pairing with the device
947  hci_state = HCI_SCANNING_STATE;
948  } else {
949 #ifdef DEBUG_USB_HOST
950  Notify(PSTR("\r\nTrying to connect one more time..."), 0x80);
951 #endif
952  hci_connect(); // Try to connect one more time
953  }
954  }
955  break;
956 
957  case HCI_SCANNING_STATE:
959 #ifdef DEBUG_USB_HOST
960  Notify(PSTR("\r\nWait For Incoming Connection Request"), 0x80);
961 #endif
963  waitingForConnection = true;
964  hci_state = HCI_CONNECT_IN_STATE;
965  }
966  break;
967 
970  waitingForConnection = false;
971 #ifdef DEBUG_USB_HOST
972  Notify(PSTR("\r\nIncoming Connection Request"), 0x80);
973 #endif
974  hci_remote_name();
975  hci_state = HCI_REMOTE_NAME_STATE;
977  hci_state = HCI_DISCONNECT_STATE;
978  break;
979 
982 #ifdef DEBUG_USB_HOST
983  Notify(PSTR("\r\nRemote Name: "), 0x80);
984  for(uint8_t i = 0; i < strlen(remote_name); i++)
985  Notifyc(remote_name[i], 0x80);
986 #endif
987  if(strncmp((const char*)remote_name, "Nintendo", 8) == 0) {
988  incomingWii = true;
989  motionPlusInside = false;
990  wiiUProController = false;
991  pairWiiUsingSync = false;
992 #ifdef DEBUG_USB_HOST
993  Notify(PSTR("\r\nWiimote is connecting"), 0x80);
994 #endif
995  if(strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-TR", 22) == 0) {
996 #ifdef DEBUG_USB_HOST
997  Notify(PSTR(" with Motion Plus Inside"), 0x80);
998 #endif
999  motionPlusInside = true;
1000  } else if(strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-UC", 22) == 0) {
1001 #ifdef DEBUG_USB_HOST
1002  Notify(PSTR(" - Wii U Pro Controller"), 0x80);
1003 #endif
1004  wiiUProController = motionPlusInside = pairWiiUsingSync = true;
1005  } else if(strncmp((const char*)remote_name, "Nintendo RVL-WBC-01", 19) == 0) {
1006 #ifdef DEBUG_USB_HOST
1007  Notify(PSTR(" - Wii Balance Board"), 0x80);
1008 #endif
1009  pairWiiUsingSync = true;
1010  }
1011  }
1012  if(classOfDevice[2] == 0 && classOfDevice[1] == 0x25 && classOfDevice[0] == 0x08 && strncmp((const char*)remote_name, "Wireless Controller", 19) == 0) {
1013 #ifdef DEBUG_USB_HOST
1014  Notify(PSTR("\r\nPS4 controller is connecting"), 0x80);
1015 #endif
1016  incomingPS4 = true;
1017  }
1018  if((pairWithWii || pairWithHIDDevice) && checkRemoteName)
1019  hci_state = HCI_CONNECT_DEVICE_STATE;
1020  else {
1022  hci_state = HCI_CONNECTED_STATE;
1023  }
1024  }
1025  break;
1026 
1027  case HCI_CONNECTED_STATE:
1029 #ifdef DEBUG_USB_HOST
1030  Notify(PSTR("\r\nConnected to Device: "), 0x80);
1031  for(int8_t i = 5; i > 0; i--) {
1032  D_PrintHex<uint8_t > (disc_bdaddr[i], 0x80);
1033  Notify(PSTR(":"), 0x80);
1034  }
1035  D_PrintHex<uint8_t > (disc_bdaddr[0], 0x80);
1036 #endif
1037  if(incomingPS4)
1038  connectToHIDDevice = true; // We should always connect to the PS4 controller
1039 
1040  // Clear these flags for a new connection
1041  l2capConnectionClaimed = false;
1042  sdpConnectionClaimed = false;
1043  rfcommConnectionClaimed = false;
1044 
1045  hci_event_flag = 0;
1046  hci_state = HCI_DONE_STATE;
1047  }
1048  break;
1049 
1050  case HCI_DONE_STATE:
1051  hci_counter++;
1052  if(hci_counter > 1000) { // Wait until we have looped 1000 times to make sure that the L2CAP connection has been started
1053  hci_counter = 0;
1054  hci_state = HCI_SCANNING_STATE;
1055  }
1056  break;
1057 
1058  case HCI_DISCONNECT_STATE:
1060 #ifdef DEBUG_USB_HOST
1061  Notify(PSTR("\r\nHCI Disconnected from Device"), 0x80);
1062 #endif
1063  hci_event_flag = 0; // Clear all flags
1064 
1065  // Reset all buffers
1066  memset(hcibuf, 0, BULK_MAXPKTSIZE);
1067  memset(l2capinbuf, 0, BULK_MAXPKTSIZE);
1068 
1069  connectToWii = incomingWii = pairWithWii = false;
1070  connectToHIDDevice = incomingHIDDevice = pairWithHIDDevice = checkRemoteName = false;
1071  incomingPS4 = false;
1072 
1073  hci_state = HCI_SCANNING_STATE;
1074  }
1075  break;
1076  default:
1077  break;
1078  }
1079 }
1080 
1081 void BTD::ACL_event_task() {
1082  uint16_t length = BULK_MAXPKTSIZE;
1083  uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_DATAIN_PIPE ].epAddr, &length, l2capinbuf, pollInterval); // Input on endpoint 2
1084 
1085  if(!rcode) { // Check for errors
1086  if(length > 0) { // Check if any data was read
1087  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) {
1088  if(btService[i])
1089  btService[i]->ACLData(l2capinbuf);
1090  }
1091  }
1092  }
1093 #ifdef EXTRADEBUG
1094  else if(rcode != hrNAK) {
1095  Notify(PSTR("\r\nACL data in error: "), 0x80);
1096  D_PrintHex<uint8_t > (rcode, 0x80);
1097  }
1098 #endif
1099  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
1100  if(btService[i])
1101  btService[i]->Run();
1102 }
1103 
1104 /************************************************************/
1105 /* HCI Commands */
1106 
1107 /************************************************************/
1108 void BTD::HCI_Command(uint8_t* data, uint16_t nbytes) {
1110  pUsb->ctrlReq(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bmREQ_HCI_OUT, 0x00, 0x00, 0x00, 0x00, nbytes, nbytes, data, NULL);
1111 }
1112 
1114  hci_event_flag = 0; // Clear all the flags
1115  hcibuf[0] = 0x03; // HCI OCF = 3
1116  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1117  hcibuf[2] = 0x00;
1118 
1119  HCI_Command(hcibuf, 3);
1120 }
1121 
1124  hcibuf[0] = 0x1A; // HCI OCF = 1A
1125  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1126  hcibuf[2] = 0x01; // parameter length = 1
1127  if(btdName != NULL)
1128  hcibuf[3] = 0x03; // Inquiry Scan enabled. Page Scan enabled.
1129  else
1130  hcibuf[3] = 0x02; // Inquiry Scan disabled. Page Scan enabled.
1131 
1132  HCI_Command(hcibuf, 4);
1133 }
1134 
1136  hcibuf[0] = 0x1A; // HCI OCF = 1A
1137  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1138  hcibuf[2] = 0x01; // parameter length = 1
1139  hcibuf[3] = 0x00; // Inquiry Scan disabled. Page Scan disabled.
1140 
1141  HCI_Command(hcibuf, 4);
1142 }
1143 
1146  hcibuf[0] = 0x09; // HCI OCF = 9
1147  hcibuf[1] = 0x04 << 2; // HCI OGF = 4
1148  hcibuf[2] = 0x00;
1149 
1150  HCI_Command(hcibuf, 3);
1151 }
1152 
1155  hcibuf[0] = 0x01; // HCI OCF = 1
1156  hcibuf[1] = 0x04 << 2; // HCI OGF = 4
1157  hcibuf[2] = 0x00;
1158 
1159  HCI_Command(hcibuf, 3);
1160 }
1161 
1162 void BTD::hci_read_local_extended_features(uint8_t page_number) {
1164  hcibuf[0] = 0x04; // HCI OCF = 4
1165  hcibuf[1] = 0x04 << 2; // HCI OGF = 4
1166  hcibuf[2] = 0x01; // parameter length = 1
1167  hcibuf[3] = page_number;
1168 
1169  HCI_Command(hcibuf, 4);
1170 }
1171 
1174  hcibuf[0] = 0x09; // HCI OCF = 9
1175  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1176  hcibuf[2] = 0x07; // parameter length 7
1177  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1178  hcibuf[4] = disc_bdaddr[1];
1179  hcibuf[5] = disc_bdaddr[2];
1180  hcibuf[6] = disc_bdaddr[3];
1181  hcibuf[7] = disc_bdaddr[4];
1182  hcibuf[8] = disc_bdaddr[5];
1183  hcibuf[9] = 0x00; // Switch role to master
1184 
1185  HCI_Command(hcibuf, 10);
1186 }
1187 
1190  hcibuf[0] = 0x19; // HCI OCF = 19
1191  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1192  hcibuf[2] = 0x0A; // parameter length = 10
1193  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1194  hcibuf[4] = disc_bdaddr[1];
1195  hcibuf[5] = disc_bdaddr[2];
1196  hcibuf[6] = disc_bdaddr[3];
1197  hcibuf[7] = disc_bdaddr[4];
1198  hcibuf[8] = disc_bdaddr[5];
1199  hcibuf[9] = 0x01; // Page Scan Repetition Mode
1200  hcibuf[10] = 0x00; // Reserved
1201  hcibuf[11] = 0x00; // Clock offset - low byte
1202  hcibuf[12] = 0x00; // Clock offset - high byte
1203 
1204  HCI_Command(hcibuf, 13);
1205 }
1206 
1207 void BTD::hci_write_local_name(const char* name) {
1208  hcibuf[0] = 0x13; // HCI OCF = 13
1209  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1210  hcibuf[2] = strlen(name) + 1; // parameter length = the length of the string + end byte
1211  uint8_t i;
1212  for(i = 0; i < strlen(name); i++)
1213  hcibuf[i + 3] = name[i];
1214  hcibuf[i + 3] = 0x00; // End of string
1215 
1216  HCI_Command(hcibuf, 4 + strlen(name));
1217 }
1218 
1220  hcibuf[0] = 0x01; // HCI OCF = 01
1221  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1222  hcibuf[2] = 0x08;
1223  // The first 6 bytes are the default of 1FFF FFFF FFFF
1224  // However we need to set bits 48-55 for simple pairing to work
1225  hcibuf[3] = 0xFF;
1226  hcibuf[4] = 0xFF;
1227  hcibuf[5] = 0xFF;
1228  hcibuf[6] = 0xFF;
1229  hcibuf[7] = 0xFF;
1230  hcibuf[8] = 0x1F;
1231  hcibuf[9] = 0xFF; // Enable bits 48-55 used for simple pairing
1232  hcibuf[10] = 0x00;
1233 
1234  HCI_Command(hcibuf, 11);
1235 }
1236 
1238  hcibuf[0] = 0x56; // HCI OCF = 56
1239  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1240  hcibuf[2] = 1; // parameter length = 1
1241  hcibuf[3] = enable ? 1 : 0;
1242 
1243  HCI_Command(hcibuf, 4);
1244 }
1245 
1248  hcibuf[0] = 0x01;
1249  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1250  hcibuf[2] = 0x05; // Parameter Total Length = 5
1251  hcibuf[3] = 0x33; // LAP: Genera/Unlimited Inquiry Access Code (GIAC = 0x9E8B33) - see https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
1252  hcibuf[4] = 0x8B;
1253  hcibuf[5] = 0x9E;
1254  hcibuf[6] = 0x30; // Inquiry time = 61.44 sec (maximum)
1255  hcibuf[7] = 0x0A; // 10 number of responses
1256 
1257  HCI_Command(hcibuf, 8);
1258 }
1259 
1261  hcibuf[0] = 0x02;
1262  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1263  hcibuf[2] = 0x00; // Parameter Total Length = 0
1264 
1265  HCI_Command(hcibuf, 3);
1266 }
1267 
1269  hci_connect(disc_bdaddr); // Use last discovered device
1270 }
1271 
1272 void BTD::hci_connect(uint8_t *bdaddr) {
1274  hcibuf[0] = 0x05; // HCI OCF = 5
1275  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1276  hcibuf[2] = 0x0D; // parameter Total Length = 13
1277  hcibuf[3] = bdaddr[0]; // 6 octet bdaddr (LSB)
1278  hcibuf[4] = bdaddr[1];
1279  hcibuf[5] = bdaddr[2];
1280  hcibuf[6] = bdaddr[3];
1281  hcibuf[7] = bdaddr[4];
1282  hcibuf[8] = bdaddr[5];
1283  hcibuf[9] = 0x18; // DM1 or DH1 may be used
1284  hcibuf[10] = 0xCC; // DM3, DH3, DM5, DH5 may be used
1285  hcibuf[11] = 0x01; // Page repetition mode R1
1286  hcibuf[12] = 0x00; // Reserved
1287  hcibuf[13] = 0x00; // Clock offset
1288  hcibuf[14] = 0x00; // Invalid clock offset
1289  hcibuf[15] = 0x00; // Do not allow role switch
1290 
1291  HCI_Command(hcibuf, 16);
1292 }
1293 
1295  hcibuf[0] = 0x0D; // HCI OCF = 0D
1296  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1297  hcibuf[2] = 0x17; // parameter length 23
1298  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1299  hcibuf[4] = disc_bdaddr[1];
1300  hcibuf[5] = disc_bdaddr[2];
1301  hcibuf[6] = disc_bdaddr[3];
1302  hcibuf[7] = disc_bdaddr[4];
1303  hcibuf[8] = disc_bdaddr[5];
1304  if(pairWithWii) {
1305  hcibuf[9] = 6; // Pin length is the length of the Bluetooth address
1306  if(pairWiiUsingSync) {
1307 #ifdef DEBUG_USB_HOST
1308  Notify(PSTR("\r\nPairing with Wii controller via SYNC"), 0x80);
1309 #endif
1310  for(uint8_t i = 0; i < 6; i++)
1311  hcibuf[10 + i] = my_bdaddr[i]; // The pin is the Bluetooth dongles Bluetooth address backwards
1312  } else {
1313  for(uint8_t i = 0; i < 6; i++)
1314  hcibuf[10 + i] = disc_bdaddr[i]; // The pin is the Wiimote's Bluetooth address backwards
1315  }
1316  for(uint8_t i = 16; i < 26; i++)
1317  hcibuf[i] = 0x00; // The rest should be 0
1318  } else {
1319  hcibuf[9] = strlen(btdPin); // Length of pin
1320  uint8_t i;
1321  for(i = 0; i < strlen(btdPin); i++) // The maximum size of the pin is 16
1322  hcibuf[i + 10] = btdPin[i];
1323  for(; i < 16; i++)
1324  hcibuf[i + 10] = 0x00; // The rest should be 0
1325  }
1326 
1327  HCI_Command(hcibuf, 26);
1328 }
1329 
1331  hcibuf[0] = 0x0E; // HCI OCF = 0E
1332  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1333  hcibuf[2] = 0x06; // parameter length 6
1334  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1335  hcibuf[4] = disc_bdaddr[1];
1336  hcibuf[5] = disc_bdaddr[2];
1337  hcibuf[6] = disc_bdaddr[3];
1338  hcibuf[7] = disc_bdaddr[4];
1339  hcibuf[8] = disc_bdaddr[5];
1340 
1341  HCI_Command(hcibuf, 9);
1342 }
1343 
1345  hcibuf[0] = 0x0C; // HCI OCF = 0C
1346  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1347  hcibuf[2] = 0x06; // parameter length 6
1348  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1349  hcibuf[4] = disc_bdaddr[1];
1350  hcibuf[5] = disc_bdaddr[2];
1351  hcibuf[6] = disc_bdaddr[3];
1352  hcibuf[7] = disc_bdaddr[4];
1353  hcibuf[8] = disc_bdaddr[5];
1354 
1355  HCI_Command(hcibuf, 9);
1356 }
1357 
1359  hcibuf[0] = 0x2B; // HCI OCF = 2B
1360  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1361  hcibuf[2] = 0x09;
1362  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1363  hcibuf[4] = disc_bdaddr[1];
1364  hcibuf[5] = disc_bdaddr[2];
1365  hcibuf[6] = disc_bdaddr[3];
1366  hcibuf[7] = disc_bdaddr[4];
1367  hcibuf[8] = disc_bdaddr[5];
1368  hcibuf[9] = 0x03; // NoInputNoOutput
1369  hcibuf[10] = 0x00; // OOB authentication data not present
1370  hcibuf[11] = 0x00; // MITM Protection Not Required – No Bonding. Numeric comparison with automatic accept allowed
1371 
1372  HCI_Command(hcibuf, 12);
1373 }
1374 
1376  hcibuf[0] = 0x2C; // HCI OCF = 2C
1377  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1378  hcibuf[2] = 0x06; // parameter length 6
1379  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1380  hcibuf[4] = disc_bdaddr[1];
1381  hcibuf[5] = disc_bdaddr[2];
1382  hcibuf[6] = disc_bdaddr[3];
1383  hcibuf[7] = disc_bdaddr[4];
1384  hcibuf[8] = disc_bdaddr[5];
1385 
1386  HCI_Command(hcibuf, 9);
1387 }
1388 
1390  hcibuf[0] = 0x11; // HCI OCF = 11
1391  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1392  hcibuf[2] = 0x02; // parameter length = 2
1393  hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte
1394  hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte
1395 
1396  HCI_Command(hcibuf, 5);
1397 }
1398 
1399 void BTD::hci_disconnect(uint16_t handle) { // This is called by the different services
1401  hcibuf[0] = 0x06; // HCI OCF = 6
1402  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1403  hcibuf[2] = 0x03; // parameter length = 3
1404  hcibuf[3] = (uint8_t)(handle & 0xFF); //connection handle - low byte
1405  hcibuf[4] = (uint8_t)((handle >> 8) & 0x0F); //connection handle - high byte
1406  hcibuf[5] = 0x13; // reason
1407 
1408  HCI_Command(hcibuf, 6);
1409 }
1410 
1411 void BTD::hci_write_class_of_device() { // See http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html
1412  hcibuf[0] = 0x24; // HCI OCF = 24
1413  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1414  hcibuf[2] = 0x03; // parameter length = 3
1415  hcibuf[3] = 0x04; // Robot
1416  hcibuf[4] = 0x08; // Toy
1417  hcibuf[5] = 0x00;
1418 
1419  HCI_Command(hcibuf, 6);
1420 }
1421 /*******************************************************************
1422  * *
1423  * HCI ACL Data Packet *
1424  * *
1425  * buf[0] buf[1] buf[2] buf[3]
1426  * 0 4 8 11 12 16 24 31 MSB
1427  * .-+-+-+-+-+-+-+-|-+-+-+-|-+-|-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1428  * | HCI Handle |PB |BC | Data Total Length | HCI ACL Data Packet
1429  * .-+-+-+-+-+-+-+-|-+-+-+-|-+-|-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1430  *
1431  * buf[4] buf[5] buf[6] buf[7]
1432  * 0 8 16 31 MSB
1433  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1434  * | Length | Channel ID | Basic L2CAP header
1435  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1436  *
1437  * buf[8] buf[9] buf[10] buf[11]
1438  * 0 8 16 31 MSB
1439  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1440  * | Code | Identifier | Length | Control frame (C-frame)
1441  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-. (signaling packet format)
1442  */
1443 /************************************************************/
1444 /* L2CAP Commands */
1445 
1446 /************************************************************/
1447 void BTD::L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t channelLow, uint8_t channelHigh) {
1448  uint8_t buf[8 + nbytes];
1449  buf[0] = (uint8_t)(handle & 0xff); // HCI handle with PB,BC flag
1450  buf[1] = (uint8_t)(((handle >> 8) & 0x0f) | 0x20);
1451  buf[2] = (uint8_t)((4 + nbytes) & 0xff); // HCI ACL total data length
1452  buf[3] = (uint8_t)((4 + nbytes) >> 8);
1453  buf[4] = (uint8_t)(nbytes & 0xff); // L2CAP header: Length
1454  buf[5] = (uint8_t)(nbytes >> 8);
1455  buf[6] = channelLow;
1456  buf[7] = channelHigh;
1457 
1458  for(uint16_t i = 0; i < nbytes; i++) // L2CAP C-frame
1459  buf[8 + i] = data[i];
1460 
1461  uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ BTD_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf);
1462  if(rcode) {
1463  delay(100); // This small delay prevents it from overflowing if it fails
1464 #ifdef DEBUG_USB_HOST
1465  Notify(PSTR("\r\nError sending L2CAP message: 0x"), 0x80);
1466  D_PrintHex<uint8_t > (rcode, 0x80);
1467  Notify(PSTR(" - Channel ID: "), 0x80);
1468  D_PrintHex<uint8_t > (channelHigh, 0x80);
1469  Notify(PSTR(" "), 0x80);
1470  D_PrintHex<uint8_t > (channelLow, 0x80);
1471 #endif
1472  }
1473 }
1474 
1475 void BTD::l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm) {
1476  l2capoutbuf[0] = L2CAP_CMD_CONNECTION_REQUEST; // Code
1477  l2capoutbuf[1] = rxid; // Identifier
1478  l2capoutbuf[2] = 0x04; // Length
1479  l2capoutbuf[3] = 0x00;
1480  l2capoutbuf[4] = (uint8_t)(psm & 0xff); // PSM
1481  l2capoutbuf[5] = (uint8_t)(psm >> 8);
1482  l2capoutbuf[6] = scid[0]; // Source CID
1483  l2capoutbuf[7] = scid[1];
1484 
1485  L2CAP_Command(handle, l2capoutbuf, 8);
1486 }
1487 
1488 void BTD::l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result) {
1489  l2capoutbuf[0] = L2CAP_CMD_CONNECTION_RESPONSE; // Code
1490  l2capoutbuf[1] = rxid; // Identifier
1491  l2capoutbuf[2] = 0x08; // Length
1492  l2capoutbuf[3] = 0x00;
1493  l2capoutbuf[4] = dcid[0]; // Destination CID
1494  l2capoutbuf[5] = dcid[1];
1495  l2capoutbuf[6] = scid[0]; // Source CID
1496  l2capoutbuf[7] = scid[1];
1497  l2capoutbuf[8] = result; // Result: Pending or Success
1498  l2capoutbuf[9] = 0x00;
1499  l2capoutbuf[10] = 0x00; // No further information
1500  l2capoutbuf[11] = 0x00;
1501 
1502  L2CAP_Command(handle, l2capoutbuf, 12);
1503 }
1504 
1505 void BTD::l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t* dcid) {
1506  l2capoutbuf[0] = L2CAP_CMD_CONFIG_REQUEST; // Code
1507  l2capoutbuf[1] = rxid; // Identifier
1508  l2capoutbuf[2] = 0x08; // Length
1509  l2capoutbuf[3] = 0x00;
1510  l2capoutbuf[4] = dcid[0]; // Destination CID
1511  l2capoutbuf[5] = dcid[1];
1512  l2capoutbuf[6] = 0x00; // Flags
1513  l2capoutbuf[7] = 0x00;
1514  l2capoutbuf[8] = 0x01; // Config Opt: type = MTU (Maximum Transmission Unit) - Hint
1515  l2capoutbuf[9] = 0x02; // Config Opt: length
1516  l2capoutbuf[10] = 0xFF; // MTU
1517  l2capoutbuf[11] = 0xFF;
1518 
1519  L2CAP_Command(handle, l2capoutbuf, 12);
1520 }
1521 
1522 void BTD::l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid) {
1523  l2capoutbuf[0] = L2CAP_CMD_CONFIG_RESPONSE; // Code
1524  l2capoutbuf[1] = rxid; // Identifier
1525  l2capoutbuf[2] = 0x0A; // Length
1526  l2capoutbuf[3] = 0x00;
1527  l2capoutbuf[4] = scid[0]; // Source CID
1528  l2capoutbuf[5] = scid[1];
1529  l2capoutbuf[6] = 0x00; // Flag
1530  l2capoutbuf[7] = 0x00;
1531  l2capoutbuf[8] = 0x00; // Result
1532  l2capoutbuf[9] = 0x00;
1533  l2capoutbuf[10] = 0x01; // Config
1534  l2capoutbuf[11] = 0x02;
1535  l2capoutbuf[12] = 0xA0;
1536  l2capoutbuf[13] = 0x02;
1537 
1538  L2CAP_Command(handle, l2capoutbuf, 14);
1539 }
1540 
1541 void BTD::l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid) {
1542  l2capoutbuf[0] = L2CAP_CMD_DISCONNECT_REQUEST; // Code
1543  l2capoutbuf[1] = rxid; // Identifier
1544  l2capoutbuf[2] = 0x04; // Length
1545  l2capoutbuf[3] = 0x00;
1546  l2capoutbuf[4] = dcid[0];
1547  l2capoutbuf[5] = dcid[1];
1548  l2capoutbuf[6] = scid[0];
1549  l2capoutbuf[7] = scid[1];
1550 
1551  L2CAP_Command(handle, l2capoutbuf, 8);
1552 }
1553 
1554 void BTD::l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid) {
1555  l2capoutbuf[0] = L2CAP_CMD_DISCONNECT_RESPONSE; // Code
1556  l2capoutbuf[1] = rxid; // Identifier
1557  l2capoutbuf[2] = 0x04; // Length
1558  l2capoutbuf[3] = 0x00;
1559  l2capoutbuf[4] = dcid[0];
1560  l2capoutbuf[5] = dcid[1];
1561  l2capoutbuf[6] = scid[0];
1562  l2capoutbuf[7] = scid[1];
1563 
1564  L2CAP_Command(handle, l2capoutbuf, 8);
1565 }
1566 
1567 void BTD::l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh) {
1568  l2capoutbuf[0] = L2CAP_CMD_INFORMATION_RESPONSE; // Code
1569  l2capoutbuf[1] = rxid; // Identifier
1570  l2capoutbuf[2] = 0x08; // Length
1571  l2capoutbuf[3] = 0x00;
1572  l2capoutbuf[4] = infoTypeLow;
1573  l2capoutbuf[5] = infoTypeHigh;
1574  l2capoutbuf[6] = 0x00; // Result = success
1575  l2capoutbuf[7] = 0x00; // Result = success
1576  l2capoutbuf[8] = 0x00;
1577  l2capoutbuf[9] = 0x00;
1578  l2capoutbuf[10] = 0x00;
1579  l2capoutbuf[11] = 0x00;
1580 
1581  L2CAP_Command(handle, l2capoutbuf, 12);
1582 }
1583 
1584 /* PS3 Commands - only set Bluetooth address is implemented in this library */
1585 void BTD::setBdaddr(uint8_t* bdaddr) {
1586  /* Set the internal Bluetooth address */
1587  uint8_t buf[8];
1588  buf[0] = 0x01;
1589  buf[1] = 0x00;
1590 
1591  for(uint8_t i = 0; i < 6; i++)
1592  buf[i + 2] = bdaddr[5 - i]; // Copy into buffer, has to be written reversed, so it is MSB first
1593 
1594  // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
1595  pUsb->ctrlReq(bAddress, epInfo[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL);
1596 }
1597 
1598 void BTD::setMoveBdaddr(uint8_t* bdaddr) {
1599  /* Set the internal Bluetooth address */
1600  uint8_t buf[11];
1601  buf[0] = 0x05;
1602  buf[7] = 0x10;
1603  buf[8] = 0x01;
1604  buf[9] = 0x02;
1605  buf[10] = 0x12;
1606 
1607  for(uint8_t i = 0; i < 6; i++)
1608  buf[i + 1] = bdaddr[i];
1609 
1610  // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x05), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
1611  pUsb->ctrlReq(bAddress, epInfo[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00, 11, 11, buf, NULL);
1612 }
static const uint8_t BTD_DATAOUT_PIPE
Definition: BTD.h:558
+Go to the documentation of this file.
1 /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
2 
3  This software may be distributed and modified under the terms of the GNU
4  General Public License version 2 (GPL2) as published by the Free Software
5  Foundation and appearing in the file GPL2.TXT included in the packaging of
6  this file. Please note that GPL2 Section 2[b] requires that all works based
7  on this software must also be made publicly available under the terms of
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Lauszus, TKJ Electronics
14  Web : http://www.tkjelectronics.com
15  e-mail : kristianl@tkjelectronics.com
16  */
17 
18 #include "BTD.h"
19 // To enable serial debugging see "settings.h"
20 //#define EXTRADEBUG // Uncomment to get even more debugging data
21 
22 const uint8_t BTD::BTD_CONTROL_PIPE = 0;
23 const uint8_t BTD::BTD_EVENT_PIPE = 1;
24 const uint8_t BTD::BTD_DATAIN_PIPE = 2;
25 const uint8_t BTD::BTD_DATAOUT_PIPE = 3;
26 
28 connectToWii(false),
29 pairWithWii(false),
30 connectToHIDDevice(false),
31 pairWithHIDDevice(false),
32 useSimplePairing(false),
33 pUsb(p), // Pointer to USB class instance - mandatory
34 bAddress(0), // Device address - mandatory
35 bNumEP(1), // If config descriptor needs to be parsed
36 qNextPollTime(0), // Reset NextPollTime
37 pollInterval(0),
38 simple_pairing_supported(false),
39 bPollEnable(false) // Don't start polling before dongle is connected
40 {
41  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
42  btService[i] = NULL;
43 
44  Initialize(); // Set all variables, endpoint structs etc. to default values
45 
46  if(pUsb) // Register in USB subsystem
47  pUsb->RegisterDeviceClass(this); // Set devConfig[] entry
48 }
49 
50 uint8_t BTD::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
51  const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
52  uint8_t buf[constBufSize];
53  USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
54  uint8_t rcode;
55  UsbDevice *p = NULL;
56  EpInfo *oldep_ptr = NULL;
57 
58  Initialize(); // Set all variables, endpoint structs etc. to default values
59 
60  AddressPool &addrPool = pUsb->GetAddressPool(); // Get memory address of USB device address pool
61 #ifdef EXTRADEBUG
62  Notify(PSTR("\r\nBTD ConfigureDevice"), 0x80);
63 #endif
64 
65  if(bAddress) { // Check if address has already been assigned to an instance
66 #ifdef DEBUG_USB_HOST
67  Notify(PSTR("\r\nAddress in use"), 0x80);
68 #endif
70  }
71 
72  p = addrPool.GetUsbDevicePtr(0); // Get pointer to pseudo device with address 0 assigned
73  if(!p) {
74 #ifdef DEBUG_USB_HOST
75  Notify(PSTR("\r\nAddress not found"), 0x80);
76 #endif
78  }
79 
80  if(!p->epinfo) {
81 #ifdef DEBUG_USB_HOST
82  Notify(PSTR("\r\nepinfo is null"), 0x80);
83 #endif
85  }
86 
87  oldep_ptr = p->epinfo; // Save old pointer to EP_RECORD of address 0
88  p->epinfo = epInfo; // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
89  p->lowspeed = lowspeed;
90  rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
91 
92  p->epinfo = oldep_ptr; // Restore p->epinfo
93 
94  if(rcode)
95  goto FailGetDevDescr;
96 
97  bAddress = addrPool.AllocAddress(parent, false, port); // Allocate new address according to device class
98 
99  if(!bAddress) {
100 #ifdef DEBUG_USB_HOST
101  Notify(PSTR("\r\nOut of address space"), 0x80);
102 #endif
104  }
105 
106  if (udd->bDeviceClass == 0x09) // Some dongles have an USB hub inside
107  goto FailHub;
108 
109  epInfo[0].maxPktSize = udd->bMaxPacketSize0; // Extract Max Packet Size from device descriptor
110  epInfo[1].epAddr = udd->bNumConfigurations; // Steal and abuse from epInfo structure to save memory
111 
112  VID = udd->idVendor;
113  PID = udd->idProduct;
114 
116 
117 FailHub:
118 #ifdef DEBUG_USB_HOST
119  Notify(PSTR("\r\nPlease create a hub instance in your code: \"USBHub Hub1(&Usb);\""), 0x80);
120 #endif
121  pUsb->setAddr(bAddress, 0, 0); // Reset address
123  Release();
124  return rcode;
125 
126 FailGetDevDescr:
127 #ifdef DEBUG_USB_HOST
128  NotifyFailGetDevDescr(rcode);
129 #endif
130  if(rcode != hrJERR)
132  Release();
133  return rcode;
134 };
135 
136 uint8_t BTD::Init(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed) {
137  uint8_t rcode;
138  uint8_t num_of_conf = epInfo[1].epAddr; // Number of configurations
139  epInfo[1].epAddr = 0;
140 
141  AddressPool &addrPool = pUsb->GetAddressPool();
142 #ifdef EXTRADEBUG
143  Notify(PSTR("\r\nBTD Init"), 0x80);
144 #endif
145  UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record
146 
147  if(!p) {
148 #ifdef DEBUG_USB_HOST
149  Notify(PSTR("\r\nAddress not found"), 0x80);
150 #endif
152  }
153 
154  delay(300); // Assign new address to the device
155 
156  rcode = pUsb->setAddr(0, 0, bAddress); // Assign new address to the device
157  if(rcode) {
158 #ifdef DEBUG_USB_HOST
159  Notify(PSTR("\r\nsetAddr: "), 0x80);
160  D_PrintHex<uint8_t > (rcode, 0x80);
161 #endif
162  p->lowspeed = false;
163  goto Fail;
164  }
165 #ifdef EXTRADEBUG
166  Notify(PSTR("\r\nAddr: "), 0x80);
167  D_PrintHex<uint8_t > (bAddress, 0x80);
168 #endif
169 
170  p->lowspeed = false;
171 
172  p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record
173  if(!p) {
174 #ifdef DEBUG_USB_HOST
175  Notify(PSTR("\r\nAddress not found"), 0x80);
176 #endif
178  }
179 
180  p->lowspeed = lowspeed;
181 
182  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); // Assign epInfo to epinfo pointer - only EP0 is known
183  if(rcode)
184  goto FailSetDevTblEntry;
185 
186  if(VID == PS3_VID && (PID == PS3_PID || PID == PS3NAVIGATION_PID || PID == PS3MOVE_PID)) {
187  delay(100);
188  rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 1); // We only need the Control endpoint, so we don't have to initialize the other endpoints of device
189  if(rcode)
190  goto FailSetConfDescr;
191 
192 #ifdef DEBUG_USB_HOST
193  if(PID == PS3_PID || PID == PS3NAVIGATION_PID) {
194  if(PID == PS3_PID)
195  Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80);
196  else // It must be a navigation controller
197  Notify(PSTR("\r\nNavigation Controller Connected"), 0x80);
198  } else // It must be a Motion controller
199  Notify(PSTR("\r\nMotion Controller Connected"), 0x80);
200 #endif
201 
202  if(my_bdaddr[0] == 0x00 && my_bdaddr[1] == 0x00 && my_bdaddr[2] == 0x00 && my_bdaddr[3] == 0x00 && my_bdaddr[4] == 0x00 && my_bdaddr[5] == 0x00) {
203 #ifdef DEBUG_USB_HOST
204  Notify(PSTR("\r\nPlease plug in the dongle before trying to pair with the PS3 Controller\r\nor set the Bluetooth address in the constructor of the PS3BT class"), 0x80);
205 #endif
206  } else {
207  if(PID == PS3_PID || PID == PS3NAVIGATION_PID)
208  setBdaddr(my_bdaddr); // Set internal Bluetooth address
209  else
210  setMoveBdaddr(my_bdaddr); // Set internal Bluetooth address
211 #ifdef DEBUG_USB_HOST
212  Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80);
213  for(int8_t i = 5; i > 0; i--) {
214  D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
215  Notify(PSTR(":"), 0x80);
216  }
217  D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
218 #endif
219  }
220 
221  pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 0); // Reset configuration value
222  pUsb->setAddr(bAddress, 0, 0); // Reset address
223  Release(); // Release device
225  } else {
226  // Check if attached device is a Bluetooth dongle and fill endpoint data structure
227  // First interface in the configuration must have Bluetooth assigned Class/Subclass/Protocol
228  // And 3 endpoints - interrupt-IN, bulk-IN, bulk-OUT, not necessarily in this order
229  for(uint8_t i = 0; i < num_of_conf; i++) {
230  if((VID == IOGEAR_GBU521_VID && PID == IOGEAR_GBU521_PID) || (VID == BELKIN_F8T065BF_VID && PID == BELKIN_F8T065BF_PID)) {
231  ConfigDescParser<USB_CLASS_VENDOR_SPECIFIC, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Workaround issue with some dongles
232  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
233  } else {
234  ConfigDescParser<USB_CLASS_WIRELESS_CTRL, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Set class id according to the specification
235  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
236  }
237  if(rcode) // Check error code
238  goto FailGetConfDescr;
239  if(bNumEP >= BTD_MAX_ENDPOINTS) // All endpoints extracted
240  break;
241  }
242 
244  goto FailUnknownDevice;
245 
246  // Assign epInfo to epinfo pointer - this time all 3 endpoins
247  rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
248  if(rcode)
249  goto FailSetDevTblEntry;
250 
251  // Set Configuration Value
252  rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bConfNum);
253  if(rcode)
254  goto FailSetConfDescr;
255 
256  hci_num_reset_loops = 100; // only loop 100 times before trying to send the hci reset command
257  hci_counter = 0;
258  hci_state = HCI_INIT_STATE;
259  waitingForConnection = false;
260  bPollEnable = true;
261 
262 #ifdef DEBUG_USB_HOST
263  Notify(PSTR("\r\nBluetooth Dongle Initialized"), 0x80);
264 #endif
265  }
266  return 0; // Successful configuration
267 
268  /* Diagnostic messages */
269 FailSetDevTblEntry:
270 #ifdef DEBUG_USB_HOST
272  goto Fail;
273 #endif
274 
275 FailGetConfDescr:
276 #ifdef DEBUG_USB_HOST
278  goto Fail;
279 #endif
280 
281 FailSetConfDescr:
282 #ifdef DEBUG_USB_HOST
284 #endif
285  goto Fail;
286 
287 FailUnknownDevice:
288 #ifdef DEBUG_USB_HOST
289  NotifyFailUnknownDevice(VID, PID);
290 #endif
291  pUsb->setAddr(bAddress, 0, 0); // Reset address
293 Fail:
294 #ifdef DEBUG_USB_HOST
295  Notify(PSTR("\r\nBTD Init Failed, error code: "), 0x80);
296  NotifyFail(rcode);
297 #endif
298  Release();
299  return rcode;
300 }
301 
302 void BTD::Initialize() {
303  uint8_t i;
304  for(i = 0; i < BTD_MAX_ENDPOINTS; i++) {
305  epInfo[i].epAddr = 0;
306  epInfo[i].maxPktSize = (i) ? 0 : 8;
307  epInfo[i].bmSndToggle = 0;
308  epInfo[i].bmRcvToggle = 0;
310  }
311  for(i = 0; i < BTD_NUM_SERVICES; i++) {
312  if(btService[i])
313  btService[i]->Reset(); // Reset all Bluetooth services
314  }
315 
316  connectToWii = false;
317  incomingWii = false;
318  connectToHIDDevice = false;
319  incomingHIDDevice = false;
320  incomingPSController = false;
321  bAddress = 0; // Clear device address
322  bNumEP = 1; // Must have to be reset to 1
323  qNextPollTime = 0; // Reset next poll time
324  pollInterval = 0;
325  bPollEnable = false; // Don't start polling before dongle is connected
326  simple_pairing_supported = false;
327 }
328 
329 /* Extracts interrupt-IN, bulk-IN, bulk-OUT endpoint information from config descriptor */
330 void BTD::EndpointXtract(uint8_t conf, uint8_t iface __attribute__((unused)), uint8_t alt, uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR *pep) {
331  //ErrorMessage<uint8_t>(PSTR("Conf.Val"),conf);
332  //ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
333  //ErrorMessage<uint8_t>(PSTR("Alt.Set"),alt);
334 
335  if(alt) // Wrong interface - by BT spec, no alt setting
336  return;
337 
338  bConfNum = conf;
339  uint8_t index;
340 
341  if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80) { // Interrupt In endpoint found
342  index = BTD_EVENT_PIPE;
344  } else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) // Bulk endpoint found
345  index = ((pep->bEndpointAddress & 0x80) == 0x80) ? BTD_DATAIN_PIPE : BTD_DATAOUT_PIPE;
346  else
347  return;
348 
349  // Fill the rest of endpoint data structure
350  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
351  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
352 #ifdef EXTRADEBUG
354 #endif
355  if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
356  pollInterval = pep->bInterval;
357  bNumEP++;
358 }
359 
360 void BTD::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr __attribute__((unused))) {
361 #ifdef EXTRADEBUG
362  Notify(PSTR("\r\nEndpoint descriptor:"), 0x80);
363  Notify(PSTR("\r\nLength:\t\t"), 0x80);
364  D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
365  Notify(PSTR("\r\nType:\t\t"), 0x80);
366  D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
367  Notify(PSTR("\r\nAddress:\t"), 0x80);
368  D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
369  Notify(PSTR("\r\nAttributes:\t"), 0x80);
370  D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
371  Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
372  D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
373  Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
374  D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
375 #endif
376 }
377 
378 /* Performs a cleanup after failed Init() attempt */
379 uint8_t BTD::Release() {
380  Initialize(); // Set all variables, endpoint structs etc. to default values
382  return 0;
383 }
384 
385 uint8_t BTD::Poll() {
386  if(!bPollEnable)
387  return 0;
388  if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) { // Don't poll if shorter than polling interval
389  qNextPollTime = (uint32_t)millis() + pollInterval; // Set new poll time
390  HCI_event_task(); // Poll the HCI event pipe
391  HCI_task(); // HCI state machine
392  ACL_event_task(); // Poll the ACL input pipe too
393  }
394  return 0;
395 }
396 
398  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
399  if(btService[i])
400  btService[i]->disconnect();
401 };
402 
403 void BTD::HCI_event_task() {
404  uint16_t length = BULK_MAXPKTSIZE; // Request more than 16 bytes anyway, the inTransfer routine will take care of this
405  uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_EVENT_PIPE ].epAddr, &length, hcibuf, pollInterval); // Input on endpoint 1
406 
407  if(!rcode || rcode == hrNAK) { // Check for errors
408  switch(hcibuf[0]) { // Switch on event type
409  case EV_COMMAND_COMPLETE:
410  if(!hcibuf[5]) { // Check if command succeeded
411  hci_set_flag(HCI_FLAG_CMD_COMPLETE); // Set command complete flag
412  if((hcibuf[3] == 0x01) && (hcibuf[4] == 0x10)) { // Parameters from read local version information
413  hci_version = hcibuf[6]; // Used to check if it supports 2.0+EDR - see http://www.bluetooth.org/Technical/AssignedNumbers/hci.htm
414 #ifdef EXTRADEBUG
416  Notify(PSTR("\r\nHCI version: "), 0x80);
417  D_PrintHex<uint8_t > (hci_version, 0x80);
418  }
419 #endif
421  } else if((hcibuf[3] == 0x04) && (hcibuf[4] == 0x10)) { // Parameters from read local extended features
423 #ifdef EXTRADEBUG
424  Notify(PSTR("\r\nPage number: "), 0x80);
425  D_PrintHex<uint8_t > (hcibuf[6], 0x80);
426  Notify(PSTR("\r\nMaximum page number: "), 0x80);
427  D_PrintHex<uint8_t > (hcibuf[7], 0x80);
428  Notify(PSTR("\r\nExtended LMP features:"), 0x80);
429  for(uint8_t i = 0; i < 8; i++) {
430  Notify(PSTR(" "), 0x80);
431  D_PrintHex<uint8_t > (hcibuf[8 + i], 0x80);
432  }
433 #endif
434  if(hcibuf[6] == 0) { // Page 0
435 #ifdef DEBUG_USB_HOST
436  Notify(PSTR("\r\nDongle "), 0x80);
437 #endif
438  if(hcibuf[8 + 6] & (1U << 3)) {
439  simple_pairing_supported = true;
440 #ifdef DEBUG_USB_HOST
441  Notify(PSTR("supports"), 0x80);
442 #endif
443  } else {
444  simple_pairing_supported = false;
445 #ifdef DEBUG_USB_HOST
446  Notify(PSTR("does NOT support"), 0x80);
447 #endif
448  }
449 #ifdef DEBUG_USB_HOST
450  Notify(PSTR(" secure simple pairing (controller support)"), 0x80);
451 #endif
452  } else if(hcibuf[6] == 1) { // Page 1
453 #ifdef DEBUG_USB_HOST
454  Notify(PSTR("\r\nDongle "), 0x80);
455  if(hcibuf[8 + 0] & (1U << 0))
456  Notify(PSTR("supports"), 0x80);
457  else
458  Notify(PSTR("does NOT support"), 0x80);
459  Notify(PSTR(" secure simple pairing (host support)"), 0x80);
460 #endif
461  }
462  }
463 
465  } else if((hcibuf[3] == 0x09) && (hcibuf[4] == 0x10)) { // Parameters from read local bluetooth address
466  for(uint8_t i = 0; i < 6; i++)
467  my_bdaddr[i] = hcibuf[6 + i];
469  }
470  }
471  break;
472 
473  case EV_COMMAND_STATUS:
474  if(hcibuf[2]) { // Show status on serial if not OK
475 #ifdef DEBUG_USB_HOST
476  Notify(PSTR("\r\nHCI Command Failed: "), 0x80);
477  D_PrintHex<uint8_t > (hcibuf[2], 0x80);
478  Notify(PSTR("\r\nNum HCI Command Packets: "), 0x80);
479  D_PrintHex<uint8_t > (hcibuf[3], 0x80);
480  Notify(PSTR("\r\nCommand Opcode: "), 0x80);
481  D_PrintHex<uint8_t > (hcibuf[4], 0x80);
482  Notify(PSTR(" "), 0x80);
483  D_PrintHex<uint8_t > (hcibuf[5], 0x80);
484 #endif
485  }
486  break;
487 
488  case EV_INQUIRY_COMPLETE:
489  if(inquiry_counter >= 5 && (pairWithWii || pairWithHIDDevice)) {
490  inquiry_counter = 0;
491 #ifdef DEBUG_USB_HOST
492  if(pairWithWii)
493  Notify(PSTR("\r\nCouldn't find Wiimote"), 0x80);
494  else
495  Notify(PSTR("\r\nCouldn't find HID device"), 0x80);
496 #endif
497  connectToWii = false;
498  pairWithWii = false;
499  connectToHIDDevice = false;
500  pairWithHIDDevice = false;
501  hci_state = HCI_SCANNING_STATE;
502  }
503  inquiry_counter++;
504  break;
505 
506  case EV_INQUIRY_RESULT:
507  if(hcibuf[2]) { // Check that there is more than zero responses
508 #ifdef EXTRADEBUG
509  Notify(PSTR("\r\nNumber of responses: "), 0x80);
510  Notify(hcibuf[2], 0x80);
511 #endif
512  for(uint8_t i = 0; i < hcibuf[2]; i++) {
513  uint8_t offset = 8 * hcibuf[2] + 3 * i;
514 
515  for(uint8_t j = 0; j < 3; j++)
516  classOfDevice[j] = hcibuf[j + 4 + offset];
517 
518 #ifdef EXTRADEBUG
519  Notify(PSTR("\r\nClass of device: "), 0x80);
520  D_PrintHex<uint8_t > (classOfDevice[2], 0x80);
521  Notify(PSTR(" "), 0x80);
522  D_PrintHex<uint8_t > (classOfDevice[1], 0x80);
523  Notify(PSTR(" "), 0x80);
524  D_PrintHex<uint8_t > (classOfDevice[0], 0x80);
525 #endif
526 
527  if(pairWithWii && classOfDevice[2] == 0x00 && (classOfDevice[1] == 0x05) && (classOfDevice[0] & 0x0C)) { // See http://wiibrew.org/wiki/Wiimote#SDP_information
528  checkRemoteName = true; // Check remote name to distinguish between the different controllers
529 
530  for(uint8_t j = 0; j < 6; j++)
531  disc_bdaddr[j] = hcibuf[j + 3 + 6 * i];
532 
534  break;
535  } else if(pairWithHIDDevice && (classOfDevice[1] & 0x0F) == 0x05 && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad - see: http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html
536 #ifdef DEBUG_USB_HOST
537  checkRemoteName = true; // Used to print name in the serial monitor if serial debugging is enabled
538 
539  if(classOfDevice[0] & 0x80)
540  Notify(PSTR("\r\nMouse found"), 0x80);
541  if(classOfDevice[0] & 0x40)
542  Notify(PSTR("\r\nKeyboard found"), 0x80);
543  if(classOfDevice[0] & 0x08)
544  Notify(PSTR("\r\nGamepad found"), 0x80);
545 #endif
546  for(uint8_t j = 0; j < 6; j++)
547  disc_bdaddr[j] = hcibuf[j + 3 + 6 * i];
548 
550  break;
551  }
552  }
553  }
554  break;
555 
556  case EV_CONNECT_COMPLETE:
558  if(!hcibuf[2]) { // Check if connected OK
559 #ifdef EXTRADEBUG
560  Notify(PSTR("\r\nConnection established"), 0x80);
561 #endif
562  hci_handle = hcibuf[3] | ((hcibuf[4] & 0x0F) << 8); // Store the handle for the ACL connection
563  hci_set_flag(HCI_FLAG_CONNECT_COMPLETE); // Set connection complete flag
564  } else {
565  hci_state = HCI_CHECK_DEVICE_SERVICE;
566 #ifdef DEBUG_USB_HOST
567  Notify(PSTR("\r\nConnection Failed: "), 0x80);
568  D_PrintHex<uint8_t > (hcibuf[2], 0x80);
569 #endif
570  }
571  break;
572 
574  if(!hcibuf[2]) { // Check if disconnected OK
575  hci_set_flag(HCI_FLAG_DISCONNECT_COMPLETE); // Set disconnect command complete flag
576  hci_clear_flag(HCI_FLAG_CONNECT_COMPLETE); // Clear connection complete flag
577  }
578  break;
579 
581  if(!hcibuf[2]) { // Check if reading is OK
582  for(uint8_t i = 0; i < min(sizeof (remote_name), sizeof (hcibuf) - 9); i++) {
583  remote_name[i] = hcibuf[9 + i];
584  if(remote_name[i] == '\0') // End of string
585  break;
586  }
587  // TODO: Always set '\0' in remote name!
589  }
590  break;
591 
592  case EV_INCOMING_CONNECT:
593  for(uint8_t i = 0; i < 6; i++)
594  disc_bdaddr[i] = hcibuf[i + 2];
595 
596  for(uint8_t i = 0; i < 3; i++)
597  classOfDevice[i] = hcibuf[i + 8];
598 
599  if((classOfDevice[1] & 0x0F) == 0x05 && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad
600 #ifdef DEBUG_USB_HOST
601  if(classOfDevice[0] & 0x80)
602  Notify(PSTR("\r\nMouse is connecting"), 0x80);
603  if(classOfDevice[0] & 0x40)
604  Notify(PSTR("\r\nKeyboard is connecting"), 0x80);
605  if(classOfDevice[0] & 0x08)
606  Notify(PSTR("\r\nGamepad is connecting"), 0x80);
607 #endif
608  incomingHIDDevice = true;
609  }
610 
611 #ifdef EXTRADEBUG
612  Notify(PSTR("\r\nClass of device: "), 0x80);
613  D_PrintHex<uint8_t > (classOfDevice[2], 0x80);
614  Notify(PSTR(" "), 0x80);
615  D_PrintHex<uint8_t > (classOfDevice[1], 0x80);
616  Notify(PSTR(" "), 0x80);
617  D_PrintHex<uint8_t > (classOfDevice[0], 0x80);
618 #endif
620  break;
621 
622  case EV_PIN_CODE_REQUEST:
623  if(pairWithWii) {
624 #ifdef DEBUG_USB_HOST
625  Notify(PSTR("\r\nPairing with Wiimote"), 0x80);
626 #endif
628  } else if(btdPin != NULL) {
629 #ifdef DEBUG_USB_HOST
630  Notify(PSTR("\r\nBluetooth pin is set too: "), 0x80);
631  NotifyStr(btdPin, 0x80);
632 #endif
634  } else {
635 #ifdef DEBUG_USB_HOST
636  Notify(PSTR("\r\nNo pin was set"), 0x80);
637 #endif
639  }
640  break;
641 
642  case EV_LINK_KEY_REQUEST:
643 #ifdef DEBUG_USB_HOST
644  Notify(PSTR("\r\nReceived Key Request"), 0x80);
645 #endif
647  break;
648 
650  if(!hcibuf[2]) { // Check if pairing was successful
651  if(pairWithWii && !connectToWii) {
652 #ifdef DEBUG_USB_HOST
653  Notify(PSTR("\r\nPairing successful with Wiimote"), 0x80);
654 #endif
655  connectToWii = true; // Used to indicate to the Wii service, that it should connect to this device
656  } else if(pairWithHIDDevice && !connectToHIDDevice) {
657 #ifdef DEBUG_USB_HOST
658  Notify(PSTR("\r\nPairing successful with HID device"), 0x80);
659 #endif
660  connectToHIDDevice = true; // Used to indicate to the BTHID service, that it should connect to this device
661  } else {
662 #ifdef EXTRADEBUG
663  Notify(PSTR("\r\nPairing was successful"), 0x80);
664 #endif
665  }
666  } else {
667 #ifdef DEBUG_USB_HOST
668  Notify(PSTR("\r\nPairing Failed: "), 0x80);
669  D_PrintHex<uint8_t > (hcibuf[2], 0x80);
670 #endif
672  hci_state = HCI_DISCONNECT_STATE;
673  }
674  break;
675 
677 #ifdef DEBUG_USB_HOST
678  Notify(PSTR("\r\nReceived IO Capability Request"), 0x80);
679 #endif
681  break;
682 
684 #ifdef EXTRADEBUG
685  Notify(PSTR("\r\nReceived IO Capability Response: "), 0x80);
686  Notify(PSTR("\r\nIO capability: "), 0x80);
687  D_PrintHex<uint8_t > (hcibuf[8], 0x80);
688  Notify(PSTR("\r\nOOB data present: "), 0x80);
689  D_PrintHex<uint8_t > (hcibuf[9], 0x80);
690  Notify(PSTR("\r\nAuthentication request: "), 0x80);
691  D_PrintHex<uint8_t > (hcibuf[10], 0x80);
692 #endif
693  break;
694 
696 #ifdef DEBUG_USB_HOST
697  Notify(PSTR("\r\nUser confirmation Request"), 0x80);
698 #ifdef EXTRADEBUG
699  Notify(PSTR(": \r\nNumeric value: "), 0x80);
700  for(uint8_t i = 0; i < 4; i++) {
701  Notify(PSTR(" "), 0x80);
702  D_PrintHex<uint8_t > (hcibuf[8 + i], 0x80);
703  }
704 #endif
705 #endif
706  // Simply confirm the connection, as the host has no "NoInputNoOutput" capabilities
708  break;
709 
711 #ifdef EXTRADEBUG
712  if(!hcibuf[2]) { // Check if connected OK
713  Notify(PSTR("\r\nSimple Pairing succeeded"), 0x80);
714  } else {
715  Notify(PSTR("\r\nSimple Pairing failed: "), 0x80);
716  D_PrintHex<uint8_t > (hcibuf[2], 0x80);
717  }
718 #endif
719  break;
720 
721  /* We will just ignore the following events */
722  case EV_MAX_SLOTS_CHANGE:
723  case EV_NUM_COMPLETE_PKT:
724  break;
725  case EV_ROLE_CHANGED:
727  case EV_LOOPBACK_COMMAND:
734 #ifdef EXTRADEBUG
735  if(hcibuf[0] != 0x00) {
736  Notify(PSTR("\r\nIgnore HCI Event: "), 0x80);
737  D_PrintHex<uint8_t > (hcibuf[0], 0x80);
738  }
739 #endif
740  break;
741 #ifdef EXTRADEBUG
742  default:
743  if(hcibuf[0] != 0x00) {
744  Notify(PSTR("\r\nUnmanaged HCI Event: "), 0x80);
745  D_PrintHex<uint8_t > (hcibuf[0], 0x80);
746  Notify(PSTR(", data: "), 0x80);
747  for(uint16_t i = 0; i < hcibuf[1]; i++) {
748  D_PrintHex<uint8_t > (hcibuf[2 + i], 0x80);
749  Notify(PSTR(" "), 0x80);
750  }
751  }
752  break;
753 #endif
754  } // Switch
755  }
756 #ifdef EXTRADEBUG
757  else {
758  Notify(PSTR("\r\nHCI event error: "), 0x80);
759  D_PrintHex<uint8_t > (rcode, 0x80);
760  }
761 #endif
762 }
763 
764 /* Poll Bluetooth and print result */
765 void BTD::HCI_task() {
766  switch(hci_state) {
767  case HCI_INIT_STATE:
768  hci_counter++;
769  if(hci_counter > hci_num_reset_loops) { // wait until we have looped x times to clear any old events
770  hci_reset();
771  hci_state = HCI_RESET_STATE;
772  hci_counter = 0;
773  }
774  break;
775 
776  case HCI_RESET_STATE:
777  hci_counter++;
779  hci_counter = 0;
780 #ifdef DEBUG_USB_HOST
781  Notify(PSTR("\r\nHCI Reset complete"), 0x80);
782 #endif
783  hci_state = HCI_CLASS_STATE;
785  } else if(hci_counter > hci_num_reset_loops) {
786  hci_num_reset_loops *= 10;
787  if(hci_num_reset_loops > 2000)
788  hci_num_reset_loops = 2000;
789 #ifdef DEBUG_USB_HOST
790  Notify(PSTR("\r\nNo response to HCI Reset"), 0x80);
791 #endif
792  hci_state = HCI_INIT_STATE;
793  hci_counter = 0;
794  }
795  break;
796 
797  case HCI_CLASS_STATE:
799 #ifdef DEBUG_USB_HOST
800  Notify(PSTR("\r\nWrite class of device"), 0x80);
801 #endif
802  hci_state = HCI_BDADDR_STATE;
803  hci_read_bdaddr();
804  }
805  break;
806 
807  case HCI_BDADDR_STATE:
809 #ifdef DEBUG_USB_HOST
810  Notify(PSTR("\r\nLocal Bluetooth Address: "), 0x80);
811  for(int8_t i = 5; i > 0; i--) {
812  D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
813  Notify(PSTR(":"), 0x80);
814  }
815  D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
816 #endif
818  hci_state = HCI_LOCAL_VERSION_STATE;
819  }
820  break;
821 
822  case HCI_LOCAL_VERSION_STATE: // The local version is used by the PS3BT class
824  if(btdName != NULL) {
826  hci_state = HCI_WRITE_NAME_STATE;
827  } else if(useSimplePairing) {
828  hci_read_local_extended_features(0); // "Requests the normal LMP features as returned by Read_Local_Supported_Features"
829  //hci_read_local_extended_features(1); // Read page 1
831  } else
832  hci_state = HCI_CHECK_DEVICE_SERVICE;
833  }
834  break;
835 
838 #ifdef DEBUG_USB_HOST
839  Notify(PSTR("\r\nThe name was set to: "), 0x80);
840  NotifyStr(btdName, 0x80);
841 #endif
842  if(useSimplePairing) {
843  hci_read_local_extended_features(0); // "Requests the normal LMP features as returned by Read_Local_Supported_Features"
844  //hci_read_local_extended_features(1); // Read page 1
846  } else
847  hci_state = HCI_CHECK_DEVICE_SERVICE;
848  }
849  break;
850 
853  if(simple_pairing_supported) {
855  hci_state = HCI_WRITE_SIMPLE_PAIRING_STATE;
856  } else
857  hci_state = HCI_CHECK_DEVICE_SERVICE;
858  }
859  break;
860 
863 #ifdef DEBUG_USB_HOST
864  Notify(PSTR("\r\nSimple pairing was enabled"), 0x80);
865 #endif
867  hci_state = HCI_SET_EVENT_MASK_STATE;
868  }
869  break;
870 
873 #ifdef DEBUG_USB_HOST
874  Notify(PSTR("\r\nSet event mask completed"), 0x80);
875 #endif
876  hci_state = HCI_CHECK_DEVICE_SERVICE;
877  }
878  break;
879 
881  if(pairWithHIDDevice || pairWithWii) { // Check if it should try to connect to a Wiimote
882 #ifdef DEBUG_USB_HOST
883  if(pairWithWii)
884  Notify(PSTR("\r\nStarting inquiry\r\nPress 1 & 2 on the Wiimote\r\nOr press the SYNC button if you are using a Wii U Pro Controller or a Wii Balance Board"), 0x80);
885  else
886  Notify(PSTR("\r\nPlease enable discovery of your device"), 0x80);
887 #endif
888  hci_inquiry();
889  hci_state = HCI_INQUIRY_STATE;
890  } else
891  hci_state = HCI_SCANNING_STATE; // Don't try to connect to a Wiimote
892  break;
893 
894  case HCI_INQUIRY_STATE:
896  hci_inquiry_cancel(); // Stop inquiry
897 #ifdef DEBUG_USB_HOST
898  if(pairWithWii)
899  Notify(PSTR("\r\nWiimote found"), 0x80);
900  else
901  Notify(PSTR("\r\nHID device found"), 0x80);
902 
903  Notify(PSTR("\r\nNow just create the instance like so:"), 0x80);
904  if(pairWithWii)
905  Notify(PSTR("\r\nWII Wii(&Btd);"), 0x80);
906  else
907  Notify(PSTR("\r\nBTHID bthid(&Btd);"), 0x80);
908 
909  Notify(PSTR("\r\nAnd then press any button on the "), 0x80);
910  if(pairWithWii)
911  Notify(PSTR("Wiimote"), 0x80);
912  else
913  Notify(PSTR("device"), 0x80);
914 #endif
915  if(checkRemoteName) {
916  hci_remote_name(); // We need to know the name to distinguish between the Wiimote, the new Wiimote with Motion Plus inside, a Wii U Pro Controller and a Wii Balance Board
917  hci_state = HCI_REMOTE_NAME_STATE;
918  } else
919  hci_state = HCI_CONNECT_DEVICE_STATE;
920  }
921  break;
922 
925 #ifdef DEBUG_USB_HOST
926  if(pairWithWii)
927  Notify(PSTR("\r\nConnecting to Wiimote"), 0x80);
928  else
929  Notify(PSTR("\r\nConnecting to HID device"), 0x80);
930 #endif
931  checkRemoteName = false;
932  hci_connect();
933  hci_state = HCI_CONNECTED_DEVICE_STATE;
934  }
935  break;
936 
940 #ifdef DEBUG_USB_HOST
941  if(pairWithWii)
942  Notify(PSTR("\r\nConnected to Wiimote"), 0x80);
943  else
944  Notify(PSTR("\r\nConnected to HID device"), 0x80);
945 #endif
946  hci_authentication_request(); // This will start the pairing with the device
947  hci_state = HCI_SCANNING_STATE;
948  } else {
949 #ifdef DEBUG_USB_HOST
950  Notify(PSTR("\r\nTrying to connect one more time..."), 0x80);
951 #endif
952  hci_connect(); // Try to connect one more time
953  }
954  }
955  break;
956 
957  case HCI_SCANNING_STATE:
959 #ifdef DEBUG_USB_HOST
960  Notify(PSTR("\r\nWait For Incoming Connection Request"), 0x80);
961 #endif
963  waitingForConnection = true;
964  hci_state = HCI_CONNECT_IN_STATE;
965  }
966  break;
967 
970  waitingForConnection = false;
971 #ifdef DEBUG_USB_HOST
972  Notify(PSTR("\r\nIncoming Connection Request"), 0x80);
973 #endif
974  hci_remote_name();
975  hci_state = HCI_REMOTE_NAME_STATE;
977  hci_state = HCI_DISCONNECT_STATE;
978  break;
979 
982 #ifdef DEBUG_USB_HOST
983  Notify(PSTR("\r\nRemote Name: "), 0x80);
984  for(uint8_t i = 0; i < strlen(remote_name); i++)
985  Notifyc(remote_name[i], 0x80);
986 #endif
987  if(strncmp((const char*)remote_name, "Nintendo", 8) == 0) {
988  incomingWii = true;
989  motionPlusInside = false;
990  wiiUProController = false;
991  pairWiiUsingSync = false;
992 #ifdef DEBUG_USB_HOST
993  Notify(PSTR("\r\nWiimote is connecting"), 0x80);
994 #endif
995  if(strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-TR", 22) == 0) {
996 #ifdef DEBUG_USB_HOST
997  Notify(PSTR(" with Motion Plus Inside"), 0x80);
998 #endif
999  motionPlusInside = true;
1000  } else if(strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-UC", 22) == 0) {
1001 #ifdef DEBUG_USB_HOST
1002  Notify(PSTR(" - Wii U Pro Controller"), 0x80);
1003 #endif
1004  wiiUProController = motionPlusInside = pairWiiUsingSync = true;
1005  } else if(strncmp((const char*)remote_name, "Nintendo RVL-WBC-01", 19) == 0) {
1006 #ifdef DEBUG_USB_HOST
1007  Notify(PSTR(" - Wii Balance Board"), 0x80);
1008 #endif
1009  pairWiiUsingSync = true;
1010  }
1011  }
1012  if(classOfDevice[2] == 0 && classOfDevice[1] == 0x25 && classOfDevice[0] == 0x08 && strncmp((const char*)remote_name, "Wireless Controller", 19) == 0) {
1013 #ifdef DEBUG_USB_HOST
1014  Notify(PSTR("\r\nPS4/PS5 controller is connecting"), 0x80);
1015 #endif
1016  incomingPSController = true;
1017  }
1018  if((pairWithWii || pairWithHIDDevice) && checkRemoteName)
1019  hci_state = HCI_CONNECT_DEVICE_STATE;
1020  else {
1022  hci_state = HCI_CONNECTED_STATE;
1023  }
1024  }
1025  break;
1026 
1027  case HCI_CONNECTED_STATE:
1029 #ifdef DEBUG_USB_HOST
1030  Notify(PSTR("\r\nConnected to Device: "), 0x80);
1031  for(int8_t i = 5; i > 0; i--) {
1032  D_PrintHex<uint8_t > (disc_bdaddr[i], 0x80);
1033  Notify(PSTR(":"), 0x80);
1034  }
1035  D_PrintHex<uint8_t > (disc_bdaddr[0], 0x80);
1036 #endif
1037  if(incomingPSController)
1038  connectToHIDDevice = true; // We should always connect to the PS4/PS5 controller
1039 
1040  // Clear these flags for a new connection
1041  l2capConnectionClaimed = false;
1042  sdpConnectionClaimed = false;
1043  rfcommConnectionClaimed = false;
1044 
1045  hci_event_flag = 0;
1046  hci_state = HCI_DONE_STATE;
1047  }
1048  break;
1049 
1050  case HCI_DONE_STATE:
1051  hci_counter++;
1052  if(hci_counter > 1000) { // Wait until we have looped 1000 times to make sure that the L2CAP connection has been started
1053  hci_counter = 0;
1054  hci_state = HCI_SCANNING_STATE;
1055  }
1056  break;
1057 
1058  case HCI_DISCONNECT_STATE:
1060 #ifdef DEBUG_USB_HOST
1061  Notify(PSTR("\r\nHCI Disconnected from Device"), 0x80);
1062 #endif
1063  hci_event_flag = 0; // Clear all flags
1064 
1065  // Reset all buffers
1066  memset(hcibuf, 0, BULK_MAXPKTSIZE);
1067  memset(l2capinbuf, 0, BULK_MAXPKTSIZE);
1068 
1069  connectToWii = incomingWii = pairWithWii = false;
1070  connectToHIDDevice = incomingHIDDevice = pairWithHIDDevice = checkRemoteName = false;
1071  incomingPSController = false;
1072 
1073  hci_state = HCI_SCANNING_STATE;
1074  }
1075  break;
1076  default:
1077  break;
1078  }
1079 }
1080 
1081 void BTD::ACL_event_task() {
1082  uint16_t length = BULK_MAXPKTSIZE;
1083  uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_DATAIN_PIPE ].epAddr, &length, l2capinbuf, pollInterval); // Input on endpoint 2
1084 
1085  if(!rcode) { // Check for errors
1086  if(length > 0) { // Check if any data was read
1087  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) {
1088  if(btService[i])
1089  btService[i]->ACLData(l2capinbuf);
1090  }
1091  }
1092  }
1093 #ifdef EXTRADEBUG
1094  else if(rcode != hrNAK) {
1095  Notify(PSTR("\r\nACL data in error: "), 0x80);
1096  D_PrintHex<uint8_t > (rcode, 0x80);
1097  }
1098 #endif
1099  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
1100  if(btService[i])
1101  btService[i]->Run();
1102 }
1103 
1104 /************************************************************/
1105 /* HCI Commands */
1106 
1107 /************************************************************/
1108 void BTD::HCI_Command(uint8_t* data, uint16_t nbytes) {
1110  pUsb->ctrlReq(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bmREQ_HCI_OUT, 0x00, 0x00, 0x00, 0x00, nbytes, nbytes, data, NULL);
1111 }
1112 
1114  hci_event_flag = 0; // Clear all the flags
1115  hcibuf[0] = 0x03; // HCI OCF = 3
1116  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1117  hcibuf[2] = 0x00;
1118 
1119  HCI_Command(hcibuf, 3);
1120 }
1121 
1124  hcibuf[0] = 0x1A; // HCI OCF = 1A
1125  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1126  hcibuf[2] = 0x01; // parameter length = 1
1127  if(btdName != NULL)
1128  hcibuf[3] = 0x03; // Inquiry Scan enabled. Page Scan enabled.
1129  else
1130  hcibuf[3] = 0x02; // Inquiry Scan disabled. Page Scan enabled.
1131 
1132  HCI_Command(hcibuf, 4);
1133 }
1134 
1136  hcibuf[0] = 0x1A; // HCI OCF = 1A
1137  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1138  hcibuf[2] = 0x01; // parameter length = 1
1139  hcibuf[3] = 0x00; // Inquiry Scan disabled. Page Scan disabled.
1140 
1141  HCI_Command(hcibuf, 4);
1142 }
1143 
1146  hcibuf[0] = 0x09; // HCI OCF = 9
1147  hcibuf[1] = 0x04 << 2; // HCI OGF = 4
1148  hcibuf[2] = 0x00;
1149 
1150  HCI_Command(hcibuf, 3);
1151 }
1152 
1155  hcibuf[0] = 0x01; // HCI OCF = 1
1156  hcibuf[1] = 0x04 << 2; // HCI OGF = 4
1157  hcibuf[2] = 0x00;
1158 
1159  HCI_Command(hcibuf, 3);
1160 }
1161 
1162 void BTD::hci_read_local_extended_features(uint8_t page_number) {
1164  hcibuf[0] = 0x04; // HCI OCF = 4
1165  hcibuf[1] = 0x04 << 2; // HCI OGF = 4
1166  hcibuf[2] = 0x01; // parameter length = 1
1167  hcibuf[3] = page_number;
1168 
1169  HCI_Command(hcibuf, 4);
1170 }
1171 
1174  hcibuf[0] = 0x09; // HCI OCF = 9
1175  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1176  hcibuf[2] = 0x07; // parameter length 7
1177  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1178  hcibuf[4] = disc_bdaddr[1];
1179  hcibuf[5] = disc_bdaddr[2];
1180  hcibuf[6] = disc_bdaddr[3];
1181  hcibuf[7] = disc_bdaddr[4];
1182  hcibuf[8] = disc_bdaddr[5];
1183  hcibuf[9] = 0x00; // Switch role to master
1184 
1185  HCI_Command(hcibuf, 10);
1186 }
1187 
1190  hcibuf[0] = 0x19; // HCI OCF = 19
1191  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1192  hcibuf[2] = 0x0A; // parameter length = 10
1193  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1194  hcibuf[4] = disc_bdaddr[1];
1195  hcibuf[5] = disc_bdaddr[2];
1196  hcibuf[6] = disc_bdaddr[3];
1197  hcibuf[7] = disc_bdaddr[4];
1198  hcibuf[8] = disc_bdaddr[5];
1199  hcibuf[9] = 0x01; // Page Scan Repetition Mode
1200  hcibuf[10] = 0x00; // Reserved
1201  hcibuf[11] = 0x00; // Clock offset - low byte
1202  hcibuf[12] = 0x00; // Clock offset - high byte
1203 
1204  HCI_Command(hcibuf, 13);
1205 }
1206 
1207 void BTD::hci_write_local_name(const char* name) {
1208  hcibuf[0] = 0x13; // HCI OCF = 13
1209  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1210  hcibuf[2] = strlen(name) + 1; // parameter length = the length of the string + end byte
1211  uint8_t i;
1212  for(i = 0; i < strlen(name); i++)
1213  hcibuf[i + 3] = name[i];
1214  hcibuf[i + 3] = 0x00; // End of string
1215 
1216  HCI_Command(hcibuf, 4 + strlen(name));
1217 }
1218 
1220  hcibuf[0] = 0x01; // HCI OCF = 01
1221  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1222  hcibuf[2] = 0x08;
1223  // The first 6 bytes are the default of 1FFF FFFF FFFF
1224  // However we need to set bits 48-55 for simple pairing to work
1225  hcibuf[3] = 0xFF;
1226  hcibuf[4] = 0xFF;
1227  hcibuf[5] = 0xFF;
1228  hcibuf[6] = 0xFF;
1229  hcibuf[7] = 0xFF;
1230  hcibuf[8] = 0x1F;
1231  hcibuf[9] = 0xFF; // Enable bits 48-55 used for simple pairing
1232  hcibuf[10] = 0x00;
1233 
1234  HCI_Command(hcibuf, 11);
1235 }
1236 
1238  hcibuf[0] = 0x56; // HCI OCF = 56
1239  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1240  hcibuf[2] = 1; // parameter length = 1
1241  hcibuf[3] = enable ? 1 : 0;
1242 
1243  HCI_Command(hcibuf, 4);
1244 }
1245 
1248  hcibuf[0] = 0x01;
1249  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1250  hcibuf[2] = 0x05; // Parameter Total Length = 5
1251  hcibuf[3] = 0x33; // LAP: Genera/Unlimited Inquiry Access Code (GIAC = 0x9E8B33) - see https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
1252  hcibuf[4] = 0x8B;
1253  hcibuf[5] = 0x9E;
1254  hcibuf[6] = 0x30; // Inquiry time = 61.44 sec (maximum)
1255  hcibuf[7] = 0x0A; // 10 number of responses
1256 
1257  HCI_Command(hcibuf, 8);
1258 }
1259 
1261  hcibuf[0] = 0x02;
1262  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1263  hcibuf[2] = 0x00; // Parameter Total Length = 0
1264 
1265  HCI_Command(hcibuf, 3);
1266 }
1267 
1269  hci_connect(disc_bdaddr); // Use last discovered device
1270 }
1271 
1272 void BTD::hci_connect(uint8_t *bdaddr) {
1274  hcibuf[0] = 0x05; // HCI OCF = 5
1275  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1276  hcibuf[2] = 0x0D; // parameter Total Length = 13
1277  hcibuf[3] = bdaddr[0]; // 6 octet bdaddr (LSB)
1278  hcibuf[4] = bdaddr[1];
1279  hcibuf[5] = bdaddr[2];
1280  hcibuf[6] = bdaddr[3];
1281  hcibuf[7] = bdaddr[4];
1282  hcibuf[8] = bdaddr[5];
1283  hcibuf[9] = 0x18; // DM1 or DH1 may be used
1284  hcibuf[10] = 0xCC; // DM3, DH3, DM5, DH5 may be used
1285  hcibuf[11] = 0x01; // Page repetition mode R1
1286  hcibuf[12] = 0x00; // Reserved
1287  hcibuf[13] = 0x00; // Clock offset
1288  hcibuf[14] = 0x00; // Invalid clock offset
1289  hcibuf[15] = 0x00; // Do not allow role switch
1290 
1291  HCI_Command(hcibuf, 16);
1292 }
1293 
1295  hcibuf[0] = 0x0D; // HCI OCF = 0D
1296  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1297  hcibuf[2] = 0x17; // parameter length 23
1298  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1299  hcibuf[4] = disc_bdaddr[1];
1300  hcibuf[5] = disc_bdaddr[2];
1301  hcibuf[6] = disc_bdaddr[3];
1302  hcibuf[7] = disc_bdaddr[4];
1303  hcibuf[8] = disc_bdaddr[5];
1304  if(pairWithWii) {
1305  hcibuf[9] = 6; // Pin length is the length of the Bluetooth address
1306  if(pairWiiUsingSync) {
1307 #ifdef DEBUG_USB_HOST
1308  Notify(PSTR("\r\nPairing with Wii controller via SYNC"), 0x80);
1309 #endif
1310  for(uint8_t i = 0; i < 6; i++)
1311  hcibuf[10 + i] = my_bdaddr[i]; // The pin is the Bluetooth dongles Bluetooth address backwards
1312  } else {
1313  for(uint8_t i = 0; i < 6; i++)
1314  hcibuf[10 + i] = disc_bdaddr[i]; // The pin is the Wiimote's Bluetooth address backwards
1315  }
1316  for(uint8_t i = 16; i < 26; i++)
1317  hcibuf[i] = 0x00; // The rest should be 0
1318  } else {
1319  hcibuf[9] = strlen(btdPin); // Length of pin
1320  uint8_t i;
1321  for(i = 0; i < strlen(btdPin); i++) // The maximum size of the pin is 16
1322  hcibuf[i + 10] = btdPin[i];
1323  for(; i < 16; i++)
1324  hcibuf[i + 10] = 0x00; // The rest should be 0
1325  }
1326 
1327  HCI_Command(hcibuf, 26);
1328 }
1329 
1331  hcibuf[0] = 0x0E; // HCI OCF = 0E
1332  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1333  hcibuf[2] = 0x06; // parameter length 6
1334  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1335  hcibuf[4] = disc_bdaddr[1];
1336  hcibuf[5] = disc_bdaddr[2];
1337  hcibuf[6] = disc_bdaddr[3];
1338  hcibuf[7] = disc_bdaddr[4];
1339  hcibuf[8] = disc_bdaddr[5];
1340 
1341  HCI_Command(hcibuf, 9);
1342 }
1343 
1345  hcibuf[0] = 0x0C; // HCI OCF = 0C
1346  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1347  hcibuf[2] = 0x06; // parameter length 6
1348  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1349  hcibuf[4] = disc_bdaddr[1];
1350  hcibuf[5] = disc_bdaddr[2];
1351  hcibuf[6] = disc_bdaddr[3];
1352  hcibuf[7] = disc_bdaddr[4];
1353  hcibuf[8] = disc_bdaddr[5];
1354 
1355  HCI_Command(hcibuf, 9);
1356 }
1357 
1359  hcibuf[0] = 0x2B; // HCI OCF = 2B
1360  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1361  hcibuf[2] = 0x09;
1362  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1363  hcibuf[4] = disc_bdaddr[1];
1364  hcibuf[5] = disc_bdaddr[2];
1365  hcibuf[6] = disc_bdaddr[3];
1366  hcibuf[7] = disc_bdaddr[4];
1367  hcibuf[8] = disc_bdaddr[5];
1368  hcibuf[9] = 0x03; // NoInputNoOutput
1369  hcibuf[10] = 0x00; // OOB authentication data not present
1370  hcibuf[11] = 0x00; // MITM Protection Not Required – No Bonding. Numeric comparison with automatic accept allowed
1371 
1372  HCI_Command(hcibuf, 12);
1373 }
1374 
1376  hcibuf[0] = 0x2C; // HCI OCF = 2C
1377  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1378  hcibuf[2] = 0x06; // parameter length 6
1379  hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
1380  hcibuf[4] = disc_bdaddr[1];
1381  hcibuf[5] = disc_bdaddr[2];
1382  hcibuf[6] = disc_bdaddr[3];
1383  hcibuf[7] = disc_bdaddr[4];
1384  hcibuf[8] = disc_bdaddr[5];
1385 
1386  HCI_Command(hcibuf, 9);
1387 }
1388 
1390  hcibuf[0] = 0x11; // HCI OCF = 11
1391  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1392  hcibuf[2] = 0x02; // parameter length = 2
1393  hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte
1394  hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte
1395 
1396  HCI_Command(hcibuf, 5);
1397 }
1398 
1399 void BTD::hci_disconnect(uint16_t handle) { // This is called by the different services
1401  hcibuf[0] = 0x06; // HCI OCF = 6
1402  hcibuf[1] = 0x01 << 2; // HCI OGF = 1
1403  hcibuf[2] = 0x03; // parameter length = 3
1404  hcibuf[3] = (uint8_t)(handle & 0xFF); //connection handle - low byte
1405  hcibuf[4] = (uint8_t)((handle >> 8) & 0x0F); //connection handle - high byte
1406  hcibuf[5] = 0x13; // reason
1407 
1408  HCI_Command(hcibuf, 6);
1409 }
1410 
1411 void BTD::hci_write_class_of_device() { // See http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html
1412  hcibuf[0] = 0x24; // HCI OCF = 24
1413  hcibuf[1] = 0x03 << 2; // HCI OGF = 3
1414  hcibuf[2] = 0x03; // parameter length = 3
1415  hcibuf[3] = 0x04; // Robot
1416  hcibuf[4] = 0x08; // Toy
1417  hcibuf[5] = 0x00;
1418 
1419  HCI_Command(hcibuf, 6);
1420 }
1421 /*******************************************************************
1422  * *
1423  * HCI ACL Data Packet *
1424  * *
1425  * buf[0] buf[1] buf[2] buf[3]
1426  * 0 4 8 11 12 16 24 31 MSB
1427  * .-+-+-+-+-+-+-+-|-+-+-+-|-+-|-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1428  * | HCI Handle |PB |BC | Data Total Length | HCI ACL Data Packet
1429  * .-+-+-+-+-+-+-+-|-+-+-+-|-+-|-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1430  *
1431  * buf[4] buf[5] buf[6] buf[7]
1432  * 0 8 16 31 MSB
1433  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1434  * | Length | Channel ID | Basic L2CAP header
1435  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1436  *
1437  * buf[8] buf[9] buf[10] buf[11]
1438  * 0 8 16 31 MSB
1439  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-.
1440  * | Code | Identifier | Length | Control frame (C-frame)
1441  * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-. (signaling packet format)
1442  */
1443 /************************************************************/
1444 /* L2CAP Commands */
1445 
1446 /************************************************************/
1447 void BTD::L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t channelLow, uint8_t channelHigh) {
1448  uint8_t buf[8 + nbytes];
1449  buf[0] = (uint8_t)(handle & 0xff); // HCI handle with PB,BC flag
1450  buf[1] = (uint8_t)(((handle >> 8) & 0x0f) | 0x20);
1451  buf[2] = (uint8_t)((4 + nbytes) & 0xff); // HCI ACL total data length
1452  buf[3] = (uint8_t)((4 + nbytes) >> 8);
1453  buf[4] = (uint8_t)(nbytes & 0xff); // L2CAP header: Length
1454  buf[5] = (uint8_t)(nbytes >> 8);
1455  buf[6] = channelLow;
1456  buf[7] = channelHigh;
1457 
1458  for(uint16_t i = 0; i < nbytes; i++) // L2CAP C-frame
1459  buf[8 + i] = data[i];
1460 
1461  uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ BTD_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf);
1462  if(rcode) {
1463  delay(100); // This small delay prevents it from overflowing if it fails
1464 #ifdef DEBUG_USB_HOST
1465  Notify(PSTR("\r\nError sending L2CAP message: 0x"), 0x80);
1466  D_PrintHex<uint8_t > (rcode, 0x80);
1467  Notify(PSTR(" - Channel ID: "), 0x80);
1468  D_PrintHex<uint8_t > (channelHigh, 0x80);
1469  Notify(PSTR(" "), 0x80);
1470  D_PrintHex<uint8_t > (channelLow, 0x80);
1471 #endif
1472  }
1473 }
1474 
1475 void BTD::l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm) {
1476  l2capoutbuf[0] = L2CAP_CMD_CONNECTION_REQUEST; // Code
1477  l2capoutbuf[1] = rxid; // Identifier
1478  l2capoutbuf[2] = 0x04; // Length
1479  l2capoutbuf[3] = 0x00;
1480  l2capoutbuf[4] = (uint8_t)(psm & 0xff); // PSM
1481  l2capoutbuf[5] = (uint8_t)(psm >> 8);
1482  l2capoutbuf[6] = scid[0]; // Source CID
1483  l2capoutbuf[7] = scid[1];
1484 
1485  L2CAP_Command(handle, l2capoutbuf, 8);
1486 }
1487 
1488 void BTD::l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result) {
1489  l2capoutbuf[0] = L2CAP_CMD_CONNECTION_RESPONSE; // Code
1490  l2capoutbuf[1] = rxid; // Identifier
1491  l2capoutbuf[2] = 0x08; // Length
1492  l2capoutbuf[3] = 0x00;
1493  l2capoutbuf[4] = dcid[0]; // Destination CID
1494  l2capoutbuf[5] = dcid[1];
1495  l2capoutbuf[6] = scid[0]; // Source CID
1496  l2capoutbuf[7] = scid[1];
1497  l2capoutbuf[8] = result; // Result: Pending or Success
1498  l2capoutbuf[9] = 0x00;
1499  l2capoutbuf[10] = 0x00; // No further information
1500  l2capoutbuf[11] = 0x00;
1501 
1502  L2CAP_Command(handle, l2capoutbuf, 12);
1503 }
1504 
1505 void BTD::l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t* dcid) {
1506  l2capoutbuf[0] = L2CAP_CMD_CONFIG_REQUEST; // Code
1507  l2capoutbuf[1] = rxid; // Identifier
1508  l2capoutbuf[2] = 0x08; // Length
1509  l2capoutbuf[3] = 0x00;
1510  l2capoutbuf[4] = dcid[0]; // Destination CID
1511  l2capoutbuf[5] = dcid[1];
1512  l2capoutbuf[6] = 0x00; // Flags
1513  l2capoutbuf[7] = 0x00;
1514  l2capoutbuf[8] = 0x01; // Config Opt: type = MTU (Maximum Transmission Unit) - Hint
1515  l2capoutbuf[9] = 0x02; // Config Opt: length
1516  l2capoutbuf[10] = 0xFF; // MTU
1517  l2capoutbuf[11] = 0xFF;
1518 
1519  L2CAP_Command(handle, l2capoutbuf, 12);
1520 }
1521 
1522 void BTD::l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid) {
1523  l2capoutbuf[0] = L2CAP_CMD_CONFIG_RESPONSE; // Code
1524  l2capoutbuf[1] = rxid; // Identifier
1525  l2capoutbuf[2] = 0x0A; // Length
1526  l2capoutbuf[3] = 0x00;
1527  l2capoutbuf[4] = scid[0]; // Source CID
1528  l2capoutbuf[5] = scid[1];
1529  l2capoutbuf[6] = 0x00; // Flag
1530  l2capoutbuf[7] = 0x00;
1531  l2capoutbuf[8] = 0x00; // Result
1532  l2capoutbuf[9] = 0x00;
1533  l2capoutbuf[10] = 0x01; // Config
1534  l2capoutbuf[11] = 0x02;
1535  l2capoutbuf[12] = 0xA0;
1536  l2capoutbuf[13] = 0x02;
1537 
1538  L2CAP_Command(handle, l2capoutbuf, 14);
1539 }
1540 
1541 void BTD::l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid) {
1542  l2capoutbuf[0] = L2CAP_CMD_DISCONNECT_REQUEST; // Code
1543  l2capoutbuf[1] = rxid; // Identifier
1544  l2capoutbuf[2] = 0x04; // Length
1545  l2capoutbuf[3] = 0x00;
1546  l2capoutbuf[4] = dcid[0];
1547  l2capoutbuf[5] = dcid[1];
1548  l2capoutbuf[6] = scid[0];
1549  l2capoutbuf[7] = scid[1];
1550 
1551  L2CAP_Command(handle, l2capoutbuf, 8);
1552 }
1553 
1554 void BTD::l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid) {
1555  l2capoutbuf[0] = L2CAP_CMD_DISCONNECT_RESPONSE; // Code
1556  l2capoutbuf[1] = rxid; // Identifier
1557  l2capoutbuf[2] = 0x04; // Length
1558  l2capoutbuf[3] = 0x00;
1559  l2capoutbuf[4] = dcid[0];
1560  l2capoutbuf[5] = dcid[1];
1561  l2capoutbuf[6] = scid[0];
1562  l2capoutbuf[7] = scid[1];
1563 
1564  L2CAP_Command(handle, l2capoutbuf, 8);
1565 }
1566 
1567 void BTD::l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh) {
1568  l2capoutbuf[0] = L2CAP_CMD_INFORMATION_RESPONSE; // Code
1569  l2capoutbuf[1] = rxid; // Identifier
1570  l2capoutbuf[2] = 0x08; // Length
1571  l2capoutbuf[3] = 0x00;
1572  l2capoutbuf[4] = infoTypeLow;
1573  l2capoutbuf[5] = infoTypeHigh;
1574  l2capoutbuf[6] = 0x00; // Result = success
1575  l2capoutbuf[7] = 0x00; // Result = success
1576  l2capoutbuf[8] = 0x00;
1577  l2capoutbuf[9] = 0x00;
1578  l2capoutbuf[10] = 0x00;
1579  l2capoutbuf[11] = 0x00;
1580 
1581  L2CAP_Command(handle, l2capoutbuf, 12);
1582 }
1583 
1584 /* PS3 Commands - only set Bluetooth address is implemented in this library */
1585 void BTD::setBdaddr(uint8_t* bdaddr) {
1586  /* Set the internal Bluetooth address */
1587  uint8_t buf[8];
1588  buf[0] = 0x01;
1589  buf[1] = 0x00;
1590 
1591  for(uint8_t i = 0; i < 6; i++)
1592  buf[i + 2] = bdaddr[5 - i]; // Copy into buffer, has to be written reversed, so it is MSB first
1593 
1594  // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
1595  pUsb->ctrlReq(bAddress, epInfo[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL);
1596 }
1597 
1598 void BTD::setMoveBdaddr(uint8_t* bdaddr) {
1599  /* Set the internal Bluetooth address */
1600  uint8_t buf[11];
1601  buf[0] = 0x05;
1602  buf[7] = 0x10;
1603  buf[8] = 0x01;
1604  buf[9] = 0x02;
1605  buf[10] = 0x12;
1606 
1607  for(uint8_t i = 0; i < 6; i++)
1608  buf[i + 1] = bdaddr[i];
1609 
1610  // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x05), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
1611  pUsb->ctrlReq(bAddress, epInfo[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00, 11, 11, buf, NULL);
1612 }
static const uint8_t BTD_DATAOUT_PIPE
Definition: BTD.h:558
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr)
Definition: Usb.cpp:801
uint8_t bmRcvToggle
Definition: address.h:48
bool incomingWii
Definition: BTD.h:504
diff --git a/_b_t_d_8h.html b/_b_t_d_8h.html index f2fd6182..5cc205f5 100644 --- a/_b_t_d_8h.html +++ b/_b_t_d_8h.html @@ -83,17 +83,18 @@ This graph shows which files directly or indirectly include this file:
- - - - - + + + + + - - - - + + + + +
diff --git a/_b_t_d_8h__dep__incl.map b/_b_t_d_8h__dep__incl.map index d124b572..f7b0e8bb 100644 --- a/_b_t_d_8h__dep__incl.map +++ b/_b_t_d_8h__dep__incl.map @@ -1,13 +1,14 @@ - - - - - + + + + + - - - - + + + + + diff --git a/_b_t_d_8h__dep__incl.md5 b/_b_t_d_8h__dep__incl.md5 index c59fa974..e025c0af 100644 --- a/_b_t_d_8h__dep__incl.md5 +++ b/_b_t_d_8h__dep__incl.md5 @@ -1 +1 @@ -f319401190d1085c45724d4fdcb1e6d0 \ No newline at end of file +cf0549b2c2a90bf20d4d75b13087ec87 \ No newline at end of file diff --git a/_b_t_d_8h__dep__incl.png b/_b_t_d_8h__dep__incl.png index 008b22f1569959e642d19c33f5b498d6ab9dfdb1..4712263cfe47cbc2b65f47e1669e26ece6d8d3ee 100644 GIT binary patch literal 20754 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 literal 19106 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 diff --git a/_b_t_d_8h_source.html b/_b_t_d_8h_source.html index d4605bdf..290b5a5e 100644 --- a/_b_t_d_8h_source.html +++ b/_b_t_d_8h_source.html @@ -63,7 +63,7 @@ $(function() {
BTD.h
-Go to the documentation of this file.
1 /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
2 
3  This software may be distributed and modified under the terms of the GNU
4  General Public License version 2 (GPL2) as published by the Free Software
5  Foundation and appearing in the file GPL2.TXT included in the packaging of
6  this file. Please note that GPL2 Section 2[b] requires that all works based
7  on this software must also be made publicly available under the terms of
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Lauszus, TKJ Electronics
14  Web : http://www.tkjelectronics.com
15  e-mail : kristianl@tkjelectronics.com
16  */
17 
18 #ifndef _btd_h_
19 #define _btd_h_
20 
21 #include "Usb.h"
22 #include "usbhid.h"
23 
24 //PID and VID of the Sony PS3 devices
25 #define PS3_VID 0x054C // Sony Corporation
26 #define PS3_PID 0x0268 // PS3 Controller DualShock 3
27 #define PS3NAVIGATION_PID 0x042F // Navigation controller
28 #define PS3MOVE_PID 0x03D5 // Motion controller
29 
30 // These dongles do not present themselves correctly, so we have to check for them manually
31 #define IOGEAR_GBU521_VID 0x0A5C
32 #define IOGEAR_GBU521_PID 0x21E8
33 #define BELKIN_F8T065BF_VID 0x050D
34 #define BELKIN_F8T065BF_PID 0x065A
35 
36 /* Bluetooth dongle data taken from descriptors */
37 #define BULK_MAXPKTSIZE 64 // Max size for ACL data
38 
39 // Used in control endpoint header for HCI Commands
40 #define bmREQ_HCI_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
41 
42 /* Bluetooth HCI states for hci_task() */
43 #define HCI_INIT_STATE 0
44 #define HCI_RESET_STATE 1
45 #define HCI_CLASS_STATE 2
46 #define HCI_BDADDR_STATE 3
47 #define HCI_LOCAL_VERSION_STATE 4
48 #define HCI_WRITE_NAME_STATE 5
49 #define HCI_CHECK_DEVICE_SERVICE 6
50 
51 #define HCI_INQUIRY_STATE 7 // These three states are only used if it should pair and connect to a device
52 #define HCI_CONNECT_DEVICE_STATE 8
53 #define HCI_CONNECTED_DEVICE_STATE 9
54 
55 #define HCI_SCANNING_STATE 10
56 #define HCI_CONNECT_IN_STATE 11
57 #define HCI_REMOTE_NAME_STATE 12
58 #define HCI_CONNECTED_STATE 13
59 #define HCI_DISABLE_SCAN_STATE 14
60 #define HCI_DONE_STATE 15
61 #define HCI_DISCONNECT_STATE 16
62 #define HCI_LOCAL_EXTENDED_FEATURES_STATE 17
63 #define HCI_WRITE_SIMPLE_PAIRING_STATE 18
64 #define HCI_SET_EVENT_MASK_STATE 19
65 
66 /* HCI event flags*/
67 #define HCI_FLAG_CMD_COMPLETE (1UL << 0)
68 #define HCI_FLAG_CONNECT_COMPLETE (1UL << 1)
69 #define HCI_FLAG_DISCONNECT_COMPLETE (1UL << 2)
70 #define HCI_FLAG_REMOTE_NAME_COMPLETE (1UL << 3)
71 #define HCI_FLAG_INCOMING_REQUEST (1UL << 4)
72 #define HCI_FLAG_READ_BDADDR (1UL << 5)
73 #define HCI_FLAG_READ_VERSION (1UL << 6)
74 #define HCI_FLAG_DEVICE_FOUND (1UL << 7)
75 #define HCI_FLAG_CONNECT_EVENT (1UL << 8)
76 #define HCI_FLAG_LOCAL_EXTENDED_FEATURES (1UL << 9)
77 
78 /* Macros for HCI event flag tests */
79 #define hci_check_flag(flag) (hci_event_flag & (flag))
80 #define hci_set_flag(flag) (hci_event_flag |= (flag))
81 #define hci_clear_flag(flag) (hci_event_flag &= ~(flag))
82 
83 /* HCI Events managed */
84 #define EV_INQUIRY_COMPLETE 0x01
85 #define EV_INQUIRY_RESULT 0x02
86 #define EV_CONNECT_COMPLETE 0x03
87 #define EV_INCOMING_CONNECT 0x04
88 #define EV_DISCONNECT_COMPLETE 0x05
89 #define EV_AUTHENTICATION_COMPLETE 0x06
90 #define EV_REMOTE_NAME_COMPLETE 0x07
91 #define EV_ENCRYPTION_CHANGE 0x08
92 #define EV_CHANGE_CONNECTION_LINK 0x09
93 #define EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE 0x0C
94 #define EV_QOS_SETUP_COMPLETE 0x0D
95 #define EV_COMMAND_COMPLETE 0x0E
96 #define EV_COMMAND_STATUS 0x0F
97 #define EV_ROLE_CHANGED 0x12
98 #define EV_NUM_COMPLETE_PKT 0x13
99 #define EV_PIN_CODE_REQUEST 0x16
100 #define EV_LINK_KEY_REQUEST 0x17
101 #define EV_LINK_KEY_NOTIFICATION 0x18
102 #define EV_DATA_BUFFER_OVERFLOW 0x1A
103 #define EV_MAX_SLOTS_CHANGE 0x1B
104 #define EV_LOOPBACK_COMMAND 0x19
105 #define EV_PAGE_SCAN_REP_MODE 0x20
106 #define EV_READ_REMOTE_EXTENDED_FEATURES_COMPLETE 0x23
107 #define EV_IO_CAPABILITY_REQUEST 0x31
108 #define EV_IO_CAPABILITY_RESPONSE 0x32
109 #define EV_USER_CONFIRMATION_REQUEST 0x33
110 #define EV_SIMPLE_PAIRING_COMPLETE 0x36
111 
112 /* Bluetooth states for the different Bluetooth drivers */
113 #define L2CAP_WAIT 0
114 #define L2CAP_DONE 1
115 
116 /* Used for HID Control channel */
117 #define L2CAP_CONTROL_CONNECT_REQUEST 2
118 #define L2CAP_CONTROL_CONFIG_REQUEST 3
119 #define L2CAP_CONTROL_SUCCESS 4
120 #define L2CAP_CONTROL_DISCONNECT 5
121 
122 /* Used for HID Interrupt channel */
123 #define L2CAP_INTERRUPT_SETUP 6
124 #define L2CAP_INTERRUPT_CONNECT_REQUEST 7
125 #define L2CAP_INTERRUPT_CONFIG_REQUEST 8
126 #define L2CAP_INTERRUPT_DISCONNECT 9
127 
128 /* Used for SDP channel */
129 #define L2CAP_SDP_WAIT 10
130 #define L2CAP_SDP_SUCCESS 11
131 
132 /* Used for RFCOMM channel */
133 #define L2CAP_RFCOMM_WAIT 12
134 #define L2CAP_RFCOMM_SUCCESS 13
135 
136 #define L2CAP_DISCONNECT_RESPONSE 14 // Used for both SDP and RFCOMM channel
137 
138 /* Bluetooth states used by some drivers */
139 #define TURN_ON_LED 17
140 #define PS3_ENABLE_SIXAXIS 18
141 #define WII_CHECK_MOTION_PLUS_STATE 19
142 #define WII_CHECK_EXTENSION_STATE 20
143 #define WII_INIT_MOTION_PLUS_STATE 21
144 
145 /* L2CAP event flags for HID Control channel */
146 #define L2CAP_FLAG_CONNECTION_CONTROL_REQUEST (1UL << 0)
147 #define L2CAP_FLAG_CONFIG_CONTROL_SUCCESS (1UL << 1)
148 #define L2CAP_FLAG_CONTROL_CONNECTED (1UL << 2)
149 #define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE (1UL << 3)
150 
151 /* L2CAP event flags for HID Interrupt channel */
152 #define L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST (1UL << 4)
153 #define L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS (1UL << 5)
154 #define L2CAP_FLAG_INTERRUPT_CONNECTED (1UL << 6)
155 #define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE (1UL << 7)
156 
157 /* L2CAP event flags for SDP channel */
158 #define L2CAP_FLAG_CONNECTION_SDP_REQUEST (1UL << 8)
159 #define L2CAP_FLAG_CONFIG_SDP_SUCCESS (1UL << 9)
160 #define L2CAP_FLAG_DISCONNECT_SDP_REQUEST (1UL << 10)
161 
162 /* L2CAP event flags for RFCOMM channel */
163 #define L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST (1UL << 11)
164 #define L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS (1UL << 12)
165 #define L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST (1UL << 13)
166 
167 #define L2CAP_FLAG_DISCONNECT_RESPONSE (1UL << 14)
168 
169 /* Macros for L2CAP event flag tests */
170 #define l2cap_check_flag(flag) (l2cap_event_flag & (flag))
171 #define l2cap_set_flag(flag) (l2cap_event_flag |= (flag))
172 #define l2cap_clear_flag(flag) (l2cap_event_flag &= ~(flag))
173 
174 /* L2CAP signaling commands */
175 #define L2CAP_CMD_COMMAND_REJECT 0x01
176 #define L2CAP_CMD_CONNECTION_REQUEST 0x02
177 #define L2CAP_CMD_CONNECTION_RESPONSE 0x03
178 #define L2CAP_CMD_CONFIG_REQUEST 0x04
179 #define L2CAP_CMD_CONFIG_RESPONSE 0x05
180 #define L2CAP_CMD_DISCONNECT_REQUEST 0x06
181 #define L2CAP_CMD_DISCONNECT_RESPONSE 0x07
182 #define L2CAP_CMD_INFORMATION_REQUEST 0x0A
183 #define L2CAP_CMD_INFORMATION_RESPONSE 0x0B
184 
185 // Used For Connection Response - Remember to Include High Byte
186 #define PENDING 0x01
187 #define SUCCESSFUL 0x00
188 
189 /* Bluetooth L2CAP PSM - see http://www.bluetooth.org/Technical/AssignedNumbers/logical_link.htm */
190 #define SDP_PSM 0x01 // Service Discovery Protocol PSM Value
191 #define RFCOMM_PSM 0x03 // RFCOMM PSM Value
192 #define HID_CTRL_PSM 0x11 // HID_Control PSM Value
193 #define HID_INTR_PSM 0x13 // HID_Interrupt PSM Value
194 
195 /* Used for SDP */
196 #define SDP_SERVICE_SEARCH_REQUEST 0x02
197 #define SDP_SERVICE_SEARCH_RESPONSE 0x03
198 #define SDP_SERVICE_ATTRIBUTE_REQUEST 0x04
199 #define SDP_SERVICE_ATTRIBUTE_RESPONSE 0x05
200 #define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST 0x06 // See the RFCOMM specs
201 #define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE 0x07 // See the RFCOMM specs
202 #define PNP_INFORMATION_UUID 0x1200
203 #define SERIALPORT_UUID 0x1101 // See http://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm
204 #define L2CAP_UUID 0x0100
205 
206 // Used to determine if it is a Bluetooth dongle
207 #define WI_SUBCLASS_RF 0x01 // RF Controller
208 #define WI_PROTOCOL_BT 0x01 // Bluetooth Programming Interface
209 
210 #define BTD_MAX_ENDPOINTS 4
211 #define BTD_NUM_SERVICES 4 // Max number of Bluetooth services - if you need more than 4 simply increase this number
212 
213 #define PAIR 1
214 
215 class BluetoothService;
216 
221 class BTD : public USBDeviceConfig, public UsbConfigXtracter {
222 public:
227  BTD(USB *p);
228 
237  uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed);
245  uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
250  uint8_t Release();
255  uint8_t Poll();
256 
261  virtual uint8_t GetAddress() {
262  return bAddress;
263  };
264 
269  virtual bool isReady() {
270  return bPollEnable;
271  };
272 
278  virtual bool DEVCLASSOK(uint8_t klass) {
279  return (klass == USB_CLASS_WIRELESS_CTRL);
280  };
281 
289  virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) {
290  if((vid == IOGEAR_GBU521_VID && pid == IOGEAR_GBU521_PID) || (vid == BELKIN_F8T065BF_VID && pid == BELKIN_F8T065BF_PID))
291  return true;
292  if(my_bdaddr[0] != 0x00 || my_bdaddr[1] != 0x00 || my_bdaddr[2] != 0x00 || my_bdaddr[3] != 0x00 || my_bdaddr[4] != 0x00 || my_bdaddr[5] != 0x00) { // Check if Bluetooth address is set
293  if(vid == PS3_VID && (pid == PS3_PID || pid == PS3NAVIGATION_PID || pid == PS3MOVE_PID))
294  return true;
295  }
296  return false;
297  };
309  void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
313  void disconnect();
314 
321  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) {
322  if(!btService[i]) {
323  btService[i] = pService;
324  return i; // Return ID
325  }
326  }
327  return -1; // Error registering BluetoothService
328  };
329 
336  void HCI_Command(uint8_t* data, uint16_t nbytes);
338  void hci_reset();
340  void hci_read_bdaddr();
344  void hci_read_local_extended_features(uint8_t page_number);
349  void hci_write_local_name(const char* name);
351  void hci_write_simple_pairing_mode(bool enable);
353  void hci_set_event_mask();
355  void hci_write_scan_enable();
357  void hci_write_scan_disable();
359  void hci_remote_name();
361  void hci_accept_connection();
366  void hci_disconnect(uint16_t handle);
385  void hci_inquiry();
387  void hci_inquiry_cancel();
389  void hci_connect();
396  void hci_connect(uint8_t *bdaddr);
410  void L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t channelLow = 0x01, uint8_t channelHigh = 0x00);
418  void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm);
427  void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result);
434  void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t* dcid);
441  void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid);
449  void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid);
457  void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid);
464  void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh);
475 
477  const char* btdName;
479  const char* btdPin;
480 
482  uint8_t my_bdaddr[6];
484  uint16_t hci_handle;
486  uint8_t disc_bdaddr[6];
488  char remote_name[30];
494  uint8_t hci_version;
495 
498  pairWithWii = true;
499  hci_state = HCI_CHECK_DEVICE_SERVICE;
500  };
502  bool connectToWii;
511 
513  void pairWithHID() {
514  waitingForConnection = false;
515  pairWithHIDDevice = true;
516  hci_state = HCI_CHECK_DEVICE_SERVICE;
517  };
519  bool connectToHIDDevice;
524 
529  uint8_t readPollInterval() {
530  return pollInterval;
531  };
532 
534  bool useSimplePairing;
535 
536 protected:
540  uint8_t bAddress;
543 
545  uint8_t bConfNum;
547  uint8_t bNumEP;
549  uint32_t qNextPollTime;
550 
552  static const uint8_t BTD_CONTROL_PIPE;
554  static const uint8_t BTD_EVENT_PIPE;
556  static const uint8_t BTD_DATAIN_PIPE;
558  static const uint8_t BTD_DATAOUT_PIPE;
559 
565 
566 private:
567  void Initialize(); // Set all variables, endpoint structs etc. to default values
569 
570  uint16_t PID, VID; // PID and VID of device connected
571 
572  uint8_t pollInterval;
573  bool simple_pairing_supported;
574  bool bPollEnable;
575 
576  bool pairWiiUsingSync; // True if pairing was done using the Wii SYNC button.
577  bool checkRemoteName; // Used to check remote device's name before connecting.
578  bool incomingPS4; // True if a PS4 controller is connecting
579  uint8_t classOfDevice[3]; // Class of device of last device
580 
581  /* Variables used by high level HCI task */
582  uint8_t hci_state; // Current state of Bluetooth HCI connection
583  uint16_t hci_counter; // Counter used for Bluetooth HCI reset loops
584  uint16_t hci_num_reset_loops; // This value indicate how many times it should read before trying to reset
585  uint16_t hci_event_flag; // HCI flags of received Bluetooth events
586  uint8_t inquiry_counter;
587 
588  uint8_t hcibuf[BULK_MAXPKTSIZE]; // General purpose buffer for HCI data
589  uint8_t l2capinbuf[BULK_MAXPKTSIZE]; // General purpose buffer for L2CAP in data
590  uint8_t l2capoutbuf[14]; // General purpose buffer for L2CAP out data
591 
592  /* State machines */
593  void HCI_event_task(); // Poll the HCI event pipe
594  void HCI_task(); // HCI state machine
595  void ACL_event_task(); // ACL input pipe
596 
597  /* Used to set the Bluetooth Address internally to the PS3 Controllers */
598  void setBdaddr(uint8_t* BDADDR);
599  void setMoveBdaddr(uint8_t* BDADDR);
600 };
601 
604 public:
605  BluetoothService(BTD *p) : pBtd(p) {
606  if(pBtd)
607  pBtd->registerBluetoothService(this); // Register it as a Bluetooth service
608  };
613  virtual void ACLData(uint8_t* ACLData) = 0;
615  virtual void Run() = 0;
617  virtual void Reset() = 0;
619  virtual void disconnect() = 0;
620 
625  void attachOnInit(void (*funcOnInit)(void)) {
626  pFuncOnInit = funcOnInit; // TODO: This really belong in a class of it's own as it is repeated several times
627  };
628 
629 protected:
635  virtual void onInit() = 0;
636 
638  bool checkHciHandle(uint8_t *buf, uint16_t handle) {
639  return (buf[0] == (handle & 0xFF)) && (buf[1] == ((handle >> 8) | 0x20));
640  }
641 
643  void (*pFuncOnInit)(void);
644 
647 
649  uint16_t hci_handle;
650 
653 
655  uint8_t identifier;
656 };
657 
658 #endif
static const uint8_t BTD_DATAOUT_PIPE
Definition: BTD.h:558
+Go to the documentation of this file.
1 /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
2 
3  This software may be distributed and modified under the terms of the GNU
4  General Public License version 2 (GPL2) as published by the Free Software
5  Foundation and appearing in the file GPL2.TXT included in the packaging of
6  this file. Please note that GPL2 Section 2[b] requires that all works based
7  on this software must also be made publicly available under the terms of
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Lauszus, TKJ Electronics
14  Web : http://www.tkjelectronics.com
15  e-mail : kristianl@tkjelectronics.com
16  */
17 
18 #ifndef _btd_h_
19 #define _btd_h_
20 
21 #include "Usb.h"
22 #include "usbhid.h"
23 
24 //PID and VID of the Sony PS3 devices
25 #define PS3_VID 0x054C // Sony Corporation
26 #define PS3_PID 0x0268 // PS3 Controller DualShock 3
27 #define PS3NAVIGATION_PID 0x042F // Navigation controller
28 #define PS3MOVE_PID 0x03D5 // Motion controller
29 
30 // These dongles do not present themselves correctly, so we have to check for them manually
31 #define IOGEAR_GBU521_VID 0x0A5C
32 #define IOGEAR_GBU521_PID 0x21E8
33 #define BELKIN_F8T065BF_VID 0x050D
34 #define BELKIN_F8T065BF_PID 0x065A
35 
36 /* Bluetooth dongle data taken from descriptors */
37 #define BULK_MAXPKTSIZE 64 // Max size for ACL data
38 
39 // Used in control endpoint header for HCI Commands
40 #define bmREQ_HCI_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
41 
42 /* Bluetooth HCI states for hci_task() */
43 #define HCI_INIT_STATE 0
44 #define HCI_RESET_STATE 1
45 #define HCI_CLASS_STATE 2
46 #define HCI_BDADDR_STATE 3
47 #define HCI_LOCAL_VERSION_STATE 4
48 #define HCI_WRITE_NAME_STATE 5
49 #define HCI_CHECK_DEVICE_SERVICE 6
50 
51 #define HCI_INQUIRY_STATE 7 // These three states are only used if it should pair and connect to a device
52 #define HCI_CONNECT_DEVICE_STATE 8
53 #define HCI_CONNECTED_DEVICE_STATE 9
54 
55 #define HCI_SCANNING_STATE 10
56 #define HCI_CONNECT_IN_STATE 11
57 #define HCI_REMOTE_NAME_STATE 12
58 #define HCI_CONNECTED_STATE 13
59 #define HCI_DISABLE_SCAN_STATE 14
60 #define HCI_DONE_STATE 15
61 #define HCI_DISCONNECT_STATE 16
62 #define HCI_LOCAL_EXTENDED_FEATURES_STATE 17
63 #define HCI_WRITE_SIMPLE_PAIRING_STATE 18
64 #define HCI_SET_EVENT_MASK_STATE 19
65 
66 /* HCI event flags*/
67 #define HCI_FLAG_CMD_COMPLETE (1UL << 0)
68 #define HCI_FLAG_CONNECT_COMPLETE (1UL << 1)
69 #define HCI_FLAG_DISCONNECT_COMPLETE (1UL << 2)
70 #define HCI_FLAG_REMOTE_NAME_COMPLETE (1UL << 3)
71 #define HCI_FLAG_INCOMING_REQUEST (1UL << 4)
72 #define HCI_FLAG_READ_BDADDR (1UL << 5)
73 #define HCI_FLAG_READ_VERSION (1UL << 6)
74 #define HCI_FLAG_DEVICE_FOUND (1UL << 7)
75 #define HCI_FLAG_CONNECT_EVENT (1UL << 8)
76 #define HCI_FLAG_LOCAL_EXTENDED_FEATURES (1UL << 9)
77 
78 /* Macros for HCI event flag tests */
79 #define hci_check_flag(flag) (hci_event_flag & (flag))
80 #define hci_set_flag(flag) (hci_event_flag |= (flag))
81 #define hci_clear_flag(flag) (hci_event_flag &= ~(flag))
82 
83 /* HCI Events managed */
84 #define EV_INQUIRY_COMPLETE 0x01
85 #define EV_INQUIRY_RESULT 0x02
86 #define EV_CONNECT_COMPLETE 0x03
87 #define EV_INCOMING_CONNECT 0x04
88 #define EV_DISCONNECT_COMPLETE 0x05
89 #define EV_AUTHENTICATION_COMPLETE 0x06
90 #define EV_REMOTE_NAME_COMPLETE 0x07
91 #define EV_ENCRYPTION_CHANGE 0x08
92 #define EV_CHANGE_CONNECTION_LINK 0x09
93 #define EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE 0x0C
94 #define EV_QOS_SETUP_COMPLETE 0x0D
95 #define EV_COMMAND_COMPLETE 0x0E
96 #define EV_COMMAND_STATUS 0x0F
97 #define EV_ROLE_CHANGED 0x12
98 #define EV_NUM_COMPLETE_PKT 0x13
99 #define EV_PIN_CODE_REQUEST 0x16
100 #define EV_LINK_KEY_REQUEST 0x17
101 #define EV_LINK_KEY_NOTIFICATION 0x18
102 #define EV_DATA_BUFFER_OVERFLOW 0x1A
103 #define EV_MAX_SLOTS_CHANGE 0x1B
104 #define EV_LOOPBACK_COMMAND 0x19
105 #define EV_PAGE_SCAN_REP_MODE 0x20
106 #define EV_READ_REMOTE_EXTENDED_FEATURES_COMPLETE 0x23
107 #define EV_IO_CAPABILITY_REQUEST 0x31
108 #define EV_IO_CAPABILITY_RESPONSE 0x32
109 #define EV_USER_CONFIRMATION_REQUEST 0x33
110 #define EV_SIMPLE_PAIRING_COMPLETE 0x36
111 
112 /* Bluetooth states for the different Bluetooth drivers */
113 #define L2CAP_WAIT 0
114 #define L2CAP_DONE 1
115 
116 /* Used for HID Control channel */
117 #define L2CAP_CONTROL_CONNECT_REQUEST 2
118 #define L2CAP_CONTROL_CONFIG_REQUEST 3
119 #define L2CAP_CONTROL_SUCCESS 4
120 #define L2CAP_CONTROL_DISCONNECT 5
121 
122 /* Used for HID Interrupt channel */
123 #define L2CAP_INTERRUPT_SETUP 6
124 #define L2CAP_INTERRUPT_CONNECT_REQUEST 7
125 #define L2CAP_INTERRUPT_CONFIG_REQUEST 8
126 #define L2CAP_INTERRUPT_DISCONNECT 9
127 
128 /* Used for SDP channel */
129 #define L2CAP_SDP_WAIT 10
130 #define L2CAP_SDP_SUCCESS 11
131 
132 /* Used for RFCOMM channel */
133 #define L2CAP_RFCOMM_WAIT 12
134 #define L2CAP_RFCOMM_SUCCESS 13
135 
136 #define L2CAP_DISCONNECT_RESPONSE 14 // Used for both SDP and RFCOMM channel
137 
138 /* Bluetooth states used by some drivers */
139 #define TURN_ON_LED 17
140 #define PS3_ENABLE_SIXAXIS 18
141 #define WII_CHECK_MOTION_PLUS_STATE 19
142 #define WII_CHECK_EXTENSION_STATE 20
143 #define WII_INIT_MOTION_PLUS_STATE 21
144 
145 /* L2CAP event flags for HID Control channel */
146 #define L2CAP_FLAG_CONNECTION_CONTROL_REQUEST (1UL << 0)
147 #define L2CAP_FLAG_CONFIG_CONTROL_SUCCESS (1UL << 1)
148 #define L2CAP_FLAG_CONTROL_CONNECTED (1UL << 2)
149 #define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE (1UL << 3)
150 
151 /* L2CAP event flags for HID Interrupt channel */
152 #define L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST (1UL << 4)
153 #define L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS (1UL << 5)
154 #define L2CAP_FLAG_INTERRUPT_CONNECTED (1UL << 6)
155 #define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE (1UL << 7)
156 
157 /* L2CAP event flags for SDP channel */
158 #define L2CAP_FLAG_CONNECTION_SDP_REQUEST (1UL << 8)
159 #define L2CAP_FLAG_CONFIG_SDP_SUCCESS (1UL << 9)
160 #define L2CAP_FLAG_DISCONNECT_SDP_REQUEST (1UL << 10)
161 
162 /* L2CAP event flags for RFCOMM channel */
163 #define L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST (1UL << 11)
164 #define L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS (1UL << 12)
165 #define L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST (1UL << 13)
166 
167 #define L2CAP_FLAG_DISCONNECT_RESPONSE (1UL << 14)
168 
169 /* Macros for L2CAP event flag tests */
170 #define l2cap_check_flag(flag) (l2cap_event_flag & (flag))
171 #define l2cap_set_flag(flag) (l2cap_event_flag |= (flag))
172 #define l2cap_clear_flag(flag) (l2cap_event_flag &= ~(flag))
173 
174 /* L2CAP signaling commands */
175 #define L2CAP_CMD_COMMAND_REJECT 0x01
176 #define L2CAP_CMD_CONNECTION_REQUEST 0x02
177 #define L2CAP_CMD_CONNECTION_RESPONSE 0x03
178 #define L2CAP_CMD_CONFIG_REQUEST 0x04
179 #define L2CAP_CMD_CONFIG_RESPONSE 0x05
180 #define L2CAP_CMD_DISCONNECT_REQUEST 0x06
181 #define L2CAP_CMD_DISCONNECT_RESPONSE 0x07
182 #define L2CAP_CMD_INFORMATION_REQUEST 0x0A
183 #define L2CAP_CMD_INFORMATION_RESPONSE 0x0B
184 
185 // Used For Connection Response - Remember to Include High Byte
186 #define PENDING 0x01
187 #define SUCCESSFUL 0x00
188 
189 /* Bluetooth L2CAP PSM - see http://www.bluetooth.org/Technical/AssignedNumbers/logical_link.htm */
190 #define SDP_PSM 0x01 // Service Discovery Protocol PSM Value
191 #define RFCOMM_PSM 0x03 // RFCOMM PSM Value
192 #define HID_CTRL_PSM 0x11 // HID_Control PSM Value
193 #define HID_INTR_PSM 0x13 // HID_Interrupt PSM Value
194 
195 /* Used for SDP */
196 #define SDP_SERVICE_SEARCH_REQUEST 0x02
197 #define SDP_SERVICE_SEARCH_RESPONSE 0x03
198 #define SDP_SERVICE_ATTRIBUTE_REQUEST 0x04
199 #define SDP_SERVICE_ATTRIBUTE_RESPONSE 0x05
200 #define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST 0x06 // See the RFCOMM specs
201 #define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE 0x07 // See the RFCOMM specs
202 #define PNP_INFORMATION_UUID 0x1200
203 #define SERIALPORT_UUID 0x1101 // See http://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm
204 #define L2CAP_UUID 0x0100
205 
206 // Used to determine if it is a Bluetooth dongle
207 #define WI_SUBCLASS_RF 0x01 // RF Controller
208 #define WI_PROTOCOL_BT 0x01 // Bluetooth Programming Interface
209 
210 #define BTD_MAX_ENDPOINTS 4
211 #define BTD_NUM_SERVICES 4 // Max number of Bluetooth services - if you need more than 4 simply increase this number
212 
213 #define PAIR 1
214 
215 class BluetoothService;
216 
221 class BTD : public USBDeviceConfig, public UsbConfigXtracter {
222 public:
227  BTD(USB *p);
228 
237  uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed);
245  uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
250  uint8_t Release();
255  uint8_t Poll();
256 
261  virtual uint8_t GetAddress() {
262  return bAddress;
263  };
264 
269  virtual bool isReady() {
270  return bPollEnable;
271  };
272 
278  virtual bool DEVCLASSOK(uint8_t klass) {
279  return (klass == USB_CLASS_WIRELESS_CTRL);
280  };
281 
289  virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) {
290  if((vid == IOGEAR_GBU521_VID && pid == IOGEAR_GBU521_PID) || (vid == BELKIN_F8T065BF_VID && pid == BELKIN_F8T065BF_PID))
291  return true;
292  if(my_bdaddr[0] != 0x00 || my_bdaddr[1] != 0x00 || my_bdaddr[2] != 0x00 || my_bdaddr[3] != 0x00 || my_bdaddr[4] != 0x00 || my_bdaddr[5] != 0x00) { // Check if Bluetooth address is set
293  if(vid == PS3_VID && (pid == PS3_PID || pid == PS3NAVIGATION_PID || pid == PS3MOVE_PID))
294  return true;
295  }
296  return false;
297  };
309  void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
313  void disconnect();
314 
321  for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) {
322  if(!btService[i]) {
323  btService[i] = pService;
324  return i; // Return ID
325  }
326  }
327  return -1; // Error registering BluetoothService
328  };
329 
336  void HCI_Command(uint8_t* data, uint16_t nbytes);
338  void hci_reset();
340  void hci_read_bdaddr();
344  void hci_read_local_extended_features(uint8_t page_number);
349  void hci_write_local_name(const char* name);
351  void hci_write_simple_pairing_mode(bool enable);
353  void hci_set_event_mask();
355  void hci_write_scan_enable();
357  void hci_write_scan_disable();
359  void hci_remote_name();
361  void hci_accept_connection();
366  void hci_disconnect(uint16_t handle);
385  void hci_inquiry();
387  void hci_inquiry_cancel();
389  void hci_connect();
396  void hci_connect(uint8_t *bdaddr);
410  void L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t channelLow = 0x01, uint8_t channelHigh = 0x00);
418  void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm);
427  void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result);
434  void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t* dcid);
441  void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid);
449  void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid);
457  void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid);
464  void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh);
475 
477  const char* btdName;
479  const char* btdPin;
480 
482  uint8_t my_bdaddr[6];
484  uint16_t hci_handle;
486  uint8_t disc_bdaddr[6];
488  char remote_name[30];
494  uint8_t hci_version;
495 
498  pairWithWii = true;
499  hci_state = HCI_CHECK_DEVICE_SERVICE;
500  };
502  bool connectToWii;
511 
513  void pairWithHID() {
514  waitingForConnection = false;
515  pairWithHIDDevice = true;
516  hci_state = HCI_CHECK_DEVICE_SERVICE;
517  };
519  bool connectToHIDDevice;
524 
529  uint8_t readPollInterval() {
530  return pollInterval;
531  };
532 
534  bool useSimplePairing;
535 
536 protected:
540  uint8_t bAddress;
543 
545  uint8_t bConfNum;
547  uint8_t bNumEP;
549  uint32_t qNextPollTime;
550 
552  static const uint8_t BTD_CONTROL_PIPE;
554  static const uint8_t BTD_EVENT_PIPE;
556  static const uint8_t BTD_DATAIN_PIPE;
558  static const uint8_t BTD_DATAOUT_PIPE;
559 
565 
566 private:
567  void Initialize(); // Set all variables, endpoint structs etc. to default values
569 
570  uint16_t PID, VID; // PID and VID of device connected
571 
572  uint8_t pollInterval;
573  bool simple_pairing_supported;
574  bool bPollEnable;
575 
576  bool pairWiiUsingSync; // True if pairing was done using the Wii SYNC button.
577  bool checkRemoteName; // Used to check remote device's name before connecting.
578  bool incomingPSController; // True if a PS4/PS5 controller is connecting
579  uint8_t classOfDevice[3]; // Class of device of last device
580 
581  /* Variables used by high level HCI task */
582  uint8_t hci_state; // Current state of Bluetooth HCI connection
583  uint16_t hci_counter; // Counter used for Bluetooth HCI reset loops
584  uint16_t hci_num_reset_loops; // This value indicate how many times it should read before trying to reset
585  uint16_t hci_event_flag; // HCI flags of received Bluetooth events
586  uint8_t inquiry_counter;
587 
588  uint8_t hcibuf[BULK_MAXPKTSIZE]; // General purpose buffer for HCI data
589  uint8_t l2capinbuf[BULK_MAXPKTSIZE]; // General purpose buffer for L2CAP in data
590  uint8_t l2capoutbuf[14]; // General purpose buffer for L2CAP out data
591 
592  /* State machines */
593  void HCI_event_task(); // Poll the HCI event pipe
594  void HCI_task(); // HCI state machine
595  void ACL_event_task(); // ACL input pipe
596 
597  /* Used to set the Bluetooth Address internally to the PS3 Controllers */
598  void setBdaddr(uint8_t* BDADDR);
599  void setMoveBdaddr(uint8_t* BDADDR);
600 };
601 
604 public:
605  BluetoothService(BTD *p) : pBtd(p) {
606  if(pBtd)
607  pBtd->registerBluetoothService(this); // Register it as a Bluetooth service
608  };
613  virtual void ACLData(uint8_t* ACLData) = 0;
615  virtual void Run() = 0;
617  virtual void Reset() = 0;
619  virtual void disconnect() = 0;
620 
625  void attachOnInit(void (*funcOnInit)(void)) {
626  pFuncOnInit = funcOnInit; // TODO: This really belong in a class of it's own as it is repeated several times
627  };
628 
629 protected:
635  virtual void onInit() = 0;
636 
638  bool checkHciHandle(uint8_t *buf, uint16_t handle) {
639  return (buf[0] == (handle & 0xFF)) && (buf[1] == ((handle >> 8) | 0x20));
640  }
641 
643  void (*pFuncOnInit)(void);
644 
647 
649  uint16_t hci_handle;
650 
653 
655  uint8_t identifier;
656 };
657 
658 #endif
static const uint8_t BTD_DATAOUT_PIPE
Definition: BTD.h:558
bool incomingWii
Definition: BTD.h:504
bool useSimplePairing
Definition: BTD.h:531
void hci_connect()
Definition: BTD.cpp:1268
diff --git a/_b_t_h_i_d_8cpp_source.html b/_b_t_h_i_d_8cpp_source.html index f3ffeace..08e7cbc7 100644 --- a/_b_t_h_i_d_8cpp_source.html +++ b/_b_t_h_i_d_8cpp_source.html @@ -63,7 +63,7 @@ $(function() {
BTHID.cpp
-Go to the documentation of this file.
1 /* Copyright (C) 2013 Kristian Lauszus, TKJ Electronics. All rights reserved.
2 
3  This software may be distributed and modified under the terms of the GNU
4  General Public License version 2 (GPL2) as published by the Free Software
5  Foundation and appearing in the file GPL2.TXT included in the packaging of
6  this file. Please note that GPL2 Section 2[b] requires that all works based
7  on this software must also be made publicly available under the terms of
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Lauszus, TKJ Electronics
14  Web : http://www.tkjelectronics.com
15  e-mail : kristianl@tkjelectronics.com
16  */
17 
18 #include "BTHID.h"
19 // To enable serial debugging see "settings.h"
20 //#define EXTRADEBUG // Uncomment to get even more debugging data
21 //#define PRINTREPORT // Uncomment to print the report send by the HID device
22 
23 BTHID::BTHID(BTD *p, bool pair, const char *pin) :
24 BluetoothService(p), // Pointer to USB class instance - mandatory
25 protocolMode(USB_HID_BOOT_PROTOCOL) {
26  for(uint8_t i = 0; i < NUM_PARSERS; i++)
27  pRptParser[i] = NULL;
28 
30  pBtd->btdPin = pin;
31 
32  /* Set device cid for the control and intterrupt channelse - LSB */
33  sdp_dcid[0] = 0x50; // 0x0050
34  sdp_dcid[1] = 0x00;
35  control_dcid[0] = 0x70; // 0x0070
36  control_dcid[1] = 0x00;
37  interrupt_dcid[0] = 0x71; // 0x0071
38  interrupt_dcid[1] = 0x00;
39 
40  Reset();
41 }
42 
43 void BTHID::Reset() {
44  connected = false;
45  activeConnection = false;
46  SDPConnected = false;
47  l2cap_event_flag = 0; // Reset flags
49  l2cap_state = L2CAP_WAIT;
50  ResetBTHID();
51 }
52 
53 void BTHID::disconnect() { // Use this void to disconnect the device
54  if(SDPConnected)
56  // First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection
58  Reset();
60  l2cap_state = L2CAP_INTERRUPT_DISCONNECT;
61 }
62 
63 void BTHID::ACLData(uint8_t* l2capinbuf) {
64  if(!connected) {
65  if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
66  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM && !pBtd->sdpConnectionClaimed) {
67  pBtd->sdpConnectionClaimed = true;
68  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
69  l2cap_sdp_state = L2CAP_SDP_WAIT; // Reset state
70  }
71  }
72  }
73 
74  if(!pBtd->l2capConnectionClaimed && pBtd->incomingHIDDevice && !connected && !activeConnection) {
75  if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
76  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
77  pBtd->incomingHIDDevice = false;
78  pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service
79  activeConnection = true;
80  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
81  l2cap_state = L2CAP_WAIT;
82  }
83  }
84  }
85 
86  if(checkHciHandle(l2capinbuf, hci_handle)) { // acl_handle_ok
87  if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
88  if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
89 #ifdef DEBUG_USB_HOST
90  Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
91  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
92  Notify(PSTR(" "), 0x80);
93  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
94  Notify(PSTR(" "), 0x80);
95  D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
96  Notify(PSTR(" "), 0x80);
97  D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
98  Notify(PSTR(" "), 0x80);
99  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
100  Notify(PSTR(" "), 0x80);
101  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
102 #endif
103  } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) {
104  if(((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success
105  if(l2capinbuf[14] == sdp_dcid[0] && l2capinbuf[15] == sdp_dcid[1]) {
106 #ifdef EXTRADEBUG
107  Notify(PSTR("\r\nSDP Connection Complete"), 0x80);
108 #endif
109  identifier = l2capinbuf[9];
110  sdp_scid[0] = l2capinbuf[12];
111  sdp_scid[1] = l2capinbuf[13];
112 #ifdef DEBUG_USB_HOST
113  Notify(PSTR("\r\nSend SDP Config Request"), 0x80);
114 #endif
115  identifier++;
117  } else if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) {
118 #ifdef EXTRADEBUG
119  Notify(PSTR("\r\nHID Control Connection Complete"), 0x80);
120 #endif
121  identifier = l2capinbuf[9];
122  control_scid[0] = l2capinbuf[12];
123  control_scid[1] = l2capinbuf[13];
125  } else if(l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) {
126 #ifdef EXTRADEBUG
127  Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80);
128 #endif
129  identifier = l2capinbuf[9];
130  interrupt_scid[0] = l2capinbuf[12];
131  interrupt_scid[1] = l2capinbuf[13];
133  }
134  }
135  } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
136 #ifdef EXTRADEBUG
137  Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
138  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
139  Notify(PSTR(" "), 0x80);
140  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
141  Notify(PSTR(" SCID: "), 0x80);
142  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
143  Notify(PSTR(" "), 0x80);
144  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
145  Notify(PSTR(" Identifier: "), 0x80);
146  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
147 #endif
148  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM) {
149  identifier = l2capinbuf[9];
150  sdp_scid[0] = l2capinbuf[14];
151  sdp_scid[1] = l2capinbuf[15];
153  } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
154  identifier = l2capinbuf[9];
155  control_scid[0] = l2capinbuf[14];
156  control_scid[1] = l2capinbuf[15];
158  } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) {
159  identifier = l2capinbuf[9];
160  interrupt_scid[0] = l2capinbuf[14];
161  interrupt_scid[1] = l2capinbuf[15];
163  }
164  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
165  if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
166  if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
167 #ifdef EXTRADEBUG
168  Notify(PSTR("\r\nSDP Configuration Complete"), 0x80);
169 #endif
170  identifier = l2capinbuf[9];
172  } else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
173 #ifdef EXTRADEBUG
174  Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
175 #endif
176  identifier = l2capinbuf[9];
178  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
179 #ifdef EXTRADEBUG
180  Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
181 #endif
182  identifier = l2capinbuf[9];
184  }
185  }
186  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
187  if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
188 #ifdef EXTRADEBUG
189  Notify(PSTR("\r\nSDP Configuration Request"), 0x80);
190 #endif
191  pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], sdp_scid);
192  } else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
193 #ifdef EXTRADEBUG
194  Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
195 #endif
197  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
198 #ifdef EXTRADEBUG
199  Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
200 #endif
202  }
203  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
204  if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
205 #ifdef DEBUG_USB_HOST
206  Notify(PSTR("\r\nDisconnect Request: SDP Channel"), 0x80);
207 #endif
208  identifier = l2capinbuf[9];
210  } else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
211 #ifdef DEBUG_USB_HOST
212  Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
213 #endif
214  identifier = l2capinbuf[9];
216  Reset();
217  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
218 #ifdef DEBUG_USB_HOST
219  Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80);
220 #endif
221  identifier = l2capinbuf[9];
223  Reset();
224  }
225  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
226  if(l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) {
227 #ifdef EXTRADEBUG
228  Notify(PSTR("\r\nDisconnect Response: SDP Channel"), 0x80);
229 #endif
230  identifier = l2capinbuf[9];
232  } else if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
233 #ifdef EXTRADEBUG
234  Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80);
235 #endif
236  identifier = l2capinbuf[9];
238  } else if(l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
239 #ifdef EXTRADEBUG
240  Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80);
241 #endif
242  identifier = l2capinbuf[9];
244  }
245  } else if(l2capinbuf[8] == L2CAP_CMD_INFORMATION_REQUEST) {
246 #ifdef DEBUG_USB_HOST
247  Notify(PSTR("\r\nInformation request"), 0x80);
248 #endif
249  identifier = l2capinbuf[9];
250  pBtd->l2cap_information_response(hci_handle, identifier, l2capinbuf[12], l2capinbuf[13]);
251  }
252 #ifdef EXTRADEBUG
253  else {
254  identifier = l2capinbuf[9];
255  Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
256  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
257  }
258 #endif
259  } else if(l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP
260  if(l2capinbuf[8] == SDP_SERVICE_SEARCH_REQUEST) {
261 #ifdef EXTRADEBUG
262  Notify(PSTR("\r\nSDP_SERVICE_SEARCH_REQUEST"), 0x80);
263 #endif
264  // Send response
265  l2capoutbuf[0] = SDP_SERVICE_SEARCH_RESPONSE;
266  l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh;
267  l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow;
268 
269  l2capoutbuf[3] = 0x00; // MSB Parameter Length
270  l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
271 
272  l2capoutbuf[5] = 0x00; // MSB TotalServiceRecordCount
273  l2capoutbuf[6] = 0x00; // LSB TotalServiceRecordCount = 0
274 
275  l2capoutbuf[7] = 0x00; // MSB CurrentServiceRecordCount
276  l2capoutbuf[8] = 0x00; // LSB CurrentServiceRecordCount = 0
277 
278  l2capoutbuf[9] = 0x00; // No continuation state
279 
280  SDP_Command(l2capoutbuf, 10);
281  } else if(l2capinbuf[8] == SDP_SERVICE_ATTRIBUTE_REQUEST) {
282 #ifdef EXTRADEBUG
283  Notify(PSTR("\r\nSDP_SERVICE_ATTRIBUTE_REQUEST"), 0x80);
284 #endif
285  // Send response
286  l2capoutbuf[0] = SDP_SERVICE_ATTRIBUTE_RESPONSE;
287  l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh;
288  l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow;
289 
290  l2capoutbuf[3] = 0x00; // MSB Parameter Length
291  l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
292 
293  l2capoutbuf[5] = 0x00; // MSB AttributeListByteCount
294  l2capoutbuf[6] = 0x02; // LSB AttributeListByteCount = 2
295 
296  // TODO: What to send?
297  l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte
298  l2capoutbuf[8] = 0x00; // Length = 0
299 
300  l2capoutbuf[9] = 0x00; // No continuation state
301 
302  SDP_Command(l2capoutbuf, 10);
303  } else if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST) {
304 #ifdef EXTRADEBUG
305  Notify(PSTR("\r\nSDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST"), 0x80);
306  Notify(PSTR("\r\nUUID: "), 0x80);
307  uint16_t uuid;
308  if((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000) // Check if it's sending the UUID as a 128-bit UUID
309  uuid = (l2capinbuf[18] << 8 | l2capinbuf[19]);
310  else // Short UUID
311  uuid = (l2capinbuf[16] << 8 | l2capinbuf[17]);
312  D_PrintHex<uint16_t > (uuid, 0x80);
313 
314  Notify(PSTR("\r\nLength: "), 0x80);
315  uint16_t length = l2capinbuf[11] << 8 | l2capinbuf[12];
316  D_PrintHex<uint16_t > (length, 0x80);
317  Notify(PSTR("\r\nData: "), 0x80);
318  for(uint8_t i = 0; i < length; i++) {
319  D_PrintHex<uint8_t > (l2capinbuf[13 + i], 0x80);
320  Notify(PSTR(" "), 0x80);
321  }
322 #endif
323  serviceNotSupported(l2capinbuf[9], l2capinbuf[10]); // The service is not supported
324  }
325 #ifdef EXTRADEBUG
326  else {
327  Notify(PSTR("\r\nUnknown PDU: "), 0x80);
328  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
329  }
330 #endif
331  } else if(l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
332 #ifdef PRINTREPORT
333  Notify(PSTR("\r\nL2CAP Interrupt: "), 0x80);
334  for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
335  D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
336  Notify(PSTR(" "), 0x80);
337  }
338 #endif
339  if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
340  uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
341  ParseBTHIDData((uint8_t)(length - 1), &l2capinbuf[9]);
342 
343  switch(l2capinbuf[9]) {
344  case 0x01: // Keyboard or Joystick events
345  if(pRptParser[KEYBOARD_PARSER_ID])
346  pRptParser[KEYBOARD_PARSER_ID]->Parse(reinterpret_cast<USBHID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
347  break;
348 
349  case 0x02: // Mouse events
350  if(pRptParser[MOUSE_PARSER_ID])
351  pRptParser[MOUSE_PARSER_ID]->Parse(reinterpret_cast<USBHID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
352  break;
353 #ifdef EXTRADEBUG
354  default:
355  Notify(PSTR("\r\nUnknown Report type: "), 0x80);
356  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
357  break;
358 #endif
359  }
360  }
361  } else if(l2capinbuf[6] == control_dcid[0] && l2capinbuf[7] == control_dcid[1]) { // l2cap_control
362 #ifdef PRINTREPORT
363  Notify(PSTR("\r\nL2CAP Control: "), 0x80);
364  for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
365  D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
366  Notify(PSTR(" "), 0x80);
367  }
368 #endif
369  if(l2capinbuf[8] == 0xA3) {
370  uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
371  ParseBTHIDControlData((uint8_t)(length - 1), &l2capinbuf[9]);
372  }
373  }
374 #ifdef EXTRADEBUG
375  else {
376  Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
377  D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
378  Notify(PSTR(" "), 0x80);
379  D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
380 
381  Notify(PSTR("\r\nData: "), 0x80);
382  Notify(PSTR("\r\n"), 0x80);
383  for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
384  D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
385  Notify(PSTR(" "), 0x80);
386  }
387  }
388 #endif
389  SDP_task();
390  L2CAP_task();
391  }
392 }
393 
394 void BTHID::SDP_task() {
395  switch(l2cap_sdp_state) {
396  case L2CAP_SDP_WAIT:
399 #ifdef DEBUG_USB_HOST
400  Notify(PSTR("\r\nSDP Incoming Connection Request"), 0x80);
401 #endif
403  delay(1);
405  identifier++;
406  delay(1);
411  SDPConnected = false;
412 #ifdef DEBUG_USB_HOST
413  Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80);
414 #endif
416  }
417  break;
418  case L2CAP_SDP_SUCCESS:
421 #ifdef DEBUG_USB_HOST
422  Notify(PSTR("\r\nSDP Successfully Configured"), 0x80);
423 #endif
424  SDPConnected = true;
426  }
427  break;
428 
429  case L2CAP_DISCONNECT_RESPONSE: // This is for both disconnection response from the RFCOMM and SDP channel if they were connected
431 #ifdef DEBUG_USB_HOST
432  Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80);
433 #endif
435  hci_handle = -1; // Reset handle
436  Reset();
437  }
438  break;
439  }
440 }
441 
442 void BTHID::L2CAP_task() {
443  switch(l2cap_state) {
444  /* These states are used if the HID device is the host */
447 #ifdef DEBUG_USB_HOST
448  Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
449 #endif
450  setProtocol(); // Set protocol before establishing HID interrupt channel
451  l2cap_state = L2CAP_INTERRUPT_SETUP;
452  }
453  break;
454 
457 #ifdef DEBUG_USB_HOST
458  Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
459 #endif
461  delay(1);
463  identifier++;
464  delay(1);
466 
467  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
468  }
469  break;
470 
471  /* These states are used if the Arduino is the host */
474 #ifdef DEBUG_USB_HOST
475  Notify(PSTR("\r\nSend HID Control Config Request"), 0x80);
476 #endif
477  identifier++;
479  l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST;
480  }
481  break;
482 
485  setProtocol(); // Set protocol before establishing HID interrupt channel
486  delay(1); // Short delay between commands - just to be sure
487 #ifdef DEBUG_USB_HOST
488  Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80);
489 #endif
490  identifier++;
492  l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST;
493  }
494  break;
495 
498 #ifdef DEBUG_USB_HOST
499  Notify(PSTR("\r\nSend HID Interrupt Config Request"), 0x80);
500 #endif
501  identifier++;
503  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
504  }
505  break;
506 
508  if(l2cap_check_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)) { // Now the HID channels is established
509 #ifdef DEBUG_USB_HOST
510  Notify(PSTR("\r\nHID Channels Established"), 0x80);
511 #endif
512  pBtd->connectToHIDDevice = false;
513  pBtd->pairWithHIDDevice = false;
514  connected = true;
515  onInit();
516  l2cap_state = L2CAP_DONE;
517  }
518  break;
519 
520  case L2CAP_DONE:
521  break;
522 
525 #ifdef DEBUG_USB_HOST
526  Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
527 #endif
528  identifier++;
530  l2cap_state = L2CAP_CONTROL_DISCONNECT;
531  }
532  break;
533 
536 #ifdef DEBUG_USB_HOST
537  Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
538 #endif
540  hci_handle = -1; // Reset handle
541  l2cap_event_flag = 0; // Reset flags
542  l2cap_state = L2CAP_WAIT;
543  }
544  break;
545  }
546 }
547 
548 void BTHID::Run() {
549  switch(l2cap_state) {
550  case L2CAP_WAIT:
551  if(pBtd->connectToHIDDevice && !pBtd->l2capConnectionClaimed && !connected && !activeConnection) {
553  activeConnection = true;
554 #ifdef DEBUG_USB_HOST
555  Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80);
556 #endif
557  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
558  l2cap_event_flag = 0; // Reset flags
559  identifier = 0;
561  l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST;
563 #ifdef DEBUG_USB_HOST
564  Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
565 #endif
567  delay(1);
569  identifier++;
570  delay(1);
572  l2cap_state = L2CAP_CONTROL_SUCCESS;
573  }
574  break;
575  }
576 }
577 
578 void BTHID::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bluetooth specs
579  pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_scid[0], sdp_scid[1]);
580 }
581 
582 void BTHID::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs
583  l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
584  l2capoutbuf[1] = transactionIDHigh;
585  l2capoutbuf[2] = transactionIDLow;
586  l2capoutbuf[3] = 0x00; // MSB Parameter Length
587  l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
588  l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
589  l2capoutbuf[6] = 0x02; // LSB AttributeListsByteCount = 2
590 
591  /* Attribute ID/Value Sequence: */
592  l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte
593  l2capoutbuf[8] = 0x00; // Length = 0
594  l2capoutbuf[9] = 0x00; // No continuation state
595 
596  SDP_Command(l2capoutbuf, 10);
597 }
598 
599 /************************************************************/
600 /* HID Commands */
601 
602 /************************************************************/
603 void BTHID::setProtocol() {
604 #ifdef DEBUG_USB_HOST
605  Notify(PSTR("\r\nSet protocol mode: "), 0x80);
606  D_PrintHex<uint8_t > (protocolMode, 0x80);
607 #endif
608  if (protocolMode != USB_HID_BOOT_PROTOCOL && protocolMode != HID_RPT_PROTOCOL) {
609 #ifdef DEBUG_USB_HOST
610  Notify(PSTR("\r\nNot a valid protocol mode. Using Boot protocol instead."), 0x80);
611 #endif
612  protocolMode = USB_HID_BOOT_PROTOCOL; // Use Boot Protocol by default
613  }
614  uint8_t command = 0x70 | protocolMode; // Set Protocol, see Bluetooth HID specs page 33
615  pBtd->L2CAP_Command(hci_handle, &command, 1, control_scid[0], control_scid[1]);
616 }
617 
618 void BTHID::setLeds(uint8_t data) {
619  uint8_t buf[3];
620  buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
621  buf[1] = 0x01; // Report ID
622  buf[2] = data;
624 }
#define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE
Definition: BTD.h:149
+Go to the documentation of this file.
1 /* Copyright (C) 2013 Kristian Lauszus, TKJ Electronics. All rights reserved.
2 
3  This software may be distributed and modified under the terms of the GNU
4  General Public License version 2 (GPL2) as published by the Free Software
5  Foundation and appearing in the file GPL2.TXT included in the packaging of
6  this file. Please note that GPL2 Section 2[b] requires that all works based
7  on this software must also be made publicly available under the terms of
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Lauszus, TKJ Electronics
14  Web : http://www.tkjelectronics.com
15  e-mail : kristianl@tkjelectronics.com
16  */
17 
18 #include "BTHID.h"
19 // To enable serial debugging see "settings.h"
20 //#define EXTRADEBUG // Uncomment to get even more debugging data
21 //#define PRINTREPORT // Uncomment to print the report send by the HID device
22 
23 BTHID::BTHID(BTD *p, bool pair, const char *pin) :
24 BluetoothService(p), // Pointer to USB class instance - mandatory
25 protocolMode(USB_HID_BOOT_PROTOCOL) {
26  for(uint8_t i = 0; i < NUM_PARSERS; i++)
27  pRptParser[i] = NULL;
28 
30  pBtd->btdPin = pin;
31 
32  /* Set device cid for the control and intterrupt channelse - LSB */
33  sdp_dcid[0] = 0x50; // 0x0050
34  sdp_dcid[1] = 0x00;
35  control_dcid[0] = 0x70; // 0x0070
36  control_dcid[1] = 0x00;
37  interrupt_dcid[0] = 0x71; // 0x0071
38  interrupt_dcid[1] = 0x00;
39 
40  Reset();
41 }
42 
43 void BTHID::Reset() {
44  connected = false;
45  activeConnection = false;
46  SDPConnected = false;
47  l2cap_event_flag = 0; // Reset flags
49  l2cap_state = L2CAP_WAIT;
50  ResetBTHID();
51 }
52 
53 void BTHID::disconnect() { // Use this void to disconnect the device
54  if(SDPConnected)
56  // First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection
58  Reset();
60  l2cap_state = L2CAP_INTERRUPT_DISCONNECT;
61 }
62 
63 void BTHID::ACLData(uint8_t* l2capinbuf) {
64  if(!connected) {
65  if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
66  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM && !pBtd->sdpConnectionClaimed) {
67  pBtd->sdpConnectionClaimed = true;
68  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
69  l2cap_sdp_state = L2CAP_SDP_WAIT; // Reset state
70  }
71  }
72  }
73 
74  if(!pBtd->l2capConnectionClaimed && pBtd->incomingHIDDevice && !connected && !activeConnection) {
75  if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
76  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
77  pBtd->incomingHIDDevice = false;
78  pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service
79  activeConnection = true;
80  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
81  l2cap_state = L2CAP_WAIT;
82  }
83  }
84  }
85 
86  if(checkHciHandle(l2capinbuf, hci_handle)) { // acl_handle_ok
87  if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
88  if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
89 #ifdef DEBUG_USB_HOST
90  Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
91  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
92  Notify(PSTR(" "), 0x80);
93  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
94  Notify(PSTR(" "), 0x80);
95  D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
96  Notify(PSTR(" "), 0x80);
97  D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
98  Notify(PSTR(" "), 0x80);
99  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
100  Notify(PSTR(" "), 0x80);
101  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
102 #endif
103  } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) {
104  if(((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success
105  if(l2capinbuf[14] == sdp_dcid[0] && l2capinbuf[15] == sdp_dcid[1]) {
106 #ifdef EXTRADEBUG
107  Notify(PSTR("\r\nSDP Connection Complete"), 0x80);
108 #endif
109  identifier = l2capinbuf[9];
110  sdp_scid[0] = l2capinbuf[12];
111  sdp_scid[1] = l2capinbuf[13];
112 #ifdef DEBUG_USB_HOST
113  Notify(PSTR("\r\nSend SDP Config Request"), 0x80);
114 #endif
115  identifier++;
117  } else if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) {
118 #ifdef EXTRADEBUG
119  Notify(PSTR("\r\nHID Control Connection Complete"), 0x80);
120 #endif
121  identifier = l2capinbuf[9];
122  control_scid[0] = l2capinbuf[12];
123  control_scid[1] = l2capinbuf[13];
125  } else if(l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) {
126 #ifdef EXTRADEBUG
127  Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80);
128 #endif
129  identifier = l2capinbuf[9];
130  interrupt_scid[0] = l2capinbuf[12];
131  interrupt_scid[1] = l2capinbuf[13];
133  }
134  }
135  } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
136 #ifdef EXTRADEBUG
137  Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
138  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
139  Notify(PSTR(" "), 0x80);
140  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
141  Notify(PSTR(" SCID: "), 0x80);
142  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
143  Notify(PSTR(" "), 0x80);
144  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
145  Notify(PSTR(" Identifier: "), 0x80);
146  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
147 #endif
148  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM) {
149  identifier = l2capinbuf[9];
150  sdp_scid[0] = l2capinbuf[14];
151  sdp_scid[1] = l2capinbuf[15];
153  } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
154  identifier = l2capinbuf[9];
155  control_scid[0] = l2capinbuf[14];
156  control_scid[1] = l2capinbuf[15];
158  } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) {
159  identifier = l2capinbuf[9];
160  interrupt_scid[0] = l2capinbuf[14];
161  interrupt_scid[1] = l2capinbuf[15];
163  }
164  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
165  if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
166  if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
167 #ifdef EXTRADEBUG
168  Notify(PSTR("\r\nSDP Configuration Complete"), 0x80);
169 #endif
170  identifier = l2capinbuf[9];
172  } else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
173 #ifdef EXTRADEBUG
174  Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
175 #endif
176  identifier = l2capinbuf[9];
178  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
179 #ifdef EXTRADEBUG
180  Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
181 #endif
182  identifier = l2capinbuf[9];
184  }
185  }
186  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
187  if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
188 #ifdef EXTRADEBUG
189  Notify(PSTR("\r\nSDP Configuration Request"), 0x80);
190 #endif
191  pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], sdp_scid);
192  } else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
193 #ifdef EXTRADEBUG
194  Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
195 #endif
197  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
198 #ifdef EXTRADEBUG
199  Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
200 #endif
202  }
203  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
204  if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
205 #ifdef DEBUG_USB_HOST
206  Notify(PSTR("\r\nDisconnect Request: SDP Channel"), 0x80);
207 #endif
208  identifier = l2capinbuf[9];
210  } else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
211 #ifdef DEBUG_USB_HOST
212  Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
213 #endif
214  identifier = l2capinbuf[9];
216  Reset();
217  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
218 #ifdef DEBUG_USB_HOST
219  Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80);
220 #endif
221  identifier = l2capinbuf[9];
223  Reset();
224  }
225  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
226  if(l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) {
227 #ifdef EXTRADEBUG
228  Notify(PSTR("\r\nDisconnect Response: SDP Channel"), 0x80);
229 #endif
230  identifier = l2capinbuf[9];
232  } else if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
233 #ifdef EXTRADEBUG
234  Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80);
235 #endif
236  identifier = l2capinbuf[9];
238  } else if(l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
239 #ifdef EXTRADEBUG
240  Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80);
241 #endif
242  identifier = l2capinbuf[9];
244  }
245  } else if(l2capinbuf[8] == L2CAP_CMD_INFORMATION_REQUEST) {
246 #ifdef DEBUG_USB_HOST
247  Notify(PSTR("\r\nInformation request"), 0x80);
248 #endif
249  identifier = l2capinbuf[9];
250  pBtd->l2cap_information_response(hci_handle, identifier, l2capinbuf[12], l2capinbuf[13]);
251  }
252 #ifdef EXTRADEBUG
253  else {
254  identifier = l2capinbuf[9];
255  Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
256  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
257  }
258 #endif
259  } else if(l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP
260  if(l2capinbuf[8] == SDP_SERVICE_SEARCH_REQUEST) {
261 #ifdef EXTRADEBUG
262  Notify(PSTR("\r\nSDP_SERVICE_SEARCH_REQUEST"), 0x80);
263 #endif
264  // Send response
265  l2capoutbuf[0] = SDP_SERVICE_SEARCH_RESPONSE;
266  l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh;
267  l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow;
268 
269  l2capoutbuf[3] = 0x00; // MSB Parameter Length
270  l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
271 
272  l2capoutbuf[5] = 0x00; // MSB TotalServiceRecordCount
273  l2capoutbuf[6] = 0x00; // LSB TotalServiceRecordCount = 0
274 
275  l2capoutbuf[7] = 0x00; // MSB CurrentServiceRecordCount
276  l2capoutbuf[8] = 0x00; // LSB CurrentServiceRecordCount = 0
277 
278  l2capoutbuf[9] = 0x00; // No continuation state
279 
280  SDP_Command(l2capoutbuf, 10);
281  } else if(l2capinbuf[8] == SDP_SERVICE_ATTRIBUTE_REQUEST) {
282 #ifdef EXTRADEBUG
283  Notify(PSTR("\r\nSDP_SERVICE_ATTRIBUTE_REQUEST"), 0x80);
284 #endif
285  // Send response
286  l2capoutbuf[0] = SDP_SERVICE_ATTRIBUTE_RESPONSE;
287  l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh;
288  l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow;
289 
290  l2capoutbuf[3] = 0x00; // MSB Parameter Length
291  l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
292 
293  l2capoutbuf[5] = 0x00; // MSB AttributeListByteCount
294  l2capoutbuf[6] = 0x02; // LSB AttributeListByteCount = 2
295 
296  // TODO: What to send?
297  l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte
298  l2capoutbuf[8] = 0x00; // Length = 0
299 
300  l2capoutbuf[9] = 0x00; // No continuation state
301 
302  SDP_Command(l2capoutbuf, 10);
303  } else if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST) {
304 #ifdef EXTRADEBUG
305  Notify(PSTR("\r\nSDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST"), 0x80);
306  Notify(PSTR("\r\nUUID: "), 0x80);
307  uint16_t uuid;
308  if((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000) // Check if it's sending the UUID as a 128-bit UUID
309  uuid = (l2capinbuf[18] << 8 | l2capinbuf[19]);
310  else // Short UUID
311  uuid = (l2capinbuf[16] << 8 | l2capinbuf[17]);
312  D_PrintHex<uint16_t > (uuid, 0x80);
313 
314  Notify(PSTR("\r\nLength: "), 0x80);
315  uint16_t length = l2capinbuf[11] << 8 | l2capinbuf[12];
316  D_PrintHex<uint16_t > (length, 0x80);
317  Notify(PSTR("\r\nData: "), 0x80);
318  for(uint8_t i = 0; i < length; i++) {
319  D_PrintHex<uint8_t > (l2capinbuf[13 + i], 0x80);
320  Notify(PSTR(" "), 0x80);
321  }
322 #endif
323  serviceNotSupported(l2capinbuf[9], l2capinbuf[10]); // The service is not supported
324  }
325 #ifdef EXTRADEBUG
326  else {
327  Notify(PSTR("\r\nUnknown PDU: "), 0x80);
328  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
329  }
330 #endif
331  } else if(l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
332 #ifdef PRINTREPORT
333  Notify(PSTR("\r\nL2CAP Interrupt: "), 0x80);
334  for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
335  D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
336  Notify(PSTR(" "), 0x80);
337  }
338 #endif
339  if(l2capinbuf[8] == 0xA1) { // HID BT DATA (0xA0) | Report Type (Input 0x01)
340  uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
341  ParseBTHIDData((uint8_t)(length - 1), &l2capinbuf[9]); // First byte will be the report ID
342 
343  switch(l2capinbuf[9]) { // Report ID
344  case 0x01: // Keyboard or Joystick events
345  if(pRptParser[KEYBOARD_PARSER_ID])
346  pRptParser[KEYBOARD_PARSER_ID]->Parse(reinterpret_cast<USBHID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
347  break;
348 
349  case 0x02: // Mouse events
350  if(pRptParser[MOUSE_PARSER_ID])
351  pRptParser[MOUSE_PARSER_ID]->Parse(reinterpret_cast<USBHID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
352  break;
353 #ifdef EXTRADEBUG
354  default:
355  Notify(PSTR("\r\nUnknown Report type: "), 0x80);
356  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
357  break;
358 #endif
359  }
360  } else {
361 #ifdef EXTRADEBUG
362  Notify(PSTR("\r\nUnhandled L2CAP interrupt report: "), 0x80);
363  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
364 #endif
365  }
366  } else if(l2capinbuf[6] == control_dcid[0] && l2capinbuf[7] == control_dcid[1]) { // l2cap_control
367 #ifdef PRINTREPORT
368  Notify(PSTR("\r\nL2CAP Control: "), 0x80);
369  for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
370  D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
371  Notify(PSTR(" "), 0x80);
372  }
373 #endif
374  if(l2capinbuf[8] == 0xA3) { // HID BT DATA (0xA0) | Report Type (Feature 0x03)
375  uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
376  ParseBTHIDControlData((uint8_t)(length - 1), &l2capinbuf[9]); // First byte will be the report ID
377  } else {
378 #ifdef EXTRADEBUG
379  Notify(PSTR("\r\nUnhandled L2CAP control report: "), 0x80);
380  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
381 #endif
382  }
383  }
384 #ifdef EXTRADEBUG
385  else {
386  Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
387  D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
388  Notify(PSTR(" "), 0x80);
389  D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
390 
391  Notify(PSTR("\r\nData: "), 0x80);
392  Notify(PSTR("\r\n"), 0x80);
393  for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
394  D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
395  Notify(PSTR(" "), 0x80);
396  }
397  }
398 #endif
399  SDP_task();
400  L2CAP_task();
401  }
402 }
403 
404 void BTHID::SDP_task() {
405  switch(l2cap_sdp_state) {
406  case L2CAP_SDP_WAIT:
409 #ifdef DEBUG_USB_HOST
410  Notify(PSTR("\r\nSDP Incoming Connection Request"), 0x80);
411 #endif
413  delay(1);
415  identifier++;
416  delay(1);
421  SDPConnected = false;
422 #ifdef DEBUG_USB_HOST
423  Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80);
424 #endif
426  }
427  break;
428  case L2CAP_SDP_SUCCESS:
431 #ifdef DEBUG_USB_HOST
432  Notify(PSTR("\r\nSDP Successfully Configured"), 0x80);
433 #endif
434  SDPConnected = true;
436  }
437  break;
438 
439  case L2CAP_DISCONNECT_RESPONSE: // This is for both disconnection response from the RFCOMM and SDP channel if they were connected
441 #ifdef DEBUG_USB_HOST
442  Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80);
443 #endif
445  hci_handle = -1; // Reset handle
446  Reset();
447  }
448  break;
449  }
450 }
451 
452 void BTHID::L2CAP_task() {
453  switch(l2cap_state) {
454  /* These states are used if the HID device is the host */
457 #ifdef DEBUG_USB_HOST
458  Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
459 #endif
460  setProtocol(); // Set protocol before establishing HID interrupt channel
461  l2cap_state = L2CAP_INTERRUPT_SETUP;
462  }
463  break;
464 
467 #ifdef DEBUG_USB_HOST
468  Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
469 #endif
471  delay(1);
473  identifier++;
474  delay(1);
476 
477  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
478  }
479  break;
480 
481  /* These states are used if the Arduino is the host */
484 #ifdef DEBUG_USB_HOST
485  Notify(PSTR("\r\nSend HID Control Config Request"), 0x80);
486 #endif
487  identifier++;
489  l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST;
490  }
491  break;
492 
495  setProtocol(); // Set protocol before establishing HID interrupt channel
496  delay(1); // Short delay between commands - just to be sure
497 #ifdef DEBUG_USB_HOST
498  Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80);
499 #endif
500  identifier++;
502  l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST;
503  }
504  break;
505 
508 #ifdef DEBUG_USB_HOST
509  Notify(PSTR("\r\nSend HID Interrupt Config Request"), 0x80);
510 #endif
511  identifier++;
513  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
514  }
515  break;
516 
518  if(l2cap_check_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)) { // Now the HID channels is established
519 #ifdef DEBUG_USB_HOST
520  Notify(PSTR("\r\nHID Channels Established"), 0x80);
521 #endif
522  pBtd->connectToHIDDevice = false;
523  pBtd->pairWithHIDDevice = false;
524  connected = true;
525  onInit();
526  l2cap_state = L2CAP_DONE;
527  }
528  break;
529 
530  case L2CAP_DONE:
531  break;
532 
535 #ifdef DEBUG_USB_HOST
536  Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
537 #endif
538  identifier++;
540  l2cap_state = L2CAP_CONTROL_DISCONNECT;
541  }
542  break;
543 
546 #ifdef DEBUG_USB_HOST
547  Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
548 #endif
550  hci_handle = -1; // Reset handle
551  l2cap_event_flag = 0; // Reset flags
552  l2cap_state = L2CAP_WAIT;
553  }
554  break;
555  }
556 }
557 
558 void BTHID::Run() {
559  switch(l2cap_state) {
560  case L2CAP_WAIT:
561  if(pBtd->connectToHIDDevice && !pBtd->l2capConnectionClaimed && !connected && !activeConnection) {
563  activeConnection = true;
564 #ifdef DEBUG_USB_HOST
565  Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80);
566 #endif
567  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
568  l2cap_event_flag = 0; // Reset flags
569  identifier = 0;
571  l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST;
573 #ifdef DEBUG_USB_HOST
574  Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
575 #endif
577  delay(1);
579  identifier++;
580  delay(1);
582  l2cap_state = L2CAP_CONTROL_SUCCESS;
583  }
584  break;
585  }
586 }
587 
588 void BTHID::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bluetooth specs
589  pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_scid[0], sdp_scid[1]);
590 }
591 
592 void BTHID::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs
593  l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
594  l2capoutbuf[1] = transactionIDHigh;
595  l2capoutbuf[2] = transactionIDLow;
596  l2capoutbuf[3] = 0x00; // MSB Parameter Length
597  l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
598  l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
599  l2capoutbuf[6] = 0x02; // LSB AttributeListsByteCount = 2
600 
601  /* Attribute ID/Value Sequence: */
602  l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte
603  l2capoutbuf[8] = 0x00; // Length = 0
604  l2capoutbuf[9] = 0x00; // No continuation state
605 
606  SDP_Command(l2capoutbuf, 10);
607 }
608 
609 /************************************************************/
610 /* HID Commands */
611 
612 /************************************************************/
613 void BTHID::setProtocol() {
614 #ifdef DEBUG_USB_HOST
615  Notify(PSTR("\r\nSet protocol mode: "), 0x80);
616  D_PrintHex<uint8_t > (protocolMode, 0x80);
617 #endif
618  if (protocolMode != USB_HID_BOOT_PROTOCOL && protocolMode != HID_RPT_PROTOCOL) {
619 #ifdef DEBUG_USB_HOST
620  Notify(PSTR("\r\nNot a valid protocol mode. Using Boot protocol instead."), 0x80);
621 #endif
622  protocolMode = USB_HID_BOOT_PROTOCOL; // Use Boot Protocol by default
623  }
624  uint8_t command = 0x70 | protocolMode; // Set Protocol, see Bluetooth HID specs page 33
625  pBtd->L2CAP_Command(hci_handle, &command, 1, control_scid[0], control_scid[1]);
626 }
627 
628 void BTHID::setLeds(uint8_t data) {
629  uint8_t buf[3];
630  buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
631  buf[1] = 0x01; // Report ID
632  buf[2] = data;
634 }
#define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE
Definition: BTD.h:149
#define L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS
Definition: BTD.h:153
#define L2CAP_INTERRUPT_CONFIG_REQUEST
Definition: BTD.h:125
#define L2CAP_INTERRUPT_SETUP
Definition: BTD.h:123
@@ -81,7 +81,7 @@ $(function() {
#define SDP_SERVICE_ATTRIBUTE_REQUEST
Definition: BTD.h:198
bool connected
Definition: BTHID.h:88
#define L2CAP_SDP_SUCCESS
Definition: BTD.h:130
-
void Run()
Definition: BTHID.cpp:548
+
void Run()
Definition: BTHID.cpp:558
const char * btdPin
Definition: BTD.h:479
#define L2CAP_DONE
Definition: BTD.h:114
#define L2CAP_CONTROL_SUCCESS
Definition: BTD.h:119
diff --git a/_b_t_h_i_d_8h.html b/_b_t_h_i_d_8h.html index 7fe9dd9e..883475aa 100644 --- a/_b_t_h_i_d_8h.html +++ b/_b_t_h_i_d_8h.html @@ -87,7 +87,8 @@ This graph shows which files directly or indirectly include this file:
- + +
diff --git a/_b_t_h_i_d_8h__dep__incl.map b/_b_t_h_i_d_8h__dep__incl.map index a8f40d95..9357d95b 100644 --- a/_b_t_h_i_d_8h__dep__incl.map +++ b/_b_t_h_i_d_8h__dep__incl.map @@ -1,5 +1,6 @@ - + + diff --git a/_b_t_h_i_d_8h__dep__incl.md5 b/_b_t_h_i_d_8h__dep__incl.md5 index 6a659db3..fd41a5a7 100644 --- a/_b_t_h_i_d_8h__dep__incl.md5 +++ b/_b_t_h_i_d_8h__dep__incl.md5 @@ -1 +1 @@ -f5ffabeee933ef99da0ca226df2def53 \ No newline at end of file +23a000c41dd5dd0fa67a484993db484a \ No newline at end of file diff --git a/_b_t_h_i_d_8h__dep__incl.png b/_b_t_h_i_d_8h__dep__incl.png index 2b3e98b59c5633d52a69418bb6c150154244279c..f68eb584168d5ff87c00b23d753c7672b63d8883 100644 GIT binary patch literal 7455 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 literal 6746 zcmZ`;by$?$w;e)2N|2OpP-^HJQ3)wYr9oQhlPK2S0wq1rnopC zE6t)M$M4upy3F_4O36|W)QV*}x}XurFca3|e}ZKiUinmvm$i&m_$=CHn(!n!C@5}7E;JWCZkX8fo9sU$Mw zK}o#KVO$Us6b1=OSw*FDEjO@o8!8!lu+(dDy!mH^p6^3GLoSdv|Y=x+~gxJ_FxYeNZ_JqLE?o6}N6j3hKX=8rQV_);GDAKdDrG(KI zU(aZPn5_g7ZTbFG2&AL4bF@sCAKIg#p%GMF4c$i7;syr?SJ&6e+uQR%=25k8^}f0m z?F&HGH#YhUor0eR^(HVb{VsW_S7UyMm;r`IPyf-QUNx#TPY@FWvc9#|+1?I`h=`yT zwkCnWV9v*z+K`~)Vh%z=LQ_*yh`+x-ghW~t3WX%}CM(T7fBw80f#``KqWuZ1kW)}- zK)aI`JmNy#uW2;mYjWQzuDgCaoXP&;WcaJg63+DWG}LYN1)YSe+_OYdr075PcOiKN z1(*~R6kPoLy~&*F&hzaUFERv+R2_tkCQF^>TD>lgO1d17NF)gd>wgii7up1i!g z!)^kJ_oqx=3`k>ha|~>3Y%C%-*Q9yU`kqat&EDc7CND4Vi*zUkL_D~9~uWpHHX^|ZrGDTg^7e_V|6BCNl5lK87itBwK1^5I6qxE*W5cm4=i3vSwT3Qv@ zxb~Po0XF9H>MDz*B#pPXw_deruyfX4E1LM^p8w-q?QA_OGQNmK*J3%NJU3S zXklR?nVZIiIb)m#upIm!EVCQR;AujX5n&_+5D;f(ISh~$nJ7#RI6Jkg^+@R@Z!R#?%0=#|Mj<^ znwlDWOqRks|JX~Fj7X!))YbhPKes_KJABVue!9CdYH>^sAby6CqfZ`wPTpl^QEbzEPmSdj?_6%@F> z_}D}yA;JHB$%UB&ubn#Y^Ed^oLTk9@ry(<|W6JW1Ihh28Cc&+=528`UmSx4eGlR0` zi&cusO)*DDxFmSgUNAme+fCatKWVDf)yMl+rvdB8BL5r6*Jj3!uWoHmUnVC^HHgXR zHpK9}#)L3&uCW)Z5y>klQD9>R?|TzRVi6HBl$P3JK&fdq=c@vDaP91bVyVp{1T1*+ zs?^8zneb)%b&UT>(O&3f+*|4hH*vYXbRZ`u4;@*{N9Zt}$js2t7_qVWg)qzd)R)aI zF5(l?o;bbI9S`YTVB)bST^**KsT8Gc_LCrsq1=&ms8}u;T5)Y(a?vz4CU84sXnbcw zBrH6s8^a-|{LTT}{X?z^Hg_2lkFgJgQ|w&hN4{q(7dfd3a437+%0D+fNlvL(_(meJ2NvOA_Xv^N=6 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 R@MjT3NnTB^QpPmozW`C^52XMA diff --git a/_b_t_h_i_d_8h_source.html b/_b_t_h_i_d_8h_source.html index cc0f4445..7bbc038c 100644 --- a/_b_t_h_i_d_8h_source.html +++ b/_b_t_h_i_d_8h_source.html @@ -70,7 +70,7 @@ $(function() {
Definition: BTD.h:221
uint8_t interrupt_scid[2]
Definition: BTHID.h:149
bool connected
Definition: BTHID.h:88
-
void Run()
Definition: BTHID.cpp:548
+
void Run()
Definition: BTHID.cpp:558
virtual void ResetBTHID()
Definition: BTHID.h:140
void Reset()
Definition: BTHID.cpp:43
uint8_t control_scid[2]
Definition: BTHID.h:146
diff --git a/_p_s3_b_t_8cpp_source.html b/_p_s3_b_t_8cpp_source.html index 960ac8ec..8dfcf971 100644 --- a/_p_s3_b_t_8cpp_source.html +++ b/_p_s3_b_t_8cpp_source.html @@ -86,20 +86,20 @@ $(function() {
uint8_t hci_version
Definition: BTD.h:494
- - + +
bool pairWithWii
Definition: BTD.h:506
uint8_t identifier
Definition: BTD.h:655
String getTemperature()
Definition: PS3BT.cpp:141
-
AnalogHatEnum
+
AnalogHatEnum
void moveSetRumble(uint8_t rumble)
Definition: PS3BT.cpp:617
#define TURN_ON_LED
Definition: BTD.h:139
- - + +
void printStatusString()
Definition: PS3BT.cpp:160
void setAllOff()
Definition: PS3BT.cpp:519
- +
#define L2CAP_DONE
Definition: BTD.h:114
@@ -109,9 +109,9 @@ $(function() {
#define HID_BUFFERSIZE
Definition: PS3BT.h:24
void Reset()
Definition: PS3BT.cpp:204
#define pgm_read_byte(addr)
- +
char remote_name[30]
Definition: BTD.h:488
- +
const uint32_t PS3_BUTTONS[]
Definition: PS3Enums.h:62
bool getButtonPress(ButtonEnum b)
Definition: PS3BT.cpp:49
LEDEnum
@@ -121,10 +121,10 @@ $(function() {
RumbleEnum
#define USB_HOST_SERIAL
Definition: settings.h:49
#define HID_CTRL_PSM
Definition: BTD.h:192
- +
Definition: PS3Enums.h:123
- +
bool connectToWii
Definition: BTD.h:500
uint8_t getAnalogHat(AnalogHatEnum a)
Definition: PS3BT.cpp:64
@@ -133,12 +133,12 @@ $(function() {
void hci_disconnect(uint16_t handle)
Definition: BTD.cpp:1399
#define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE
Definition: BTD.h:155
- +
ButtonEnum
void moveSetBulb(uint8_t r, uint8_t g, uint8_t b)
Definition: PS3BT.cpp:604
bool PS3MoveConnected
Definition: PS3BT.h:182
uint8_t my_bdaddr[6]
Definition: BTD.h:482
- +
void setRumbleOn(RumbleEnum mode)
Definition: PS3BT.cpp:540
void(* pFuncOnInit)(void)
Definition: BTD.h:643
float get9DOFValues(SensorEnum a)
Definition: PS3BT.cpp:112
@@ -154,13 +154,13 @@ $(function() {
ColorsEnum
BTD * pBtd
Definition: BTD.h:646
#define BULK_MAXPKTSIZE
Definition: BTD.h:37
- +
#define HID_INTR_PSM
Definition: BTD.h:193
const uint8_t PS3_ANALOG_BUTTONS[]
Definition: PS3Enums.h:92
- +
bool l2capConnectionClaimed
Definition: BTD.h:470
-
AngleEnum
+
AngleEnum
#define PS3_ENABLE_SIXAXIS
Definition: BTD.h:140
#define L2CAP_CMD_DISCONNECT_RESPONSE
Definition: BTD.h:181
@@ -186,15 +186,15 @@ $(function() {
#define l2cap_set_flag(flag)
Definition: BTD.h:171
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t *dcid)
Definition: BTD.cpp:1505
#define L2CAP_FLAG_CONFIG_CONTROL_SUCCESS
Definition: BTD.h:147
-
SensorEnum
+
SensorEnum
#define L2CAP_CMD_CONNECTION_REQUEST
Definition: BTD.h:176
uint8_t getAnalogButton(ButtonEnum a)
Definition: PS3BT.cpp:60
- +
float getAngle(AngleEnum a)
Definition: PS3BT.cpp:85
void setLedRaw(uint8_t value)
Definition: PS3BT.cpp:559
PS3BT(BTD *pBtd, uint8_t btadr5=0, uint8_t btadr4=0, uint8_t btadr3=0, uint8_t btadr2=0, uint8_t btadr1=0, uint8_t btadr0=0)
Definition: PS3BT.cpp:23
- +
bool checkHciHandle(uint8_t *buf, uint16_t handle)
Definition: BTD.h:638
void onInit()
Definition: PS3BT.cpp:628
Definition: PS3Enums.h:125
diff --git a/_p_s3_b_t_8h_source.html b/_p_s3_b_t_8h_source.html index 7cea80c8..b9159374 100644 --- a/_p_s3_b_t_8h_source.html +++ b/_p_s3_b_t_8h_source.html @@ -69,7 +69,7 @@ $(function() {
Definition: BTD.h:221
void setLedOn(LEDEnum a)
Definition: PS3BT.cpp:569
String getTemperature()
Definition: PS3BT.cpp:141
-
AnalogHatEnum
+
AnalogHatEnum
void moveSetRumble(uint8_t rumble)
Definition: PS3BT.cpp:617
void printStatusString()
Definition: PS3BT.cpp:160
void setAllOff()
Definition: PS3BT.cpp:519
@@ -93,12 +93,12 @@ $(function() {
ColorsEnum
BTD * pBtd
Definition: BTD.h:646
#define BULK_MAXPKTSIZE
Definition: BTD.h:37
-
AngleEnum
+
AngleEnum
void ACLData(uint8_t *ACLData)
Definition: PS3BT.cpp:224
void setLedOff()
Definition: PS3BT.h:138
void setLedToggle(LEDEnum a)
Definition: PS3BT.cpp:578
void disconnect()
Definition: PS3BT.cpp:217
-
SensorEnum
+
SensorEnum
uint8_t getAnalogButton(ButtonEnum a)
Definition: PS3BT.cpp:60
float getAngle(AngleEnum a)
Definition: PS3BT.cpp:85
diff --git a/_p_s3_u_s_b_8cpp_source.html b/_p_s3_u_s_b_8cpp_source.html index 35e51af7..4d8ed597 100644 --- a/_p_s3_u_s_b_8cpp_source.html +++ b/_p_s3_u_s_b_8cpp_source.html @@ -90,8 +90,8 @@ $(function() {
#define PS3_OUTPUT_PIPE
Definition: PS3USB.h:30
#define NotifyFail(...)
Definition: message.h:62
bool PS3MoveConnected
Definition: PS3USB.h:262
-
AnalogHatEnum
- +
AnalogHatEnum
+
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition: Usb.cpp:840
@@ -103,7 +103,7 @@ $(function() {
#define pgm_read_byte(addr)
#define NotifyFailGetDevDescr(...)
Definition: message.h:57
uint8_t getAnalogButton(ButtonEnum a)
Definition: PS3USB.cpp:327
- +
uint16_t getSensor(SensorEnum a)
Definition: PS3USB.cpp:335
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo *eprecord_ptr)
Definition: Usb.cpp:64
void setRumbleOff()
Definition: PS3USB.cpp:410
@@ -133,7 +133,7 @@ $(function() {
void printStatusString()
Definition: PS3USB.cpp:364
void setAllOff()
Definition: PS3USB.cpp:403
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data)
Definition: Usb.cpp:303
- +
ButtonEnum
const uint8_t PS3_LEDS[]
Definition: PS3Enums.h:43
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)=0
@@ -147,7 +147,7 @@ $(function() {
const uint8_t PS3_ANALOG_BUTTONS[]
Definition: PS3Enums.h:92
#define USB_NAK_NOWAIT
Definition: address.h:36
-
AngleEnum
+
AngleEnum
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
Definition: UsbCore.h:95
#define PS3_PID
Definition: BTD.h:26
#define PS3NAVIGATION_PID
Definition: BTD.h:27
@@ -174,12 +174,12 @@ $(function() {
#define bmREQ_HID_IN
Definition: usbhid.h:64
float getAngle(AngleEnum a)
Definition: PS3USB.cpp:339
-
SensorEnum
+
SensorEnum
#define HID_REQUEST_SET_REPORT
Definition: usbhid.h:72
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
Definition: UsbCore.h:230
#define NotifyFailSetConfDescr(...)
Definition: message.h:60
#define HID_REQUEST_GET_REPORT
Definition: usbhid.h:69
- +
PS3USB(USB *pUsb, uint8_t btadr5=0, uint8_t btadr4=0, uint8_t btadr3=0, uint8_t btadr2=0, uint8_t btadr1=0, uint8_t btadr0=0)
Definition: PS3USB.cpp:23
void getMoveCalibration(uint8_t *data)
Definition: PS3USB.cpp:553
Definition: PS3Enums.h:125
diff --git a/_p_s3_u_s_b_8h_source.html b/_p_s3_u_s_b_8h_source.html index 3899d50d..cc03bb87 100644 --- a/_p_s3_u_s_b_8h_source.html +++ b/_p_s3_u_s_b_8h_source.html @@ -72,7 +72,7 @@ $(function() {
uint8_t Release()
Definition: PS3USB.cpp:262
bool getButtonPress(ButtonEnum b)
Definition: PS3USB.cpp:316
bool PS3MoveConnected
Definition: PS3USB.h:262
-
AnalogHatEnum
+
AnalogHatEnum
StatusEnum
Definition: PS3Enums.h:113
void getMoveBdaddr(uint8_t *bdaddr)
Definition: PS3USB.cpp:543
@@ -99,7 +99,7 @@ $(function() {
uint8_t getAnalogHat(AnalogHatEnum a)
Definition: PS3USB.cpp:331
USB * pUsb
Definition: PS3USB.h:268
ColorsEnum
-
AngleEnum
+
AngleEnum
void moveSetRumble(uint8_t rumble)
Definition: PS3USB.cpp:517
uint8_t Poll()
Definition: PS3USB.cpp:272
#define PS3MOVE_PID
Definition: PS3USB.h:37
@@ -114,7 +114,7 @@ $(function() {
void setMoveBdaddr(uint8_t *bdaddr)
Definition: PS3USB.cpp:527
Definition: UsbCore.h:210
float getAngle(AngleEnum a)
Definition: PS3USB.cpp:339
-
SensorEnum
+
SensorEnum
PS3USB(USB *pUsb, uint8_t btadr5=0, uint8_t btadr4=0, uint8_t btadr3=0, uint8_t btadr2=0, uint8_t btadr1=0, uint8_t btadr0=0)
Definition: PS3USB.cpp:23
void getMoveCalibration(uint8_t *data)
Definition: PS3USB.cpp:553
bool getStatus(StatusEnum c)
Definition: PS3USB.cpp:360
diff --git a/_p_s4_parser_8cpp.html b/_p_s4_parser_8cpp.html index 9a1f433f..2cd7cd32 100644 --- a/_p_s4_parser_8cpp.html +++ b/_p_s4_parser_8cpp.html @@ -93,16 +93,27 @@ Enumerations DPAD_LEFT_UP = 0x7,
  DPAD_OFF = 0x8, +DPAD_UP = 0x0, +DPAD_UP_RIGHT = 0x1, +DPAD_RIGHT = 0x2, +
+  DPAD_RIGHT_DOWN = 0x3, +DPAD_DOWN = 0x4, +DPAD_DOWN_LEFT = 0x5, +DPAD_LEFT = 0x6, +
+  DPAD_LEFT_UP = 0x7, +DPAD_OFF = 0x8, DPAD_OFF = 0x0, DPAD_UP = 0x1, -DPAD_UP_RIGHT = 0x2,
-  DPAD_RIGHT = 0x3, +  DPAD_UP_RIGHT = 0x2, +DPAD_RIGHT = 0x3, DPAD_RIGHT_DOWN = 0x4, DPAD_DOWN = 0x5, -DPAD_DOWN_LEFT = 0x6,
-  DPAD_LEFT = 0x7, +  DPAD_DOWN_LEFT = 0x6, +DPAD_LEFT = 0x7, DPAD_LEFT_UP = 0x8
} @@ -130,6 +141,15 @@ Enumerations DPAD_LEFT  DPAD_LEFT_UP  DPAD_OFF  +DPAD_UP  +DPAD_UP_RIGHT  +DPAD_RIGHT  +DPAD_RIGHT_DOWN  +DPAD_DOWN  +DPAD_DOWN_LEFT  +DPAD_LEFT  +DPAD_LEFT_UP  +DPAD_OFF  DPAD_OFF  DPAD_UP  DPAD_UP_RIGHT  diff --git a/_p_s4_parser_8cpp_source.html b/_p_s4_parser_8cpp_source.html index d4b23eea..c9d3f210 100644 --- a/_p_s4_parser_8cpp_source.html +++ b/_p_s4_parser_8cpp_source.html @@ -70,7 +70,7 @@ $(function() {
uint8_t hatValue[4]
Definition: PS4Parser.h:94
uint8_t b
Definition: PS4Parser.h:118
bool getButtonPress(ButtonEnum b)
Definition: PS4Parser.cpp:50
-
AnalogHatEnum
+
AnalogHatEnum
DPADEnum
Definition: PS4Parser.cpp:20
uint8_t touching
Definition: PS4Parser.h:78
diff --git a/_p_s4_parser_8h_source.html b/_p_s4_parser_8h_source.html index df4083a6..a226603b 100644 --- a/_p_s4_parser_8h_source.html +++ b/_p_s4_parser_8h_source.html @@ -67,16 +67,16 @@ $(function() {
uint32_t val
Definition: PS4Parser.h:71
uint16_t getY(uint8_t finger=0, uint8_t xyId=0)
Definition: PS4Parser.h:182
uint8_t usb
Definition: PS4Parser.h:86
- +
uint8_t r1
Definition: PS4Parser.h:59
PS4Status status
Definition: PS4Parser.h:104
void setLed(uint8_t r, uint8_t g, uint8_t b)
Definition: PS4Parser.h:320
uint8_t mic
Definition: PS4Parser.h:88
-
AnalogHatEnum
+
AnalogHatEnum
uint8_t reportCounter
Definition: PS4Parser.h:69
- +
void setLed(ColorsEnum color)
Definition: PS4Parser.h:331
uint8_t audio
Definition: PS4Parser.h:87
void setRumbleOn(uint8_t bigRumble, uint8_t smallRumble)
Definition: PS4Parser.h:305
@@ -85,7 +85,7 @@ $(function() {
int16_t getSensor(SensorEnum s)
Definition: PS4Parser.h:227
uint8_t flashOn
Definition: PS4Parser.h:119
- +
uint8_t share
Definition: PS4Parser.h:62
uint8_t unknown
Definition: PS4Parser.h:89
@@ -105,7 +105,7 @@ $(function() {
uint16_t y
Definition: PS4Parser.h:80
const uint8_t PS4_BUTTONS[]
Definition: PS4Parser.h:25
- +
ButtonEnum
uint8_t r
Definition: PS4Parser.h:118
void setRumbleOff()
Definition: PS4Parser.h:285
@@ -118,8 +118,8 @@ $(function() {
uint8_t dpad
Definition: PS4Parser.h:52
ColorsEnum
int16_t gyroZ
Definition: PS4Parser.h:100
- -
AngleEnum
+ +
AngleEnum
uint16_t getX(uint8_t finger=0, uint8_t xyId=0)
Definition: PS4Parser.h:170
@@ -133,13 +133,13 @@ $(function() {
uint8_t battery
Definition: PS4Parser.h:85
uint8_t l3
Definition: PS4Parser.h:64
PS4Buttons btn
Definition: PS4Parser.h:95
-
SensorEnum
+
SensorEnum
uint8_t circle
Definition: PS4Parser.h:55
uint16_t x
Definition: PS4Parser.h:79
int16_t accZ
Definition: PS4Parser.h:101
- +
void setLedFlash(uint8_t flashOn, uint8_t flashOff)
Definition: PS4Parser.h:340
- +
bool getUsbStatus()
Definition: PS4Parser.h:258
bool getAudioStatus()
Definition: PS4Parser.h:266
diff --git a/_p_s5_b_t_8h.html b/_p_s5_b_t_8h.html new file mode 100644 index 00000000..36d586e0 --- /dev/null +++ b/_p_s5_b_t_8h.html @@ -0,0 +1,149 @@ + + + + + + + +USB Host Shield 2.0: PS5BT.h File Reference + + + + + + + + + + +
+
+ + + + + + +
+
USB Host Shield 2.0 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
PS5BT.h File Reference
+
+
+
#include "BTHID.h"
+#include "PS5Parser.h"
+
+Include dependency graph for PS5BT.h:
+
+
+ + + + + + + + + + + +
+
+

Go to the source code of this file.

+ + + + +

+Classes

class  PS5BT
 
+ + + +

+Macros

#define CRC32_POLY_LE   0xedb88320
 
+ + + +

+Variables

const uint32_t crc32_table []
 
+

Macro Definition Documentation

+ +

◆ CRC32_POLY_LE

+ +
+
+ + + + +
#define CRC32_POLY_LE   0xedb88320
+
+ +

Definition at line 80 of file PS5BT.h.

+ +
+
+

Variable Documentation

+ +

◆ crc32_table

+ +
+
+ + + + +
const uint32_t crc32_table[]
+
+

Generated from the standard Ethernet CRC-32 polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0 Source: http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/libkern/crc32.c

+ +

Definition at line 29 of file PS5BT.h.

+ +
+
+
+ + + + diff --git a/_p_s5_b_t_8h__incl.map b/_p_s5_b_t_8h__incl.map new file mode 100644 index 00000000..2f631df2 --- /dev/null +++ b/_p_s5_b_t_8h__incl.map @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/_p_s5_b_t_8h__incl.md5 b/_p_s5_b_t_8h__incl.md5 new file mode 100644 index 00000000..96eb877c --- /dev/null +++ b/_p_s5_b_t_8h__incl.md5 @@ -0,0 +1 @@ +1e5d5d372677845ed1b1074bd58a0189 \ No newline at end of file diff --git a/_p_s5_b_t_8h__incl.png b/_p_s5_b_t_8h__incl.png new file mode 100644 index 0000000000000000000000000000000000000000..ba671d7d74055c4f8ce8397a2f5b323639aa9b17 GIT binary patch literal 30714 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 + + + + + + +USB Host Shield 2.0: PS5BT.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
USB Host Shield 2.0 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
PS5BT.h
+
+
+Go to the documentation of this file.
1 /* Copyright (C) 2021 Kristian Sloth Lauszus. All rights reserved.
2 
3  This software may be distributed and modified under the terms of the GNU
4  General Public License version 2 (GPL2) as published by the Free Software
5  Foundation and appearing in the file GPL2.TXT included in the packaging of
6  this file. Please note that GPL2 Section 2[b] requires that all works based
7  on this software must also be made publicly available under the terms of
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Sloth Lauszus
14  Web : https://lauszus.com
15  e-mail : lauszus@gmail.com
16  */
17 
18 #ifndef _ps5bt_h_
19 #define _ps5bt_h_
20 
21 #include "BTHID.h"
22 #include "PS5Parser.h"
23 
29 const uint32_t crc32_table[] PROGMEM = {
30  0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
31  0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
32  0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
33  0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
34  0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
35  0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
36  0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
37  0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
38  0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
39  0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
40  0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
41  0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
42  0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
43  0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
44  0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
45  0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
46  0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
47  0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
48  0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
49  0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
50  0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
51  0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
52  0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
53  0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
54  0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
55  0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
56  0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
57  0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
58  0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
59  0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
60  0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
61  0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
62  0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
63  0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
64  0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
65  0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
66  0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
67  0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
68  0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
69  0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
70  0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
71  0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
72  0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
73 };
74 
75 /*
76  * There are multiple 16-bit CRC polynomials in common use, but this is
77  * *the* standard CRC-32 polynomial, first popularized by Ethernet.
78  * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
79  */
80 #define CRC32_POLY_LE 0xedb88320
81 
82 static inline uint32_t crc32_le_generic(uint32_t crc, uint8_t const *p, size_t len, uint32_t polynomial) {
83  // Source: https://github.com/torvalds/linux/blob/c4cf498dc0241fa2d758dba177634268446afb06/lib/crc32.c
84  int i;
85  while (len--) {
86  crc ^= *p++;
87  for (i = 0; i < 8; i++)
88  crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0);
89  }
90  return crc;
91 }
92 
93 static inline uint32_t crc32(uint32_t crc, const void *buf, size_t size) {
94 #if 1 // Use a table, as it's faster, but takes up more space
95  // Inspired by: http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/libkern/crc32.c
96  const uint8_t *p = (const uint8_t*)buf;
97  while (size--)
98  crc = pgm_read_dword(&crc32_table[*p++ ^ (crc & 0xFF)]) ^ (crc >> 8);
99  return crc;
100 #else // Can be used to save flash, but is slower
101  return crc32_le_generic(crc, (uint8_t const*)buf, size, CRC32_POLY_LE);
102 #endif
103 };
104 
109 class PS5BT : public BTHID, public PS5Parser {
110 public:
117  PS5BT(BTD *p, bool pair = false, const char *pin = "0000") :
118  BTHID(p, pair, pin), output_sequence_counter(0) {
120  };
121 
126  bool connected() {
127  return BTHID::connected;
128  };
129 
130 protected:
137  virtual void ParseBTHIDData(uint8_t len, uint8_t *buf) {
138  PS5Parser::Parse(len, buf);
139  };
140 
146  virtual void OnInitBTHID() {
148  enable_sixaxis(); // Make the controller send out the entire output report
149 
150  // Only call this is a user function has not been set
151  if (!pFuncOnInit)
152  setLed(Red); // Set the LED to red, as the PS5 controller turns Bluetooth when searching for a device
153  };
154 
156  virtual void ResetBTHID() {
158  };
162  virtual void sendOutputReport(PS5Output *output) {
163  // See the series of patches here: https://patchwork.kernel.org/project/linux-input/cover/20201219062336.72568-1-roderick@gaikai.com/
164  uint8_t buf[1 /* BT DATA Output Report */ + 1 /* report id */ + 1 /* seq_tag */ + 1 /* tag */ + 47 /* common */ + 24 /* reserved */ + 4 /* crc32 */];
165  memset(buf, 0, sizeof(buf));
166 
167  // Send as a Bluetooth HID DATA output report on the interrupt channel
168  buf[0] = 0xA2; // HID BT DATA (0xA0) | Report Type (Output 0x02)
169 
170  buf[0x01] = 0x31; // Report ID
171  buf[0x02] = (output_sequence_counter << 4) | 0x0; // Highest 4-bit is a sequence number, which needs to be increased every report. Lowest 4-bit is tag and can be zero for now.
172  if(++output_sequence_counter == 15)
173  output_sequence_counter = 0;
174  buf[0x03] = 0x10; // Magic number must be set to 0x10
175 
176  buf[0x01 + 3] = 0xFF; // feature flags 1
177  buf[0x02 + 3]= 0xF7; // feature flags 2
178 
179  buf[0x03 + 3] = output->smallRumble; // Small Rumble
180  buf[0x04 + 3] = output->bigRumble; // Big rumble
181 
182  // 5-7 headphone, speaker, mic volume, audio flags
183 
184  buf[0x09 + 3] = (uint8_t)output->microphoneLed;
185 
186  // 0x0A mute flags
187 
188  // Adaptive Triggers: 0x0B-0x14 right, 0x15 unknown, 0x16-0x1F left
189  rightTrigger.processTrigger(&buf[0x0B + 3]); // right
190  leftTrigger.processTrigger(&buf[0x16 + 3]); // left
191 
192  // 0x20-0x24 unknown
193  // 0x25 trigger motor effect strengths
194  // 0x26 speaker volume
195 
196  // player LEDs
197  buf[0x27 + 3] = 0x03; // led brightness, pulse
198  buf[0x2A + 3] = output->disableLeds ? 0x01 : 0x2; // led pulse option
199  // buf[0x2B] LED brightness, 0 = full, 1= medium, 2 = low
200  buf[0x2C + 3] = output->playerLeds; // 5 white player LEDs
201 
202  // lightbar
203  buf[0x2D + 3] = output->r; // Red
204  buf[0x2E + 3] = output->g; // Green
205  buf[0x2F + 3] = output->b; // Blue
206 
207  uint32_t crc = ~crc32(0xFFFFFFFF, buf, sizeof(buf) - 4 /* Do not include the crc32 */); // Note how the report type is also included in the output report
208  buf[75] = crc & 0xFF;
209  buf[76] = (crc >> 8) & 0xFF;
210  buf[77] = (crc >> 16);
211  buf[78] = (crc >> 24);
212 
213  output->reportChanged = false;
214 
215  // Send the Bluetooth DATA output report on the interrupt channel
216  pBtd->L2CAP_Command(hci_handle, buf, sizeof(buf), interrupt_scid[0], interrupt_scid[1]);
217  };
220 private:
221  void enable_sixaxis() { // Command used to make the PS5 controller send out the entire output report
222  // Request the paring info. This makes the controller send out the full report - see: https://patchwork.kernel.org/project/linux-input/cover/20201219062336.72568-1-roderick@gaikai.com/
223  uint8_t buf[2];
224  buf[0] = 0x43; // HID BT Get_report (0x40) | Report Type (Feature 0x03)
225  buf[1] = 0x09; // Report ID for paring info
226 
227  // Send the Bluetooth Get_report Feature report on the control channel
229  };
230 
231  uint8_t output_sequence_counter;
232 };
233 #endif
+
#define pgm_read_dword(addr)
+
bool reportChanged
Definition: PS5Parser.h:145
+
Definition: BTD.h:221
+
uint8_t disableLeds
Definition: PS5Parser.h:142
+
uint8_t playerLeds
Definition: PS5Parser.h:143
+
uint8_t interrupt_scid[2]
Definition: BTHID.h:149
+
bool connected()
Definition: PS5BT.h:126
+ +
bool connected
Definition: BTHID.h:88
+
Definition: PS5BT.h:109
+
PS5BT(BTD *p, bool pair=false, const char *pin="0000")
Definition: PS5BT.h:117
+
#define CRC32_POLY_LE
Definition: PS5BT.h:80
+
uint8_t r
Definition: PS5Parser.h:144
+ +
uint8_t control_scid[2]
Definition: BTHID.h:146
+
virtual void OnInitBTHID()
Definition: PS5BT.h:146
+
void Parse(uint8_t len, uint8_t *buf)
Definition: PS5Parser.cpp:80
+
PS5Trigger leftTrigger
Definition: PS5Parser.h:154
+ +
PS5Trigger rightTrigger
Definition: PS5Parser.h:154
+
virtual void ParseBTHIDData(uint8_t len, uint8_t *buf)
Definition: PS5BT.h:137
+
void(* pFuncOnInit)(void)
Definition: BTD.h:643
+
BTD * pBtd
Definition: BTD.h:646
+
uint8_t microphoneLed
Definition: PS5Parser.h:141
+
uint8_t bigRumble
Definition: PS5Parser.h:140
+
const uint32_t crc32_table[]
Definition: PS5BT.h:29
+
void setLed(uint8_t r, uint8_t g, uint8_t b)
Definition: PS5Parser.h:339
+
uint8_t b
Definition: PS5Parser.h:144
+
uint16_t hci_handle
Definition: BTD.h:649
+
virtual void sendOutputReport(PS5Output *output)
Definition: PS5BT.h:162
+
void processTrigger(uint8_t *buffer)
Apply the trigger data to a PS5 update buffer.
Definition: PS5Trigger.cpp:34
+
uint8_t smallRumble
Definition: PS5Parser.h:140
+ +
void L2CAP_Command(uint16_t handle, uint8_t *data, uint8_t nbytes, uint8_t channelLow=0x01, uint8_t channelHigh=0x00)
Definition: BTD.cpp:1447
+
Definition: BTHID.h:29
+
uint8_t g
Definition: PS5Parser.h:144
+
virtual void ResetBTHID()
Definition: PS5BT.h:156
+
void Reset()
Definition: PS5Parser.cpp:140
+
void pair(void)
Definition: BTHID.h:91
+
+ + + + diff --git a/_p_s5_parser_8cpp.html b/_p_s5_parser_8cpp.html new file mode 100644 index 00000000..9412a727 --- /dev/null +++ b/_p_s5_parser_8cpp.html @@ -0,0 +1,177 @@ + + + + + + + +USB Host Shield 2.0: PS5Parser.cpp File Reference + + + + + + + + + + +
+
+ + + + + + +
+
USB Host Shield 2.0 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
PS5Parser.cpp File Reference
+
+
+
#include "PS5Parser.h"
+
+Include dependency graph for PS5Parser.cpp:
+
+
+ + + + + + +
+
+

Go to the source code of this file.

+ + + + +

+Enumerations

enum  DPADEnum {
+  DPAD_UP = 0x0, +DPAD_UP_RIGHT = 0x1, +DPAD_RIGHT = 0x2, +DPAD_RIGHT_DOWN = 0x3, +
+  DPAD_DOWN = 0x4, +DPAD_DOWN_LEFT = 0x5, +DPAD_LEFT = 0x6, +DPAD_LEFT_UP = 0x7, +
+  DPAD_OFF = 0x8, +DPAD_UP = 0x0, +DPAD_UP_RIGHT = 0x1, +DPAD_RIGHT = 0x2, +
+  DPAD_RIGHT_DOWN = 0x3, +DPAD_DOWN = 0x4, +DPAD_DOWN_LEFT = 0x5, +DPAD_LEFT = 0x6, +
+  DPAD_LEFT_UP = 0x7, +DPAD_OFF = 0x8, +DPAD_OFF = 0x0, +DPAD_UP = 0x1, +
+  DPAD_UP_RIGHT = 0x2, +DPAD_RIGHT = 0x3, +DPAD_RIGHT_DOWN = 0x4, +DPAD_DOWN = 0x5, +
+  DPAD_DOWN_LEFT = 0x6, +DPAD_LEFT = 0x7, +DPAD_LEFT_UP = 0x8 +
+ }
 
+

Enumeration Type Documentation

+ +

◆ DPADEnum

+ +
+
+ + + + +
enum DPADEnum
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Enumerator
DPAD_UP 
DPAD_UP_RIGHT 
DPAD_RIGHT 
DPAD_RIGHT_DOWN 
DPAD_DOWN 
DPAD_DOWN_LEFT 
DPAD_LEFT 
DPAD_LEFT_UP 
DPAD_OFF 
DPAD_UP 
DPAD_UP_RIGHT 
DPAD_RIGHT 
DPAD_RIGHT_DOWN 
DPAD_DOWN 
DPAD_DOWN_LEFT 
DPAD_LEFT 
DPAD_LEFT_UP 
DPAD_OFF 
DPAD_OFF 
DPAD_UP 
DPAD_UP_RIGHT 
DPAD_RIGHT 
DPAD_RIGHT_DOWN 
DPAD_DOWN 
DPAD_DOWN_LEFT 
DPAD_LEFT 
DPAD_LEFT_UP 
+ +

Definition at line 24 of file PS5Parser.cpp.

+ +
+
+
+ + + + diff --git a/_p_s5_parser_8cpp__incl.map b/_p_s5_parser_8cpp__incl.map new file mode 100644 index 00000000..d5974310 --- /dev/null +++ b/_p_s5_parser_8cpp__incl.map @@ -0,0 +1,6 @@ + + + + + + diff --git a/_p_s5_parser_8cpp__incl.md5 b/_p_s5_parser_8cpp__incl.md5 new file mode 100644 index 00000000..f83a78ca --- /dev/null +++ b/_p_s5_parser_8cpp__incl.md5 @@ -0,0 +1 @@ +97c8c343dcbc6359725e2020c4a1f735 \ No newline at end of file diff --git a/_p_s5_parser_8cpp__incl.png b/_p_s5_parser_8cpp__incl.png new file mode 100644 index 0000000000000000000000000000000000000000..546ee2a8a1d51b8a5a89e58cb955565d99e0a04f GIT binary patch literal 10854 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 + + + + + + +USB Host Shield 2.0: PS5Parser.cpp Source File + + + + + + + + + + +
+
+ + + + + + +
+
USB Host Shield 2.0 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
PS5Parser.cpp
+
+
+Go to the documentation of this file.
1 /* Copyright (C) 2021 Kristian Sloth Lauszus. All rights reserved.
2 
3  This software may be distributed and modified under the terms of the GNU
4  General Public License version 2 (GPL2) as published by the Free Software
5  Foundation and appearing in the file GPL2.TXT included in the packaging of
6  this file. Please note that GPL2 Section 2[b] requires that all works based
7  on this software must also be made publicly available under the terms of
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Sloth Lauszus
14  Web : https://lauszus.com
15  e-mail : lauszus@gmail.com
16 
17  Thanks to Joseph Duchesne for the initial code.
18  Based on Ludwig Füchsl's https://github.com/Ohjurot/DualSense-Windows PS5 port
19  and the series of patches found here: https://patchwork.kernel.org/project/linux-input/cover/20201219062336.72568-1-roderick@gaikai.com/
20  */
21 
22 #include "PS5Parser.h"
23 
24 enum DPADEnum {
25  DPAD_UP = 0x0,
27  DPAD_RIGHT = 0x2,
29  DPAD_DOWN = 0x4,
31  DPAD_LEFT = 0x6,
32  DPAD_LEFT_UP = 0x7,
33  DPAD_OFF = 0x8,
34 };
35 
36 // To enable serial debugging see "settings.h"
37 //#define PRINTREPORT // Uncomment to print the report send by the PS5 Controller
38 
39 bool PS5Parser::checkDpad(ButtonEnum b) {
40  switch (b) {
41  case UP:
42  return ps5Data.btn.dpad == DPAD_LEFT_UP || ps5Data.btn.dpad == DPAD_UP || ps5Data.btn.dpad == DPAD_UP_RIGHT;
43  case RIGHT:
44  return ps5Data.btn.dpad == DPAD_UP_RIGHT || ps5Data.btn.dpad == DPAD_RIGHT || ps5Data.btn.dpad == DPAD_RIGHT_DOWN;
45  case DOWN:
46  return ps5Data.btn.dpad == DPAD_RIGHT_DOWN || ps5Data.btn.dpad == DPAD_DOWN || ps5Data.btn.dpad == DPAD_DOWN_LEFT;
47  case LEFT:
48  return ps5Data.btn.dpad == DPAD_DOWN_LEFT || ps5Data.btn.dpad == DPAD_LEFT || ps5Data.btn.dpad == DPAD_LEFT_UP;
49  default:
50  return false;
51  }
52 }
53 
55  if (b <= LEFT) // Dpad
56  return checkDpad(b);
57  else
58  return ps5Data.btn.val & (1UL << pgm_read_byte(&PS5_BUTTONS[(uint8_t)b]));
59 }
60 
62  uint32_t mask = 1UL << pgm_read_byte(&PS5_BUTTONS[(uint8_t)b]);
63  bool click = buttonClickState.val & mask;
64  buttonClickState.val &= ~mask; // Clear "click" event
65  return click;
66 }
67 
69  if (b == L2) // These are the only analog buttons on the controller
70  return ps5Data.trigger[0];
71  else if (b == R2)
72  return ps5Data.trigger[1];
73  return 0;
74 }
75 
77  return ps5Data.hatValue[(uint8_t)a];
78 }
79 
80 void PS5Parser::Parse(uint8_t len, uint8_t *buf) {
81  if (len > 1 && buf) {
82 #ifdef PRINTREPORT
83  Notify(PSTR("\r\nLen: "), 0x80); Notify(len, 0x80);
84  Notify(PSTR(", data: "), 0x80);
85  for (uint8_t i = 0; i < len; i++) {
86  D_PrintHex<uint8_t > (buf[i], 0x80);
87  Notify(PSTR(" "), 0x80);
88  }
89 #endif
90 
91  if (buf[0] == 0x01) // Check report ID
92  memcpy(&ps5Data, buf + 1, min((uint8_t)(len - 1), MFK_CASTUINT8T sizeof(ps5Data)));
93  else if (buf[0] == 0x31) { // This report is send via Bluetooth, it has an offset of 1 compared to the USB data
94  if (len < 3) {
95 #ifdef DEBUG_USB_HOST
96  Notify(PSTR("\r\nReport is too short: "), 0x80);
97  D_PrintHex<uint8_t > (len, 0x80);
98 #endif
99  return;
100  }
101  memcpy(&ps5Data, buf + 2, min((uint8_t)(len - 2), MFK_CASTUINT8T sizeof(ps5Data)));
102  } else {
103 #ifdef DEBUG_USB_HOST
104  Notify(PSTR("\r\nUnknown report id: "), 0x80);
105  D_PrintHex<uint8_t > (buf[0], 0x80);
106  Notify(PSTR(", len: "), 0x80);
107  D_PrintHex<uint8_t > (len, 0x80);
108 #endif
109  return;
110  }
111 
112  if (ps5Data.btn.val != oldButtonState.val) { // Check if anything has changed
113  buttonClickState.val = ps5Data.btn.val & ~oldButtonState.val; // Update click state variable
114  oldButtonState.val = ps5Data.btn.val;
115 
116  // The DPAD buttons does not set the different bits, but set a value corresponding to the buttons pressed, we will simply set the bits ourself
117  uint8_t newDpad = 0;
118  if (checkDpad(UP))
119  newDpad |= 1 << UP;
120  if (checkDpad(RIGHT))
121  newDpad |= 1 << RIGHT;
122  if (checkDpad(DOWN))
123  newDpad |= 1 << DOWN;
124  if (checkDpad(LEFT))
125  newDpad |= 1 << LEFT;
126  if (newDpad != oldDpad) {
127  buttonClickState.dpad = newDpad & ~oldDpad; // Override values
128  oldDpad = newDpad;
129  }
130  }
131 
132  message_counter++;
133  }
134 
136  sendOutputReport(&ps5Output); // Send output report
137 }
138 
139 
141  uint8_t i;
142  for (i = 0; i < sizeof(ps5Data.hatValue); i++)
143  ps5Data.hatValue[i] = 127; // Center value
144  ps5Data.btn.val = 0;
145  oldButtonState.val = 0;
146  for (i = 0; i < sizeof(ps5Data.trigger); i++)
147  ps5Data.trigger[i] = 0;
148  for (i = 0; i < sizeof(ps5Data.xy.finger)/sizeof(ps5Data.xy.finger[0]); i++)
149  ps5Data.xy.finger[i].touching = 1; // The bit is cleared if the finger is touching the touchpad
150 
151  ps5Data.btn.dpad = DPAD_OFF;
152  oldButtonState.dpad = DPAD_OFF;
153  buttonClickState.dpad = 0;
154  oldDpad = 0;
155 
156  leftTrigger.Reset();
158 
159  ps5Output.bigRumble = ps5Output.smallRumble = 0;
160  ps5Output.microphoneLed = 0;
161  ps5Output.disableLeds = 0;
162  ps5Output.playerLeds = 0;
163  ps5Output.r = ps5Output.g = ps5Output.b = 0;
164  ps5Output.reportChanged = false;
165 };
bool reportChanged
Definition: PS5Parser.h:145
+
uint8_t disableLeds
Definition: PS5Parser.h:142
+
uint8_t playerLeds
Definition: PS5Parser.h:143
+ + + +
AnalogHatEnum
+
uint8_t hatValue[4]
Definition: PS5Parser.h:107
+
DPADEnum
Definition: PS4Parser.cpp:20
+
#define pgm_read_byte(addr)
+
uint32_t val
Definition: PS5Parser.h:78
+ + +
uint8_t r
Definition: PS5Parser.h:144
+
uint8_t touching
Definition: PS5Parser.h:84
+ +
uint8_t trigger[2]
Definition: PS5Parser.h:108
+ +
struct ps5TouchpadXY::@31 finger[2]
+
#define Notify(...)
Definition: message.h:51
+
virtual void sendOutputReport(PS5Output *output)=0
+
void Parse(uint8_t len, uint8_t *buf)
Definition: PS5Parser.cpp:80
+ +
PS5Buttons btn
Definition: PS5Parser.h:112
+
const uint8_t PS5_BUTTONS[]
Definition: PS5Parser.h:30
+
bool getButtonPress(ButtonEnum b)
Definition: PS5Parser.cpp:54
+
PS5Trigger leftTrigger
Definition: PS5Parser.h:154
+
uint8_t getAnalogButton(ButtonEnum b)
Definition: PS5Parser.cpp:68
+ +
ButtonEnum
+
PS5Trigger rightTrigger
Definition: PS5Parser.h:154
+
uint8_t dpad
Definition: PS5Parser.h:58
+
bool reportChanged
Definition: PS5Trigger.h:88
+ + +
uint8_t getAnalogHat(AnalogHatEnum a)
Definition: PS5Parser.cpp:76
+
#define PSTR(str)
+
#define MFK_CASTUINT8T
Definition: settings.h:194
+ +
uint8_t microphoneLed
Definition: PS5Parser.h:141
+
uint8_t bigRumble
Definition: PS5Parser.h:140
+
ps5TouchpadXY xy
Definition: PS5Parser.h:125
+
uint8_t b
Definition: PS5Parser.h:144
+ +
bool getButtonClick(ButtonEnum b)
Definition: PS5Parser.cpp:61
+ +
uint8_t smallRumble
Definition: PS5Parser.h:140
+
uint8_t g
Definition: PS5Parser.h:144
+ +
void Reset()
Definition: PS5Trigger.h:100
+
void Reset()
Definition: PS5Parser.cpp:140
+ +
+ + + + diff --git a/_p_s5_parser_8h.html b/_p_s5_parser_8h.html new file mode 100644 index 00000000..92fe0740 --- /dev/null +++ b/_p_s5_parser_8h.html @@ -0,0 +1,145 @@ + + + + + + + +USB Host Shield 2.0: PS5Parser.h File Reference + + + + + + + + + + +
+
+ + + + + + +
+
USB Host Shield 2.0 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
PS5Parser.h File Reference
+
+
+
#include "Usb.h"
+#include "controllerEnums.h"
+#include "PS5Trigger.h"
+
+Include dependency graph for PS5Parser.h:
+
+
+ + + + + +
+
+This graph shows which files directly or indirectly include this file:
+
+
+ + + + + +
+
+

Go to the source code of this file.

+ + + + + + + + + + + + + + +

+Classes

union  PS5Buttons
 
struct  ps5TouchpadXY
 
union  PS5Status
 
struct  PS5Data
 
struct  PS5Output
 
class  PS5Parser
 
+ + + +

+Variables

const uint8_t PS5_BUTTONS []
 
+

Variable Documentation

+ +

◆ PS5_BUTTONS

+ +
+
+ + + + +
const uint8_t PS5_BUTTONS[]
+
+Initial value:
= {
UP,
DOWN,
LEFT,
0x0C,
0x0D,
0x0E,
0x0F,
0x0A,
0x0B,
0x08,
0x09,
0x07,
0x06,
0x05,
0x04,
0x10,
0x11,
0x12,
}
+ + + +

Buttons on the controller

+ +

Definition at line 30 of file PS5Parser.h.

+ +
+
+
+ + + + diff --git a/_p_s5_parser_8h__dep__incl.map b/_p_s5_parser_8h__dep__incl.map new file mode 100644 index 00000000..deb25120 --- /dev/null +++ b/_p_s5_parser_8h__dep__incl.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_p_s5_parser_8h__dep__incl.md5 b/_p_s5_parser_8h__dep__incl.md5 new file mode 100644 index 00000000..9d4bf899 --- /dev/null +++ b/_p_s5_parser_8h__dep__incl.md5 @@ -0,0 +1 @@ +fcee511d6736a910b5372bdfcac4f8bc \ No newline at end of file diff --git a/_p_s5_parser_8h__dep__incl.png b/_p_s5_parser_8h__dep__incl.png new file mode 100644 index 0000000000000000000000000000000000000000..3cbc7ff0eb9c278acb2e60f2232cbaeed5b1c7c4 GIT binary patch literal 5762 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 V4#=x9eLz$udw5?LUZ!pp@?TB1MwkEq literal 0 HcmV?d00001 diff --git a/_p_s5_parser_8h__incl.map b/_p_s5_parser_8h__incl.map new file mode 100644 index 00000000..713c9b1f --- /dev/null +++ b/_p_s5_parser_8h__incl.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_p_s5_parser_8h__incl.md5 b/_p_s5_parser_8h__incl.md5 new file mode 100644 index 00000000..6c2415a3 --- /dev/null +++ b/_p_s5_parser_8h__incl.md5 @@ -0,0 +1 @@ +cde57ab91e7f48eccb70d2bfffb8cf36 \ No newline at end of file diff --git a/_p_s5_parser_8h__incl.png b/_p_s5_parser_8h__incl.png new file mode 100644 index 0000000000000000000000000000000000000000..9eac82860a1f0f7589944937a59c7bec3de4a485 GIT binary patch literal 9787 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 INt*}%7e=MKTmS$7 literal 0 HcmV?d00001 diff --git a/_p_s5_parser_8h_source.html b/_p_s5_parser_8h_source.html new file mode 100644 index 00000000..0b92f0e4 --- /dev/null +++ b/_p_s5_parser_8h_source.html @@ -0,0 +1,165 @@ + + + + + + + +USB Host Shield 2.0: PS5Parser.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
USB Host Shield 2.0 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
PS5Parser.h
+
+
+Go to the documentation of this file.
1 /* Copyright (C) 2021 Kristian Sloth Lauszus. All rights reserved.
2 
3  This software may be distributed and modified under the terms of the GNU
4  General Public License version 2 (GPL2) as published by the Free Software
5  Foundation and appearing in the file GPL2.TXT included in the packaging of
6  this file. Please note that GPL2 Section 2[b] requires that all works based
7  on this software must also be made publicly available under the terms of
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Sloth Lauszus
14  Web : https://lauszus.com
15  e-mail : lauszus@gmail.com
16 
17  Thanks to Joseph Duchesne for the initial code.
18  Based on Ludwig Füchsl's https://github.com/Ohjurot/DualSense-Windows PS5 port
19  and the series of patches found here: https://patchwork.kernel.org/project/linux-input/cover/20201219062336.72568-1-roderick@gaikai.com/
20  */
21 
22 #ifndef _ps5parser_h_
23 #define _ps5parser_h_
24 
25 #include "Usb.h"
26 #include "controllerEnums.h"
27 #include "PS5Trigger.h"
28 
30 const uint8_t PS5_BUTTONS[] PROGMEM = {
31  UP, // UP
32  RIGHT, // RIGHT
33  DOWN, // DOWN
34  LEFT, // LEFT
35 
36  0x0C, // CREATE
37  0x0D, // OPTIONS
38  0x0E, // L3
39  0x0F, // R3
40 
41  0x0A, // L2
42  0x0B, // R2
43  0x08, // L1
44  0x09, // R1
45 
46  0x07, // TRIANGLE
47  0x06, // CIRCLE
48  0x05, // CROSS
49  0x04, // SQUARE
50 
51  0x10, // PS
52  0x11, // TOUCHPAD
53  0x12, // MICROPHONE
54 };
55 
56 union PS5Buttons {
57  struct {
58  uint8_t dpad : 4;
59  uint8_t square : 1;
60  uint8_t cross : 1;
61  uint8_t circle : 1;
62  uint8_t triangle : 1;
63 
64  uint8_t l1 : 1;
65  uint8_t r1 : 1;
66  uint8_t l2 : 1;
67  uint8_t r2 : 1;
68  uint8_t create : 1;
69  uint8_t menu : 1;
70  uint8_t l3 : 1;
71  uint8_t r3 : 1;
72 
73  uint8_t ps : 1;
74  uint8_t touchpad : 1;
75  uint8_t mic : 1;
76  uint8_t dummy : 5;
77  } __attribute__((packed));
78  uint32_t val : 24;
79 } __attribute__((packed));
80 
81 struct ps5TouchpadXY {
82  struct {
83  uint8_t counter : 7; // Increments every time a finger is touching the touchpad
84  uint8_t touching : 1; // The top bit is cleared if the finger is touching the touchpad
85  uint16_t x : 12;
86  uint16_t y : 12;
87  } __attribute__((packed)) finger[2]; // 0 = first finger, 1 = second finger
88 } __attribute__((packed));
89 
90 union PS5Status {
91  struct {
92  // first byte
93  uint8_t headphone : 1;
94  uint8_t dummy : 2; // Seems to change when a jack is plugged in. First bit stays on when a mic is plugged in.
95  uint8_t usb : 1; // charging
96  uint8_t dummy2: 4;
97 
98  // second byte
99  uint8_t mic : 1;
100  uint8_t dummy3 : 3;
101  } __attribute__((packed));
102  uint16_t val;
103 } __attribute__((packed));
104 
105 struct PS5Data {
106  /* Button and joystick values */
107  uint8_t hatValue[4]; // 0-3 bytes
108  uint8_t trigger[2]; // 4-5
109 
110  uint8_t sequence_number; // 6
111 
112  PS5Buttons btn; // 7-9
113 
114  uint8_t reserved[5]; // 0xA-0xD
115 
116  /* Gyro and accelerometer values */
117  int16_t gyroX, gyroZ, gyroY; // 0x0F - 0x14
118  int16_t accX, accZ, accY; // 0x15-0x1A
120 
121  uint8_t reserved2;
122 
123  // 0x20 - 0x23 touchpad point 1
124  // 0x24 - 0x27 touchpad point 2
126 
127 #if 0 // The status byte depends on if it's sent via USB or Bluetooth, so is not parsed for now
128  uint8_t reserved3; // 0x28
129 
130  uint8_t rightTriggerFeedback; // 0x29
131  uint8_t leftTriggerFeedback; // 0x2A
132  uint8_t reserved4[10]; // 0x2B - 0x34
133 
134  // status bytes 0x35-0x36
135  PS5Status status;
136 #endif
137 } __attribute__((packed));
138 
139 struct PS5Output {
140  uint8_t bigRumble, smallRumble; // Rumble
141  uint8_t microphoneLed;
142  uint8_t disableLeds;
143  uint8_t playerLeds;
144  uint8_t r, g, b; // RGB for lightbar
145  bool reportChanged; // The data is send when data is received from the controller
146 } __attribute__((packed));
147 
149 class PS5Parser {
150 public:
152  PS5Parser() : leftTrigger(), rightTrigger() {
153  Reset();
154  };
155 
157  PS5Trigger leftTrigger, rightTrigger;
158 
170  bool getButtonPress(ButtonEnum b);
171  bool getButtonClick(ButtonEnum b);
181  uint8_t getAnalogButton(ButtonEnum b);
182 
188  uint8_t getAnalogHat(AnalogHatEnum a);
189 
194  uint16_t getX(uint8_t finger = 0) {
195  return ps5Data.xy.finger[finger].x;
196  };
197 
203  uint16_t getY(uint8_t finger = 0) {
204  return ps5Data.xy.finger[finger].y;
205  };
206 
212  bool isTouching(uint8_t finger = 0) {
213  return !(ps5Data.xy.finger[finger].touching); // The bit is cleared when a finger is touching the touchpad
214  };
215 
221  uint8_t getTouchCounter(uint8_t finger = 00) {
222  return ps5Data.xy.finger[finger].counter;
223  };
224 
230  float getAngle(AngleEnum a) {
231  if (a == Pitch)
232  return (atan2f(-ps5Data.accY, -ps5Data.accZ) + PI) * RAD_TO_DEG;
233  else
234  return (atan2f(ps5Data.accX, -ps5Data.accZ) + PI) * RAD_TO_DEG;
235  };
236 
242  int16_t getSensor(SensorEnum s) {
243  switch(s) {
244  case gX:
245  return ps5Data.gyroX;
246  case gY:
247  return ps5Data.gyroY;
248  case gZ:
249  return ps5Data.gyroZ;
250  case aX:
251  return ps5Data.accX;
252  case aY:
253  return ps5Data.accY;
254  case aZ:
255  return ps5Data.accZ;
256  default:
257  return 0;
258  }
259  };
260 
261 #if 0 // Seems to only be available via Bluetooth, so have been disabled for now
262 
266  uint8_t getBatteryLevel() {
267  return ps5Data.status.battery;
268  };
269 #endif
270 
271 #if 0 // These are only valid via USB, so have been commented out for now
272 
276  bool getUsbStatus() {
277  return ps5Data.status.usb;
278  };
279 
284  bool getAudioStatus() {
285  return ps5Data.status.headphone;
286  };
287 
292  bool getMicStatus() {
293  return ps5Data.status.mic;
294  };
295 #endif
296 
298  void setAllOff() {
299  setRumbleOff();
300  setLedOff();
301  };
302 
304  void setRumbleOff() {
305  setRumbleOn(0, 0);
306  };
307 
312  void setRumbleOn(RumbleEnum mode) {
313  if (mode == RumbleLow)
314  setRumbleOn(0x00, 0xFF);
315  else
316  setRumbleOn(0xFF, 0x00);
317  };
318 
324  void setRumbleOn(uint8_t bigRumble, uint8_t smallRumble) {
325  ps5Output.bigRumble = bigRumble;
326  ps5Output.smallRumble = smallRumble;
327  ps5Output.reportChanged = true;
328  };
329 
331  void setLedOff() {
332  setLed(0, 0, 0);
333  };
334 
339  void setLed(uint8_t r, uint8_t g, uint8_t b) {
340  ps5Output.r = r;
341  ps5Output.g = g;
342  ps5Output.b = b;
343  ps5Output.reportChanged = true;
344  };
345 
350  void setLed(ColorsEnum color) {
351  setLed((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color));
352  };
353 
356  setPlayerLed(0);
357  }
358 
363  void setPlayerLed(uint8_t mask) {
364  ps5Output.playerLeds = mask;
365  ps5Output.reportChanged = true;
366  }
367 
369  void setMicLedOff() {
370  setMicLed(0);
371  }
372 
377  void setMicLed(bool on) {
378  ps5Output.microphoneLed = on ? 1 : 0;
379  ps5Output.reportChanged = true;
380  }
381 
383  uint16_t getMessageCounter(){
384  return message_counter;
385  }
386 
387 protected:
393  void Parse(uint8_t len, uint8_t *buf);
394 
396  void Reset();
397 
402  virtual void sendOutputReport(PS5Output *output) = 0;
403 
404 
405 private:
406  bool checkDpad(ButtonEnum b); // Used to check PS5 DPAD buttons
407 
408  PS5Data ps5Data;
409  PS5Buttons oldButtonState, buttonClickState;
410  PS5Output ps5Output;
411  uint8_t oldDpad;
412  uint16_t message_counter = 0;
413 };
414 #endif
uint8_t getTouchCounter(uint8_t finger=00)
Definition: PS5Parser.h:221
+ +
uint8_t cross
Definition: PS5Parser.h:60
+
uint16_t getX(uint8_t finger=0)
Definition: PS5Parser.h:194
+ +
bool reportChanged
Definition: PS5Parser.h:145
+
uint8_t dummy
Definition: PS5Parser.h:76
+
uint8_t reserved2
Definition: PS5Parser.h:121
+ +
uint8_t circle
Definition: PS5Parser.h:61
+
void setLed(ColorsEnum color)
Definition: PS5Parser.h:350
+
uint8_t disableLeds
Definition: PS5Parser.h:142
+
uint8_t playerLeds
Definition: PS5Parser.h:143
+
uint8_t l2
Definition: PS5Parser.h:66
+
AnalogHatEnum
+
uint16_t getY(uint8_t finger=0)
Definition: PS5Parser.h:203
+
void setMicLed(bool on)
Definition: PS5Parser.h:377
+ + + +
Based on Ludwig Füchsl&#39;s DualSense Windows driver https://github.com/Ohjurot/DualSense-Windows.
+
void setLedOff()
Definition: PS5Parser.h:331
+ +
uint16_t x
Definition: PS5Parser.h:85
+
uint32_t val
Definition: PS5Parser.h:78
+ +
uint16_t val
Definition: PS5Parser.h:102
+
uint8_t r2
Definition: PS5Parser.h:67
+
uint8_t mic
Definition: PS5Parser.h:75
+
void setRumbleOn(uint8_t bigRumble, uint8_t smallRumble)
Definition: PS5Parser.h:324
+
uint8_t r
Definition: PS5Parser.h:144
+
uint8_t touching
Definition: PS5Parser.h:84
+ + +
void setMicLedOff()
Definition: PS5Parser.h:369
+ +
RumbleEnum
+
uint8_t dummy3
Definition: PS5Parser.h:100
+
uint8_t headphone
Definition: PS5Parser.h:93
+
uint8_t touchpad
Definition: PS5Parser.h:74
+
PS5Buttons btn
Definition: PS5Parser.h:112
+
uint8_t l1
Definition: PS5Parser.h:64
+
const uint8_t PS5_BUTTONS[]
Definition: PS5Parser.h:30
+
uint8_t square
Definition: PS5Parser.h:59
+ +
void setRumbleOn(RumbleEnum mode)
Definition: PS5Parser.h:312
+ +
ButtonEnum
+
int16_t getSensor(SensorEnum s)
Definition: PS5Parser.h:242
+
PS5Trigger rightTrigger
Definition: PS5Parser.h:154
+
uint8_t dpad
Definition: PS5Parser.h:58
+
void setRumbleOff()
Definition: PS5Parser.h:304
+
uint8_t r1
Definition: PS5Parser.h:65
+
uint8_t usb
Definition: PS5Parser.h:95
+
void setPlayerLed(uint8_t mask)
Definition: PS5Parser.h:363
+
float getAngle(AngleEnum a)
Definition: PS5Parser.h:230
+
int16_t gyroZ
Definition: PS5Parser.h:117
+
ColorsEnum
+
uint8_t microphoneLed
Definition: PS5Parser.h:141
+ + +
uint8_t mic
Definition: PS5Parser.h:99
+
int16_t accZ
Definition: PS5Parser.h:118
+
AngleEnum
+
ps5TouchpadXY xy
Definition: PS5Parser.h:125
+
uint8_t r3
Definition: PS5Parser.h:71
+ +
uint8_t create
Definition: PS5Parser.h:68
+
void setLed(uint8_t r, uint8_t g, uint8_t b)
Definition: PS5Parser.h:339
+ +
uint16_t y
Definition: PS5Parser.h:86
+
uint8_t menu
Definition: PS5Parser.h:69
+
uint8_t counter
Definition: PS5Parser.h:83
+
uint8_t sequence_number
Definition: PS5Parser.h:110
+
uint8_t triangle
Definition: PS5Parser.h:62
+
uint16_t getMessageCounter()
Definition: PS5Parser.h:383
+
uint8_t dummy2
Definition: PS5Parser.h:96
+
uint8_t smallRumble
Definition: PS5Parser.h:140
+
bool isTouching(uint8_t finger=0)
Definition: PS5Parser.h:212
+
void setAllOff()
Definition: PS5Parser.h:298
+
int32_t sensor_timestamp
Definition: PS5Parser.h:119
+
SensorEnum
+
uint8_t dummy
Definition: PS5Parser.h:94
+ + +
void setPlayerLedOff()
Definition: PS5Parser.h:355
+ +
uint8_t l3
Definition: PS5Parser.h:70
+ +
uint8_t ps
Definition: PS5Parser.h:73
+ +
+ + + + diff --git a/_p_s5_trigger_8cpp.html b/_p_s5_trigger_8cpp.html new file mode 100644 index 00000000..09814a14 --- /dev/null +++ b/_p_s5_trigger_8cpp.html @@ -0,0 +1,100 @@ + + + + + + + +USB Host Shield 2.0: PS5Trigger.cpp File Reference + + + + + + + + + + +
+
+ + + + + + +
+
USB Host Shield 2.0 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ +
+
+
+
PS5Trigger.cpp File Reference
+
+
+ +

Based on Ludwig Füchsl's DualSense Windows driver https://github.com/Ohjurot/DualSense-Windows. +More...

+
#include "PS5Trigger.h"
+
+Include dependency graph for PS5Trigger.cpp:
+
+
+ + + +
+
+

Go to the source code of this file.

+

Detailed Description

+

Based on Ludwig Füchsl's DualSense Windows driver https://github.com/Ohjurot/DualSense-Windows.

+
Author
Ludwig Füchsl, adapted for USB_Host_Library SAMD by Joseph Duchesne
+
Date
2020-11-25
+ +

MIT License

+

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.

+

Minor updates by Kristian Sloth Lauszus.

+ +

Definition in file PS5Trigger.cpp.

+
+ + + + diff --git a/_p_s5_trigger_8cpp__incl.map b/_p_s5_trigger_8cpp__incl.map new file mode 100644 index 00000000..42d95d5f --- /dev/null +++ b/_p_s5_trigger_8cpp__incl.map @@ -0,0 +1,3 @@ + + + diff --git a/_p_s5_trigger_8cpp__incl.md5 b/_p_s5_trigger_8cpp__incl.md5 new file mode 100644 index 00000000..5dd45910 --- /dev/null +++ b/_p_s5_trigger_8cpp__incl.md5 @@ -0,0 +1 @@ +4d8a1847a0c39433a111a80b8167f291 \ No newline at end of file diff --git a/_p_s5_trigger_8cpp__incl.png b/_p_s5_trigger_8cpp__incl.png new file mode 100644 index 0000000000000000000000000000000000000000..880838ba3da438308991802a1bf32a8e2a9a4360 GIT binary patch literal 5379 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 R0;Zafih_oGg{*n#e*nXsev$wH literal 0 HcmV?d00001 diff --git a/_p_s5_trigger_8cpp_source.html b/_p_s5_trigger_8cpp_source.html new file mode 100644 index 00000000..58487b47 --- /dev/null +++ b/_p_s5_trigger_8cpp_source.html @@ -0,0 +1,77 @@ + + + + + + + +USB Host Shield 2.0: PS5Trigger.cpp Source File + + + + + + + + + + +
+
+ + + + + + +
+
USB Host Shield 2.0 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
PS5Trigger.cpp
+
+
+Go to the documentation of this file.
1 
32 #include "PS5Trigger.h"
33 
34 void PS5Trigger::processTrigger(uint8_t* buffer) {
35  // Switch on effect
36  switch (data.effectType) {
37  // Continious
38  case EffectType::ContinuousResitance:
39  // Mode
40  buffer[0x00] = 0x01;
41  // Parameters
42  buffer[0x01] = data.Continuous.startPosition;
43  buffer[0x02] = data.Continuous.force;
44 
45  break;
46 
47  // Section
48  case EffectType::SectionResitance:
49  // Mode
50  buffer[0x00] = 0x02;
51  // Parameters
52  buffer[0x01] = data.Section.startPosition;
53  buffer[0x02] = data.Section.endPosition;
54 
55  break;
56 
57  // EffectEx
58  case EffectType::EffectEx:
59  // Mode
60  buffer[0x00] = 0x02 | 0x20 | 0x04;
61  // Parameters
62  buffer[0x01] = 0xFF - data.EffectEx.startPosition;
63  // Keep flag
64  if (data.EffectEx.keepEffect)
65  buffer[0x02] = 0x02;
66  // Forces
67  buffer[0x04] = data.EffectEx.beginForce;
68  buffer[0x05] = data.EffectEx.middleForce;
69  buffer[0x06] = data.EffectEx.endForce;
70  // Frequency
71  buffer[0x09] = data.EffectEx.frequency / 2;
72  if(buffer[0x09] < 1) buffer[0x09] = 1; // minimum frequency
73 
74  break;
75 
76  // Calibrate
77  case EffectType::Calibrate:
78  // Mode
79  buffer[0x00] = 0xFC;
80 
81  break;
82 
83  // No resistance / default
84  case EffectType::NoResitance:
85  default:
86  // All zero
87  buffer[0x00] = 0x00;
88  buffer[0x01] = 0x00;
89  buffer[0x02] = 0x00;
90 
91  break;
92  }
93  reportChanged = false;
94 }
Based on Ludwig Füchsl&#39;s DualSense Windows driver https://github.com/Ohjurot/DualSense-Windows.
+
bool reportChanged
Definition: PS5Trigger.h:88
+
void processTrigger(uint8_t *buffer)
Apply the trigger data to a PS5 update buffer.
Definition: PS5Trigger.cpp:34
+
+ + + + diff --git a/_p_s5_trigger_8h.html b/_p_s5_trigger_8h.html new file mode 100644 index 00000000..9d315360 --- /dev/null +++ b/_p_s5_trigger_8h.html @@ -0,0 +1,120 @@ + + + + + + + +USB Host Shield 2.0: PS5Trigger.h File Reference + + + + + + + + + + +
+
+ + + + + + +
+
USB Host Shield 2.0 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
PS5Trigger.h File Reference
+
+
+ +

Based on Ludwig Füchsl's DualSense Windows driver https://github.com/Ohjurot/DualSense-Windows. +More...

+
#include <inttypes.h>
+
+Include dependency graph for PS5Trigger.h:
+
+
+ + +
+
+This graph shows which files directly or indirectly include this file:
+
+
+ + + + + + + +
+
+

Go to the source code of this file.

+ + + + +

+Classes

class  PS5Trigger
 
+

Detailed Description

+

Based on Ludwig Füchsl's DualSense Windows driver https://github.com/Ohjurot/DualSense-Windows.

+
Author
Ludwig Füchsl, adapted for USB_Host_Library SAMD by Joseph Duchesne
+
Version
0.1
+
Date
2020-11-25
+ +

MIT License

+

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.

+

Minor updates by Kristian Sloth Lauszus.

+ +

Definition in file PS5Trigger.h.

+
+ + + + diff --git a/_p_s5_trigger_8h__dep__incl.map b/_p_s5_trigger_8h__dep__incl.map new file mode 100644 index 00000000..4f43eed1 --- /dev/null +++ b/_p_s5_trigger_8h__dep__incl.map @@ -0,0 +1,7 @@ + + + + + + + diff --git a/_p_s5_trigger_8h__dep__incl.md5 b/_p_s5_trigger_8h__dep__incl.md5 new file mode 100644 index 00000000..302208f1 --- /dev/null +++ b/_p_s5_trigger_8h__dep__incl.md5 @@ -0,0 +1 @@ +819587c266e34a5fdeb368f8f4a05d54 \ No newline at end of file diff --git a/_p_s5_trigger_8h__dep__incl.png b/_p_s5_trigger_8h__dep__incl.png new file mode 100644 index 0000000000000000000000000000000000000000..b3f38ec43fc0ac5cec0cf45b262af4abe15f0862 GIT binary patch literal 10349 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 DIhT3m literal 0 HcmV?d00001 diff --git a/_p_s5_trigger_8h__incl.map b/_p_s5_trigger_8h__incl.map new file mode 100644 index 00000000..c7e6e901 --- /dev/null +++ b/_p_s5_trigger_8h__incl.map @@ -0,0 +1,2 @@ + + diff --git a/_p_s5_trigger_8h__incl.md5 b/_p_s5_trigger_8h__incl.md5 new file mode 100644 index 00000000..a3c38e2e --- /dev/null +++ b/_p_s5_trigger_8h__incl.md5 @@ -0,0 +1 @@ +933b51d2a99b1ab644e570075ab908af \ No newline at end of file diff --git a/_p_s5_trigger_8h__incl.png b/_p_s5_trigger_8h__incl.png new file mode 100644 index 0000000000000000000000000000000000000000..ef677ba90639bdc8a1fe3402d4a9199576c5b6e3 GIT binary patch literal 2986 zcmb_eXIK+k0v#V!dQn752t`l`y@*JaCcPt|6a`TqAXPy~jG}2DV`B z2c7}Ue}LD_;Rgm_#dyce*Z?^B`^af2d<_7s?j{C$_F_6 zkqR+o_hTM6N401O|G_FEO?TN*wp1jMW)<626Wbqy-M(>Rlt`jJW6( zU;DdfAVZ(R4Csj5>@(=Jii(QHMh&ZcY>iXfQ`$}c7DI;Bnt!}HBoj9uaazPIkJncCX&ICxhRcw#@6 zm94ZMuF(N4ZnML~L6j9jZ0u?6?6yFn5$@I+ne0<7oMu`ZvA2c`%(p#%{=5lVRUq+} z+>K&;%SD`SYHF&>&71oA`sYSoDML=>NW6r;LLO5Ki;I_A_GU^eE190rF>xd$ zBz*t=otZu|H#hg-;2=Fc9g9^0)F1u+eoQ+o=G)rdW@TZ~(9i(px)KHbn>QJq83B$M zeZMa6>h10AEN!j&`H#kOZw2}JnE^dLz4hkpBy-88M`Uz%_AGUKX>WB>iYFG(6-)7* zZAGllw0tzKb;(Li-CBs3PnD&or{6y~NOj$%tWE;DYWEpp+Am2<2g#X)MtVH$2owU$ zC3%6r2rK@rRHMR?6nPVg)IpsS46JnY&nhP&zJC@7WPlX3`#eeiRDDMR;?I z)XTuYkg4XU5x!Ft%!64$g}1m>j`PwhUb#|ieG&3>fBxAs04ORcDJd;|-Q%UGs7M|w zH@kkFnS(qD*D;R-f{q=HW`Ue9O*oUtb^C-o2lp>XVU?@taJ(z|*rlQn=xC+> zCy8{|`7BEmlD2!!L0CZG?*TO-m9@1F`L@OOCH`$R%C}s7waJf833@zlAaCW}-)CgF z*x3ay59gD|E3>bLu7T}6Jw3o*cRJ$+wGYd3bM^9ujzHG1M2X4D_UCq0W3d8)f=x|L z_q@F;ZsCF!yHluv3MSaXCA2z-6OR^2B=9-N@#5l3xz_J67|iR}FNph7ImW{` zl^}sa^02>4P240~WA+8*iU%B^{3RHxfLiE5)EFTUmMJP|eh^@|_KCabm&m$0HO>p( zoP1`Bq_cC&u(FgMFZ6GP1LTRKN=VE#o8L*$kjS}-+W9rB<%(}Z;(#wfEGtXZnE?TB4hlYL+OL(kb;?33t}{0!T1b} zd9aPQFg}fZHqUVDGlCy-FbUX0In_(2bD?92O@R{wsS>&KAetMLio*w}Z zsQNKWD?PJ8J^JJC)Twth`mHuz>hp#XaLxR z^>=@N$h7<8$2>l@I~!X=1)>82`rJU) z)uo6>0RhP_(LGo==d&N;D7^TMqS{!3FGNHn`(`UszH( zbT|M}QBg+{7K^>%j!2s#|Lo5^K0dxt>2@JgR3OGcx|#>Yc9 z7YtLb+q=42a2bFb-ds`;0$E#LPBF~~#jDP;aC>*x;o=!_aq<5Cer;{-%lZkugcsGQk9wsbmx zvf>;G?ekVnPoVJze$Vq+kLbR~6c#Z{nwCl;g3>K4EbLNF!HXbk;B#zLW2R zW`6#5uJxI977FXMn~JWJO~Qf`Vz$&-f|2^1Y;BgoEkwT zy|uHmD=aAZ3Hg$L*$dLZSr5-)bVx#>E~lF}g|64REVVW_!#zB5nwk!$Lub=^NkDRT zw!4juqPlw6>O?KLE@1KjbWKgaR(ax$jE(Vle4vn&2U_ z3`{VwYnMD;P4JC`!g?ht+m0K-WV5qVbJq^Uhnt%lu8lmTtS<8U?}XDb{aY`cVWFd= z12YqdmL6Amc{$jn7cCo~lmt3?<&v4l!zbFB@GNJxv^0>gm=c#`lPOdl}XwXqnQL(YH_Q~z@Z{EBKle>h^F+{?D7Z=vJlshC3 zE+LOL@sJ+;>H9+>>!<#sm@$>gpc`h&Y~=`!jErz-u@65#?!HsCmT&dfYWsYE(AIVQ m>>$kW9rfQ54#wH`6JT70&dg+8ksl1-fQg}{LB%zX$bSHso!Nx| literal 0 HcmV?d00001 diff --git a/_p_s5_trigger_8h_source.html b/_p_s5_trigger_8h_source.html new file mode 100644 index 00000000..54c60998 --- /dev/null +++ b/_p_s5_trigger_8h_source.html @@ -0,0 +1,82 @@ + + + + + + + +USB Host Shield 2.0: PS5Trigger.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
USB Host Shield 2.0 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
PS5Trigger.h
+
+
+Go to the documentation of this file.
1 
33 #ifndef _ps5trigger_h_
34 #define _ps5trigger_h_
35 
36 #include <inttypes.h>
37 
38 class PS5Trigger {
39 private:
40  // Type of trigger effect
41  typedef enum _EffectType : uint8_t {
42  NoResitance = 0x00, // No resistance is applied
43  ContinuousResitance = 0x01, // Continuous Resitance is applied
44  SectionResitance = 0x02, // Seciton resistance is appleyed
45  EffectEx = 0x26, // Extended trigger effect
46  Calibrate = 0xFC, // Calibrate triggers
47  } EffectType;
48 
49  // Trigger effect
50  typedef struct _EffectData {
51  // Trigger effect type
52  EffectType effectType;
53 
54  // Union for effect parameters
55  union {
56  // Union one raw data
57  uint8_t _u1_raw[6];
58 
59  // For type == ContinuousResitance
60  struct {
61  uint8_t startPosition; // Start position of resistance
62  uint8_t force; // Force of resistance
63  uint8_t _pad[4]; // PAD / UNUSED
64  } __attribute__((packed)) Continuous;
65 
66  // For type == SectionResitance
67  struct {
68  uint8_t startPosition; // Start position of resistance
69  uint8_t endPosition; // End position of resistance (>= start)
70  uint8_t _pad[4]; // PAD / UNUSED
71  } __attribute__((packed)) Section;
72 
73  // For type == EffectEx
74  struct {
75  uint8_t startPosition; // Position at witch the effect starts
76  bool keepEffect; // Wher the effect should keep playing when trigger goes beyond 255
77  uint8_t beginForce; // Force applied when trigger >= (255 / 2)
78  uint8_t middleForce; // Force applied when trigger <= (255 / 2)
79  uint8_t endForce; // Force applied when trigger is beyond 255
80  uint8_t frequency; // Vibration frequency of the trigger
81  } __attribute__((packed)) EffectEx;
82  } __attribute__((packed));
83  } __attribute__((packed)) EffectData;
84 
85  EffectData data;
86 
87 public:
88  bool reportChanged = false;
89 
95  void processTrigger(uint8_t* buffer);
96 
100  void Reset() {
101  data.effectType = EffectType::NoResitance;
102 
103  reportChanged = false;
104  };
105 
110  data.effectType = EffectType::NoResitance;
111 
112  reportChanged = true;
113  };
114 
120  void setTriggerForce(uint8_t start, uint8_t force) {
121  if (force == 0)
122  data.effectType = EffectType::NoResitance;
123  else {
124  data.effectType = EffectType::ContinuousResitance;
125  data.Continuous.startPosition = start;
126  data.Continuous.force = force;
127  }
128 
129  reportChanged = true;
130  };
131 
137  void setTriggerForceSection(uint8_t start, uint8_t end) {
138  data.effectType = EffectType::SectionResitance;
139  data.Section.startPosition = start;
140  data.Section.endPosition = end;
141 
142  reportChanged = true;
143  };
144 
154  void setTriggerForceEffect(uint8_t start, bool keep, uint8_t begin_force, uint8_t mid_force, uint8_t end_force, uint8_t frequency) {
155  data.effectType = EffectType::SectionResitance;
156  data.EffectEx.startPosition = start;
157  data.EffectEx.keepEffect = keep;
158  data.EffectEx.beginForce = begin_force;
159  data.EffectEx.middleForce = mid_force;
160  data.EffectEx.endForce = end_force;
161  data.EffectEx.frequency = frequency;
162 
163  reportChanged = true;
164  };
165 
166 };
167 
168 #endif
void clearTriggerForce()
Definition: PS5Trigger.h:109
+
void setTriggerForceEffect(uint8_t start, bool keep, uint8_t begin_force, uint8_t mid_force, uint8_t end_force, uint8_t frequency)
Definition: PS5Trigger.h:154
+
bool reportChanged
Definition: PS5Trigger.h:88
+ +
void processTrigger(uint8_t *buffer)
Apply the trigger data to a PS5 update buffer.
Definition: PS5Trigger.cpp:34
+
void Reset()
Definition: PS5Trigger.h:100
+
void setTriggerForceSection(uint8_t start, uint8_t end)
Definition: PS5Trigger.h:137
+
void setTriggerForce(uint8_t start, uint8_t force)
Definition: PS5Trigger.h:120
+
+ + + + diff --git a/_p_s5_u_s_b_8h.html b/_p_s5_u_s_b_8h.html new file mode 100644 index 00000000..7fee2703 --- /dev/null +++ b/_p_s5_u_s_b_8h.html @@ -0,0 +1,142 @@ + + + + + + + +USB Host Shield 2.0: PS5USB.h File Reference + + + + + + + + + + +
+
+ + + + + + +
+
USB Host Shield 2.0 +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
PS5USB.h File Reference
+
+
+
#include "hiduniversal.h"
+#include "PS5Parser.h"
+
+Include dependency graph for PS5USB.h:
+
+
+ + + + + + + + + + +
+
+

Go to the source code of this file.

+ + + + +

+Classes

class  PS5USB
 
+ + + + + +

+Macros

#define PS5_VID   0x054C
 
#define PS5_PID   0x0CE6
 
+

Macro Definition Documentation

+ +

◆ PS5_VID

+ +
+
+ + + + +
#define PS5_VID   0x054C
+
+ +

Definition at line 27 of file PS5USB.h.

+ +
+
+ +

◆ PS5_PID

+ +
+
+ + + + +
#define PS5_PID   0x0CE6
+
+ +

Definition at line 28 of file PS5USB.h.

+ +
+
+
+ + + + diff --git a/_p_s5_u_s_b_8h__incl.map b/_p_s5_u_s_b_8h__incl.map new file mode 100644 index 00000000..bf9d475f --- /dev/null +++ b/_p_s5_u_s_b_8h__incl.map @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/_p_s5_u_s_b_8h__incl.md5 b/_p_s5_u_s_b_8h__incl.md5 new file mode 100644 index 00000000..fe18e879 --- /dev/null +++ b/_p_s5_u_s_b_8h__incl.md5 @@ -0,0 +1 @@ +3be065c8ceb7b72bb0cc17dc2e48f08f \ No newline at end of file diff --git a/_p_s5_u_s_b_8h__incl.png b/_p_s5_u_s_b_8h__incl.png new file mode 100644 index 0000000000000000000000000000000000000000..11e3ef3f1c1f3208a7420b629775336fb5796fb7 GIT binary patch literal 25117 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 literal 0 HcmV?d00001 diff --git a/_p_s5_u_s_b_8h_source.html b/_p_s5_u_s_b_8h_source.html new file mode 100644 index 00000000..804a3faf --- /dev/null +++ b/_p_s5_u_s_b_8h_source.html @@ -0,0 +1,116 @@ + + + + + + + +USB Host Shield 2.0: PS5USB.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
USB Host Shield 2.0 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
PS5USB.h
+
+
+Go to the documentation of this file.
1 /* Copyright (C) 2021 Kristian Sloth Lauszus. All rights reserved.
2 
3  This software may be distributed and modified under the terms of the GNU
4  General Public License version 2 (GPL2) as published by the Free Software
5  Foundation and appearing in the file GPL2.TXT included in the packaging of
6  this file. Please note that GPL2 Section 2[b] requires that all works based
7  on this software must also be made publicly available under the terms of
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Sloth Lauszus
14  Web : https://lauszus.com
15  e-mail : lauszus@gmail.com
16 
17  Thanks to Joseph Duchesne for the initial port. Data structure mapping partially based
18  on values from Ludwig Füchsl's https://github.com/Ohjurot/DualSense-Windows
19  */
20 
21 #ifndef _ps5usb_h_
22 #define _ps5usb_h_
23 
24 #include "hiduniversal.h"
25 #include "PS5Parser.h"
26 
27 #define PS5_VID 0x054C // Sony Corporation
28 #define PS5_PID 0x0CE6 // PS5 Controller
29 
34 class PS5USB : public HIDUniversal, public PS5Parser {
35 public:
40  PS5USB(USB *p) :
41  HIDUniversal(p) {
43  };
44 
49  bool connected() {
51  };
52 
57  void attachOnInit(void (*funcOnInit)(void)) {
58  pFuncOnInit = funcOnInit;
59  };
60 
61 protected:
70  virtual void ParseHIDData(USBHID *hid __attribute__((unused)), bool is_rpt_id __attribute__((unused)), uint8_t len, uint8_t *buf) {
72  PS5Parser::Parse(len, buf);
73  };
74 
80  virtual uint8_t OnInitSuccessful() {
83  if (pFuncOnInit)
84  pFuncOnInit(); // Call the user function
85  else
86  setLed(Red); // Set the LED to red, so it is consistent with the PS5BT driver
87  };
88  return 0;
89  };
93  virtual void sendOutputReport(PS5Output *output) { // Source: https://github.com/chrippa/ds4drv
94  // PS4 Source: https://github.com/chrippa/ds4drv
95  // PS5 values from https://www.reddit.com/r/gamedev/comments/jumvi5/dualsense_haptics_leds_and_more_hid_output_report/,
96  // Ludwig Füchsl's https://github.com/Ohjurot/DualSense-Windows and
97  // the series of patches found here: https://patchwork.kernel.org/project/linux-input/cover/20201219062336.72568-1-roderick@gaikai.com/
98  uint8_t buf[1 /* report id */ + 47 /* common */];
99  memset(buf, 0, sizeof(buf));
100 
101  buf[0x00] = 0x02; // Report ID
102 
103  buf[0x01] = 0xFF; // feature flags 1
104  buf[0x02]= 0xF7; // feature flags 2
105 
106  buf[0x03] = output->smallRumble; // Small Rumble
107  buf[0x04] = output->bigRumble; // Big rumble
108 
109  // 5-7 headphone, speaker, mic volume, audio flags
110 
111  buf[0x09] = (uint8_t)output->microphoneLed;
112 
113  // 0x0A mute flags
114 
115  // Adaptive Triggers: 0x0B-0x14 right, 0x15 unknown, 0x16-0x1F left
116  rightTrigger.processTrigger(&buf[0x0B]); // right
117  leftTrigger.processTrigger(&buf[0x16]); // left
118 
119  // 0x20-0x24 unknown
120  // 0x25 trigger motor effect strengths
121  // 0x26 speaker volume
122 
123  // player LEDs
124  buf[0x27] = 0x03; // led brightness, pulse
125  buf[0x2A] = output->disableLeds ? 0x01 : 0x2; // led pulse option
126  // buf[0x2B] LED brightness, 0 = full, 1= medium, 2 = low
127  buf[0x2C] = output->playerLeds; // 5 white player LEDs
128 
129  // lightbar
130  buf[0x2D] = output->r; // Red
131  buf[0x2E] = output->g; // Green
132  buf[0x2F] = output->b; // Blue
133 
134  output->reportChanged = false;
135 
136  // There is no need to calculate a crc32 when the controller is connected via USB
137 
138  pUsb->outTransfer(bAddress, epInfo[ hidInterfaces[0].epIndex[epInterruptOutIndex] ].epAddr, sizeof(buf), buf);
139  };
149  virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) {
150  return (vid == PS5_VID && pid == PS5_PID);
151  };
154 private:
155  void (*pFuncOnInit)(void); // Pointer to function called in onInit()
156 };
157 #endif
+
Definition: usbhid.h:143
+
virtual void ParseHIDData(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)
Definition: PS5USB.h:70
+
USB * pUsb
Definition: usbhid.h:145
+
bool reportChanged
Definition: PS5Parser.h:145
+
uint8_t disableLeds
Definition: PS5Parser.h:142
+
uint8_t playerLeds
Definition: PS5Parser.h:143
+ +
virtual bool isReady()
Definition: hidcomposite.h:99
+
HIDInterface hidInterfaces[maxHidInterfaces]
Definition: hidcomposite.h:64
+
EpInfo epInfo[totalEndpoints]
Definition: hidcomposite.h:63
+
virtual uint8_t OnInitSuccessful()
Definition: PS5USB.h:80
+
uint8_t r
Definition: PS5Parser.h:144
+ +
virtual bool VIDPIDOK(uint16_t vid, uint16_t pid)
Definition: PS5USB.h:149
+
PS5USB(USB *p)
Definition: PS5USB.h:40
+
void Parse(uint8_t len, uint8_t *buf)
Definition: PS5Parser.cpp:80
+
void attachOnInit(void(*funcOnInit)(void))
Definition: PS5USB.h:57
+
PS5Trigger leftTrigger
Definition: PS5Parser.h:154
+
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data)
Definition: Usb.cpp:303
+
static const uint8_t epInterruptOutIndex
Definition: usbhid.h:150
+
uint8_t bAddress
Definition: usbhid.h:146
+
PS5Trigger rightTrigger
Definition: PS5Parser.h:154
+
uint16_t PID
Definition: hidcomposite.h:71
+
Definition: PS5USB.h:34
+ +
uint8_t microphoneLed
Definition: PS5Parser.h:141
+
uint16_t VID
Definition: hidcomposite.h:71
+
#define PS5_PID
Definition: PS5USB.h:28
+
uint8_t bigRumble
Definition: PS5Parser.h:140
+
void setLed(uint8_t r, uint8_t g, uint8_t b)
Definition: PS5Parser.h:339
+
uint8_t b
Definition: PS5Parser.h:144
+
bool connected()
Definition: PS5USB.h:49
+
void processTrigger(uint8_t *buffer)
Apply the trigger data to a PS5 update buffer.
Definition: PS5Trigger.cpp:34
+
Definition: UsbCore.h:210
+
uint8_t smallRumble
Definition: PS5Parser.h:140
+ +
uint8_t g
Definition: PS5Parser.h:144
+
void Reset()
Definition: PS5Parser.cpp:140
+
#define PS5_VID
Definition: PS5USB.h:27
+
virtual void sendOutputReport(PS5Output *output)
Definition: PS5USB.h:93
+ +
+ + + + diff --git a/_p_s_buzz_8h_source.html b/_p_s_buzz_8h_source.html index 4761be98..7bbcda36 100644 --- a/_p_s_buzz_8h_source.html +++ b/_p_s_buzz_8h_source.html @@ -63,9 +63,8 @@ $(function() {
PSBuzz.h
-Go to the documentation of this file.
1 /* Copyright (C) 2014 Kristian Lauszus, TKJ Electronics. All rights reserved.
2 
3  This software may be distributed and modified under the terms of the GNU
4  General Public License version 2 (GPL2) as published by the Free Software
5  Foundation and appearing in the file GPL2.TXT included in the packaging of
6  this file. Please note that GPL2 Section 2[b] requires that all works based
7  on this software must also be made publicly available under the terms of
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Lauszus, TKJ Electronics
14  Web : http://www.tkjelectronics.com
15  e-mail : kristianl@tkjelectronics.com
16  */
17 
18 #ifndef _psbuzz_h_
19 #define _psbuzz_h_
20 
21 #include "hiduniversal.h"
22 #include "controllerEnums.h"
23 
24 #define PSBUZZ_VID 0x054C // Sony Corporation
25 #define PSBUZZ_PID 0x1000 // PS Buzz Controller
26 
29  struct {
30  uint8_t red : 1;
31  uint8_t yellow : 1;
32  uint8_t green : 1;
33  uint8_t orange : 1;
34  uint8_t blue : 1;
35  } __attribute__((packed)) btn[4];
36  uint32_t val : 20;
37 } __attribute__((packed));
38 
43 class PSBuzz : public HIDUniversal {
44 public:
49  PSBuzz(USB *p) :
50  HIDUniversal(p) {
51  Reset();
52  };
53 
58  bool connected() {
60  };
61 
66  void attachOnInit(void (*funcOnInit)(void)) {
67  pFuncOnInit = funcOnInit;
68  };
69 
82  bool getButtonPress(ButtonEnum b, uint8_t controller = 0);
83  bool getButtonClick(ButtonEnum b, uint8_t controller = 0);
95  void setLedRaw(bool value, uint8_t controller = 0);
96 
98  void setLedOffAll() {
99  for (uint8_t i = 1; i < 4; i++) // Skip first as it will be set in setLedRaw
100  ledState[i] = false; // Just an easy way to set all four off at the same time
101  setLedRaw(false); // Turn the LED off, on all four controllers
102  };
103 
108  void setLedOff(uint8_t controller = 0) {
109  setLedRaw(false, controller);
110  };
111 
112 
114  void setLedOnAll() {
115  for (uint8_t i = 1; i < 4; i++) // Skip first as it will be set in setLedRaw
116  ledState[i] = true; // Just an easy way to set all four off at the same time
117  setLedRaw(true); // Turn the LED on, on all four controllers
118  };
119 
124  void setLedOn(uint8_t controller = 0) {
125  setLedRaw(true, controller);
126  };
127 
132  void setLedToggle(uint8_t controller = 0) {
133  setLedRaw(!ledState[controller], controller);
134  };
137 protected:
146  void ParseHIDData(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
147 
153  uint8_t OnInitSuccessful();
157  void Reset() {
158  psbuzzButtons.val = 0;
159  oldButtonState.val = 0;
160  buttonClickState.val = 0;
161  for (uint8_t i = 0; i < sizeof(ledState); i++)
162  ledState[i] = 0;
163  };
164 
172  virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) {
173  return (vid == PSBUZZ_VID && pid == PSBUZZ_PID);
174  };
177 private:
178  void (*pFuncOnInit)(void); // Pointer to function called in onInit()
179 
180  void PSBuzz_Command(uint8_t *data, uint16_t nbytes);
181 
182  PSBUZZButtons psbuzzButtons, oldButtonState, buttonClickState;
183  bool ledState[4];
184 };
185 #endif
Definition: usbhid.h:143
+Go to the documentation of this file.
1 /* Copyright (C) 2014 Kristian Lauszus, TKJ Electronics. All rights reserved.
2 
3  This software may be distributed and modified under the terms of the GNU
4  General Public License version 2 (GPL2) as published by the Free Software
5  Foundation and appearing in the file GPL2.TXT included in the packaging of
6  this file. Please note that GPL2 Section 2[b] requires that all works based
7  on this software must also be made publicly available under the terms of
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Lauszus, TKJ Electronics
14  Web : http://www.tkjelectronics.com
15  e-mail : kristianl@tkjelectronics.com
16  */
17 
18 #ifndef _psbuzz_h_
19 #define _psbuzz_h_
20 
21 #include "hiduniversal.h"
22 #include "controllerEnums.h"
23 
24 #define PSBUZZ_VID 0x054C // Sony Corporation
25 #define PSBUZZ_PID 0x1000 // PS Buzz Controller
26 
29  struct {
30  uint8_t red : 1;
31  uint8_t yellow : 1;
32  uint8_t green : 1;
33  uint8_t orange : 1;
34  uint8_t blue : 1;
35  } __attribute__((packed)) btn[4];
36  uint32_t val : 20;
37 } __attribute__((packed));
38 
43 class PSBuzz : public HIDUniversal {
44 public:
49  PSBuzz(USB *p) :
50  HIDUniversal(p) {
51  Reset();
52  };
53 
58  bool connected() {
60  };
61 
66  void attachOnInit(void (*funcOnInit)(void)) {
67  pFuncOnInit = funcOnInit;
68  };
69 
82  bool getButtonPress(ButtonEnum b, uint8_t controller = 0);
83  bool getButtonClick(ButtonEnum b, uint8_t controller = 0);
95  void setLedRaw(bool value, uint8_t controller = 0);
96 
98  void setLedOffAll() {
99  for (uint8_t i = 1; i < 4; i++) // Skip first as it will be set in setLedRaw
100  ledState[i] = false; // Just an easy way to set all four off at the same time
101  setLedRaw(false); // Turn the LED off, on all four controllers
102  };
103 
108  void setLedOff(uint8_t controller = 0) {
109  setLedRaw(false, controller);
110  };
111 
112 
114  void setLedOnAll() {
115  for (uint8_t i = 1; i < 4; i++) // Skip first as it will be set in setLedRaw
116  ledState[i] = true; // Just an easy way to set all four off at the same time
117  setLedRaw(true); // Turn the LED on, on all four controllers
118  };
119 
124  void setLedOn(uint8_t controller = 0) {
125  setLedRaw(true, controller);
126  };
127 
132  void setLedToggle(uint8_t controller = 0) {
133  setLedRaw(!ledState[controller], controller);
134  };
137 protected:
146  void ParseHIDData(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
147 
153  uint8_t OnInitSuccessful();
157  void Reset() {
158  psbuzzButtons.val = 0;
159  oldButtonState.val = 0;
160  buttonClickState.val = 0;
161  for (uint8_t i = 0; i < sizeof(ledState); i++)
162  ledState[i] = 0;
163  };
164 
172  virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) {
173  return (vid == PSBUZZ_VID && pid == PSBUZZ_PID);
174  };
177 private:
178  void (*pFuncOnInit)(void); // Pointer to function called in onInit()
179 
180  void PSBuzz_Command(uint8_t *data, uint16_t nbytes);
181 
182  PSBUZZButtons psbuzzButtons, oldButtonState, buttonClickState;
183  bool ledState[4];
184 };
185 #endif
Definition: usbhid.h:143
uint8_t red
Definition: PSBuzz.h:30
-
struct PSBUZZButtons::@29 btn[4]
void setLedToggle(uint8_t controller=0)
Definition: PSBuzz.h:132
void attachOnInit(void(*funcOnInit)(void))
Definition: PSBuzz.h:66
void Reset()
Definition: PSBuzz.h:157
@@ -86,6 +85,7 @@ $(function() {
uint16_t VID
Definition: hidcomposite.h:71
PSBuzz(USB *p)
Definition: PSBuzz.h:49
+
struct PSBUZZButtons::@39 btn[4]
void setLedOnAll()
Definition: PSBuzz.h:114
Definition: UsbCore.h:210
void setLedOn(uint8_t controller=0)
Definition: PSBuzz.h:124
diff --git a/_r_e_a_d_m_e_8md_source.html b/_r_e_a_d_m_e_8md_source.html index 8518808d..bf006baf 100644 --- a/_r_e_a_d_m_e_8md_source.html +++ b/_r_e_a_d_m_e_8md_source.html @@ -63,7 +63,7 @@ $(function() {
README.md
-Go to the documentation of this file.
1 # USB Host Library Rev. 2.0
2 
3 The code is released under the GNU General Public License.
4 __________
5 [![](https://github.com/felis/USB_Host_Shield_2.0/workflows/CI/badge.svg)](https://github.com/felis/USB_Host_Shield_2.0/actions?query=branch%3Amaster)
6 
7 # Summary
8 This is Revision 2.0 of MAX3421E-based USB Host Shield Library for AVR's.
9 
10 Project main web site is: <https://chome.nerpa.tech/arduino_usb_host_shield_projects/>.
11 
12 Some information can also be found at: <http://blog.tkjelectronics.dk/>.
13 
14 The shield can be purchased from [TKJ Electronics](http://tkjelectronics.com/): <http://shop.tkjelectronics.dk/product_info.php?products_id=43>.
15 
16 ![USB Host Shield](http://shop.tkjelectronics.dk/images/USB_Host_Shield1.jpg)
17 
18 For more information about the hardware see the [Hardware Manual](https://chome.nerpa.tech/usb-host-shield-hardware-manual/).
19 
20 # Developed By
21 
22 * __Oleg Mazurov__ - <mazurov@gmail.com>
23 * __Alexei Glushchenko__ - <alex-gl@mail.ru>
24  * Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries
25 * __Kristian Sloth Lauszus__ - <lauszus@gmail.com>
26  * Developer of the [BTD](#bluetooth-libraries), [BTHID](#bthid-library), [SPP](#spp-library), [PS4](#ps4-library), [PS3](#ps3-library), [Wii](#wii-library), [Xbox](#xbox-library), and [PSBuzz](#ps-buzz-library) libraries
27 * __Andrew Kroll__ - <xxxajk@gmail.com>
28  * Major contributor to mass storage code
29 * __guruthree__
30  * [Xbox ONE](#xbox-one-library) controller support
31 * __Yuuichi Akagawa__ - [\@YuuichiAkagawa](https://twitter.com/yuuichiakagawa)
32  * Developer of the [MIDI](#midi-library) library
33 
34 
35 # Table of Contents
36 
37 * [How to include the library](#how-to-include-the-library)
38  * [Arduino Library Manager](#arduino-library-manager)
39  * [Manual installation](#manual-installation)
40 * [How to use the library](#how-to-use-the-library)
41  * [Documentation](#documentation)
42  * [Enable debugging](#enable-debugging)
43  * [Boards](#boards)
44  * [Bluetooth libraries](#bluetooth-libraries)
45  * [BTHID library](#bthid-library)
46  * [SPP library](#spp-library)
47  * [PS4 Library](#ps4-library)
48  * [PS3 Library](#ps3-library)
49  * [Xbox Libraries](#xbox-libraries)
50  * [Xbox library](#xbox-library)
51  * [Xbox 360 Library](#xbox-360-library)
52  * [Xbox ONE Library](#xbox-one-library)
53  * [Xbox ONE S Library](#xbox-one-s-library)
54  * [Wii library](#wii-library)
55  * [PS Buzz Library](#ps-buzz-library)
56  * [HID Libraries](#hid-libraries)
57  * [MIDI Library](#midi-library)
58 * [Interface modifications](#interface-modifications)
59 * [FAQ](#faq)
60 
61 # How to include the library
62 
63 ### Arduino Library Manager
64 
65 First install Arduino IDE version 1.6.2 or newer, then simply use the Arduino Library Manager to install the library.
66 
67 Please see the following page for instructions: <http://www.arduino.cc/en/Guide/Libraries#toc3>.
68 
69 ### Manual installation
70 
71 First download the library by clicking on the following link: <https://github.com/felis/USB_Host_Shield_2.0/archive/master.zip>.
72 
73 Then uncompress the zip folder and rename the directory to "USB\_Host\_Shield\_20", as any special characters are not supported by the Arduino IDE.
74 
75 Now open up the Arduino IDE and open "File>Preferences". There you will see the location of your sketchbook. Open that directory and create a directory called "libraries" inside that directory.
76 Now move the "USB\_Host\_Shield\_20" directory to the "libraries" directory.
77 
78 The final structure should look like this:
79 
80 * Arduino/
81  * libraries/
82  * USB\_Host\_Shield\_20/
83 
84 Now quit the Arduino IDE and reopen it.
85 
86 Now you should be able to go open all the examples codes by navigating to "File>Examples>USB\_Host\_Shield\_20" and then select the example you will like to open.
87 
88 For more information visit the following sites: <http://arduino.cc/en/Guide/Libraries> and <https://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use>.
89 
90 # How to use the library
91 
92 ### Documentation
93 
94 Documentation for the library can be found at the following link: <https://felis.github.io/USB_Host_Shield_2.0/>.
95 
96 ### Enable debugging
97 
98 By default serial debugging is disabled. To turn it on simply change ```ENABLE_UHS_DEBUGGING``` to 1 in [settings.h](settings.h) like so:
99 
100 ```C++
101 #define ENABLE_UHS_DEBUGGING 1
102 ```
103 
104 ### Boards
105 
106 Currently the following boards are supported by the library:
107 
108 * All official Arduino AVR boards (Uno, Duemilanove, Mega, Mega 2560, Mega ADK, Leonardo etc.)
109 * Arduino Due, Intel Galileo, Intel Galileo 2, and Intel Edison
110  * Note that the Intel Galileo uses pin 2 and 3 as INT and SS pin respectively by default, so some modifications to the shield are needed. See the "Interface modifications" section in the [hardware manual](https://chome.nerpa.tech/usb-host-shield-hardware-manual) for more information.
111  * Note native USB host is not supported on any of these platforms. You will have to use the shield for now.
112 * Teensy (Teensy++ 1.0, Teensy 2.0, Teensy++ 2.0, Teensy 3.x, Teensy LC and Teensy 4.x)
113  * Note if you are using the Teensy 3.x you should download this SPI library as well: <https://github.com/xxxajk/spi4teensy3>. You should then add ```#include <spi4teensy3.h>``` to your .ino file.
114 * Balanduino
115 * Sanguino
116 * Black Widdow
117 * RedBearLab nRF51822
118 * Digilent chipKIT
119  * Please see: <https://chome.nerpa.tech/mcu/usb/running-usb-host-code-on-digilent-chipkit-board>.
120 * STM32F4
121  * Currently the [NUCLEO-F446RE](http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF262063) is supported featuring the STM32F446. Take a look at the following example code: <https://github.com/Lauszus/Nucleo_F446RE_USBHost>.
122 * ESP8266 is supported using the [ESP8266 Arduino core](https://github.com/esp8266/Arduino)
123  * Note it uses pin 15 and 5 for SS and INT respectively
124  * Also please be aware that:
125  * GPIO16 is **NOT** usable, as it will be used for some other purposes. For example, reset the SoC itself from sleep mode.
126  * GPIO6 to 11 is also **NOT** usable, as they are used to connect SPI flash chip and it is used for storing the executable binary content.
127 * ESP32 is supported using the [arduino-esp32](https://github.com/espressif/arduino-esp32/)
128  * GPIO5 : SS, GPIO17 : INT, GPIO18 : SCK, GPIO19 : MISO, GPIO23 : MOSI
129 
130 The following boards need to be activated manually in [settings.h](settings.h):
131 
132 * Arduino Mega ADK
133  * If you are using Arduino 1.5.5 or newer there is no need to activate the Arduino Mega ADK manually
134 * Black Widdow
135 
136 Simply set the corresponding value to 1 instead of 0.
137 
138 ### [Bluetooth libraries](BTD.cpp)
139 
140 The [BTD library](BTD.cpp) is a general purpose library for an ordinary Bluetooth dongle.
141 This library make it easy to add support for different Bluetooth services like a PS3 or a Wii controller or SPP which is a virtual serial port via Bluetooth.
142 Some different examples can be found in the [example directory](examples/Bluetooth).
143 
144 The BTD library also makes it possible to use multiple services at once, the following example sketch is an example of this:
145 [PS3SPP.ino](examples/Bluetooth/PS3SPP/PS3SPP.ino).
146 
147 ### [BTHID library](BTHID.cpp)
148 
149 The [Bluetooth HID library](BTHID.cpp) allows you to connect HID devices via Bluetooth to the USB Host Shield.
150 
151 Currently HID mice and keyboards are supported.
152 
153 It uses the standard Boot protocol by default, but it is also able to use the Report protocol as well. You would simply have to call ```setProtocolMode()``` and then parse ```HID_RPT_PROTOCOL``` as an argument. You will then have to modify the parser for your device. See the example: [BTHID.ino](examples/Bluetooth/BTHID/BTHID.ino) for more information.
154 
155 The [PS4 library](#ps4-library) also uses this class to handle all Bluetooth communication.
156 
157 For information see the following blog post: <http://blog.tkjelectronics.dk/2013/12/bluetooth-hid-devices-now-supported-by-the-usb-host-library/>.
158 
159 ### [SPP library](SPP.cpp)
160 
161 SPP stands for "Serial Port Profile" and is a Bluetooth protocol that implements a virtual comport which allows you to send data back and forth from your computer/phone to your Arduino via Bluetooth.
162 It has been tested successfully on Windows, Mac OS X, Linux, and Android.
163 
164 Take a look at the [SPP.ino](examples/Bluetooth/SPP/SPP.ino) example for more information.
165 
166 More information can be found at these blog posts:
167 
168 * <http://chome.nerpa.tech/mcu/bluetooth-rfcommspp-service-support-for-usb-host-2-0-library-released>
169 * <http://blog.tkjelectronics.dk/2012/07/rfcommspp-library-for-arduino/>
170 
171 To implement the SPP protocol I used a Bluetooth sniffing tool called [PacketLogger](http://www.tkjelectronics.com/uploads/PacketLogger.zip) developed by Apple.
172 It enables me to see the Bluetooth communication between my Mac and any device.
173 
174 ### PS4 Library
175 
176 The PS4BT library is split up into the [PS4BT](PS4BT.h) and the [PS4USB](PS4USB.h) library. These allow you to use the Sony PS4 controller via Bluetooth and USB.
177 
178 The [PS4BT.ino](examples/Bluetooth/PS4BT/PS4BT.ino) and [PS4USB.ino](examples/PS4USB/PS4USB.ino) examples shows how to easily read the buttons, joysticks, touchpad and IMU on the controller via Bluetooth and USB respectively. It is also possible to control the rumble and light on the controller and get the battery level.
179 
180 Before you can use the PS4 controller via Bluetooth you will need to pair with it.
181 
182 Simply create the PS4BT instance like so: ```PS4BT PS4(&Btd, PAIR);``` and then hold down the Share button and then hold down the PS without releasing the Share button. The PS4 controller will then start to blink rapidly indicating that it is in pairing mode.
183 
184 It should then automatically pair the dongle with your controller. This only have to be done once.
185 
186 For information see the following blog post: <http://blog.tkjelectronics.dk/2014/01/ps4-controller-now-supported-by-the-usb-host-library/>.
187 
188 Also check out this excellent Wiki by Frank Zhao about the PS4 controller: <http://eleccelerator.com/wiki/index.php?title=DualShock_4> and this Linux driver: <https://github.com/chrippa/ds4drv>.
189 
190 Several guides on how to use the PS4 library has been written by Dr. James E. Barger and are available at the following link: <https://sites.google.com/view/crosswaystation/ps4-tutorials>.
191 
192 ### PS3 Library
193 
194 These libraries consist of the [PS3BT](PS3BT.cpp) and [PS3USB](PS3USB.cpp). These libraries allows you to use a Dualshock 3, Navigation or a Motion controller with the USB Host Shield both via Bluetooth and USB.
195 
196 In order to use your Playstation controller via Bluetooth you have to set the Bluetooth address of the dongle internally to your PS3 Controller. This can be achieved by first plugging in the Bluetooth dongle and wait a few seconds. Now plug in the controller via USB and wait until the LEDs start to flash. The library has now written the Bluetooth address of the dongle to the PS3 controller.
197 
198 Finally simply plug in the Bluetooth dongle again and press PS on the PS3 controller. After a few seconds it should be connected to the dongle and ready to use.
199 
200 __Note:__ You will have to plug in the Bluetooth dongle before connecting the controller, as the library needs to read the address of the dongle. Alternatively you could set it in code like so: [PS3BT.ino#L20](examples/Bluetooth/PS3BT/PS3BT.ino#L20).
201 
202 For more information about the PS3 protocol see the official wiki: <https://github.com/felis/USB_Host_Shield_2.0/wiki/PS3-Information>.
203 
204 Also take a look at the blog posts:
205 
206 * <http://blog.tkjelectronics.dk/2012/01/ps3-controller-bt-library-for-arduino/>
207 * <http://chome.nerpa.tech/mcu/sony-ps3-controller-support-added-to-usb-host-library>
208 * <http://chome.nerpa.tech/mcu/arduino/interfacing-ps3-controllers-via-usb>
209 
210 A special thanks go to the following people:
211 
212 1. _Richard Ibbotson_ who made this excellent guide: <http://chome.nerpa.tech/mcu/ps3-and-wiimote-game-controllers-on-the-arduino-host-shield-part>
213 2. _Tomoyuki Tanaka_ for releasing his code for the Arduino USB Host shield connected to the wiimote: <http://chome.nerpa.tech/mcu/rc-car-controlled-by-wii-remote-on-arduino>
214 
215 Also a big thanks all the people behind these sites about the Motion controller:
216 
217 * <http://thp.io/2010/psmove/>
218 * <http://www.copenhagengamecollective.org/unimove/>
219 * <https://github.com/thp/psmoveapi>
220 * <http://code.google.com/p/moveonpc/>
221 
222 ### Xbox Libraries
223 
224 The library supports both the original Xbox controller via USB and the Xbox 360 controller both via USB and wirelessly.
225 
226 #### Xbox library
227 
228 The [XBOXOLD](XBOXOLD.cpp) class implements support for the original Xbox controller via USB.
229 
230 All the information are from the following sites:
231 
232 * <https://github.com/torvalds/linux/blob/master/Documentation/input/xpad.txt>
233 * <https://github.com/torvalds/linux/blob/master/drivers/input/joystick/xpad.c>
234 * <http://euc.jp/periphs/xbox-controller.ja.html>
235 * <https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL#L15>
236 
237 #### Xbox 360 Library
238 
239 The library support one Xbox 360 via USB or up to four Xbox 360 controllers wirelessly by using a [Xbox 360 wireless receiver](http://blog.tkjelectronics.dk/wp-content/uploads/xbox360-wireless-receiver.jpg).
240 
241 To use it via USB use the [XBOXUSB](XBOXUSB.cpp) library or to use it wirelessly use the [XBOXRECV](XBOXRECV.cpp) library.
242 
243 __Note that a Wireless controller can NOT be used via USB!__
244 
245 Examples code can be found in the [examples directory](examples/Xbox).
246 
247 Also see the following blog posts:
248 
249 * <http://chome.nerpa.tech/mcu/xbox360-controller-support-added-to-usb-host-shield-2-0-library>
250 * <http://blog.tkjelectronics.dk/2012/07/xbox-360-controller-support-added-to-the-usb-host-library/>
251 * <http://blog.tkjelectronics.dk/2012/12/xbox-360-receiver-added-to-the-usb-host-library/>
252 
253 All the information regarding the Xbox 360 controller protocol are form these sites:
254 
255 * <http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/UsbInfo>
256 * <http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/WirelessUsbInfo>
257 * <https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL>
258 
259 #### Xbox ONE Library
260 
261 A Xbox ONE controller is supported via USB in the [XBOXONE](XBOXONE.cpp) class. It is heavily based on the 360 library above. In addition to cross referencing the above, information on the protocol was found at:
262 
263 * <https://github.com/quantus/xbox-one-controller-protocol>
264 * <https://github.com/torvalds/linux/blob/master/drivers/input/joystick/xpad.c>
265 * <https://github.com/kylelemons/xbox/blob/master/xbox.go>
266 
267 #### Xbox ONE S Library
268 
269 A Xbox ONE controller is supported via Bluetooth in the [XBOXONESBT](XBOXONESBT.cpp) class.
270 
271 Special thanks to [HisashiKato](https://github.com/HisashiKato) for his help: <https://github.com/felis/USB_Host_Shield_2.0/issues/252#issuecomment-716912362>.
272 
273 ### [Wii library](Wii.cpp)
274 
275 The [Wii](Wii.cpp) library support the Wiimote, but also the Nunchuch and Motion Plus extensions via Bluetooth. The Wii U Pro Controller and Wii Balance Board are also supported via Bluetooth.
276 
277 First you have to pair with the controller, this is done automatically by the library if you create the instance like so:
278 
279 ```C++
280 WII Wii(&Btd, PAIR);
281 ```
282 
283 And then press 1 & 2 at once on the Wiimote or the SYNC buttons if you are using a Wii U Pro Controller or a Wii Balance Board.
284 
285 After that you can simply create the instance like so:
286 
287 ```C++
288 WII Wii(&Btd);
289 ```
290 
291 Then just press any button on the Wiimote and it will then connect to the dongle.
292 
293 Take a look at the example for more information: [Wii.ino](examples/Bluetooth/Wii/Wii.ino).
294 
295 Also take a look at the blog post:
296 
297 * <http://blog.tkjelectronics.dk/2012/08/wiimote-added-to-usb-host-library/>
298 
299 The Wii IR camera can also be used, but you will have to activate the code for it manually as it is quite large. Simply set ```ENABLE_WII_IR_CAMERA``` to 1 in [settings.h](settings.h).
300 
301 The [WiiIRCamera.ino](examples/Bluetooth/WiiIRCamera/WiiIRCamera.ino) example shows how it can be used.
302 
303 All the information about the Wii controllers are from these sites:
304 
305 * <http://wiibrew.org/wiki/Wiimote>
306 * <http://wiibrew.org/wiki/Wiimote/Extension_Controllers>
307 * <http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Nunchuck>
308 * <http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Wii_Motion_Plus>
309 * <http://wiibrew.org/wiki/Wii_Balance_Board>
310 * The old library created by _Tomoyuki Tanaka_: <https://github.com/moyuchin/WiiRemote_on_Arduino> also helped a lot.
311 
312 ### [PS Buzz Library](PSBuzz.cpp)
313 
314 This library implements support for the Playstation Buzz controllers via USB.
315 
316 It is essentially just a wrapper around the [HIDUniversal](hiduniversal.cpp) which takes care of the initializing and reading of the controllers. The [PSBuzz](PSBuzz.cpp) class simply inherits this and parses the data, so it is easy for users to read the buttons and turn the big red button on the controllers on and off.
317 
318 The example [PSBuzz.ino](examples/PSBuzz/PSBuzz.ino) shows how one can do this with just a few lines of code.
319 
320 More information about the controller can be found at the following sites:
321 
322 * http://www.developerfusion.com/article/84338/making-usb-c-friendly/
323 * https://github.com/torvalds/linux/blob/master/drivers/hid/hid-sony.c
324 
325 ### HID Libraries
326 
327 HID devices are also supported by the library. However these require you to write your own driver. A few example are provided in the [examples/HID](examples/HID) directory. Including an example for the [SteelSeries SRW-S1 Steering Wheel](examples/HID/SRWS1/SRWS1.ino).
328 
329 ### [MIDI Library](usbh_midi.cpp)
330 
331 The library support MIDI devices.
332 You can convert USB MIDI keyboard to legacy serial MIDI.
333 
334 * [USB_MIDI_converter.ino](examples/USBH_MIDI/USB_MIDI_converter/USB_MIDI_converter.ino)
335 * [USB_MIDI_converter_multi.ino](examples/USBH_MIDI/USB_MIDI_converter_multi/USB_MIDI_converter_multi.ino)
336 
337 For information see the following page: <http://yuuichiakagawa.github.io/USBH_MIDI/>.
338 
339 # Interface modifications
340 
341 The shield is using SPI for communicating with the MAX3421E USB host controller. It uses the SCK, MISO and MOSI pins via the ICSP on your board.
342 
343 Note this means that it uses pin 13, 12, 11 on an Arduino Uno, so these pins can not be used for anything else than SPI communication!
344 
345 Furthermore it uses one pin as SS and one INT pin. These are by default located on pin 10 and 9 respectively. They can easily be reconfigured in case you need to use them for something else by cutting the jumper on the shield and then solder a wire from the pad to the new pin.
346 
347 After that you need modify the following entry in [UsbCore.h](UsbCore.h):
348 
349 ```C++
350 typedef MAX3421e<P10, P9> MAX3421E;
351 ```
352 
353 For instance if you have rerouted SS to pin 7 it should read:
354 
355 ```C++
356 typedef MAX3421e<P7, P9> MAX3421E;
357 ```
358 
359 See the "Interface modifications" section in the [hardware manual](https://chome.nerpa.tech/usb-host-shield-hardware-manual) for more information.
360 
361 # FAQ
362 
363 > When I plug my device into the USB connector nothing happens?
364 
365 * Try to connect a external power supply to the Arduino - this solves the problem in most cases.
366 * You can also use a powered hub between the device and the USB Host Shield. You should then include the USB hub library: ```#include <usbhub.h>``` and create the instance like so: ```USBHub Hub1(&Usb);```.
367 
368 > When I connecting my PS3 controller I get a output like this:
369 
370 ```
371 Dualshock 3 Controller Enabled
372 
373 LeftHatX: 0 LeftHatY: 0 RightHatX: 0 RightHatY: 0
374 LeftHatX: 0 LeftHatY: 0 RightHatX: 0 RightHatY: 0
375 LeftHatX: 0 LeftHatY: 0 RightHatX: 0 RightHatY: 0
376 LeftHatX: 0 LeftHatY: 0 RightHatX: 0 RightHatY: 0
377 LeftHatX: 0 LeftHatY: 0 RightHatX: 0 RightHatY: 0
378 ```
379 
380 * This means that your dongle does not support 2.0+EDR, so you will need another dongle. Please see the following [list](https://github.com/felis/USB_Host_Shield_2.0/wiki/Bluetooth-dongles) for tested working dongles.
381 
382 > When compiling I am getting the following error: "fatal error: SPI.h: No such file or directory".
383 
384 * Please make sure to include the SPI library like so: ```#include <SPI.h>``` in your .ino file.
+Go to the documentation of this file.
1 # USB Host Library Rev. 2.0
2 
3 The code is released under the GNU General Public License.
4 __________
5 [![](https://github.com/felis/USB_Host_Shield_2.0/workflows/CI/badge.svg)](https://github.com/felis/USB_Host_Shield_2.0/actions?query=branch%3Amaster)
6 
7 # Summary
8 This is Revision 2.0 of MAX3421E-based USB Host Shield Library for AVR's.
9 
10 Project main web site is: <https://chome.nerpa.tech/arduino_usb_host_shield_projects/>.
11 
12 Some information can also be found at: <http://blog.tkjelectronics.dk/>.
13 
14 The shield can be purchased from [TKJ Electronics](http://tkjelectronics.com/): <http://shop.tkjelectronics.dk/product_info.php?products_id=43>.
15 
16 ![USB Host Shield](http://shop.tkjelectronics.dk/images/USB_Host_Shield1.jpg)
17 
18 For more information about the hardware see the [Hardware Manual](https://chome.nerpa.tech/usb-host-shield-hardware-manual/).
19 
20 # Developed By
21 
22 * __Oleg Mazurov__ - <mazurov@gmail.com>
23 * __Alexei Glushchenko__ - <alex-gl@mail.ru>
24  * Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries
25 * __Kristian Sloth Lauszus__ - <lauszus@gmail.com>
26  * Developer of the [BTD](#bluetooth-libraries), [BTHID](#bthid-library), [SPP](#spp-library), [PS5](#ps5-library), [PS4](#ps4-library), [PS3](#ps3-library), [Wii](#wii-library), [Xbox](#xbox-library), and [PSBuzz](#ps-buzz-library) libraries
27 * __Andrew Kroll__ - <xxxajk@gmail.com>
28  * Major contributor to mass storage code
29 * __guruthree__
30  * [Xbox ONE](#xbox-one-library) controller support
31 * __Yuuichi Akagawa__ - [\@YuuichiAkagawa](https://twitter.com/yuuichiakagawa)
32  * Developer of the [MIDI](#midi-library) library
33 
34 
35 # Table of Contents
36 
37 * [How to include the library](#how-to-include-the-library)
38  * [Arduino Library Manager](#arduino-library-manager)
39  * [Manual installation](#manual-installation)
40 * [How to use the library](#how-to-use-the-library)
41  * [Documentation](#documentation)
42  * [Enable debugging](#enable-debugging)
43  * [Boards](#boards)
44  * [Bluetooth libraries](#bluetooth-libraries)
45  * [BTHID library](#bthid-library)
46  * [SPP library](#spp-library)
47  * [PS5 Library](#ps5-library)
48  * [PS4 Library](#ps4-library)
49  * [PS3 Library](#ps3-library)
50  * [Xbox Libraries](#xbox-libraries)
51  * [Xbox library](#xbox-library)
52  * [Xbox 360 Library](#xbox-360-library)
53  * [Xbox ONE Library](#xbox-one-library)
54  * [Xbox ONE S Library](#xbox-one-s-library)
55  * [Wii library](#wii-library)
56  * [PS Buzz Library](#ps-buzz-library)
57  * [HID Libraries](#hid-libraries)
58  * [MIDI Library](#midi-library)
59 * [Interface modifications](#interface-modifications)
60 * [FAQ](#faq)
61 
62 # How to include the library
63 
64 ### Arduino Library Manager
65 
66 First install Arduino IDE version 1.6.2 or newer, then simply use the Arduino Library Manager to install the library.
67 
68 Please see the following page for instructions: <http://www.arduino.cc/en/Guide/Libraries#toc3>.
69 
70 ### Manual installation
71 
72 First download the library by clicking on the following link: <https://github.com/felis/USB_Host_Shield_2.0/archive/master.zip>.
73 
74 Then uncompress the zip folder and rename the directory to "USB\_Host\_Shield\_20", as any special characters are not supported by the Arduino IDE.
75 
76 Now open up the Arduino IDE and open "File>Preferences". There you will see the location of your sketchbook. Open that directory and create a directory called "libraries" inside that directory.
77 Now move the "USB\_Host\_Shield\_20" directory to the "libraries" directory.
78 
79 The final structure should look like this:
80 
81 * Arduino/
82  * libraries/
83  * USB\_Host\_Shield\_20/
84 
85 Now quit the Arduino IDE and reopen it.
86 
87 Now you should be able to go open all the examples codes by navigating to "File>Examples>USB\_Host\_Shield\_20" and then select the example you will like to open.
88 
89 For more information visit the following sites: <http://arduino.cc/en/Guide/Libraries> and <https://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use>.
90 
91 # How to use the library
92 
93 ### Documentation
94 
95 Documentation for the library can be found at the following link: <https://felis.github.io/USB_Host_Shield_2.0/>.
96 
97 ### Enable debugging
98 
99 By default serial debugging is disabled. To turn it on simply change ```ENABLE_UHS_DEBUGGING``` to 1 in [settings.h](settings.h) like so:
100 
101 ```C++
102 #define ENABLE_UHS_DEBUGGING 1
103 ```
104 
105 ### Boards
106 
107 Currently the following boards are supported by the library:
108 
109 * All official Arduino AVR boards (Uno, Duemilanove, Mega, Mega 2560, Mega ADK, Leonardo etc.)
110 * Arduino Due, Intel Galileo, Intel Galileo 2, and Intel Edison
111  * Note that the Intel Galileo uses pin 2 and 3 as INT and SS pin respectively by default, so some modifications to the shield are needed. See the "Interface modifications" section in the [hardware manual](https://chome.nerpa.tech/usb-host-shield-hardware-manual) for more information.
112  * Note native USB host is not supported on any of these platforms. You will have to use the shield for now.
113 * Teensy (Teensy++ 1.0, Teensy 2.0, Teensy++ 2.0, Teensy 3.x, Teensy LC and Teensy 4.x)
114  * Note if you are using the Teensy 3.x you should download this SPI library as well: <https://github.com/xxxajk/spi4teensy3>. You should then add ```#include <spi4teensy3.h>``` to your .ino file.
115 * Balanduino
116 * Sanguino
117 * Black Widdow
118 * RedBearLab nRF51822
119 * Digilent chipKIT
120  * Please see: <https://chome.nerpa.tech/mcu/usb/running-usb-host-code-on-digilent-chipkit-board>.
121 * STM32F4
122  * Currently the [NUCLEO-F446RE](http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF262063) is supported featuring the STM32F446. Take a look at the following example code: <https://github.com/Lauszus/Nucleo_F446RE_USBHost>.
123 * ESP8266 is supported using the [ESP8266 Arduino core](https://github.com/esp8266/Arduino)
124  * Note it uses pin 15 and 5 for SS and INT respectively
125  * Also please be aware that:
126  * GPIO16 is **NOT** usable, as it will be used for some other purposes. For example, reset the SoC itself from sleep mode.
127  * GPIO6 to 11 is also **NOT** usable, as they are used to connect SPI flash chip and it is used for storing the executable binary content.
128 * ESP32 is supported using the [arduino-esp32](https://github.com/espressif/arduino-esp32/)
129  * GPIO5 : SS, GPIO17 : INT, GPIO18 : SCK, GPIO19 : MISO, GPIO23 : MOSI
130 
131 The following boards need to be activated manually in [settings.h](settings.h):
132 
133 * Arduino Mega ADK
134  * If you are using Arduino 1.5.5 or newer there is no need to activate the Arduino Mega ADK manually
135 * Black Widdow
136 
137 Simply set the corresponding value to 1 instead of 0.
138 
139 ### [Bluetooth libraries](BTD.cpp)
140 
141 The [BTD library](BTD.cpp) is a general purpose library for an ordinary Bluetooth dongle.
142 This library make it easy to add support for different Bluetooth services like a PS3 or a Wii controller or SPP which is a virtual serial port via Bluetooth.
143 Some different examples can be found in the [example directory](examples/Bluetooth).
144 
145 The BTD library also makes it possible to use multiple services at once, the following example sketch is an example of this:
146 [PS3SPP.ino](examples/Bluetooth/PS3SPP/PS3SPP.ino).
147 
148 ### [BTHID library](BTHID.cpp)
149 
150 The [Bluetooth HID library](BTHID.cpp) allows you to connect HID devices via Bluetooth to the USB Host Shield.
151 
152 Currently HID mice and keyboards are supported.
153 
154 It uses the standard Boot protocol by default, but it is also able to use the Report protocol as well. You would simply have to call ```setProtocolMode()``` and then parse ```HID_RPT_PROTOCOL``` as an argument. You will then have to modify the parser for your device. See the example: [BTHID.ino](examples/Bluetooth/BTHID/BTHID.ino) for more information.
155 
156 The [PS4 library](#ps4-library) also uses this class to handle all Bluetooth communication.
157 
158 For information see the following blog post: <http://blog.tkjelectronics.dk/2013/12/bluetooth-hid-devices-now-supported-by-the-usb-host-library/>.
159 
160 ### [SPP library](SPP.cpp)
161 
162 SPP stands for "Serial Port Profile" and is a Bluetooth protocol that implements a virtual comport which allows you to send data back and forth from your computer/phone to your Arduino via Bluetooth.
163 It has been tested successfully on Windows, Mac OS X, Linux, and Android.
164 
165 Take a look at the [SPP.ino](examples/Bluetooth/SPP/SPP.ino) example for more information.
166 
167 More information can be found at these blog posts:
168 
169 * <http://chome.nerpa.tech/mcu/bluetooth-rfcommspp-service-support-for-usb-host-2-0-library-released>
170 * <http://blog.tkjelectronics.dk/2012/07/rfcommspp-library-for-arduino/>
171 
172 To implement the SPP protocol I used a Bluetooth sniffing tool called [PacketLogger](http://www.tkjelectronics.com/uploads/PacketLogger.zip) developed by Apple.
173 It enables me to see the Bluetooth communication between my Mac and any device.
174 
175 ### PS5 Library
176 
177 The PS5 library is split up into the [PS5BT](PS5BT.h) and the [PS5USB](PS5USB.h) library. These allow you to use the Sony PS5 controller via Bluetooth and USB.
178 
179 The [PS5BT.ino](examples/Bluetooth/PS5BT/PS5BT.ino) and [PS5USB.ino](examples/PS5USB/PS5USB.ino) examples shows how to easily read the buttons, joysticks, touchpad and IMU on the controller via Bluetooth and USB respectively. It is also possible to control the rumble, lightbar, microphone LED and player LEDs on the controller. Furthermore the new haptic trigger effects are also supported.
180 
181 To pair with the PS5 controller via Bluetooth you need create the PS5BT instance like so: ```PS5BT PS5(&Btd, PAIR);``` and then hold down the Create button and then hold down the PS without releasing the Create button. The PS5 controller will then start to blink blue indicating that it is in pairing mode.
182 
183 It should then automatically pair the dongle with your controller. This only have to be done once.
184 
185 Thanks to Joseph Duchesne for the initial USB code.
186 
187 The driver is based on the official Sony driver for Linux: <https://patchwork.kernel.org/project/linux-input/cover/20201219062336.72568-1-roderick@gaikai.com/>.
188 
189 Also thanks to Ludwig Füchsl's <https://github.com/Ohjurot/DualSense-Windows> for his work on the haptic triggers.
190 
191 ### PS4 Library
192 
193 The PS4 library is split up into the [PS4BT](PS4BT.h) and the [PS4USB](PS4USB.h) library. These allow you to use the Sony PS4 controller via Bluetooth and USB.
194 
195 The [PS4BT.ino](examples/Bluetooth/PS4BT/PS4BT.ino) and [PS4USB.ino](examples/PS4USB/PS4USB.ino) examples shows how to easily read the buttons, joysticks, touchpad and IMU on the controller via Bluetooth and USB respectively. It is also possible to control the rumble and light on the controller and get the battery level.
196 
197 Before you can use the PS4 controller via Bluetooth you will need to pair with it.
198 
199 Simply create the PS4BT instance like so: ```PS4BT PS4(&Btd, PAIR);``` and then hold down the Share button and then hold down the PS without releasing the Share button. The PS4 controller will then start to blink rapidly indicating that it is in pairing mode.
200 
201 It should then automatically pair the dongle with your controller. This only have to be done once.
202 
203 For information see the following blog post: <http://blog.tkjelectronics.dk/2014/01/ps4-controller-now-supported-by-the-usb-host-library/>.
204 
205 Also check out this excellent Wiki by Frank Zhao about the PS4 controller: <http://eleccelerator.com/wiki/index.php?title=DualShock_4> and this Linux driver: <https://github.com/chrippa/ds4drv>.
206 
207 Several guides on how to use the PS4 library has been written by Dr. James E. Barger and are available at the following link: <https://sites.google.com/view/crosswaystation/ps4-tutorials>.
208 
209 ### PS3 Library
210 
211 These libraries consist of the [PS3BT](PS3BT.cpp) and [PS3USB](PS3USB.cpp). These libraries allows you to use a Dualshock 3, Navigation or a Motion controller with the USB Host Shield both via Bluetooth and USB.
212 
213 In order to use your Playstation controller via Bluetooth you have to set the Bluetooth address of the dongle internally to your PS3 Controller. This can be achieved by first plugging in the Bluetooth dongle and wait a few seconds. Now plug in the controller via USB and wait until the LEDs start to flash. The library has now written the Bluetooth address of the dongle to the PS3 controller.
214 
215 Finally simply plug in the Bluetooth dongle again and press PS on the PS3 controller. After a few seconds it should be connected to the dongle and ready to use.
216 
217 __Note:__ You will have to plug in the Bluetooth dongle before connecting the controller, as the library needs to read the address of the dongle. Alternatively you could set it in code like so: [PS3BT.ino#L20](examples/Bluetooth/PS3BT/PS3BT.ino#L20).
218 
219 For more information about the PS3 protocol see the official wiki: <https://github.com/felis/USB_Host_Shield_2.0/wiki/PS3-Information>.
220 
221 Also take a look at the blog posts:
222 
223 * <http://blog.tkjelectronics.dk/2012/01/ps3-controller-bt-library-for-arduino/>
224 * <http://chome.nerpa.tech/mcu/sony-ps3-controller-support-added-to-usb-host-library>
225 * <http://chome.nerpa.tech/mcu/arduino/interfacing-ps3-controllers-via-usb>
226 
227 A special thanks go to the following people:
228 
229 1. _Richard Ibbotson_ who made this excellent guide: <http://chome.nerpa.tech/mcu/ps3-and-wiimote-game-controllers-on-the-arduino-host-shield-part>
230 2. _Tomoyuki Tanaka_ for releasing his code for the Arduino USB Host shield connected to the wiimote: <http://chome.nerpa.tech/mcu/rc-car-controlled-by-wii-remote-on-arduino>
231 
232 Also a big thanks all the people behind these sites about the Motion controller:
233 
234 * <http://thp.io/2010/psmove/>
235 * <http://www.copenhagengamecollective.org/unimove/>
236 * <https://github.com/thp/psmoveapi>
237 * <http://code.google.com/p/moveonpc/>
238 
239 ### Xbox Libraries
240 
241 The library supports both the original Xbox controller via USB and the Xbox 360 controller both via USB and wirelessly.
242 
243 #### Xbox library
244 
245 The [XBOXOLD](XBOXOLD.cpp) class implements support for the original Xbox controller via USB.
246 
247 All the information are from the following sites:
248 
249 * <https://github.com/torvalds/linux/blob/master/Documentation/input/xpad.txt>
250 * <https://github.com/torvalds/linux/blob/master/drivers/input/joystick/xpad.c>
251 * <http://euc.jp/periphs/xbox-controller.ja.html>
252 * <https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL#L15>
253 
254 #### Xbox 360 Library
255 
256 The library support one Xbox 360 via USB or up to four Xbox 360 controllers wirelessly by using a [Xbox 360 wireless receiver](http://blog.tkjelectronics.dk/wp-content/uploads/xbox360-wireless-receiver.jpg).
257 
258 To use it via USB use the [XBOXUSB](XBOXUSB.cpp) library or to use it wirelessly use the [XBOXRECV](XBOXRECV.cpp) library.
259 
260 __Note that a Wireless controller can NOT be used via USB!__
261 
262 Examples code can be found in the [examples directory](examples/Xbox).
263 
264 Also see the following blog posts:
265 
266 * <http://chome.nerpa.tech/mcu/xbox360-controller-support-added-to-usb-host-shield-2-0-library>
267 * <http://blog.tkjelectronics.dk/2012/07/xbox-360-controller-support-added-to-the-usb-host-library/>
268 * <http://blog.tkjelectronics.dk/2012/12/xbox-360-receiver-added-to-the-usb-host-library/>
269 
270 All the information regarding the Xbox 360 controller protocol are form these sites:
271 
272 * <http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/UsbInfo>
273 * <http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/WirelessUsbInfo>
274 * <https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL>
275 
276 #### Xbox ONE Library
277 
278 A Xbox ONE controller is supported via USB in the [XBOXONE](XBOXONE.cpp) class. It is heavily based on the 360 library above. In addition to cross referencing the above, information on the protocol was found at:
279 
280 * <https://github.com/quantus/xbox-one-controller-protocol>
281 * <https://github.com/torvalds/linux/blob/master/drivers/input/joystick/xpad.c>
282 * <https://github.com/kylelemons/xbox/blob/master/xbox.go>
283 
284 #### Xbox ONE S Library
285 
286 A Xbox ONE controller is supported via Bluetooth in the [XBOXONESBT](XBOXONESBT.cpp) class.
287 
288 Special thanks to [HisashiKato](https://github.com/HisashiKato) for his help: <https://github.com/felis/USB_Host_Shield_2.0/issues/252#issuecomment-716912362>.
289 
290 ### [Wii library](Wii.cpp)
291 
292 The [Wii](Wii.cpp) library support the Wiimote, but also the Nunchuch and Motion Plus extensions via Bluetooth. The Wii U Pro Controller and Wii Balance Board are also supported via Bluetooth.
293 
294 First you have to pair with the controller, this is done automatically by the library if you create the instance like so:
295 
296 ```C++
297 WII Wii(&Btd, PAIR);
298 ```
299 
300 And then press 1 & 2 at once on the Wiimote or the SYNC buttons if you are using a Wii U Pro Controller or a Wii Balance Board.
301 
302 After that you can simply create the instance like so:
303 
304 ```C++
305 WII Wii(&Btd);
306 ```
307 
308 Then just press any button on the Wiimote and it will then connect to the dongle.
309 
310 Take a look at the example for more information: [Wii.ino](examples/Bluetooth/Wii/Wii.ino).
311 
312 Also take a look at the blog post:
313 
314 * <http://blog.tkjelectronics.dk/2012/08/wiimote-added-to-usb-host-library/>
315 
316 The Wii IR camera can also be used, but you will have to activate the code for it manually as it is quite large. Simply set ```ENABLE_WII_IR_CAMERA``` to 1 in [settings.h](settings.h).
317 
318 The [WiiIRCamera.ino](examples/Bluetooth/WiiIRCamera/WiiIRCamera.ino) example shows how it can be used.
319 
320 All the information about the Wii controllers are from these sites:
321 
322 * <http://wiibrew.org/wiki/Wiimote>
323 * <http://wiibrew.org/wiki/Wiimote/Extension_Controllers>
324 * <http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Nunchuck>
325 * <http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Wii_Motion_Plus>
326 * <http://wiibrew.org/wiki/Wii_Balance_Board>
327 * The old library created by _Tomoyuki Tanaka_: <https://github.com/moyuchin/WiiRemote_on_Arduino> also helped a lot.
328 
329 ### [PS Buzz Library](PSBuzz.cpp)
330 
331 This library implements support for the Playstation Buzz controllers via USB.
332 
333 It is essentially just a wrapper around the [HIDUniversal](hiduniversal.cpp) which takes care of the initializing and reading of the controllers. The [PSBuzz](PSBuzz.cpp) class simply inherits this and parses the data, so it is easy for users to read the buttons and turn the big red button on the controllers on and off.
334 
335 The example [PSBuzz.ino](examples/PSBuzz/PSBuzz.ino) shows how one can do this with just a few lines of code.
336 
337 More information about the controller can be found at the following sites:
338 
339 * http://www.developerfusion.com/article/84338/making-usb-c-friendly/
340 * https://github.com/torvalds/linux/blob/master/drivers/hid/hid-sony.c
341 
342 ### HID Libraries
343 
344 HID devices are also supported by the library. However these require you to write your own driver. A few example are provided in the [examples/HID](examples/HID) directory. Including an example for the [SteelSeries SRW-S1 Steering Wheel](examples/HID/SRWS1/SRWS1.ino).
345 
346 ### [MIDI Library](usbh_midi.cpp)
347 
348 The library support MIDI devices.
349 You can convert USB MIDI keyboard to legacy serial MIDI.
350 
351 * [USB_MIDI_converter.ino](examples/USBH_MIDI/USB_MIDI_converter/USB_MIDI_converter.ino)
352 * [USB_MIDI_converter_multi.ino](examples/USBH_MIDI/USB_MIDI_converter_multi/USB_MIDI_converter_multi.ino)
353 
354 For information see the following page: <http://yuuichiakagawa.github.io/USBH_MIDI/>.
355 
356 # Interface modifications
357 
358 The shield is using SPI for communicating with the MAX3421E USB host controller. It uses the SCK, MISO and MOSI pins via the ICSP on your board.
359 
360 Note this means that it uses pin 13, 12, 11 on an Arduino Uno, so these pins can not be used for anything else than SPI communication!
361 
362 Furthermore it uses one pin as SS and one INT pin. These are by default located on pin 10 and 9 respectively. They can easily be reconfigured in case you need to use them for something else by cutting the jumper on the shield and then solder a wire from the pad to the new pin.
363 
364 After that you need modify the following entry in [UsbCore.h](UsbCore.h):
365 
366 ```C++
367 typedef MAX3421e<P10, P9> MAX3421E;
368 ```
369 
370 For instance if you have rerouted SS to pin 7 it should read:
371 
372 ```C++
373 typedef MAX3421e<P7, P9> MAX3421E;
374 ```
375 
376 See the "Interface modifications" section in the [hardware manual](https://chome.nerpa.tech/usb-host-shield-hardware-manual) for more information.
377 
378 # FAQ
379 
380 > When I plug my device into the USB connector nothing happens?
381 
382 * Try to connect a external power supply to the Arduino - this solves the problem in most cases.
383 * You can also use a powered hub between the device and the USB Host Shield. You should then include the USB hub library: ```#include <usbhub.h>``` and create the instance like so: ```USBHub Hub1(&Usb);```.
384 
385 > When I connecting my PS3 controller I get a output like this:
386 
387 ```
388 Dualshock 3 Controller Enabled
389 
390 LeftHatX: 0 LeftHatY: 0 RightHatX: 0 RightHatY: 0
391 LeftHatX: 0 LeftHatY: 0 RightHatX: 0 RightHatY: 0
392 LeftHatX: 0 LeftHatY: 0 RightHatX: 0 RightHatY: 0
393 LeftHatX: 0 LeftHatY: 0 RightHatX: 0 RightHatY: 0
394 LeftHatX: 0 LeftHatY: 0 RightHatX: 0 RightHatY: 0
395 ```
396 
397 * This means that your dongle does not support 2.0+EDR, so you will need another dongle. Please see the following [list](https://github.com/felis/USB_Host_Shield_2.0/wiki/Bluetooth-dongles) for tested working dongles.
398 
399 > When compiling I am getting the following error: "fatal error: SPI.h: No such file or directory".
400 
401 * Please make sure to include the SPI library like so: ```#include <SPI.h>``` in your .ino file.