@@ -37,6 +37,13 @@ void pbdrv_bluetooth_set_receive_handler(pbdrv_bluetooth_receive_handler_t handl
3737// Functions related to sending value notifications (stdout, status, app data).
3838//
3939
40+ /**
41+ * Each event has a buffer of maximum packet size. They are prioritized by
42+ * ascending event number, so status gets sent first, then stdout, etc.
43+ */
44+ static uint32_t pbdrv_bluetooth_noti_size [PBIO_PYBRICKS_EVENT_NUM_EVENTS ];
45+ static uint8_t pbdrv_bluetooth_noti_buf [PBIO_PYBRICKS_EVENT_NUM_EVENTS ][PBDRV_BLUETOOTH_MAX_CHAR_SIZE ];
46+
4047/**
4148 * Buffer scheduled status.
4249 */
@@ -59,7 +66,6 @@ void pbdrv_bluetooth_schedule_status_update(const uint8_t *status_msg) {
5966 * Buffer for scheduled stdout.
6067 */
6168static lwrb_t stdout_ring_buf ;
62- static bool stdout_send_busy ;
6369
6470void pbdrv_bluetooth_init (void ) {
6571 // enough for two packets, one currently being sent and one to be ready
@@ -103,40 +109,34 @@ bool pbdrv_bluetooth_tx_is_idle(void) {
103109 return true;
104110 }
105111
106- return ! stdout_send_busy && lwrb_get_full (& stdout_ring_buf ) == 0 ;
112+ return lwrb_get_full (& stdout_ring_buf ) == 0 && ! pbdrv_bluetooth_noti_size [ PBIO_PYBRICKS_EVENT_WRITE_STDOUT ] ;
107113}
108114
109- /**
110- * Buffer for generic awaitable notification.
111- */
112- static uint8_t user_notification_send_buf [PBDRV_BLUETOOTH_MAX_CHAR_SIZE ];
113- static size_t user_notification_size ;
114-
115115pbio_error_t pbdrv_bluetooth_send_event_notification (pbio_os_state_t * state , pbio_pybricks_event_t event_type , const uint8_t * data , size_t size ) {
116116 PBIO_OS_ASYNC_BEGIN (state );
117117
118118 if (!pbdrv_bluetooth_is_connected (PBDRV_BLUETOOTH_CONNECTION_PYBRICKS )) {
119119 return PBIO_ERROR_INVALID_OP ;
120120 }
121121
122- if (size + 1 > PBIO_ARRAY_SIZE (user_notification_send_buf ) ) {
122+ if (size + 1 > PBIO_ARRAY_SIZE (pbdrv_bluetooth_noti_buf [ 0 ]) || event_type >= PBIO_PYBRICKS_EVENT_NUM_EVENTS ) {
123123 return PBIO_ERROR_INVALID_ARG ;
124124 }
125125
126- // Existing user notification ongoing .
127- if (user_notification_size ) {
126+ // Existing notification waiting to be sent first .
127+ if (pbdrv_bluetooth_noti_size [ event_type ] ) {
128128 return PBIO_ERROR_BUSY ;
129129 }
130130
131131 // Copy to local buffer and set size so main thread knows to handle it.
132- user_notification_size = size + 1 ;
133- user_notification_send_buf [0 ] = event_type ;
134- memcpy (& user_notification_send_buf [1 ], data , size );
132+ pbdrv_bluetooth_noti_size [ event_type ] = size + 1 ;
133+ pbdrv_bluetooth_noti_buf [ event_type ] [0 ] = event_type ;
134+ memcpy (& pbdrv_bluetooth_noti_buf [ event_type ] [1 ], data , size );
135135 pbio_os_request_poll ();
136136
137137 // Await until main process has finished sending user data. If it
138138 // disconnected while sending, this completes as well.
139- PBIO_OS_AWAIT_WHILE (state , user_notification_size );
139+ PBIO_OS_AWAIT_WHILE (state , pbdrv_bluetooth_noti_size [ event_type ] );
140140
141141 PBIO_OS_ASYNC_END (PBIO_SUCCESS );
142142}
@@ -408,6 +408,53 @@ pbio_error_t pbdrv_bluetooth_await_advertise_or_scan_command(pbio_os_state_t *st
408408 return advertising_or_scan_func ? advertising_or_scan_err : PBIO_SUCCESS ;
409409}
410410
411+ /**
412+ * Updates send buffers by draining relevant data buffers and find which event
413+ * has the highest priority to send.
414+ */
415+ static bool update_and_get_event_buffer (uint8_t * * buf , uint32_t * * len ) {
416+
417+ static pbio_os_timer_t status_timer ;
418+
419+ // Prepare status.
420+ if (status_data_pending || pbio_os_timer_is_expired (& status_timer )) {
421+ // When a status is pending, drain it here while we write it out,
422+ // so a new status can be set in the mean time without losing it.
423+ memcpy (pbdrv_bluetooth_noti_buf [PBIO_PYBRICKS_EVENT_STATUS_REPORT ], status_data , PBIO_PYBRICKS_EVENT_STATUS_REPORT_SIZE );
424+ pbdrv_bluetooth_noti_size [PBIO_PYBRICKS_EVENT_STATUS_REPORT ] = PBIO_PYBRICKS_EVENT_STATUS_REPORT_SIZE ;
425+ status_data_pending = false;
426+ pbio_os_timer_set (& status_timer , PBDRV_BLUETOOTH_STATUS_UPDATE_INTERVAL );
427+ }
428+
429+ // Prepare stdout, drain into chunk of maximum send size.
430+ if (lwrb_get_full (& stdout_ring_buf ) != 0 ) {
431+ // Message always starts with event byte.
432+ if (!pbdrv_bluetooth_noti_size [PBIO_PYBRICKS_EVENT_WRITE_STDOUT ]) {
433+ pbdrv_bluetooth_noti_buf [PBIO_PYBRICKS_EVENT_WRITE_STDOUT ][0 ] = PBIO_PYBRICKS_EVENT_WRITE_STDOUT ;
434+ pbdrv_bluetooth_noti_size [PBIO_PYBRICKS_EVENT_WRITE_STDOUT ] = 1 ;
435+ }
436+ // Drain ring buffer to send buffer as much as we can.
437+ uint32_t stdout_free = sizeof (pbdrv_bluetooth_noti_buf [PBIO_PYBRICKS_EVENT_WRITE_STDOUT ]) - pbdrv_bluetooth_noti_size [PBIO_PYBRICKS_EVENT_WRITE_STDOUT ];
438+ if (stdout_free ) {
439+ uint8_t * dest = & pbdrv_bluetooth_noti_buf [PBIO_PYBRICKS_EVENT_WRITE_STDOUT ][sizeof (pbdrv_bluetooth_noti_buf [PBIO_PYBRICKS_EVENT_WRITE_STDOUT ]) - stdout_free ];
440+ pbdrv_bluetooth_noti_size [PBIO_PYBRICKS_EVENT_WRITE_STDOUT ] += lwrb_read (& stdout_ring_buf , dest , stdout_free );
441+ }
442+ }
443+
444+ // Other events are awaited as-is and don't allow setting new data until
445+ // they have been transmitted, so don't need further processing/draining.
446+
447+ // Return highest priority pending event, ready for sending.s
448+ for (uint32_t i = 0 ; i < PBIO_PYBRICKS_EVENT_NUM_EVENTS ; i ++ ) {
449+ if (pbdrv_bluetooth_noti_size [i ]) {
450+ * len = & pbdrv_bluetooth_noti_size [i ];
451+ * buf = pbdrv_bluetooth_noti_buf [i ];
452+ return true;
453+ }
454+ }
455+ return false;
456+ }
457+
411458static bool shutting_down ;
412459
413460/**
@@ -424,7 +471,6 @@ pbio_error_t pbdrv_bluetooth_process_thread(pbio_os_state_t *state, void *contex
424471
425472 static pbio_os_state_t sub ;
426473 static pbio_os_timer_t timer ;
427- static pbio_os_timer_t status_timer ;
428474 pbio_error_t err ;
429475
430476 // Shorthand notation accessible throughout.
@@ -449,8 +495,6 @@ pbio_error_t pbdrv_bluetooth_process_thread(pbio_os_state_t *state, void *contex
449495
450496 DEBUG_PRINT ("Bluetooth is now on and initialized.\n" );
451497
452- pbio_os_timer_set (& status_timer , PBDRV_BLUETOOTH_STATUS_UPDATE_INTERVAL );
453-
454498 // Service scheduled tasks as long as Bluetooth is enabled.
455499 while (!shutting_down ) {
456500
@@ -459,41 +503,12 @@ pbio_error_t pbdrv_bluetooth_process_thread(pbio_os_state_t *state, void *contex
459503 // allows short stdout messages to be queued rather than sent separately.
460504 PBIO_OS_AWAIT_MS (state , & timer , 1 );
461505
462- // Handle pending status update, if any.
463- if (can_send && (status_data_pending || pbio_os_timer_is_expired (& status_timer ))) {
464-
465- // When a status is pending, cache it here while we write it out,
466- // so a new status can be set in the mean time without losing it.
467- static uint8_t status_buf [PBIO_PYBRICKS_EVENT_STATUS_REPORT_SIZE ];
468- memcpy (status_buf , status_data , PBIO_PYBRICKS_EVENT_STATUS_REPORT_SIZE );
469- status_data_pending = false;
470-
471- PBIO_OS_AWAIT (state , & sub , pbdrv_bluetooth_send_pybricks_value_notification (& sub , status_buf , sizeof (status_buf )));
472-
473- pbio_os_timer_set (& status_timer , status_timer .duration );
474- }
475-
476- // Handle pending stdout, if any.
477- if (can_send && lwrb_get_full (& stdout_ring_buf ) != 0 ) {
478- stdout_send_busy = true;
479-
480- static uint8_t stdout_buf [PBDRV_BLUETOOTH_MAX_CHAR_SIZE ] = { PBIO_PYBRICKS_EVENT_WRITE_STDOUT };
481- static uint16_t stdout_len ;
482-
483- stdout_len = lwrb_read (& stdout_ring_buf , & stdout_buf [1 ], PBDRV_BLUETOOTH_MAX_CHAR_SIZE - 1 ) + 1 ;
484- PBIO_OS_AWAIT (state , & sub , pbdrv_bluetooth_send_pybricks_value_notification (& sub , stdout_buf , stdout_len ));
485-
486- stdout_send_busy = false;
487- }
488-
489- // Handle pending user value notification, if any.
490- if (can_send && user_notification_size ) {
491-
492- PBIO_OS_AWAIT (state , & sub , pbdrv_bluetooth_send_pybricks_value_notification (& sub ,
493- user_notification_send_buf ,
494- user_notification_size ));
495-
496- user_notification_size = 0 ;
506+ // Send one event notification (status, stdout, ...)
507+ static uint32_t * noti_size ;
508+ static uint8_t * noti_buf ;
509+ if (can_send && update_and_get_event_buffer (& noti_buf , & noti_size )) {
510+ PBIO_OS_AWAIT (state , & sub , pbdrv_bluetooth_send_pybricks_value_notification (& sub , noti_buf , * noti_size ));
511+ * noti_size = 0 ;
497512 }
498513
499514 // Handle pending advertising/scan enable/disable task, if any.
0 commit comments