3535 *
3636 */
3737
38- //#define BTSTACK_FILE__ "hog_mouse_demo.c"
39-
40- // *****************************************************************************
41- /* EXAMPLE_START(hog_mouse_demo): HID Mouse LE
42- */
43- // *****************************************************************************
44-
4538#include <stdint.h>
4639#include <stdio.h>
4740#include <stdlib.h>
6760#include <mpu6050_i2c_lib.h>
6861#include <math.h>
6962
63+ #if !defined(i2c_default ) || !defined(PICO_DEFAULT_I2C_SDA_PIN ) || !defined(PICO_DEFAULT_I2C_SCL_PIN )
64+ #error Example requires a board with I2C pins
65+ #endif
66+
67+ #ifndef NDEBUG
68+ #define DEBUG_LOG (...) printf(__VA_ARGS__)
69+ #else
70+ #define DEBUG_LOG (...)
71+ #endif
72+ #define INFO_LOG printf
73+ #define ERROR_LOG printf
74+
7075#define ALPHA 0.05 // for complimentary filter, big alpha gives faster reponse but more noise
7176
7277// FS values are 0, 1, 2, or 3
7883// how many readings taken to find gyro offsets
7984#define OFFSET_NUM 10000
8085
81- //pins for buttons
86+ // pins for buttons
87+ #ifndef LEFT_BUTTON_GPIO_NUM
8288#define LEFT_BUTTON_GPIO_NUM 15
89+ #endif
90+
91+ #ifndef RIGHT_BUTTON_GPIO_NUM
8392#define RIGHT_BUTTON_GPIO_NUM 16
93+ #endif
94+
95+ #ifndef MOUSE_PERIOD_MS
96+ #define MOUSE_PERIOD_MS 15
97+ #endif
98+
99+ #ifndef SCREEN_WIDTH
100+ #define SCREEN_WIDTH 1920
101+ #endif
102+
103+ #ifndef SCREEN_HEIGHT
104+ #define SCREEN_HEIGHT 1080
105+ #endif
84106
85- float roll ;
86- float pitch ;
87- float yaw ;
107+ static float roll ;
108+ static float pitch ;
109+ static float yaw ;
88110
89- float roll_offset ;
90- float pitch_offset ;
91- float yaw_offset ;
111+ static float roll_offset ;
112+ static float pitch_offset ;
113+ static float yaw_offset ;
92114
93115// start in top left corner
94- int abs_x = 0 ;
95- int abs_y = 0 ;
116+ static int abs_x = 0 ;
117+ static int abs_y = 0 ;
118+
119+ static int dx ;
120+ static int dy ;
121+ static uint8_t buttons ;
122+ static btstack_timer_source_t mousing_timer ;
123+ static int mouse_active = 0 ;
96124
97125// from USB HID Specification 1.1, Appendix B.2
98126const uint8_t hid_descriptor_mouse_boot_mode [] = {
@@ -160,7 +188,7 @@ static void hog_mouse_setup(void){
160188
161189 // initialize CYW43 driver architecture (will enable BT if/because CYW43_ENABLE_BLUETOOTH == 1)
162190 if (cyw43_arch_init ()) {
163- printf ("failed to initialise cyw43_arch\n" );
191+ ERROR_LOG ("failed to initialise cyw43_arch\n" );
164192 }
165193
166194 // setup l2cap
@@ -222,21 +250,11 @@ static void send_report(uint8_t buttons, int8_t dx, int8_t dy){
222250 }
223251}
224252
225- static int dx ;
226- static int dy ;
227- static uint8_t buttons ;
228-
229- #define MOUSE_PERIOD_MS 15
230- #define SCREEN_WIDTH 1920
231- #define SCREEN_HEIGHT 1080
232-
233- static btstack_timer_source_t mousing_timer ;
234- static int mousing_active = 0 ;
235-
236253static void mousing_timer_handler (btstack_timer_source_t * ts ){
237254
238255 if (con_handle == HCI_CON_HANDLE_INVALID ) {
239- mousing_active = 0 ;
256+ INFO_LOG ("Disabling mouse\n" );
257+ mouse_active = 0 ;
240258 return ;
241259 }
242260
@@ -261,38 +279,49 @@ static void mousing_timer_handler(btstack_timer_source_t * ts){
261279 abs_x += dx ;
262280 abs_y += dy ;
263281
264- // trigger send
282+ // trigger send. We can call this from here because we are in a btstack callback
265283 hids_device_request_can_send_now_event (con_handle );
266284
267285 // set next timer
268286 btstack_run_loop_set_timer (ts , MOUSE_PERIOD_MS );
269287 btstack_run_loop_add_timer (ts );
270288}
271289
290+ static void button_notification_fn (__unused void * arg ) {
291+ hids_device_request_can_send_now_event (con_handle );
292+ }
293+ static btstack_context_callback_registration_t button_notification = { .callback = button_notification_fn };
294+
272295// IRQ handler for mouse buttons
273296void button_irq_handler (uint gpio , uint32_t events ) {
274297 if (gpio == LEFT_BUTTON_GPIO_NUM ) {
275- printf ( "left click!\n" );
298+ INFO_LOG ( "Left click!\n" );
276299 if (!gpio_get (gpio )) {
277300 buttons = 1 ;
278301 } else {
279302 buttons = 0 ;
280303 }
281304 } else if (gpio == RIGHT_BUTTON_GPIO_NUM ) {
282- printf ( "right click!\n" );
305+ INFO_LOG ( "Right click!\n" );
283306 if (!gpio_get (gpio )) {
284307 buttons = 2 ;
285308 } else {
286309 buttons = 0 ;
287310 }
288311 }
312+ // We want to call hids_device_request_can_send_now_event,
313+ // but we are in an IRQ and so it's dangerous to call BTStack directly from here.
314+ // So we ask BTstack to callback a function from the "main thread"
315+ // We could also use an async (when pending) worker using async_when_pending_worker_t,
316+ // async_context_add_when_pending_worker and async_context_set_work_pending
317+ btstack_run_loop_execute_on_main_thread (& button_notification );
289318}
290319
291320static void hid_embedded_start_mousing (void ){
292- if (mousing_active ) return ;
293- mousing_active = 1 ;
321+ if (mouse_active ) return ;
322+ mouse_active = 1 ;
294323
295- printf ( "Start mousing.. \n" );
324+ INFO_LOG ( "Enabling mouse \n" );
296325
297326 // set one-shot timer
298327 mousing_timer .process = & mousing_timer_handler ;
@@ -310,30 +339,30 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
310339 switch (hci_event_packet_get_type (packet )) {
311340 case HCI_EVENT_DISCONNECTION_COMPLETE :
312341 con_handle = HCI_CON_HANDLE_INVALID ;
313- printf ("Disconnected\n" );
342+ INFO_LOG ("Disconnected\n" );
314343 break ;
315344 case SM_EVENT_JUST_WORKS_REQUEST :
316- printf ("Just Works requested\n" );
345+ INFO_LOG ("Just Works requested\n" );
317346 sm_just_works_confirm (sm_event_just_works_request_get_handle (packet ));
318347 break ;
319348 case SM_EVENT_NUMERIC_COMPARISON_REQUEST :
320- printf ("Confirming numeric comparison: %" PRIu32 "\n" , sm_event_numeric_comparison_request_get_passkey (packet ));
349+ INFO_LOG ("Confirming numeric comparison: %" PRIu32 "\n" , sm_event_numeric_comparison_request_get_passkey (packet ));
321350 sm_numeric_comparison_confirm (sm_event_passkey_display_number_get_handle (packet ));
322351 break ;
323352 case SM_EVENT_PASSKEY_DISPLAY_NUMBER :
324- printf ("Display Passkey: %" PRIu32 "\n" , sm_event_passkey_display_number_get_passkey (packet ));
353+ INFO_LOG ("Display Passkey: %" PRIu32 "\n" , sm_event_passkey_display_number_get_passkey (packet ));
325354 break ;
326355 case L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE :
327- printf ("L2CAP Connection Parameter Update Complete, response: %x\n" , l2cap_event_connection_parameter_update_response_get_result (packet ));
356+ DEBUG_LOG ("L2CAP Connection Parameter Update Complete, response: %x\n" , l2cap_event_connection_parameter_update_response_get_result (packet ));
328357 break ;
329358 case HCI_EVENT_META_GAP :
330359 switch (hci_event_gap_meta_get_subevent_code (packet )) {
331360 case GAP_SUBEVENT_LE_CONNECTION_COMPLETE :
332361 // print connection parameters (without using float operations)
333362 conn_interval = gap_subevent_le_connection_complete_get_conn_interval (packet );
334- printf ("LE Connection Complete:\n" );
335- printf ("- Connection Interval: %u.%02u ms\n" , conn_interval * 125 / 100 , 25 * (conn_interval & 3 ));
336- printf ("- Connection Latency: %u\n" , gap_subevent_le_connection_complete_get_conn_latency (packet ));
363+ DEBUG_LOG ("LE Connection Complete:\n" );
364+ DEBUG_LOG ("- Connection Interval: %u.%02u ms\n" , conn_interval * 125 / 100 , 25 * (conn_interval & 3 ));
365+ DEBUG_LOG ("- Connection Latency: %u\n" , gap_subevent_le_connection_complete_get_conn_latency (packet ));
337366 break ;
338367 default :
339368 break ;
@@ -344,9 +373,9 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
344373 case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE :
345374 // print connection parameters (without using float operations)
346375 conn_interval = hci_subevent_le_connection_update_complete_get_conn_interval (packet );
347- printf ("LE Connection Update:\n" );
348- printf ("- Connection Interval: %u.%02u ms\n" , conn_interval * 125 / 100 , 25 * (conn_interval & 3 ));
349- printf ("- Connection Latency: %u\n" , hci_subevent_le_connection_update_complete_get_conn_latency (packet ));
376+ DEBUG_LOG ("LE Connection Update:\n" );
377+ DEBUG_LOG ("- Connection Interval: %u.%02u ms\n" , conn_interval * 125 / 100 , 25 * (conn_interval & 3 ));
378+ DEBUG_LOG ("- Connection Latency: %u\n" , hci_subevent_le_connection_update_complete_get_conn_latency (packet ));
350379 break ;
351380 default :
352381 break ;
@@ -356,28 +385,20 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
356385 switch (hci_event_hids_meta_get_subevent_code (packet )){
357386 case HIDS_SUBEVENT_INPUT_REPORT_ENABLE :
358387 con_handle = hids_subevent_input_report_enable_get_con_handle (packet );
359- printf ("Report Characteristic Subscribed %u\n" , hids_subevent_input_report_enable_get_enable (packet ));
360- #ifndef HAVE_BTSTACK_STDIN
388+ DEBUG_LOG ("Report Characteristic Subscribed %u\n" , hids_subevent_input_report_enable_get_enable (packet ));
361389 hid_embedded_start_mousing ();
362- #endif
363- // request connection param update via L2CAP following Apple Bluetooth Design Guidelines
364- // gap_request_connection_parameter_update(con_handle, 12, 12, 4, 100); // 15 ms, 4, 1s
365-
366- // directly update connection params via HCI following Apple Bluetooth Design Guidelines
367- // gap_update_connection_parameters(con_handle, 12, 12, 4, 100); // 60-75 ms, 4, 1s
368-
369390 break ;
370391 case HIDS_SUBEVENT_BOOT_KEYBOARD_INPUT_REPORT_ENABLE :
371392 con_handle = hids_subevent_boot_keyboard_input_report_enable_get_con_handle (packet );
372- printf ("Boot Keyboard Characteristic Subscribed %u\n" , hids_subevent_boot_keyboard_input_report_enable_get_enable (packet ));
393+ DEBUG_LOG ("Boot Keyboard Characteristic Subscribed %u\n" , hids_subevent_boot_keyboard_input_report_enable_get_enable (packet ));
373394 break ;
374395 case HIDS_SUBEVENT_BOOT_MOUSE_INPUT_REPORT_ENABLE :
375396 con_handle = hids_subevent_boot_mouse_input_report_enable_get_con_handle (packet );
376- printf ("Boot Mouse Characteristic Subscribed %u\n" , hids_subevent_boot_mouse_input_report_enable_get_enable (packet ));
397+ DEBUG_LOG ("Boot Mouse Characteristic Subscribed %u\n" , hids_subevent_boot_mouse_input_report_enable_get_enable (packet ));
377398 break ;
378399 case HIDS_SUBEVENT_PROTOCOL_MODE :
379400 protocol_mode = hids_subevent_protocol_mode_get_protocol_mode (packet );
380- printf ("Protocol Mode: %s mode\n" , hids_subevent_protocol_mode_get_protocol_mode (packet ) ? "Report" : "Boot" );
401+ DEBUG_LOG ("Protocol Mode: %s mode\n" , hids_subevent_protocol_mode_get_protocol_mode (packet ) ? "Report" : "Boot" );
381402 break ;
382403 case HIDS_SUBEVENT_CAN_SEND_NOW :
383404 send_report (buttons , dx , dy );
@@ -395,12 +416,6 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
395416int main (void ) {
396417 stdio_init_all ();
397418
398- #if !defined(i2c_default ) || !defined(PICO_DEFAULT_I2C_SDA_PIN ) || !defined(PICO_DEFAULT_I2C_SCL_PIN )
399- #warning Example requires a board with I2C pins
400- puts ("Default I2C pins were not defined" );
401- return 1 ;
402- #endif
403-
404419 // Make the I2C pins available to picotool
405420 bi_decl (bi_2pins_with_func (PICO_DEFAULT_I2C_SDA_PIN , PICO_DEFAULT_I2C_SCL_PIN , GPIO_FUNC_I2C ));
406421
@@ -440,8 +455,20 @@ int main(void) {
440455 // turn on!
441456 hci_power_control (HCI_POWER_ON );
442457
443- while (true) {
458+ // btstack_run_loop_execute is only required when using the 'polling' method (e.g. using pico_cyw43_arch_poll library).
459+ // This example uses the 'threadsafe background` method, where BT work is handled in a low priority IRQ, so it
460+ // is fine to call bt_stack_run_loop_execute() but equally you can continue executing user code.
461+
462+ #if 1 // this is only necessary when using polling (which we aren't, but we're showing it is still safe to call in this case)
463+ btstack_run_loop_execute ();
464+ #else
465+ // this core is free to do it's own stuff except when using 'polling' method (in which case you should use
466+ // btstacK_run_loop_ methods to add work to the run loop.
467+
468+ // this is a forever loop in place of where user code would go.
469+ while (true) {
444470 sleep_ms (1000 );
445471 }
472+ #endif
446473 return 0 ;
447474}
0 commit comments