mirror of
https://github.com/candle-usb/candleLight_fw.git
synced 2025-01-28 06:02:52 +08:00
queue: convert to Linux compatible list implementation
Convert from the queue implementation to a Linux compatible list implementation. Get rid of This way we can avoid dynamic memory allocation altogether. As the struct gs_host_frame is not placed into the data segment, requirements for the static memory grows. On the low end processors the heap reserved in the linker file is too big, resulting in a linker error. On STM32F042 and STM32F072 set a HEAP size of 0 bytes.
This commit is contained in:
parent
57d9900f5b
commit
35d6cb8941
@ -170,7 +170,7 @@ populate_ldscript(CPU_FAMILY STM32F042X6
|
||||
RAM_START 0x20000000
|
||||
RAM_SIZE 6k
|
||||
STACK_SIZE 1k
|
||||
HEAP_SIZE 1k
|
||||
HEAP_SIZE 0k
|
||||
)
|
||||
|
||||
populate_ldscript(CPU_FAMILY STM32F072XB
|
||||
@ -179,7 +179,7 @@ populate_ldscript(CPU_FAMILY STM32F072XB
|
||||
RAM_START 0x20000000
|
||||
RAM_SIZE 16k
|
||||
STACK_SIZE 2k
|
||||
HEAP_SIZE 1k
|
||||
HEAP_SIZE 0k
|
||||
)
|
||||
|
||||
populate_ldscript(CPU_FAMILY STM32F407XE
|
||||
|
@ -33,7 +33,7 @@ THE SOFTWARE.
|
||||
#include "config.h"
|
||||
#include "gs_usb.h"
|
||||
#include "led.h"
|
||||
#include "queue.h"
|
||||
#include "list.h"
|
||||
#include "usbd_def.h"
|
||||
|
||||
/* Define these here so they can be referenced in other files */
|
||||
@ -48,6 +48,11 @@ THE SOFTWARE.
|
||||
|
||||
extern USBD_ClassTypeDef USBD_GS_CAN;
|
||||
|
||||
struct gs_host_frame_object {
|
||||
struct list_head list;
|
||||
struct gs_host_frame frame;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t ep0_buf[CAN_CMD_PACKET_SIZE];
|
||||
|
||||
@ -55,10 +60,11 @@ typedef struct {
|
||||
|
||||
USBD_SetupReqTypedef last_setup_request;
|
||||
|
||||
queue_t *q_frame_pool;
|
||||
queue_t *q_from_host;
|
||||
struct list_head list_frame_pool;
|
||||
struct list_head list_from_host;
|
||||
struct list_head list_to_host;
|
||||
|
||||
struct gs_host_frame *from_host_buf;
|
||||
struct gs_host_frame_object *from_host_buf;
|
||||
|
||||
can_data_t channels[NUM_CAN_CHANNEL];
|
||||
|
||||
@ -70,7 +76,7 @@ typedef struct {
|
||||
|
||||
bool pad_pkts_to_max_pkt_size;
|
||||
|
||||
struct gs_host_frame msgbuf[CAN_QUEUE_SIZE];
|
||||
struct gs_host_frame_object msgbuf[CAN_QUEUE_SIZE];
|
||||
} USBD_GS_CAN_HandleTypeDef __attribute__ ((aligned (4)));
|
||||
|
||||
#if defined(STM32F0)
|
||||
@ -86,7 +92,7 @@ typedef struct {
|
||||
# define USB_RX_FIFO_SIZE ((256U / 4U) + 1U)
|
||||
#endif
|
||||
|
||||
uint8_t USBD_GS_CAN_Init(USBD_GS_CAN_HandleTypeDef *hcan, USBD_HandleTypeDef *pdev, queue_t *q_frame_pool, queue_t *q_from_host, led_data_t *leds);
|
||||
uint8_t USBD_GS_CAN_Init(USBD_GS_CAN_HandleTypeDef *hcan, USBD_HandleTypeDef *pdev, led_data_t *leds);
|
||||
void USBD_GS_CAN_SuspendCallback(USBD_HandleTypeDef *pdev);
|
||||
void USBD_GS_CAN_ResumeCallback(USBD_HandleTypeDef *pdev);
|
||||
bool USBD_GS_CAN_TxReady(USBD_HandleTypeDef *pdev);
|
||||
|
100
src/main.c
100
src/main.c
@ -35,7 +35,6 @@ THE SOFTWARE.
|
||||
#include "gs_usb.h"
|
||||
#include "hal_include.h"
|
||||
#include "led.h"
|
||||
#include "queue.h"
|
||||
#include "timer.h"
|
||||
#include "usbd_conf.h"
|
||||
#include "usbd_core.h"
|
||||
@ -52,10 +51,6 @@ static USBD_GS_CAN_HandleTypeDef hGS_CAN;
|
||||
static USBD_HandleTypeDef hUSB = {0};
|
||||
static led_data_t hLED = {0};
|
||||
|
||||
static queue_t *q_frame_pool = NULL;
|
||||
static queue_t *q_from_host = NULL;
|
||||
static queue_t *q_to_host = NULL;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
can_data_t *channel = &hGS_CAN.channels[0];
|
||||
@ -82,19 +77,17 @@ int main(void)
|
||||
can_init(channel, CAN_INTERFACE);
|
||||
can_disable(channel);
|
||||
|
||||
INIT_LIST_HEAD(&hGS_CAN.list_frame_pool);
|
||||
INIT_LIST_HEAD(&hGS_CAN.list_from_host);
|
||||
INIT_LIST_HEAD(&hGS_CAN.list_to_host);
|
||||
|
||||
q_frame_pool = queue_create(CAN_QUEUE_SIZE);
|
||||
q_from_host = queue_create(CAN_QUEUE_SIZE);
|
||||
q_to_host = queue_create(CAN_QUEUE_SIZE);
|
||||
assert_basic(q_frame_pool && q_from_host && q_to_host);
|
||||
|
||||
for (unsigned i=0; i<CAN_QUEUE_SIZE; i++) {
|
||||
queue_push_back(q_frame_pool, &hGS_CAN.msgbuf[i]);
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(hGS_CAN.msgbuf); i++) {
|
||||
list_add_tail(&hGS_CAN.msgbuf[i].list, &hGS_CAN.list_frame_pool);
|
||||
}
|
||||
|
||||
USBD_Init(&hUSB, (USBD_DescriptorsTypeDef*)&FS_Desc, DEVICE_FS);
|
||||
USBD_RegisterClass(&hUSB, &USBD_GS_CAN);
|
||||
USBD_GS_CAN_Init(&hGS_CAN, &hUSB, q_frame_pool, q_from_host, &hLED);
|
||||
USBD_GS_CAN_Init(&hGS_CAN, &hUSB, &hLED);
|
||||
USBD_Start(&hUSB);
|
||||
|
||||
#ifdef CAN_S_GPIO_Port
|
||||
@ -102,19 +95,32 @@ int main(void)
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
struct gs_host_frame *frame = queue_pop_front(hGS_CAN.q_from_host);
|
||||
if (frame != 0) { // send can message from host
|
||||
struct gs_host_frame_object *frame_object;
|
||||
|
||||
bool was_irq_enabled = disable_irq();
|
||||
frame_object = list_first_entry_or_null(&hGS_CAN.list_from_host,
|
||||
struct gs_host_frame_object,
|
||||
list);
|
||||
if (frame_object) { // send CAN message from host
|
||||
struct gs_host_frame *frame = &frame_object->frame;
|
||||
|
||||
list_del(&frame_object->list);
|
||||
restore_irq(was_irq_enabled);
|
||||
|
||||
if (can_send(channel, frame)) {
|
||||
// Echo sent frame back to host
|
||||
frame->flags = 0x0;
|
||||
frame->reserved = 0x0;
|
||||
frame->timestamp_us = timer_get();
|
||||
queue_push_back(q_to_host, frame);
|
||||
|
||||
list_add_tail_locked(&frame_object->list, &hGS_CAN.list_to_host);
|
||||
|
||||
led_indicate_trx(&hLED, led_tx);
|
||||
} else {
|
||||
queue_push_front(hGS_CAN.q_from_host, frame); // retry later
|
||||
list_add_locked(&frame_object->list, &hGS_CAN.list_from_host);
|
||||
}
|
||||
} else {
|
||||
restore_irq(was_irq_enabled);
|
||||
}
|
||||
|
||||
if (USBD_GS_CAN_TxReady(&hUSB)) {
|
||||
@ -122,9 +128,16 @@ int main(void)
|
||||
}
|
||||
|
||||
if (can_is_rx_pending(channel)) {
|
||||
struct gs_host_frame *frame = queue_pop_front(hGS_CAN.q_frame_pool);
|
||||
if (frame != 0)
|
||||
{
|
||||
bool was_irq_enabled = disable_irq();
|
||||
frame_object = list_first_entry_or_null(&hGS_CAN.list_frame_pool,
|
||||
struct gs_host_frame_object,
|
||||
list);
|
||||
if (frame_object) {
|
||||
struct gs_host_frame *frame = &frame_object->frame;
|
||||
|
||||
list_del(&frame_object->list);
|
||||
restore_irq(was_irq_enabled);
|
||||
|
||||
if (can_receive(channel, frame)) {
|
||||
|
||||
frame->timestamp_us = timer_get();
|
||||
@ -133,14 +146,14 @@ int main(void)
|
||||
frame->flags = 0;
|
||||
frame->reserved = 0;
|
||||
|
||||
queue_push_back(q_to_host, frame);
|
||||
list_add_tail_locked(&frame_object->list, &hGS_CAN.list_to_host);
|
||||
|
||||
led_indicate_trx(&hLED, led_rx);
|
||||
} else {
|
||||
list_add_tail_locked(&frame_object->list, &hGS_CAN.list_frame_pool);
|
||||
}
|
||||
else
|
||||
{
|
||||
queue_push_back(hGS_CAN.q_frame_pool, frame);
|
||||
}
|
||||
} else {
|
||||
restore_irq(was_irq_enabled);
|
||||
}
|
||||
// If there are frames to receive, don't report any error frames. The
|
||||
// best we can localize the errors to is "after the last successfully
|
||||
@ -148,16 +161,27 @@ int main(void)
|
||||
// to report even if multiple pass by.
|
||||
} else {
|
||||
uint32_t can_err = can_get_error_status(channel);
|
||||
struct gs_host_frame *frame = queue_pop_front(hGS_CAN.q_frame_pool);
|
||||
|
||||
if (frame != 0) {
|
||||
bool was_irq_enabled = disable_irq();
|
||||
frame_object = list_first_entry_or_null(&hGS_CAN.list_frame_pool,
|
||||
struct gs_host_frame_object,
|
||||
list);
|
||||
if (frame_object) {
|
||||
struct gs_host_frame *frame = &frame_object->frame;
|
||||
|
||||
list_del(&frame_object->list);
|
||||
restore_irq(was_irq_enabled);
|
||||
|
||||
frame->timestamp_us = timer_get();
|
||||
if (can_parse_error_status(can_err, last_can_error_status, channel, frame)) {
|
||||
queue_push_back(q_to_host, frame);
|
||||
list_add_tail_locked(&frame_object->list, &hGS_CAN.list_to_host);
|
||||
|
||||
last_can_error_status = can_err;
|
||||
} else {
|
||||
queue_push_back(hGS_CAN.q_frame_pool, frame);
|
||||
list_add_tail_locked(&frame_object->list, &hGS_CAN.list_frame_pool);
|
||||
}
|
||||
} else {
|
||||
restore_irq(was_irq_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,14 +307,22 @@ void SystemClock_Config(void)
|
||||
|
||||
void send_to_host(void)
|
||||
{
|
||||
struct gs_host_frame *frame = queue_pop_front(q_to_host);
|
||||
struct gs_host_frame_object *frame_object;
|
||||
|
||||
if (!frame)
|
||||
bool was_irq_enabled = disable_irq();
|
||||
frame_object = list_first_entry_or_null(&hGS_CAN.list_to_host,
|
||||
struct gs_host_frame_object,
|
||||
list);
|
||||
if (!frame_object) {
|
||||
restore_irq(was_irq_enabled);
|
||||
return;
|
||||
}
|
||||
list_del(&frame_object->list);
|
||||
restore_irq(was_irq_enabled);
|
||||
|
||||
if (USBD_GS_CAN_SendFrame(&hUSB, frame) == USBD_OK) {
|
||||
queue_push_back(hGS_CAN.q_frame_pool, frame);
|
||||
if (USBD_GS_CAN_SendFrame(&hUSB, &frame_object->frame) == USBD_OK) {
|
||||
list_add_tail_locked(&frame_object->list, &hGS_CAN.list_frame_pool);
|
||||
} else {
|
||||
queue_push_front(q_to_host, frame);
|
||||
list_add_locked(&frame_object->list, &hGS_CAN.list_to_host);
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ THE SOFTWARE.
|
||||
#include "gs_usb.h"
|
||||
#include "hal_include.h"
|
||||
#include "led.h"
|
||||
#include "queue.h"
|
||||
#include "timer.h"
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_ctlreq.h"
|
||||
@ -268,7 +267,9 @@ static const struct gs_device_bt_const USBD_GS_CAN_btconst = {
|
||||
static inline uint8_t USBD_GS_CAN_PrepareReceive(USBD_HandleTypeDef *pdev)
|
||||
{
|
||||
USBD_GS_CAN_HandleTypeDef *hcan = (USBD_GS_CAN_HandleTypeDef*)pdev->pClassData;
|
||||
return USBD_LL_PrepareReceive(pdev, GSUSB_ENDPOINT_OUT, (uint8_t*)hcan->from_host_buf, sizeof(*hcan->from_host_buf));
|
||||
struct gs_host_frame *frame = &hcan->from_host_buf->frame;
|
||||
|
||||
return USBD_LL_PrepareReceive(pdev, GSUSB_ENDPOINT_OUT, (uint8_t *)frame, sizeof(*frame));
|
||||
}
|
||||
|
||||
/* It's unclear from the documentation, but it appears that the USB library is
|
||||
@ -280,13 +281,10 @@ static inline uint8_t USBD_GS_CAN_PrepareReceive(USBD_HandleTypeDef *pdev)
|
||||
* within other calls, which means the USB interrupt is already disabled and we
|
||||
* don't have any other interrupts to worry about. */
|
||||
|
||||
uint8_t USBD_GS_CAN_Init(USBD_GS_CAN_HandleTypeDef *hcan, USBD_HandleTypeDef *pdev, queue_t *q_frame_pool, queue_t *q_from_host, led_data_t *leds)
|
||||
uint8_t USBD_GS_CAN_Init(USBD_GS_CAN_HandleTypeDef *hcan, USBD_HandleTypeDef *pdev, led_data_t *leds)
|
||||
{
|
||||
hcan->q_frame_pool = q_frame_pool;
|
||||
hcan->q_from_host = q_from_host;
|
||||
hcan->leds = leds;
|
||||
pdev->pClassData = hcan;
|
||||
hcan->from_host_buf = NULL;
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
@ -600,14 +598,23 @@ static uint8_t USBD_GS_CAN_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) {
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
bool was_irq_enabled = disable_irq();
|
||||
// Enqueue the frame we just received.
|
||||
queue_push_back(hcan->q_from_host, hcan->from_host_buf);
|
||||
list_add_tail(&hcan->from_host_buf->list, &hcan->list_from_host);
|
||||
|
||||
// Grab a buffer for the next frame from the pool.
|
||||
hcan->from_host_buf = queue_pop_front(hcan->q_frame_pool);
|
||||
hcan->from_host_buf = list_first_entry_or_null(&hcan->list_frame_pool,
|
||||
struct gs_host_frame_object,
|
||||
list);
|
||||
if (hcan->from_host_buf) {
|
||||
list_del(&hcan->from_host_buf->list);
|
||||
restore_irq(was_irq_enabled);
|
||||
|
||||
// We got a buffer! Get ready to receive from the USB host into it.
|
||||
USBD_GS_CAN_PrepareReceive(pdev);
|
||||
} else {
|
||||
restore_irq(was_irq_enabled);
|
||||
|
||||
// gs_can has no way to drop packets. If we just drop this one, gs_can
|
||||
// will fill up its queue of packets awaiting ACKs and then hang. Instead,
|
||||
// wait to call PrepareReceive until we have a frame to receive into.
|
||||
@ -627,8 +634,11 @@ bool USBD_GS_CAN_TxReady(USBD_HandleTypeDef *pdev)
|
||||
USBD_GS_CAN_HandleTypeDef *hcan = (USBD_GS_CAN_HandleTypeDef*)pdev->pClassData;
|
||||
bool was_irq_enabled = disable_irq();
|
||||
if (!hcan->from_host_buf) {
|
||||
hcan->from_host_buf = queue_pop_front(hcan->q_frame_pool);
|
||||
hcan->from_host_buf = list_first_entry_or_null(&hcan->list_frame_pool,
|
||||
struct gs_host_frame_object,
|
||||
list);
|
||||
if (hcan->from_host_buf) {
|
||||
list_del(&hcan->from_host_buf->list);
|
||||
USBD_GS_CAN_PrepareReceive(pdev);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user