usb_canbus: Rework USB message transmit prioritization
There is no need to heavily prioritize the sending of canbus packets over USB. A single check to flush the incoming canbus packets is sufficient. Also, be sure to wake up canserial_notify_tx() even if canhw_send() blocks. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
28f11244c3
commit
b17ae55f5b
|
@ -112,7 +112,7 @@ static struct usbcan_data {
|
||||||
uint8_t host_status;
|
uint8_t host_status;
|
||||||
|
|
||||||
// Canbus data routed locally
|
// Canbus data routed locally
|
||||||
uint8_t notify_local;
|
uint8_t notify_local, usb_send_busy;
|
||||||
uint32_t assigned_id;
|
uint32_t assigned_id;
|
||||||
|
|
||||||
// Data from physical canbus interface
|
// Data from physical canbus interface
|
||||||
|
@ -166,20 +166,24 @@ send_frame(struct canbus_msg *msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send any pending hw frames to host
|
// Send any pending hw frames to host
|
||||||
static int
|
static void
|
||||||
drain_hw_queue(void)
|
drain_hw_queue(void)
|
||||||
{
|
{
|
||||||
uint32_t pull_pos = UsbCan.pull_pos;
|
uint32_t pull_pos = UsbCan.pull_pos;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
uint32_t push_pos = readl(&UsbCan.push_pos);
|
uint32_t push_pos = readl(&UsbCan.push_pos);
|
||||||
if (push_pos == pull_pos)
|
if (push_pos == pull_pos) {
|
||||||
// No more data to send
|
// No more data to send
|
||||||
return 0;
|
UsbCan.usb_send_busy = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
uint32_t pos = pull_pos % ARRAY_SIZE(UsbCan.queue);
|
uint32_t pos = pull_pos % ARRAY_SIZE(UsbCan.queue);
|
||||||
int ret = send_frame(&UsbCan.queue[pos]);
|
int ret = send_frame(&UsbCan.queue[pos]);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
// USB is busy - retry later
|
// USB is busy - retry later
|
||||||
return -1;
|
UsbCan.usb_send_busy = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
UsbCan.pull_pos = pull_pos = pull_pos + 1;
|
UsbCan.pull_pos = pull_pos = pull_pos + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,12 +193,11 @@ usbcan_task(void)
|
||||||
{
|
{
|
||||||
if (!sched_check_wake(&UsbCan.wake))
|
if (!sched_check_wake(&UsbCan.wake))
|
||||||
return;
|
return;
|
||||||
for (;;) {
|
|
||||||
// Send any pending hw frames to host
|
|
||||||
int ret = drain_hw_queue();
|
|
||||||
if (ret < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
// Send any pending hw frames to host
|
||||||
|
drain_hw_queue();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
// See if previous host frame needs to be transmitted
|
// See if previous host frame needs to be transmitted
|
||||||
uint_fast8_t host_status = UsbCan.host_status;
|
uint_fast8_t host_status = UsbCan.host_status;
|
||||||
if (host_status & (HS_TX_HW | HS_TX_LOCAL)) {
|
if (host_status & (HS_TX_HW | HS_TX_LOCAL)) {
|
||||||
|
@ -209,53 +212,50 @@ usbcan_task(void)
|
||||||
UsbCan.host_status = host_status = host_status & ~HS_TX_LOCAL;
|
UsbCan.host_status = host_status = host_status & ~HS_TX_LOCAL;
|
||||||
}
|
}
|
||||||
if (host_status & HS_TX_HW) {
|
if (host_status & HS_TX_HW) {
|
||||||
ret = canhw_send(&msg);
|
int ret = canhw_send(&msg);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return;
|
break;
|
||||||
UsbCan.host_status = host_status = host_status & ~HS_TX_HW;
|
UsbCan.host_status = host_status = host_status & ~HS_TX_HW;
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send any previous echo frames
|
// Send any previous echo frames
|
||||||
if (host_status) {
|
if (host_status) {
|
||||||
ret = usb_send_bulk_in(&UsbCan.host_frame
|
if (UsbCan.usb_send_busy)
|
||||||
, sizeof(UsbCan.host_frame));
|
// Don't send echo frame until other traffic is sent
|
||||||
|
return;
|
||||||
|
int ret = usb_send_bulk_in(&UsbCan.host_frame
|
||||||
|
, sizeof(UsbCan.host_frame));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return;
|
return;
|
||||||
UsbCan.host_status = 0;
|
UsbCan.host_status = 0;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if can read a new frame from host
|
// Read next frame from host
|
||||||
ret = usb_read_bulk_out(&UsbCan.host_frame, USB_CDC_EP_BULK_OUT_SIZE);
|
int ret = usb_read_bulk_out(&UsbCan.host_frame
|
||||||
if (ret > 0) {
|
, USB_CDC_EP_BULK_OUT_SIZE);
|
||||||
uint32_t id = UsbCan.host_frame.can_id;
|
if (ret <= 0)
|
||||||
UsbCan.host_status = HS_TX_ECHO | HS_TX_HW;
|
// No frame available - no more work to be done
|
||||||
if (id == CANBUS_ID_ADMIN)
|
break;
|
||||||
UsbCan.host_status = HS_TX_ECHO | HS_TX_HW | HS_TX_LOCAL;
|
uint32_t id = UsbCan.host_frame.can_id;
|
||||||
else if (UsbCan.assigned_id && UsbCan.assigned_id == id)
|
UsbCan.host_status = HS_TX_ECHO | HS_TX_HW;
|
||||||
UsbCan.host_status = HS_TX_ECHO | HS_TX_LOCAL;
|
if (id == CANBUS_ID_ADMIN)
|
||||||
continue;
|
UsbCan.host_status = HS_TX_ECHO | HS_TX_HW | HS_TX_LOCAL;
|
||||||
}
|
else if (UsbCan.assigned_id && UsbCan.assigned_id == id)
|
||||||
|
UsbCan.host_status = HS_TX_ECHO | HS_TX_LOCAL;
|
||||||
// No more work to be done
|
|
||||||
if (UsbCan.notify_local) {
|
|
||||||
UsbCan.notify_local = 0;
|
|
||||||
canserial_notify_tx();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (UsbCan.notify_local && !UsbCan.usb_send_busy)
|
||||||
|
canserial_notify_tx();
|
||||||
}
|
}
|
||||||
DECL_TASK(usbcan_task);
|
DECL_TASK(usbcan_task);
|
||||||
|
|
||||||
int
|
int
|
||||||
canbus_send(struct canbus_msg *msg)
|
canbus_send(struct canbus_msg *msg)
|
||||||
{
|
{
|
||||||
int ret = drain_hw_queue();
|
if (UsbCan.usb_send_busy)
|
||||||
if (ret < 0)
|
|
||||||
goto retry_later;
|
goto retry_later;
|
||||||
ret = send_frame(msg);
|
int ret = send_frame(msg);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto retry_later;
|
goto retry_later;
|
||||||
UsbCan.notify_local = 0;
|
UsbCan.notify_local = 0;
|
||||||
|
|
Loading…
Reference in New Issue