Skip to content

Commit 2e5010e

Browse files
committed
usb: Move usb handling out into main loop
It best practice to do as little work as possible in the interrupt handlers. In this commit the parsing is moved from the interrupts handlers to the main loop. This is also a requirement for having multiple transports.
1 parent 67add36 commit 2e5010e

File tree

14 files changed

+194
-129
lines changed

14 files changed

+194
-129
lines changed

src/bootloader/startup.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "mpu_regions.h"
1717
#include "platform_config.h"
1818
#include "platform_init.h"
19+
#include "usb/class/hid/hww/hid_hww.h"
1920

2021
#include <driver_init.h>
2122
#include <hardfault.h>
@@ -56,8 +57,22 @@ int main(void)
5657
#endif
5758
bootloader_jump();
5859

60+
const uint8_t* hww_data = NULL;
61+
uint8_t hww_frame[USB_REPORT_SIZE] = {0};
62+
5963
// If did not jump to firmware code, begin USB processing
6064
while (1) {
65+
if (hid_hww_read(&hww_frame[0])) {
66+
usb_packet_process((const USB_FRAME*)hww_frame);
67+
}
68+
if (!hww_data) {
69+
hww_data = queue_pull(queue_hww_queue());
70+
}
71+
if (hww_data) {
72+
if (hid_hww_write_poll(hww_data)) {
73+
hww_data = NULL;
74+
}
75+
}
6176
usb_processing_process(usb_processing_hww());
6277
}
6378
return 0;

src/firmware_main_loop.c

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,43 +15,94 @@
1515
#include "firmware_main_loop.h"
1616

1717
#include "hardfault.h"
18+
#include "hid_hww.h"
1819
#include "hww.h"
1920
#include "touch/gestures.h"
20-
#include "u2f.h"
2121
#include "ui/screen_process.h"
2222
#include "ui/screen_stack.h"
23+
#include "usb/class/hid/hww/hid_hww.h"
2324
#include "usb/usb.h"
25+
#include "usb/usb_frame.h"
2426
#include "usb/usb_processing.h"
2527
#include "workflow/orientation_screen.h"
2628
#include <rust/rust.h>
29+
#if APP_U2F == 1
30+
#include "u2f.h"
31+
#include "u2f/u2f_packet.h"
32+
#include "usb/class/hid/u2f/hid_u2f.h"
33+
#endif
2734

2835
void firmware_main_loop(void)
2936
{
3037
// This starts the async orientation screen workflow, which is processed by the loop below.
3138
orientation_screen();
3239

33-
while (1) {
34-
screen_process();
35-
/* And finally, run the high-level event processing. */
36-
37-
rust_workflow_spin();
40+
const uint8_t* hww_data = NULL;
41+
uint8_t hww_frame[USB_REPORT_SIZE] = {0};
3842

39-
if (usb_is_enabled()) {
40-
rust_async_usb_spin();
43+
#if APP_U2F == 1
44+
u2f_packet_init();
45+
const uint8_t* u2f_data = NULL;
46+
uint8_t u2f_frame[USB_REPORT_SIZE] = {0};
47+
#endif
4148

42-
/* First, process all the incoming USB traffic. */
43-
usb_processing_process(usb_processing_hww());
49+
while (1) {
50+
// Do USB I/O
51+
if (!hww_data) {
52+
hww_data = queue_pull(queue_hww_queue());
53+
}
4454
#if APP_U2F == 1
45-
usb_processing_process(usb_processing_u2f());
55+
// Generate timeout packets
56+
uint32_t timeout_cid;
57+
while (u2f_packet_timeout_get(&timeout_cid)) {
58+
u2f_packet_timeout(timeout_cid);
59+
}
60+
if (!u2f_data) {
61+
u2f_data = queue_pull(queue_u2f_queue());
62+
}
4663
#endif
47-
/*
48-
* If USB has generated events at the application level,
49-
* process them now.
50-
*/
51-
hww_process();
64+
// Only read new messages if we have nothing to send
65+
if (!hww_data && hid_hww_read(&hww_frame[0])) {
66+
usb_packet_process((const USB_FRAME*)hww_frame);
67+
}
5268
#if APP_U2F == 1
53-
u2f_process();
69+
if (!u2f_data && hid_u2f_read(&u2f_frame[0])) {
70+
u2f_packet_process((const USB_FRAME*)u2f_frame);
71+
}
5472
#endif
73+
74+
if (hww_data) {
75+
if (hid_hww_write_poll(hww_data)) {
76+
hww_data = NULL;
77+
}
78+
}
79+
#if APP_U2F == 1
80+
if (u2f_data) {
81+
if (hid_u2f_write_poll(u2f_data)) {
82+
u2f_data = NULL;
83+
}
5584
}
85+
#endif
86+
87+
/* First, process all the incoming USB traffic. */
88+
usb_processing_process(usb_processing_hww());
89+
#if APP_U2F == 1
90+
usb_processing_process(usb_processing_u2f());
91+
#endif
92+
/*
93+
* If USB has generated events at the application level,
94+
* process them now.
95+
*/
96+
hww_process();
97+
#if APP_U2F == 1
98+
u2f_process();
99+
#endif
100+
101+
screen_process();
102+
/* And finally, run the high-level event processing. */
103+
104+
rust_workflow_spin();
105+
106+
rust_async_usb_spin();
56107
}
57108
}

src/u2f/u2f_packet.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ static void _reset_state(void)
6565
queue_clear(queue_u2f_queue());
6666
_timeout_disable(_in_state.cid);
6767
memset(&_in_state, 0, sizeof(_in_state));
68+
_in_state.buf_ptr = _in_state.data;
6869
}
6970

7071
/**
@@ -180,3 +181,8 @@ bool u2f_packet_process(const USB_FRAME* frame)
180181
}
181182
return false;
182183
}
184+
185+
void u2f_packet_init(void)
186+
{
187+
_reset_state();
188+
}

src/u2f/u2f_packet.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,6 @@ void u2f_packet_timeout_enable(uint32_t cid);
5454
*/
5555
void u2f_invalid_endpoint(struct queue* queue, uint32_t cid);
5656

57+
void u2f_packet_init(void);
58+
5759
#endif

src/usb/class/hid/hid.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
struct usbdc_handler;
2727
struct usbdf_handler;
2828
struct usbdf_driver;
29+
struct usb_req;
30+
enum usb_ctrl_stage { USB_SETUP_STAGE = 0, USB_DATA_STAGE = 1, USB_STATUS_STAGE = 2 };
2931
typedef void (*FUNC_PTR)(void);
3032
#endif
3133

src/usb/class/hid/hww/hid_hww.c

Lines changed: 34 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -51,68 +51,66 @@ static int32_t _request(uint8_t ep, struct usb_req* req, enum usb_ctrl_stage sta
5151
*/
5252
static struct usbdc_handler _request_handler = {NULL, (FUNC_PTR)_request};
5353

54-
// Stores the reports for the HWW interface.
55-
static uint8_t _out_report[USB_HID_REPORT_OUT_SIZE];
56-
57-
/**
58-
* Sets the buffer address for the incoming endpoint to `_out_report`.
54+
/*
55+
* Flags for communication between main loop and ISR
5956
*/
60-
static int32_t _read(void)
57+
static volatile bool _send_busy = false;
58+
static volatile bool _has_data = false;
59+
static volatile bool _request_in_flight = false;
60+
61+
// First time this function is called it initiates a transfer. Call it multiple times to poll for
62+
// completion. Once it returns true, there is data in the buffer.
63+
bool hid_hww_read(uint8_t* data)
6164
{
62-
return hid_read(&_func_data, _out_report, USB_HID_REPORT_OUT_SIZE);
65+
if (_request_in_flight && _has_data) {
66+
_request_in_flight = false;
67+
return true;
68+
}
69+
if (_request_in_flight) {
70+
return false;
71+
}
72+
if (hid_read(&_func_data, data, USB_HID_REPORT_OUT_SIZE) == ERR_NONE) {
73+
_has_data = false;
74+
_request_in_flight = true;
75+
}
76+
return false;
6377
}
6478

65-
/** Set when the send channel is busy sending data. */
66-
static bool _send_busy = false;
67-
6879
/**
6980
* Sends the next frame, if the USB interface is ready.
7081
*/
71-
static void _send_next(void)
82+
bool hid_hww_write_poll(const uint8_t* data)
7283
{
84+
ASSERT(data);
7385
if (_send_busy) {
74-
/*
75-
* We can't send yet. Whenever the current sender finished, it will
76-
* flush anything that's still queued.
77-
*/
78-
return;
86+
return false;
7987
}
80-
const uint8_t* data = queue_pull(queue_hww_queue());
81-
if (data != NULL) {
88+
if (hid_write(&_func_data, data, USB_HID_REPORT_OUT_SIZE) == ERR_NONE) {
8289
_send_busy = true;
83-
hid_write(&_func_data, data, USB_HID_REPORT_OUT_SIZE);
90+
return true;
8491
}
92+
return false;
8593
}
8694

8795
/**
8896
* The callback function is called after usb data has been received (endpoint = OUT).
89-
* This is a result of calling _read().
90-
* The received data is stored in '_out_report'.
9197
*/
92-
static uint8_t _out(const uint8_t ep, const enum usb_xfer_code rc, const uint32_t count)
98+
static uint8_t _rx_cb(const uint8_t ep, const enum usb_xfer_code rc, const uint32_t count)
9399
{
94100
(void)ep;
95101
(void)rc;
96102
(void)count;
97-
usb_packet_process((const USB_FRAME*)_out_report);
98-
/* Incoming data has been processed completely. Start a new read. */
99-
_read();
103+
_has_data = true;
100104
return ERR_NONE;
101105
}
102106

103107
/**
104108
* Called when a usb frame has been replied to the host via the HWW interface
105109
* and the device is ready to send the next frame.
106110
*/
107-
static void _sent_done(void)
111+
static void _tx_cb(void)
108112
{
109113
_send_busy = false;
110-
/*
111-
* If there is more data queued, push it immediately to save some time.
112-
* Otherwise, sending will stop until somebody explicitely queues
113-
* a frame again.
114-
*/
115-
_send_next();
116114
}
117115

118116
/**
@@ -135,14 +133,10 @@ int32_t hid_hww_init(void (*callback)(void))
135133
*/
136134
void hid_hww_setup(void)
137135
{
138-
hid_hww_register_callback(HID_CB_READ, (FUNC_PTR)_out);
139-
// usb_report_sent is called when the outgoing usb frame is fully transmitted.
140-
hid_hww_register_callback(HID_CB_WRITE, (FUNC_PTR)_sent_done);
141-
142-
usb_processing_set_send(usb_processing_hww(), _send_next);
143-
144-
// Wait for data
145-
_read();
136+
// RX callback is called when there is data available to read
137+
hid_hww_register_callback(HID_CB_READ, (FUNC_PTR)_rx_cb);
138+
// TX callback is called when data has been sent
139+
hid_hww_register_callback(HID_CB_WRITE, (FUNC_PTR)_tx_cb);
146140
}
147141

148142
/**

src/usb/class/hid/hww/hid_hww.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,20 @@ int32_t hid_hww_register_callback(enum hid_trans_type trans_type, FUNC_PTR func)
6060
*/
6161
void hid_hww_setup(void);
6262

63+
/**
64+
* Send out data
65+
* returns true if data sent out, false if busy (need retry)
66+
*/
67+
bool hid_hww_write_poll(const uint8_t* data);
68+
69+
/**
70+
* Read data
71+
*
72+
* data must fit 64 bytes data.
73+
* Returns true if there is valid data in the buffer. data is invalidated when this is called again.
74+
* Returns false if USB subsystem was not ready to receive or there is a request in flight and data
75+
* is not.
76+
*/
77+
bool hid_hww_read(uint8_t* data);
78+
6379
#endif

0 commit comments

Comments
 (0)