sched: Add sched.c and sched.h files to make importing Klipper code easier

Add the sched.c code and associated DECL_INIT(), DECL_TASK() macros so
that it is easier to import low-level Klipper code into the CanBoot
repo.

These additional code wrappers do not increase the overall binary size
as gcc does a good job of inlining the wrappers and removing unused
code during the compile process.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2022-05-10 13:12:57 -04:00 committed by Eric Callahan
parent ae687a404d
commit db6a9b4d96
11 changed files with 143 additions and 32 deletions

View File

@ -10,6 +10,7 @@ FILEHEADER = """
/* DO NOT EDIT! This is an autogenerated file. See scripts/buildcommands.py. */
#include <stdint.h>
#include "board/irq.h"
#include "compiler.h"
"""
@ -19,6 +20,43 @@ def error(msg):
Handlers = []
######################################################################
# C call list generation
######################################################################
# Create dynamic C functions that call a list of other C functions
class HandleCallList:
def __init__(self):
self.call_lists = {'ctr_run_initfuncs': []}
self.ctr_dispatch = { '_DECL_CALLLIST': self.decl_calllist }
def decl_calllist(self, req):
funcname, callname = req.split()[1:]
self.call_lists.setdefault(funcname, []).append(callname)
def update_data_dictionary(self, data):
pass
def generate_code(self, options):
code = []
for funcname, funcs in self.call_lists.items():
func_code = [' extern void %s(void);\n %s();' % (f, f)
for f in funcs]
if funcname == 'ctr_run_taskfuncs':
add_poll = ' irq_poll();\n'
func_code = [add_poll + fc for fc in func_code]
func_code.append(add_poll)
fmt = """
void
%s(void)
{
%s
}
"""
code.append(fmt % (funcname, "\n".join(func_code).strip()))
return "".join(code)
Handlers.append(HandleCallList())
######################################################################
# Enumeration and static string generation
######################################################################

View File

@ -1,3 +1,3 @@
# Main code build rules
src-y += canboot_main.c led.c
src-y += canboot_main.c sched.c led.c

View File

@ -14,6 +14,7 @@
#include "ctr.h" // DECL_CTR
#include "led.h" // check_blink_time
#include "byteorder.h" // cpu_to_le32
#include "sched.h" // sched_run_init
#define PROTO_VERSION 0x00010000 // Version 1.0.0
#define PROTO_SIZE 4
@ -291,12 +292,10 @@ check_double_reset(void)
static void
enter_bootloader(void)
{
can_init();
led_init();
sched_run_init();
for (;;) {
canbus_rx_task();
canbus_tx_task();
sched_run_tasks();
check_blink_time(blink_time);
if (complete && canbus_tx_clear())
// wait until we are complete and the ack has returned

View File

@ -6,6 +6,7 @@
#include "board/internal.h" // __CORTEX_M
#include "irq.h" // irqstatus_t
#include "sched.h" // DECL_SHUTDOWN
void
irq_disable(void)
@ -71,3 +72,4 @@ clear_active_irq(void)
"1:\n"
: "=&r"(temp) : "r"(psr), "r"(0xfffffff9) : "r12", "cc");
}
DECL_SHUTDOWN(clear_active_irq);

View File

@ -10,6 +10,7 @@
#include "byteorder.h" // cpu_to_le32
#include "canbus.h" // canbus_set_uuid
#include "canboot_main.h"
#include "sched.h" // sched_wake_task
static uint32_t canbus_assigned_id;
static uint8_t canbus_uuid[CANBUS_UUID_LEN];
@ -19,7 +20,7 @@ static uint8_t canbus_uuid[CANBUS_UUID_LEN];
* Data transmission over CAN
****************************************************************/
static volatile uint8_t canbus_tx_wake;
static struct task_wake canbus_tx_wake;
static uint8_t transmit_buf[96], transmit_pos, transmit_max;
uint8_t
@ -31,15 +32,14 @@ canbus_tx_clear(void)
void
canbus_notify_tx(void)
{
canbus_tx_wake = 1;
sched_wake_task(&canbus_tx_wake);
}
void
canbus_tx_task(void)
{
if (!canbus_tx_wake)
if (!sched_check_wake(&canbus_tx_wake))
return;
canbus_tx_wake = 0;
uint32_t id = canbus_assigned_id;
if (!id) {
transmit_pos = transmit_max = 0;
@ -57,6 +57,7 @@ canbus_tx_task(void)
}
transmit_pos = tpos;
}
DECL_TASK(canbus_tx_task);
// Encode and transmit a "response" message
void
@ -93,8 +94,8 @@ canboot_sendf(uint8_t* data, uint16_t size)
// Available commands and responses
#define CANBUS_CMD_QUERY_UNASSIGNED 0x00
#define CANBUS_CMD_SET_NODEID_CANBOOT 0x11
#define CANBUS_CMD_CLEAR_NODE_ID_CANBOOT 0x12
#define CANBUS_CMD_SET_CANBOOT_NODEID 0x11
#define CANBUS_CMD_CLEAR_CANBOOT_NODEID 0x12
#define CANBUS_RESP_NEED_NODEID 0x20
// Helper to verify a UUID in a command matches this chip's UUID
@ -118,7 +119,7 @@ can_process_query_unassigned(uint32_t id, uint32_t len, uint8_t *data)
uint8_t send[8];
send[0] = CANBUS_RESP_NEED_NODEID;
memcpy(&send[1], canbus_uuid, sizeof(canbus_uuid));
send[7] = CANBUS_CMD_SET_NODEID_CANBOOT;
send[7] = CANBUS_CMD_SET_CANBOOT_NODEID;
// Send with retry
for (;;) {
int ret = canbus_send(CANBUS_ID_ADMIN_RESP, 8, send);
@ -128,7 +129,7 @@ can_process_query_unassigned(uint32_t id, uint32_t len, uint8_t *data)
}
static void
can_process_clear_node_id(void)
can_process_clear_canboot_nodeid(void)
{
canbus_assigned_id = 0;
canbus_set_filter(canbus_assigned_id);
@ -143,7 +144,7 @@ can_id_conflict(void)
}
static void
can_process_set_nodeid(uint32_t id, uint32_t len, uint8_t *data)
can_process_set_canboot_nodeid(uint32_t id, uint32_t len, uint8_t *data)
{
if (len < 8)
return;
@ -168,11 +169,11 @@ can_process(uint32_t id, uint32_t len, uint8_t *data)
case CANBUS_CMD_QUERY_UNASSIGNED:
can_process_query_unassigned(id, len, data);
break;
case CANBUS_CMD_SET_NODEID_CANBOOT:
can_process_set_nodeid(id, len, data);
case CANBUS_CMD_SET_CANBOOT_NODEID:
can_process_set_canboot_nodeid(id, len, data);
break;
case CANBUS_CMD_CLEAR_NODE_ID_CANBOOT:
can_process_clear_node_id();
case CANBUS_CMD_CLEAR_CANBOOT_NODEID:
can_process_clear_canboot_nodeid();
break;
}
}
@ -182,7 +183,13 @@ can_process(uint32_t id, uint32_t len, uint8_t *data)
* CAN packet reading
****************************************************************/
static volatile uint8_t canbus_rx_wake;
static struct task_wake canbus_rx_wake;
void
canbus_notify_rx(void)
{
sched_wake_task(&canbus_rx_wake);
}
// Handle incoming data (called from IRQ handler)
void
@ -194,19 +201,12 @@ canbus_process_data(uint32_t id, uint32_t len, uint8_t *data)
canbus_notify_rx();
}
void
canbus_notify_rx(void)
{
canbus_rx_wake = 1;
}
// Task to process incoming commands and admin messages
void
canbus_rx_task(void)
{
if (!canbus_rx_wake)
if (!sched_check_wake(&canbus_rx_wake))
return;
canbus_rx_wake = 0;
// Read any pending CAN packets
for (;;) {
@ -221,6 +221,8 @@ canbus_rx_task(void)
can_process(id, ret, data);
}
}
DECL_TASK(canbus_rx_task);
/****************************************************************
* Setup and shutdown
@ -248,3 +250,4 @@ canbus_shutdown(void)
canbus_notify_tx();
canbus_notify_rx();
}
DECL_SHUTDOWN(canbus_shutdown);

View File

@ -12,15 +12,12 @@ int canbus_read(uint32_t *id, uint8_t *data);
int canbus_send(uint32_t id, uint32_t len, uint8_t *data);
void canbus_set_filter(uint32_t id);
void canbus_reboot(void);
void can_init(void);
// canbus.c
void canbus_notify_tx(void);
void canbus_notify_rx(void);
void canbus_process_data(uint32_t id, uint32_t len, uint8_t *data);
void canbus_set_uuid(void *data);
void canbus_tx_task(void);
void canbus_rx_task(void);
uint8_t canbus_tx_clear(void);
#endif // canbus.h

View File

@ -9,6 +9,7 @@
#include "board/misc.h" // timer_read_time
#include "ctr.h" // DECL_CTR
#include "led.h" // check_blink_time
#include "sched.h" // DECL_INIT
DECL_CTR("DECL_LED_PIN " __stringify(CONFIG_STATUS_LED_PIN));
extern uint32_t led_gpio, led_gpio_high; // Generated by buildcommands.py
@ -27,6 +28,7 @@ led_init(void)
udelay(10);
last_blink_time = timer_read_time();
}
DECL_INIT(led_init);
void
check_blink_time(uint32_t usec)

View File

@ -1,7 +1,6 @@
#ifndef __LED_H
#define __LED_H
void led_init();
void check_blink_time(uint32_t usec);
#endif // led.h

41
src/sched.c Normal file
View File

@ -0,0 +1,41 @@
// Basic scheduling functions and startup code
//
// Copyright (C) 2016-2022 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
#include "board/io.h" // readb
#include "sched.h" // sched_check_periodic
// Note that a task is ready to run
void
sched_wake_task(struct task_wake *w)
{
writeb(&w->wake, 1);
}
// Check if a task is ready to run (as indicated by sched_wake_task)
uint8_t
sched_check_wake(struct task_wake *w)
{
if (!readb(&w->wake))
return 0;
writeb(&w->wake, 0);
return 1;
}
void
sched_run_init(void)
{
// Run all init functions marked with DECL_INIT()
extern void ctr_run_initfuncs(void);
ctr_run_initfuncs();
}
void
sched_run_tasks(void)
{
// Run all task functions marked with DECL_TASK()
extern void ctr_run_taskfuncs(void);
ctr_run_taskfuncs();
}

29
src/sched.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef __SCHED_H
#define __SCHED_H
#include <stdint.h> // uint32_t
#include "ctr.h" // DECL_CTR
// Declare an init function (called at firmware startup)
#define DECL_INIT(FUNC) _DECL_CALLLIST(ctr_run_initfuncs, FUNC)
// Declare a task function (called periodically during normal runtime)
#define DECL_TASK(FUNC) _DECL_CALLLIST(ctr_run_taskfuncs, FUNC)
// Declare a shutdown function (called on an emergency stop)
#define DECL_SHUTDOWN(FUNC) _DECL_CALLLIST(ctr_run_shutdownfuncs, FUNC)
// Task waking struct
struct task_wake {
uint8_t wake;
};
// sched.c
void sched_wake_task(struct task_wake *w);
uint8_t sched_check_wake(struct task_wake *w);
void sched_run_init(void);
void sched_run_tasks(void);
// Compiler glue for DECL_X macros above.
#define _DECL_CALLLIST(NAME, FUNC) \
DECL_CTR("_DECL_CALLLIST " __stringify(NAME) " " __stringify(FUNC))
#endif // sched.h

View File

@ -13,7 +13,7 @@
#include "generic/armcm_boot.h" // armcm_enable_irq
#include "generic/canbus.h" // canbus_notify_tx
#include "internal.h" // enable_pclock
#include "ctr.h" // DECL_CONSTANT_STR
#include "sched.h" // DECL_INIT
#if CONFIG_STM32_CANBUS_PA11_PA12 || CONFIG_STM32_CANBUS_PA11_PA12_REMAP
DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PA11,PA12");
@ -317,3 +317,4 @@ can_init(void)
uint64_t hash = fasthash64((uint8_t*)UID_BASE, 12, 0xA16231A7);
canbus_set_uuid(&hash);
}
DECL_INIT(can_init);