Skip to content

Commit 204f5cb

Browse files
committed
pbio/drv/usb: Hook up receive handler and status.
1 parent 27d6331 commit 204f5cb

File tree

5 files changed

+101
-22
lines changed

5 files changed

+101
-22
lines changed

lib/pbio/drv/usb/usb_ev3.c

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -879,8 +879,31 @@ static void usb_device_intr(void) {
879879
HWREG(USB_0_OTGBASE + USB_0_END_OF_INTR) = 0;
880880
}
881881

882+
/**
883+
* Pybricks system command handler.
884+
*/
885+
static pbdrv_usb_receive_handler_t pbdrv_usb_receive_handler;
886+
887+
void pbdrv_usb_set_receive_handler(pbdrv_usb_receive_handler_t handler) {
888+
pbdrv_usb_receive_handler = handler;
889+
}
890+
891+
/**
892+
* Buffer for scheduled status message.
893+
*/
894+
static uint8_t pbdrv_usb_status_data[PBIO_PYBRICKS_EVENT_STATUS_REPORT_SIZE];
895+
static bool pbdrv_usb_status_data_pending;
896+
882897
void pbdrv_usb_schedule_status_update(const uint8_t *status_msg) {
883-
// todo
898+
// Ignore if message identical to last.
899+
if (!memcmp(pbdrv_usb_status_data, status_msg, sizeof(pbdrv_usb_status_data))) {
900+
return;
901+
}
902+
903+
// Schedule to send whenever the USB process gets round to it.
904+
memcpy(pbdrv_usb_status_data, status_msg, sizeof(pbdrv_usb_status_data));
905+
pbdrv_usb_status_data_pending = true;
906+
pbio_os_request_poll();
884907
}
885908

886909
static pbio_os_process_t pbdrv_usb_ev3_process;
@@ -891,16 +914,14 @@ static pbio_error_t pbdrv_usb_ev3_process_thread(pbio_os_state_t *state, void *c
891914
static pbio_os_timer_t keepalive_timer;
892915
static bool was_transmitting = false;
893916
static bool is_transmitting = false;
894-
static uint32_t prev_status_flags = ~0;
895-
static uint32_t new_status_flags = 0;
896917

897918
PBIO_OS_ASYNC_BEGIN(state);
898919

899920
for (;;) {
900921
if (pbdrv_usb_config == 0) {
901922
pbdrv_usb_is_events_subscribed = false;
902923
// Resend status flags when host subscribes
903-
prev_status_flags = ~0;
924+
pbdrv_usb_status_data_pending = true;
904925
}
905926

906927
if (usb_rx_is_ready) {
@@ -925,7 +946,10 @@ static pbio_error_t pbdrv_usb_ev3_process_thread(pbio_os_state_t *state, void *c
925946
usb_send_response = true;
926947
break;
927948
case PBIO_PYBRICKS_OUT_EP_MSG_COMMAND:
928-
result = pbsys_command(ep1_rx_buf + 1, usb_rx_sz - 1);
949+
if (!pbdrv_usb_receive_handler) {
950+
break;
951+
}
952+
result = pbdrv_usb_receive_handler(ep1_rx_buf + 1, usb_rx_sz - 1);
929953
ep1_tx_response_buf[0] = PBIO_PYBRICKS_IN_EP_MSG_RESPONSE;
930954
pbio_set_uint32_le(&ep1_tx_response_buf[1], result);
931955
usb_send_response = true;
@@ -945,26 +969,24 @@ static pbio_error_t pbdrv_usb_ev3_process_thread(pbio_os_state_t *state, void *c
945969
}
946970

947971
// Send status flags if they've changed (and we can)
948-
new_status_flags = pbsys_status_get_flags();
949972
if (pbdrv_usb_is_events_subscribed && !usb_tx_status_is_not_ready &&
950-
(new_status_flags != prev_status_flags || pbio_os_timer_is_expired(&keepalive_timer))) {
973+
(pbdrv_usb_status_data_pending || pbio_os_timer_is_expired(&keepalive_timer))) {
951974
ep1_tx_status_buf[0] = PBIO_PYBRICKS_IN_EP_MSG_EVENT;
952975
uint32_t usb_status_sz = PBIO_PYBRICKS_USB_MESSAGE_SIZE(pbsys_status_get_status_report(&ep1_tx_status_buf[1]));
953976

954977
usb_tx_status_is_not_ready = true;
955978
pbdrv_cache_prepare_before_dma(ep1_tx_status_buf, sizeof(ep1_tx_status_buf));
956979
usb_setup_tx_dma_desc(CPPI_DESC_TX_STATUS, ep1_tx_status_buf, usb_status_sz);
957980

958-
prev_status_flags = new_status_flags;
959-
960-
if (new_status_flags != prev_status_flags) {
981+
if (pbdrv_usb_status_data_pending) {
961982
// If we are sending a status because the flags have changed,
962983
// we can bump out the keepalive timer.
963984
pbio_os_timer_set(&keepalive_timer, 1000);
964985
} else {
965986
// Otherwise, we want to send keepalives at a particular rate.
966987
pbio_os_timer_extend(&keepalive_timer);
967988
}
989+
pbdrv_usb_status_data_pending = false;
968990
}
969991

970992
// Handle timeouts
@@ -985,7 +1007,7 @@ static pbio_error_t pbdrv_usb_ev3_process_thread(pbio_os_state_t *state, void *c
9851007
usb_tx_stdout_is_not_ready = false;
9861008
pbdrv_usb_is_events_subscribed = false;
9871009
// Resend status flags when host subscribes
988-
prev_status_flags = ~0;
1010+
pbdrv_usb_status_data_pending = true;
9891011
}
9901012
} else if (!was_transmitting && is_transmitting) {
9911013
pbio_os_timer_set(&tx_timeout_timer, 50);

lib/pbio/drv/usb/usb_nxt.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include <string.h>
1515

1616
#include <pbdrv/bluetooth.h>
17+
#include <pbdrv/usb.h>
18+
1719
#include <pbio/protocol.h>
1820
#include <pbio/version.h>
1921
#include <pbsys/config.h>
@@ -887,6 +889,16 @@ void pbdrv_usb_schedule_status_update(const uint8_t *status_msg) {
887889
// todo
888890
}
889891

892+
uint32_t pbdrv_usb_stdout_tx_available(void) {
893+
return UINT32_MAX;
894+
}
895+
896+
static pbdrv_usb_receive_handler_t pbdrv_usb_receive_handler;
897+
898+
void pbdrv_usb_set_receive_handler(pbdrv_usb_receive_handler_t handler) {
899+
pbdrv_usb_receive_handler = handler;
900+
}
901+
890902
void nx_usb_read(uint8_t *data, uint32_t length) {
891903
pbdrv_usb_nxt_state.rx_data = data;
892904
pbdrv_usb_nxt_state.rx_size = length;

lib/pbio/drv/usb/usb_stm32.c

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -389,8 +389,31 @@ pbdrv_usb_bcd_t pbdrv_usb_get_bcd(void) {
389389
return pbdrv_usb_bcd;
390390
}
391391

392+
/**
393+
* Pybricks system command handler.
394+
*/
395+
static pbdrv_usb_receive_handler_t pbdrv_usb_receive_handler;
396+
397+
void pbdrv_usb_set_receive_handler(pbdrv_usb_receive_handler_t handler) {
398+
pbdrv_usb_receive_handler = handler;
399+
}
400+
401+
/**
402+
* Buffer for scheduled status message.
403+
*/
404+
static uint8_t pbdrv_usb_status_data[PBIO_PYBRICKS_EVENT_STATUS_REPORT_SIZE];
405+
static bool pbdrv_usb_status_data_pending;
406+
392407
void pbdrv_usb_schedule_status_update(const uint8_t *status_msg) {
393-
// todo
408+
// Ignore if message identical to last.
409+
if (!memcmp(pbdrv_usb_status_data, status_msg, sizeof(pbdrv_usb_status_data))) {
410+
return;
411+
}
412+
413+
// Schedule to send whenever the Bluetooth process gets round to it.
414+
memcpy(pbdrv_usb_status_data, status_msg, sizeof(pbdrv_usb_status_data));
415+
pbdrv_usb_status_data_pending = true;
416+
process_poll(&pbdrv_usb_process);
394417
}
395418

396419
// Event loop
@@ -404,8 +427,6 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
404427
static pbio_pybricks_error_t result;
405428
static struct etimer status_timer;
406429
static struct etimer transmit_timer;
407-
static uint32_t prev_status_flags = ~0;
408-
static uint32_t new_status_flags;
409430

410431
PROCESS_POLLHANDLER({
411432
if (!bcd_busy && pbio_oneshot(!vbus_active, &no_vbus_oneshot)) {
@@ -463,8 +484,8 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
463484
usb_response_sz = sizeof(usb_response_buf);
464485
break;
465486
case PBIO_PYBRICKS_OUT_EP_MSG_COMMAND:
466-
if (usb_response_sz == 0) {
467-
result = pbsys_command(usb_in_buf + 1, usb_in_sz - 1);
487+
if (usb_response_sz == 0 && pbdrv_usb_receive_handler) {
488+
result = pbdrv_usb_receive_handler(usb_in_buf + 1, usb_in_sz - 1);
468489
usb_response_buf[0] = PBIO_PYBRICKS_IN_EP_MSG_RESPONSE;
469490
pbio_set_uint32_le(&usb_response_buf[1], result);
470491
usb_response_sz = sizeof(usb_response_buf);
@@ -488,25 +509,26 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
488509
continue;
489510
}
490511

491-
new_status_flags = pbsys_status_get_flags();
492-
493512
// Transmit. Give priority to response, then status updates, then stdout.
494513
if (usb_response_sz) {
495514
transmitting = true;
496515
USBD_Pybricks_TransmitPacket(&husbd, usb_response_buf, usb_response_sz);
497516
} else if (pbdrv_usb_stm32_is_events_subscribed) {
498-
if ((new_status_flags != prev_status_flags) || etimer_expired(&status_timer)) {
517+
if (pbdrv_usb_status_data_pending || etimer_expired(&status_timer)) {
518+
pbdrv_usb_status_data_pending = false;
519+
499520
usb_status_buf[0] = PBIO_PYBRICKS_IN_EP_MSG_EVENT;
500521
_Static_assert(sizeof(usb_status_buf) + 1 >= PBIO_PYBRICKS_EVENT_STATUS_REPORT_SIZE,
501522
"size of status report does not match size of event");
502-
usb_status_sz = PBIO_PYBRICKS_USB_MESSAGE_SIZE(pbsys_status_get_status_report(&usb_status_buf[1]));
523+
524+
memcpy(&usb_status_buf[1], pbdrv_usb_status_data, sizeof(pbdrv_usb_status_data));
525+
usb_status_sz = PBIO_PYBRICKS_USB_MESSAGE_SIZE(sizeof(pbdrv_usb_status_data));
503526

504527
// REVISIT: we really shouldn't need a status timer on USB since
505528
// it's not a lossy transport. We just need to make sure we send
506529
// status updates when they change and send the current status
507530
// immediately after subscribing to events.
508531
etimer_restart(&status_timer);
509-
prev_status_flags = new_status_flags;
510532

511533
transmitting = true;
512534
USBD_Pybricks_TransmitPacket(&husbd, usb_status_buf, usb_status_sz);

lib/pbio/include/pbdrv/usb.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010
#define _PBDRV_USB_H_
1111

1212
#include <stdbool.h>
13+
#include <stdint.h>
1314

1415
#include <pbdrv/config.h>
1516
#include <pbio/error.h>
17+
#include <pbio/protocol.h>
1618

1719
/**
1820
* Indicates battery charging capabilites that were detected on a USB port.
@@ -32,6 +34,14 @@ typedef enum {
3234
PBDRV_USB_BCD_DEDICATED_CHARGING = 4,
3335
} pbdrv_usb_bcd_t;
3436

37+
/**
38+
* Callback that is called when receiving a Pybricks command.
39+
*
40+
* @param [in] data The data that was received.
41+
* @param [in] size The size of @p data in bytes.
42+
*/
43+
typedef pbio_pybricks_error_t (*pbdrv_usb_receive_handler_t)(const uint8_t *data, uint32_t size);
44+
3545
#if PBDRV_CONFIG_USB
3646

3747
/**
@@ -40,6 +50,13 @@ typedef enum {
4050
*/
4151
pbdrv_usb_bcd_t pbdrv_usb_get_bcd(void);
4252

53+
/**
54+
* Registers a callback that will be called when Pybricks data is received.
55+
*
56+
* @param [in] handler The function that will be called.
57+
*/
58+
void pbdrv_usb_set_receive_handler(pbdrv_usb_receive_handler_t handler);
59+
4360
/**
4461
* Schedules Pybricks status to be sent soon.
4562
*
@@ -82,6 +99,9 @@ static inline pbdrv_usb_bcd_t pbdrv_usb_get_bcd(void) {
8299
return PBDRV_USB_BCD_NONE;
83100
}
84101

102+
static inline void pbdrv_usb_set_receive_handler(pbdrv_usb_receive_handler_t handler) {
103+
}
104+
85105
static inline void pbdrv_usb_schedule_status_update(const uint8_t *status_msg) {
86106
}
87107

lib/pbio/sys/host.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,20 @@
99

1010
#include <pbdrv/bluetooth.h>
1111
#include <pbdrv/usb.h>
12-
#include <pbsys/host.h>
1312

1413
#include "bluetooth.h"
14+
#include <pbsys/command.h>
15+
#include <pbsys/host.h>
1516

1617
static pbsys_host_stdin_event_callback_t pbsys_host_stdin_event_callback;
1718
static lwrb_t pbsys_host_stdin_ring_buf;
1819

1920
void pbsys_host_init(void) {
2021
static uint8_t stdin_buf[PBSYS_CONFIG_HOST_STDIN_BUF_SIZE];
2122
lwrb_init(&pbsys_host_stdin_ring_buf, stdin_buf, PBIO_ARRAY_SIZE(stdin_buf));
23+
2224
pbsys_bluetooth_init();
25+
pbdrv_usb_set_receive_handler(pbsys_command);
2326
}
2427

2528
/**

0 commit comments

Comments
 (0)