Skip to content

Commit c20b3ca

Browse files
committed
Merge pull request #103 from tessel/usb-daemon-close
Close and Re-open USBDaemon with USB Connection lifecycle
2 parents b893412 + f603cdc commit c20b3ca

13 files changed

+652
-187
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
build
22
target
33
node_modules
4+
spid
5+
usbexecd

boot.mk

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ $(TARGET)_SRC += \
1111
boot/usb.c \
1212
$(USB_PATH)/class/dfu/dfu.c
1313

14-
$(TARGET)_LDSCRIPT = deps/sam0/linker_scripts/samd21/gcc/samd21g15a_flash.ld
15-
$(TARGET)_DEFINE += -D __SAMD21G15A__
14+
$(TARGET)_LDSCRIPT = deps/sam0/linker_scripts/samd21/gcc/samd21g18a_flash.ld
15+
$(TARGET)_DEFINE += -D __SAMD21G18A__

common/samd21g15a_firmware_partition.ld common/samd21g18a_firmware_partition.ld

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ SEARCH_DIR(.)
4949
/* Memory Spaces Definitions */
5050
MEMORY
5151
{
52-
rom (rx) : ORIGIN = 0x00001000, LENGTH = 0x00008000
52+
rom (rx) : ORIGIN = 0x00001000, LENGTH = 0x0003efff
5353
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00001000
5454
}
5555

firmware.mk

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ $(TARGET)_SRC += \
1212
firmware/usbpipe.c \
1313
firmware/usbserial.c \
1414

15-
$(TARGET)_LDSCRIPT = common/samd21g15a_firmware_partition.ld
16-
$(TARGET)_DEFINE += -D __SAMD21G15A__
15+
$(TARGET)_LDSCRIPT = common/samd21g18a_firmware_partition.ld
16+
$(TARGET)_DEFINE += -D __SAMD21G18A__

firmware/bridge.c

+14-2
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ void bridge_handle_sync() {
111111
return;
112112
}
113113

114+
// Set this flag so the LED boot sequence stops
115+
booted = true;
116+
114117
u8 desc = 0;
115118

116119
// Create DMA chain
@@ -178,8 +181,6 @@ void bridge_dma_rx_completion() {
178181
#define CHECK_CLOSE(x) \
179182
if (!(ctrl_rx.status & (0x10<<x)) && (was_open & (0x10<<x))) { \
180183
bridge_close_##x(ctrl_rx.size[x]); \
181-
out_chan_ready &= ~ (1<<x); \
182-
in_chan_size[x] = 0; \
183184
}
184185

185186
CHECK_OPEN(0)
@@ -220,3 +221,14 @@ void bridge_start_out(u8 channel, u8* data) {
220221
out_chan_ready |= (1<<channel);
221222
pin_high(PIN_BRIDGE_IRQ);
222223
}
224+
225+
void bridge_enable_chan(u8 channel) {
226+
out_chan_ready |= (0x10<<channel);
227+
pin_high(PIN_BRIDGE_IRQ);
228+
}
229+
230+
void bridge_disable_chan(u8 channel) {
231+
out_chan_ready &= ~(0x11<<channel); // Also clears the "ready to accept data" bit
232+
in_chan_size[channel] = 0; // Clears any data that was waiting to be sent
233+
pin_high(PIN_BRIDGE_IRQ);
234+
}

firmware/firmware.h

+2
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ void bridge_dma_rx_completion();
7575

7676
void bridge_start_in(u8 channel, u8* data, u8 length);
7777
void bridge_start_out(u8 channel, u8* data);
78+
void bridge_enable_chan(u8 channel);
79+
void bridge_disable_chan(u8 channel);
7880

7981
void bridge_completion_in_0();
8082
void bridge_completion_in_1();

firmware/port.c

+26-11
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ void port_init(PortData* p, u8 chan, const TesselPort* port,
8484

8585
sercom_clock_enable(p->port->spi, p->clock_channel, 1);
8686
sercom_clock_enable(p->port->uart_i2c, p->clock_channel, 1);
87+
88+
bridge_enable_chan(chan);
8789
}
8890

8991
void port_enable(PortData* p) {
@@ -122,11 +124,14 @@ void port_disable(PortData* p) {
122124
EIC->INTFLAG.reg = p->port->pin_interrupts;
123125

124126
pin_low(p->port->power);
127+
128+
// After the port has been reset, re-enable it
129+
bridge_enable_chan(p->chan);
125130
}
126131

127132
void port_send_status(PortData* p, u8 d) {
128133
if (p->reply_len >= BRIDGE_BUF_SIZE) {
129-
invalid();
134+
bridge_disable_chan(p->chan);
130135
return;
131136
}
132137
p->reply_buf[p->reply_len++] = d;
@@ -219,7 +224,8 @@ Pin port_selected_pin(PortData* p) {
219224

220225
void port_exec_async_complete(PortData* p, ExecStatus s) {
221226
if (p->state != PORT_EXEC_ASYNC) {
222-
invalid();
227+
bridge_disable_chan(p->chan);
228+
return;
223229
}
224230
p->state = s;
225231
port_step(p);
@@ -236,7 +242,8 @@ void uart_send_data(PortData *p){
236242
if (count + 2 > BRIDGE_BUF_SIZE - p->reply_len) {
237243
// Shouldn't have to worry about insufficient buffer space because the buffer is
238244
// always flushed before enabling async events, but assert to be sure.
239-
invalid();
245+
bridge_disable_chan(p->chan);
246+
return;
240247
}
241248

242249
p->reply_buf[p->reply_len++] = REPLY_ASYNC_UART_RX;
@@ -409,7 +416,7 @@ ExecStatus port_begin_cmd(PortData *p) {
409416
pin_gpio(p->port->rx);
410417
return EXEC_DONE;
411418
}
412-
invalid();
419+
bridge_disable_chan(p->chan);
413420
return EXEC_DONE;
414421
}
415422

@@ -523,7 +530,7 @@ inline bool port_async_events_allowed(PortData* p) {
523530

524531
void port_step(PortData* p) {
525532
if (p->state == PORT_DISABLE) {
526-
invalid();
533+
bridge_disable_chan(p->chan);
527534
return;
528535
}
529536

@@ -565,7 +572,10 @@ void port_step(PortData* p) {
565572
p->state = port_begin_cmd(p);
566573
}
567574
} else if (p->state == PORT_READ_ARG) {
568-
if (p->arg_len == 0) invalid();
575+
if (p->arg_len == 0) {
576+
bridge_disable_chan(p->chan);
577+
return;
578+
}
569579
p->arg[p->arg_pos++] = p->cmd_buf[p->cmd_pos++];
570580
p->arg_len--;
571581

@@ -598,7 +608,8 @@ void port_dma_rx_completion(PortData* p) {
598608
p->state = (p->arg[0] == 0 ? EXEC_DONE : EXEC_CONTINUE);
599609
port_step(p);
600610
} else {
601-
invalid();
611+
bridge_disable_chan(p->chan);
612+
return;
602613
}
603614
}
604615

@@ -607,7 +618,8 @@ void port_dma_tx_completion(PortData* p) {
607618
p->state = (p->arg[0] == 0 ? EXEC_DONE : EXEC_CONTINUE);
608619
port_step(p);
609620
} else {
610-
invalid();
621+
bridge_disable_chan(p->chan);
622+
return;
611623
}
612624
}
613625

@@ -642,10 +654,12 @@ void bridge_handle_sercom_uart_i2c(PortData* p) {
642654
p->state = (p->arg[0] == 0 ? EXEC_DONE : EXEC_CONTINUE);
643655
port_step(p);
644656
} else {
645-
invalid();
657+
bridge_disable_chan(p->chan);
658+
return;
646659
}
647660
} else {
648-
invalid();
661+
bridge_disable_chan(p->chan);
662+
return;
649663
}
650664
}
651665

@@ -666,7 +680,8 @@ void port_handle_extint(PortData *p, u32 flags) {
666680
}
667681
EIC->INTFLAG.reg = p->port->pin_interrupts & flags;
668682
} else {
669-
invalid();
683+
bridge_disable_chan(p->chan);
684+
return;
670685
}
671686

672687
port_step(p);

firmware/usbpipe.c

+69-22
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,103 @@
11
#include "firmware.h"
2-
3-
#define FLASH_BUFFER_SIZE 64
2+
#define OUT_RING_SIZE 10
3+
#define PACKET_SIZE 64
4+
u8 out_ring_buf[OUT_RING_SIZE][PACKET_SIZE];
5+
volatile u8 out_ring_count = 0; // Number of packets in the ring buffer
6+
volatile u8 out_ring_write_pos = 0; // Packet index in which we're currently receiving a packet, or will once it's free
7+
volatile u8 out_ring_read_pos = 0; // Packet index from which we're currently sending a packet, or will once it's filled.
8+
volatile u8 out_ring_short_packet = 0; // If nonzero, the ring ends with a short packet of this size
9+
volatile bool out_usb_pending = false;
10+
volatile bool out_bridge_pending = false;
411

512
typedef enum {
613
PIPE_DISABLE,
714
PIPE_WAIT_FOR_USB,
815
PIPE_WAIT_FOR_BRIDGE,
916
} PipeState;
1017

11-
PipeState pipe_state_pc_to_soc;
1218
PipeState pipe_state_soc_to_pc;
13-
USB_ALIGN u8 pipe_buffer_pc_to_soc[BRIDGE_BUF_SIZE];
1419
USB_ALIGN u8 pipe_buffer_soc_to_pc[BRIDGE_BUF_SIZE];
1520

1621
void usbpipe_init() {
1722
usb_enable_ep(USB_EP_PIPE_OUT, USB_EP_TYPE_BULK, 64);
1823
usb_enable_ep(USB_EP_PIPE_IN, USB_EP_TYPE_BULK, 64);
1924

20-
usb_ep_start_out(USB_EP_PIPE_OUT, pipe_buffer_pc_to_soc, FLASH_BUFFER_SIZE);
21-
pipe_state_pc_to_soc = PIPE_WAIT_FOR_USB;
25+
usb_ep_start_out(USB_EP_PIPE_OUT, out_ring_buf[out_ring_write_pos], PACKET_SIZE);
26+
out_usb_pending = true;
27+
out_bridge_pending = false;
2228

2329
bridge_start_out(BRIDGE_USB, pipe_buffer_soc_to_pc);
24-
pipe_state_soc_to_pc = PIPE_WAIT_FOR_BRIDGE;
30+
pipe_state_soc_to_pc = PIPE_WAIT_FOR_BRIDGE;
31+
32+
bridge_enable_chan(BRIDGE_USB); // Tells SPI Daemon to start connection to USB Daemon
2533
}
2634

2735
void usbpipe_disable() {
2836
usb_disable_ep(USB_EP_PIPE_IN);
2937
usb_disable_ep(USB_EP_PIPE_OUT);
30-
pipe_state_pc_to_soc = PIPE_DISABLE;
38+
out_ring_count = 0;
39+
out_ring_write_pos = 0;
40+
out_ring_read_pos = 0;
41+
out_ring_short_packet = 0;
3142
pipe_state_soc_to_pc = PIPE_DISABLE;
43+
bridge_disable_chan(BRIDGE_USB); // Tells SPI Daemon to close connection to USB Daemon
3244
}
3345

34-
// Received from USB, send to bridge
35-
void pipe_usb_out_completion() {
36-
if (pipe_state_pc_to_soc == PIPE_WAIT_FOR_USB) {
37-
u32 len = usb_ep_out_length(USB_EP_PIPE_OUT);
38-
bridge_start_in(BRIDGE_USB, pipe_buffer_pc_to_soc, len);
39-
pipe_state_pc_to_soc = PIPE_WAIT_FOR_BRIDGE;
40-
} else {
41-
invalid();
46+
void out_ring_step() {
47+
// If we are not currently receiving
48+
// And there is an empty buffer to receive data into
49+
// And there isn't an unprocessed short packet
50+
if (!out_usb_pending && out_ring_count < OUT_RING_SIZE && out_ring_short_packet == 0) {
51+
// Start reading data in over USB to the buffer at the correct position (up to 64 bytes)
52+
usb_ep_start_out(USB_EP_PIPE_OUT, out_ring_buf[out_ring_write_pos], PACKET_SIZE);
53+
// We are waiting for the transfer to complete
54+
out_usb_pending = true;
55+
}
56+
57+
// If we are not waiting on a bridge transaction to complete and we have packets to send
58+
if (!out_bridge_pending && out_ring_count > 0) {
59+
// The size of the packet is 64 bytes (unless the below case is true)
60+
u8 len = PACKET_SIZE;
61+
// If we only have one outgoing packet and it is a short packet
62+
if (out_ring_count == 1 && out_ring_short_packet != 0) {
63+
// The length is actually a subset of a full packet
64+
len = out_ring_short_packet;
65+
// Reset the short packet var
66+
out_ring_short_packet = 0;
67+
}
68+
// Start sending data to the spi daemon
69+
bridge_start_in(BRIDGE_USB, out_ring_buf[out_ring_read_pos], len);
70+
// We are currently waiting on the SPI
71+
out_bridge_pending = true;
4272
}
73+
}
4374

75+
// Received from USB, send to bridge
76+
void pipe_usb_out_completion() {
77+
// Get the length of the packet from USB
78+
u32 len = usb_ep_out_length(USB_EP_PIPE_OUT);
79+
// If it is less than one full packet, mark the short packet var with the length
80+
if (len < PACKET_SIZE) out_ring_short_packet = len;
81+
// Increase the next writable buffer by 1 (but loop to the beginning if necessary)
82+
out_ring_write_pos = (out_ring_write_pos + 1) % OUT_RING_SIZE;
83+
// Mark that we have one packet that needs attention
84+
out_ring_count += 1;
85+
// We are no longer operating over USB
86+
out_usb_pending = false;
87+
// Push the data to the correct place
88+
out_ring_step();
4489
}
4590

4691
// Finished sending on bridge, start receive from USB
4792
void pipe_bridge_in_completion() {
48-
if (pipe_state_pc_to_soc == PIPE_WAIT_FOR_BRIDGE) {
49-
usb_ep_start_out(USB_EP_PIPE_OUT, pipe_buffer_pc_to_soc, FLASH_BUFFER_SIZE);
50-
pipe_state_pc_to_soc = PIPE_WAIT_FOR_USB;
51-
} else {
52-
invalid();
53-
}
93+
// Increment the location of where we will read from next (to send over USB)
94+
out_ring_read_pos = (out_ring_read_pos + 1) % OUT_RING_SIZE;
95+
// Decrement the number of packets that need reading
96+
out_ring_count -= 1;
97+
// Mark the bridge transfer as complete
98+
out_bridge_pending = false;
99+
// Move data along
100+
out_ring_step();
54101
}
55102

56103
// Received from bridge, send to USB

0 commit comments

Comments
 (0)