mirror of
https://github.com/QIDITECH/klipper.git
synced 2026-02-02 00:48:42 +03:00
plus4的klipper版本
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include "board/pgm.h" // PROGMEM
|
||||
#include "board/usb_cdc_ep.h" // USB_CDC_EP_BULK_IN
|
||||
#include "byteorder.h" // cpu_to_le16
|
||||
#include "command.h" // DECL_CONSTANT
|
||||
#include "generic/usbstd.h" // struct usb_device_descriptor
|
||||
#include "sched.h" // sched_wake_task
|
||||
#include "usb_cdc.h" // usb_notify_ep0
|
||||
@@ -103,20 +104,18 @@ struct gs_host_frame {
|
||||
static struct usbcan_data {
|
||||
struct task_wake wake;
|
||||
|
||||
// Canbus data from host
|
||||
union {
|
||||
struct gs_host_frame host_frame;
|
||||
uint8_t rx_frame_pad[USB_CDC_EP_BULK_OUT_SIZE];
|
||||
};
|
||||
uint8_t host_status;
|
||||
|
||||
// Canbus data routed locally
|
||||
uint8_t notify_local;
|
||||
uint8_t notify_local, usb_send_busy;
|
||||
uint32_t assigned_id;
|
||||
|
||||
// Canbus data from host
|
||||
uint8_t host_status;
|
||||
uint32_t host_pull_pos, host_push_pos;
|
||||
struct gs_host_frame host_frames[16];
|
||||
|
||||
// Data from physical canbus interface
|
||||
uint32_t pull_pos, push_pos;
|
||||
struct canbus_msg queue[8];
|
||||
uint32_t canhw_pull_pos, canhw_push_pos;
|
||||
struct canbus_msg canhw_queue[32];
|
||||
} UsbCan;
|
||||
|
||||
enum {
|
||||
@@ -125,6 +124,8 @@ enum {
|
||||
HS_TX_LOCAL = 4,
|
||||
};
|
||||
|
||||
DECL_CONSTANT("CANBUS_BRIDGE", 1);
|
||||
|
||||
void
|
||||
canbus_notify_tx(void)
|
||||
{
|
||||
@@ -136,16 +137,16 @@ void
|
||||
canbus_process_data(struct canbus_msg *msg)
|
||||
{
|
||||
// Add to admin command queue
|
||||
uint32_t pushp = UsbCan.push_pos;
|
||||
if (pushp - UsbCan.pull_pos >= ARRAY_SIZE(UsbCan.queue))
|
||||
uint32_t pushp = UsbCan.canhw_push_pos;
|
||||
if (pushp - UsbCan.canhw_pull_pos >= ARRAY_SIZE(UsbCan.canhw_queue))
|
||||
// No space - drop message
|
||||
return;
|
||||
if (UsbCan.assigned_id && (msg->id & ~1) == UsbCan.assigned_id)
|
||||
// Id reserved for local
|
||||
return;
|
||||
uint32_t pos = pushp % ARRAY_SIZE(UsbCan.queue);
|
||||
memcpy(&UsbCan.queue[pos], msg, sizeof(*msg));
|
||||
UsbCan.push_pos = pushp + 1;
|
||||
uint32_t pos = pushp % ARRAY_SIZE(UsbCan.canhw_queue);
|
||||
memcpy(&UsbCan.canhw_queue[pos], msg, sizeof(*msg));
|
||||
UsbCan.canhw_push_pos = pushp + 1;
|
||||
usb_notify_bulk_out();
|
||||
}
|
||||
|
||||
@@ -163,21 +164,44 @@ send_frame(struct canbus_msg *msg)
|
||||
}
|
||||
|
||||
// Send any pending hw frames to host
|
||||
static int
|
||||
drain_hw_queue(void)
|
||||
static void
|
||||
drain_canhw_queue(void)
|
||||
{
|
||||
uint32_t pull_pos = UsbCan.canhw_pull_pos;
|
||||
for (;;) {
|
||||
uint32_t push_pos = readl(&UsbCan.push_pos);
|
||||
uint32_t pull_pos = UsbCan.pull_pos;
|
||||
if (push_pos != pull_pos) {
|
||||
uint32_t pos = pull_pos % ARRAY_SIZE(UsbCan.queue);
|
||||
int ret = send_frame(&UsbCan.queue[pos]);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
UsbCan.pull_pos = pull_pos + 1;
|
||||
continue;
|
||||
uint32_t push_pos = readl(&UsbCan.canhw_push_pos);
|
||||
if (push_pos == pull_pos) {
|
||||
// No more data to send
|
||||
UsbCan.usb_send_busy = 0;
|
||||
return;
|
||||
}
|
||||
return 0;
|
||||
uint32_t pos = pull_pos % ARRAY_SIZE(UsbCan.canhw_queue);
|
||||
int ret = send_frame(&UsbCan.canhw_queue[pos]);
|
||||
if (ret < 0) {
|
||||
// USB is busy - retry later
|
||||
UsbCan.usb_send_busy = 1;
|
||||
return;
|
||||
}
|
||||
UsbCan.canhw_pull_pos = pull_pos = pull_pos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill local queue with any USB messages sent from host
|
||||
static void
|
||||
fill_usb_host_queue(void)
|
||||
{
|
||||
uint32_t pull_pos = UsbCan.host_pull_pos, push_pos = UsbCan.host_push_pos;
|
||||
for (;;) {
|
||||
if (push_pos - pull_pos >= ARRAY_SIZE(UsbCan.host_frames))
|
||||
// No more space in queue
|
||||
break;
|
||||
uint32_t pushp = push_pos % ARRAY_SIZE(UsbCan.host_frames);
|
||||
struct gs_host_frame *gs = &UsbCan.host_frames[pushp];
|
||||
int ret = usb_read_bulk_out(gs, sizeof(*gs));
|
||||
if (ret <= 0)
|
||||
// No more messages ready
|
||||
break;
|
||||
UsbCan.host_push_pos = push_pos = push_pos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,79 +210,79 @@ usbcan_task(void)
|
||||
{
|
||||
if (!sched_check_wake(&UsbCan.wake))
|
||||
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_canhw_queue();
|
||||
|
||||
// Fill local queue with any USB messages arriving from host
|
||||
fill_usb_host_queue();
|
||||
|
||||
// Route messages received from host
|
||||
uint32_t pull_pos = UsbCan.host_pull_pos, push_pos = UsbCan.host_push_pos;
|
||||
uint32_t pullp = pull_pos % ARRAY_SIZE(UsbCan.host_frames);
|
||||
struct gs_host_frame *gs = &UsbCan.host_frames[pullp];
|
||||
for (;;) {
|
||||
// See if previous host frame needs to be transmitted
|
||||
uint_fast8_t host_status = UsbCan.host_status;
|
||||
if (host_status & (HS_TX_HW | HS_TX_LOCAL)) {
|
||||
struct gs_host_frame *gs = &UsbCan.host_frame;
|
||||
struct canbus_msg msg;
|
||||
msg.id = gs->can_id;
|
||||
msg.dlc = gs->can_dlc;
|
||||
msg.data32[0] = gs->data32[0];
|
||||
msg.data32[1] = gs->data32[1];
|
||||
if (host_status & HS_TX_LOCAL) {
|
||||
canserial_process_data(&msg);
|
||||
UsbCan.host_status = host_status = host_status & ~HS_TX_LOCAL;
|
||||
}
|
||||
if (host_status & HS_TX_HW) {
|
||||
ret = canbus_send(&msg);
|
||||
int ret = canhw_send(&msg);
|
||||
if (ret < 0)
|
||||
return;
|
||||
break;
|
||||
UsbCan.host_status = host_status = host_status & ~HS_TX_HW;
|
||||
}
|
||||
if (host_status & HS_TX_LOCAL) {
|
||||
ret = canserial_process_data(&msg);
|
||||
if (ret < 0) {
|
||||
usb_notify_bulk_out();
|
||||
return;
|
||||
}
|
||||
UsbCan.host_status = host_status & ~HS_TX_LOCAL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Send any previous echo frames
|
||||
if (host_status) {
|
||||
ret = usb_send_bulk_in(&UsbCan.host_frame
|
||||
, sizeof(UsbCan.host_frame));
|
||||
if (UsbCan.notify_local || UsbCan.usb_send_busy)
|
||||
// Don't send echo frame until other traffic is sent
|
||||
break;
|
||||
int ret = usb_send_bulk_in(gs, sizeof(*gs));
|
||||
if (ret < 0)
|
||||
return;
|
||||
UsbCan.host_status = 0;
|
||||
continue;
|
||||
UsbCan.host_pull_pos = pull_pos = pull_pos + 1;
|
||||
}
|
||||
|
||||
// See if can read a new frame from host
|
||||
ret = usb_read_bulk_out(&UsbCan.host_frame, USB_CDC_EP_BULK_OUT_SIZE);
|
||||
if (ret > 0) {
|
||||
uint32_t id = UsbCan.host_frame.can_id;
|
||||
UsbCan.host_status = HS_TX_ECHO | HS_TX_HW;
|
||||
if (id == CANBUS_ID_ADMIN)
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
||||
// No more work to be done
|
||||
if (UsbCan.notify_local) {
|
||||
UsbCan.notify_local = 0;
|
||||
canserial_notify_tx();
|
||||
}
|
||||
return;
|
||||
// Process next frame from host
|
||||
if (pull_pos == push_pos)
|
||||
// No frame available - no more work to be done
|
||||
break;
|
||||
gs = &UsbCan.host_frames[pull_pos % ARRAY_SIZE(UsbCan.host_frames)];
|
||||
uint32_t id = gs->can_id;
|
||||
UsbCan.host_status = HS_TX_ECHO | HS_TX_HW;
|
||||
if (id == CANBUS_ID_ADMIN)
|
||||
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;
|
||||
}
|
||||
|
||||
// Wake up local message response handling (if usb is not busy)
|
||||
if (UsbCan.notify_local && !UsbCan.usb_send_busy)
|
||||
canserial_notify_tx();
|
||||
}
|
||||
DECL_TASK(usbcan_task);
|
||||
|
||||
int
|
||||
canserial_send(struct canbus_msg *msg)
|
||||
canbus_send(struct canbus_msg *msg)
|
||||
{
|
||||
int ret = drain_hw_queue();
|
||||
if (ret < 0)
|
||||
goto retry_later;
|
||||
ret = send_frame(msg);
|
||||
if (UsbCan.usb_send_busy)
|
||||
goto retry_later;
|
||||
int ret = send_frame(msg);
|
||||
if (ret < 0)
|
||||
goto retry_later;
|
||||
if (UsbCan.notify_local && UsbCan.host_status)
|
||||
canbus_notify_tx();
|
||||
UsbCan.notify_local = 0;
|
||||
return msg->dlc;
|
||||
retry_later:
|
||||
@@ -267,7 +291,7 @@ retry_later:
|
||||
}
|
||||
|
||||
void
|
||||
canserial_set_filter(uint32_t id)
|
||||
canbus_set_filter(uint32_t id)
|
||||
{
|
||||
UsbCan.assigned_id = id;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user