Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions examples/device/net_lwip_webserver/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,19 @@ try changing the first byte of tud_network_mac_address[] below from 0x02 to 0x00
#define INIT_IP4(a, b, c, d) \
{ PP_HTONL(LWIP_MAKEU32(a, b, c, d)) }

/* Blink pattern
* - 250 ms : device not mounted
* - 1000 ms : device mounted
* - 2500 ms : device is suspended
*/
enum {
BLINK_NOT_MOUNTED = 250,
BLINK_MOUNTED = 1000,
BLINK_SUSPENDED = 2500,
};

static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;

/* lwip context */
static struct netif netif_data;

Expand Down Expand Up @@ -218,6 +231,20 @@ uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) {
return pbuf_copy_partial(p, dst, p->tot_len, 0);
}

static void led_blinking_task(void) {
static uint32_t start_ms = 0;
static bool led_state = false;

// Blink every interval ms
if (board_millis() - start_ms < blink_interval_ms) {
return; // not enough time
}
start_ms += blink_interval_ms;

board_led_write(led_state);
led_state = 1 - led_state; // toggle
}

static void handle_link_state_switch(void) {
/* Check for button press to toggle link state */
static bool last_link_state = true;
Expand Down Expand Up @@ -275,11 +302,35 @@ int main(void) {
tud_task();
sys_check_timeouts(); // service lwip
handle_link_state_switch();
led_blinking_task();
}

return 0;
}

// Invoked when device is mounted
void tud_mount_cb(void) {
blink_interval_ms = BLINK_MOUNTED;
}

// Invoked when device is unmounted
void tud_umount_cb(void) {
blink_interval_ms = BLINK_NOT_MOUNTED;
}

// Invoked when usb bus is suspended
// remote_wakeup_en : if host allow us to perform remote wakeup
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
void tud_suspend_cb(bool remote_wakeup_en) {
(void) remote_wakeup_en;
blink_interval_ms = BLINK_SUSPENDED;
}

// Invoked when usb bus is resumed
void tud_resume_cb(void) {
blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}

/* lwip has provision for using a mutex, when applicable */
/* This implementation is for single-threaded use only */
sys_prot_t sys_arch_protect(void) {
Expand Down
85 changes: 62 additions & 23 deletions src/class/net/ncm_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,24 @@ typedef struct {

// recv handling
recv_ntb_t *recv_free_ntb[RECV_NTB_N]; // free list of recv NTBs
recv_ntb_t *recv_ready_ntb[RECV_NTB_N]; // NTBs waiting for transmission to glue logic
recv_ntb_t *recv_ready_ntb[RECV_NTB_N]; // NTBs waiting for transmission to glue logic (circular buffer)
#if RECV_NTB_N > 1
uint8_t recv_ready_head; // head index for recv_ready_ntb circular buffer
uint8_t recv_ready_tail; // tail index for recv_ready_ntb circular buffer
uint8_t recv_ready_count; // number of elements in recv_ready_ntb circular buffer
#endif
recv_ntb_t *recv_tinyusb_ntb; // buffer for the running transfer TinyUSB -> driver
recv_ntb_t *recv_glue_ntb; // buffer for the running transfer driver -> glue logic
uint16_t recv_glue_ntb_datagram_ndx; // index into \a recv_glue_ntb_datagram

// xmit handling
xmit_ntb_t *xmit_free_ntb[XMIT_NTB_N]; // free list of xmit NTBs
xmit_ntb_t *xmit_ready_ntb[XMIT_NTB_N]; // NTBs waiting for transmission to TinyUSB
xmit_ntb_t *xmit_ready_ntb[XMIT_NTB_N]; // NTBs waiting for transmission to TinyUSB (circular buffer)
#if XMIT_NTB_N > 1
uint8_t xmit_ready_head; // head index for xmit_ready_ntb circular buffer
uint8_t xmit_ready_tail; // tail index for xmit_ready_ntb circular buffer
uint8_t xmit_ready_count; // number of elements in xmit_ready_ntb circular buffer
#endif
xmit_ntb_t *xmit_tinyusb_ntb; // buffer for the running transfer driver -> TinyUSB
xmit_ntb_t *xmit_glue_ntb; // buffer for the running transfer glue logic -> driver
uint16_t xmit_sequence; // NTB sequence counter
Expand Down Expand Up @@ -279,28 +289,41 @@ static xmit_ntb_t *xmit_get_free_ntb(void) {
static void xmit_put_ntb_into_ready_list(xmit_ntb_t *ready_ntb) {
TU_LOG_DRV("xmit_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength);

for (int i = 0; i < XMIT_NTB_N; ++i) {
if (ncm_interface.xmit_ready_ntb[i] == NULL) {
ncm_interface.xmit_ready_ntb[i] = ready_ntb;
return;
}
#if XMIT_NTB_N == 1
ncm_interface.xmit_ready_ntb[0] = ready_ntb;
#else
if (ncm_interface.xmit_ready_count >= XMIT_NTB_N) {
TU_LOG_DRV("(EE) xmit_put_ntb_into_ready_list: ready list full\n");// this should not happen
return;
}
TU_LOG_DRV("(EE) xmit_put_ntb_into_ready_list: ready list full\n");// this should not happen
ncm_interface.xmit_ready_ntb[ncm_interface.xmit_ready_head] = ready_ntb;
ncm_interface.xmit_ready_head = (ncm_interface.xmit_ready_head + 1) % XMIT_NTB_N;
ncm_interface.xmit_ready_count++;
#endif
} // xmit_put_ntb_into_ready_list

/**
* Get the next NTB from the ready list (and remove it from the list).
* If the ready list is empty, return NULL.
*/
static xmit_ntb_t *xmit_get_next_ready_ntb(void) {
xmit_ntb_t *r = NULL;
#if XMIT_NTB_N == 1
xmit_ntb_t *r = ncm_interface.xmit_ready_ntb[0];
ncm_interface.xmit_ready_ntb[0] = NULL;
TU_LOG_DRV("xmit_get_next_ready_ntb: %p\n", r);
return r;
#else
if (ncm_interface.xmit_ready_count == 0) {
return NULL; // empty
}

r = ncm_interface.xmit_ready_ntb[0];
memmove(ncm_interface.xmit_ready_ntb + 0, ncm_interface.xmit_ready_ntb + 1, sizeof(ncm_interface.xmit_ready_ntb) - sizeof(ncm_interface.xmit_ready_ntb[0]));
ncm_interface.xmit_ready_ntb[XMIT_NTB_N - 1] = NULL;
xmit_ntb_t *r = ncm_interface.xmit_ready_ntb[ncm_interface.xmit_ready_tail];
ncm_interface.xmit_ready_tail = (ncm_interface.xmit_ready_tail + 1) % XMIT_NTB_N;
ncm_interface.xmit_ready_count--;

TU_LOG_DRV("recv_get_next_ready_ntb: %p\n", r);
TU_LOG_DRV("xmit_get_next_ready_ntb: %p\n", r);
return r;
#endif
} // xmit_get_next_ready_ntb

/**
Expand Down Expand Up @@ -458,14 +481,23 @@ static recv_ntb_t *recv_get_free_ntb(void) {
* If the ready list is empty, return NULL.
*/
static recv_ntb_t *recv_get_next_ready_ntb(void) {
recv_ntb_t *r = NULL;
#if RECV_NTB_N == 1
recv_ntb_t *r = ncm_interface.recv_ready_ntb[0];
ncm_interface.recv_ready_ntb[0] = NULL;
TU_LOG_DRV("recv_get_next_ready_ntb: %p\n", r);
return r;
#else
if (ncm_interface.recv_ready_count == 0) {
return NULL; // empty
}

r = ncm_interface.recv_ready_ntb[0];
memmove(ncm_interface.recv_ready_ntb + 0, ncm_interface.recv_ready_ntb + 1, sizeof(ncm_interface.recv_ready_ntb) - sizeof(ncm_interface.recv_ready_ntb[0]));
ncm_interface.recv_ready_ntb[RECV_NTB_N - 1] = NULL;
recv_ntb_t *r = ncm_interface.recv_ready_ntb[ncm_interface.recv_ready_tail];
ncm_interface.recv_ready_tail = (ncm_interface.recv_ready_tail + 1) % RECV_NTB_N;
ncm_interface.recv_ready_count--;

TU_LOG_DRV("recv_get_next_ready_ntb: %p\n", r);
return r;
#endif
} // recv_get_next_ready_ntb

/**
Expand All @@ -490,13 +522,17 @@ static void recv_put_ntb_into_free_list(recv_ntb_t *free_ntb) {
static void recv_put_ntb_into_ready_list(recv_ntb_t *ready_ntb) {
TU_LOG_DRV("recv_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength);

for (int i = 0; i < RECV_NTB_N; ++i) {
if (ncm_interface.recv_ready_ntb[i] == NULL) {
ncm_interface.recv_ready_ntb[i] = ready_ntb;
return;
}
#if RECV_NTB_N == 1
ncm_interface.recv_ready_ntb[0] = ready_ntb;
#else
if (ncm_interface.recv_ready_count >= RECV_NTB_N) {
TU_LOG_DRV("(EE) recv_put_ntb_into_ready_list: ready list full\n");// this should not happen
return;
}
TU_LOG_DRV("(EE) recv_put_ntb_into_ready_list: ready list full\n");// this should not happen
ncm_interface.recv_ready_ntb[ncm_interface.recv_ready_head] = ready_ntb;
ncm_interface.recv_ready_head = (ncm_interface.recv_ready_head + 1) % RECV_NTB_N;
ncm_interface.recv_ready_count++;
#endif
} // recv_put_ntb_into_ready_list

/**
Expand Down Expand Up @@ -940,6 +976,9 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
if (ncm_interface.itf_data_alt == 1) {
tud_network_recv_renew_r(rhport);
notification_xmit(rhport, false);
} else {
// Reset notification state to send link state update when interface is re-activated
ncm_interface.notification_xmit_state = NOTIFICATION_CONNECTED;
}
tud_control_status(rhport, request);
} break;
Expand Down