build: Define DECL_CONSTANT mechanism for defining exported constants
Add a DECL_CONSTANT macro to allow the firmware to define constants that are to be exported to the host during the "identify" phase. This replaces the existing hardcoded mechanism of scanning the Kconfig header file for certain constants. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
4e8674d5df
commit
fe95ea221b
2
Makefile
2
Makefile
|
@ -88,7 +88,7 @@ $(OUT)klipper.o: $(patsubst %.c, $(OUT)src/%.o,$(src-y)) $(OUT)declfunc.lds
|
||||||
$(OUT)compile_time_request.o: $(OUT)klipper.o ./scripts/buildcommands.py
|
$(OUT)compile_time_request.o: $(OUT)klipper.o ./scripts/buildcommands.py
|
||||||
@echo " Building $@"
|
@echo " Building $@"
|
||||||
$(Q)$(OBJCOPY) -j '.compile_time_request' -O binary $< $(OUT)klipper.o.compile_time_request
|
$(Q)$(OBJCOPY) -j '.compile_time_request' -O binary $< $(OUT)klipper.o.compile_time_request
|
||||||
$(Q)$(PYTHON) ./scripts/buildcommands.py -d $(OUT)klipper.dict $(OUT)klipper.o.compile_time_request $(OUT)autoconf.h $(OUT)compile_time_request.c
|
$(Q)$(PYTHON) ./scripts/buildcommands.py -d $(OUT)klipper.dict $(OUT)klipper.o.compile_time_request $(OUT)compile_time_request.c
|
||||||
$(Q)$(CC) $(CFLAGS) -c $(OUT)compile_time_request.c -o $@
|
$(Q)$(CC) $(CFLAGS) -c $(OUT)compile_time_request.c -o $@
|
||||||
|
|
||||||
$(OUT)klipper.elf: $(OUT)klipper.o $(OUT)compile_time_request.o
|
$(OUT)klipper.elf: $(OUT)klipper.o $(OUT)compile_time_request.o
|
||||||
|
|
|
@ -109,6 +109,19 @@ to generate and format arbitrary messages for human consumption. It is
|
||||||
a wrapper around sendf() and as with sendf() it should not be called
|
a wrapper around sendf() and as with sendf() it should not be called
|
||||||
from interrupts or timers.
|
from interrupts or timers.
|
||||||
|
|
||||||
|
Declaring constants
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The firmware can also define constants to be exported. For example,
|
||||||
|
the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
DECL_CONSTANT(SERIAL_BAUD, 250000);
|
||||||
|
```
|
||||||
|
|
||||||
|
would export a constant named "SERIAL_BAUD" with a value of 250000
|
||||||
|
from the firmware to the host.
|
||||||
|
|
||||||
Low-level message encoding
|
Low-level message encoding
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
@ -262,8 +275,8 @@ dictionary. Once all chunks are obtained the host will assemble the
|
||||||
chunks, uncompress the data, and parse the contents.
|
chunks, uncompress the data, and parse the contents.
|
||||||
|
|
||||||
In addition to information on the communication protocol, the data
|
In addition to information on the communication protocol, the data
|
||||||
dictionary also contains firmware version, configuration, and other
|
dictionary also contains firmware version, constants (as defined by
|
||||||
useful information.
|
DECL_CONSTANT), and static strings.
|
||||||
|
|
||||||
Static Strings
|
Static Strings
|
||||||
--------------
|
--------------
|
||||||
|
|
|
@ -27,7 +27,7 @@ class KeyboardReader:
|
||||||
self.reactor.unregister_timer(self.connect_timer)
|
self.reactor.unregister_timer(self.connect_timer)
|
||||||
return self.reactor.NEVER
|
return self.reactor.NEVER
|
||||||
def update_evals(self, eventtime):
|
def update_evals(self, eventtime):
|
||||||
f = self.ser.msgparser.config.get('CLOCK_FREQ', 1)
|
f = int(self.ser.msgparser.config.get('CLOCK_FREQ', 1))
|
||||||
c = self.ser.get_clock(eventtime)
|
c = self.ser.get_clock(eventtime)
|
||||||
self.eval_globals['freq'] = f
|
self.eval_globals['freq'] = f
|
||||||
self.eval_globals['clock'] = int(c)
|
self.eval_globals['clock'] = int(c)
|
||||||
|
|
|
@ -101,7 +101,7 @@ class SerialReader:
|
||||||
self.msgparser.process_identify(dictionary, decompress=False)
|
self.msgparser.process_identify(dictionary, decompress=False)
|
||||||
est_clock = 1000000000000.
|
est_clock = 1000000000000.
|
||||||
if pace:
|
if pace:
|
||||||
est_clock = self.msgparser.config['CLOCK_FREQ']
|
est_clock = float(self.msgparser.config['CLOCK_FREQ'])
|
||||||
self.serialqueue = self.ffi_lib.serialqueue_alloc(self.ser.fileno(), 1)
|
self.serialqueue = self.ffi_lib.serialqueue_alloc(self.ser.fileno(), 1)
|
||||||
self.est_clock = est_clock
|
self.est_clock = est_clock
|
||||||
self.last_ack_time = time.time()
|
self.last_ack_time = time.time()
|
||||||
|
|
|
@ -21,25 +21,6 @@ def error(msg):
|
||||||
sys.stderr.write(msg + "\n")
|
sys.stderr.write(msg + "\n")
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
# Parser for constants in simple C header files.
|
|
||||||
def scan_config(file):
|
|
||||||
f = open(file, 'r')
|
|
||||||
opts = {}
|
|
||||||
for l in f.readlines():
|
|
||||||
parts = l.split()
|
|
||||||
if len(parts) != 3:
|
|
||||||
continue
|
|
||||||
if parts[0] != '#define':
|
|
||||||
continue
|
|
||||||
value = parts[2]
|
|
||||||
if value.isdigit() or (value.startswith('0x') and value[2:].isdigit()):
|
|
||||||
value = int(value, 0)
|
|
||||||
elif value.startswith('"'):
|
|
||||||
value = value[1:-1]
|
|
||||||
opts[parts[1]] = value
|
|
||||||
f.close()
|
|
||||||
return opts
|
|
||||||
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Command and output parser generation
|
# Command and output parser generation
|
||||||
|
@ -145,7 +126,7 @@ const uint8_t command_index_size PROGMEM = ARRAY_SIZE(command_index);
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def build_identify(cmd_by_id, msg_to_id, responses, static_strings
|
def build_identify(cmd_by_id, msg_to_id, responses, static_strings
|
||||||
, config, version):
|
, constants, version):
|
||||||
#commands, messages, static_strings
|
#commands, messages, static_strings
|
||||||
messages = dict((msgid, msg) for msg, msgid in msg_to_id.items())
|
messages = dict((msgid, msg) for msg, msgid in msg_to_id.items())
|
||||||
data = {}
|
data = {}
|
||||||
|
@ -153,9 +134,7 @@ def build_identify(cmd_by_id, msg_to_id, responses, static_strings
|
||||||
data['commands'] = sorted(cmd_by_id.keys())
|
data['commands'] = sorted(cmd_by_id.keys())
|
||||||
data['responses'] = sorted(responses)
|
data['responses'] = sorted(responses)
|
||||||
data['static_strings'] = static_strings
|
data['static_strings'] = static_strings
|
||||||
configlist = ['MCU', 'CLOCK_FREQ', 'SERIAL_BAUD']
|
data['config'] = constants
|
||||||
data['config'] = dict((i, config['CONFIG_'+i]) for i in configlist
|
|
||||||
if 'CONFIG_'+i in config)
|
|
||||||
data['version'] = version
|
data['version'] = version
|
||||||
|
|
||||||
# Format compressed info into C code
|
# Format compressed info into C code
|
||||||
|
@ -223,7 +202,7 @@ def build_version(extra):
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
usage = "%prog [options] <cmd section file> <autoconf.h> <output.c>"
|
usage = "%prog [options] <cmd section file> <output.c>"
|
||||||
opts = optparse.OptionParser(usage)
|
opts = optparse.OptionParser(usage)
|
||||||
opts.add_option("-e", "--extra", dest="extra", default="",
|
opts.add_option("-e", "--extra", dest="extra", default="",
|
||||||
help="extra version string to append to version")
|
help="extra version string to append to version")
|
||||||
|
@ -233,9 +212,9 @@ def main():
|
||||||
help="enable debug messages")
|
help="enable debug messages")
|
||||||
|
|
||||||
options, args = opts.parse_args()
|
options, args = opts.parse_args()
|
||||||
if len(args) != 3:
|
if len(args) != 2:
|
||||||
opts.error("Incorrect arguments")
|
opts.error("Incorrect arguments")
|
||||||
incmdfile, inheader, outcfile = args
|
incmdfile, outcfile = args
|
||||||
if options.verbose:
|
if options.verbose:
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
|
||||||
|
@ -245,6 +224,7 @@ def main():
|
||||||
for m in msgproto.DefaultMessages.values())
|
for m in msgproto.DefaultMessages.values())
|
||||||
parsers = []
|
parsers = []
|
||||||
static_strings = []
|
static_strings = []
|
||||||
|
constants = {}
|
||||||
# Parse request file
|
# Parse request file
|
||||||
f = open(incmdfile, 'rb')
|
f = open(incmdfile, 'rb')
|
||||||
data = f.read()
|
data = f.read()
|
||||||
|
@ -280,6 +260,14 @@ def main():
|
||||||
parsers.append((None, msg))
|
parsers.append((None, msg))
|
||||||
elif cmd == '_DECL_STATIC_STR':
|
elif cmd == '_DECL_STATIC_STR':
|
||||||
static_strings.append(req[17:])
|
static_strings.append(req[17:])
|
||||||
|
elif cmd == '_DECL_CONSTANT':
|
||||||
|
name, value = parts[1:]
|
||||||
|
value = value.strip()
|
||||||
|
if value.startswith('"') and value.endswith('"'):
|
||||||
|
value = value[1:-1]
|
||||||
|
if name in constants and constants[name] != value:
|
||||||
|
error("Conflicting definition for constant '%s'" % name)
|
||||||
|
constants[name] = value
|
||||||
else:
|
else:
|
||||||
error("Unknown build time command '%s'" % cmd)
|
error("Unknown build time command '%s'" % cmd)
|
||||||
# Create unique ids for each message type
|
# Create unique ids for each message type
|
||||||
|
@ -299,13 +287,12 @@ def main():
|
||||||
cmdcode = build_commands(cmd_by_id, messages_by_name, all_param_types)
|
cmdcode = build_commands(cmd_by_id, messages_by_name, all_param_types)
|
||||||
paramcode = build_param_types(all_param_types)
|
paramcode = build_param_types(all_param_types)
|
||||||
# Create identify information
|
# Create identify information
|
||||||
config = scan_config(inheader)
|
|
||||||
version = build_version(options.extra)
|
version = build_version(options.extra)
|
||||||
sys.stdout.write("Version: %s\n" % (version,))
|
sys.stdout.write("Version: %s\n" % (version,))
|
||||||
responses = [msg_to_id[msg] for msgname, msg in messages_by_name.items()
|
responses = [msg_to_id[msg] for msgname, msg in messages_by_name.items()
|
||||||
if msgname not in commands]
|
if msgname not in commands]
|
||||||
datadict, icode = build_identify(cmd_by_id, msg_to_id, responses
|
datadict, icode = build_identify(cmd_by_id, msg_to_id, responses
|
||||||
, static_strings, config, version)
|
, static_strings, constants, version)
|
||||||
# Write output
|
# Write output
|
||||||
f = open(outcfile, 'wb')
|
f = open(outcfile, 'wb')
|
||||||
f.write(FILEHEADER + paramcode + parsercode + cmdcode + icode)
|
f.write(FILEHEADER + paramcode + parsercode + cmdcode + icode)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "autoconf.h" // CONFIG_SERIAL_BAUD
|
#include "autoconf.h" // CONFIG_SERIAL_BAUD
|
||||||
#include "board/io.h" // readb
|
#include "board/io.h" // readb
|
||||||
#include "board/misc.h" // console_get_input
|
#include "board/misc.h" // console_get_input
|
||||||
|
#include "command.h" // DECL_CONSTANT
|
||||||
#include "sched.h" // DECL_INIT
|
#include "sched.h" // DECL_INIT
|
||||||
#include "irq.h" // irq_save
|
#include "irq.h" // irq_save
|
||||||
|
|
||||||
|
@ -22,6 +23,8 @@ static uint8_t transmit_pos, transmit_max;
|
||||||
* Serial hardware
|
* Serial hardware
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
|
DECL_CONSTANT(SERIAL_BAUD, CONFIG_SERIAL_BAUD);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
serial_init(void)
|
serial_init(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
* Low level timer code
|
* Low level timer code
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
|
DECL_CONSTANT(CLOCK_FREQ, F_CPU);
|
||||||
|
DECL_CONSTANT(MCU, CONFIG_MCU);
|
||||||
|
|
||||||
// Return the number of clock ticks for a given number of microseconds
|
// Return the number of clock ticks for a given number of microseconds
|
||||||
uint32_t
|
uint32_t
|
||||||
timer_from_us(uint32_t us)
|
timer_from_us(uint32_t us)
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
// Flags for command handler declarations.
|
// Flags for command handler declarations.
|
||||||
#define HF_IN_SHUTDOWN 0x01 // Handler can run even when in emergency stop
|
#define HF_IN_SHUTDOWN 0x01 // Handler can run even when in emergency stop
|
||||||
|
|
||||||
|
// Declare a constant exported to the host
|
||||||
|
#define DECL_CONSTANT(NAME, VALUE) \
|
||||||
|
_DECL_CONSTANT(NAME, VALUE)
|
||||||
|
|
||||||
// Send an output message (and declare a static message type for it)
|
// Send an output message (and declare a static message type for it)
|
||||||
#define output(FMT, args...) \
|
#define output(FMT, args...) \
|
||||||
_sendf(_DECL_OUTPUT(FMT) , ##args )
|
_sendf(_DECL_OUTPUT(FMT) , ##args )
|
||||||
|
@ -59,6 +63,11 @@ extern const uint32_t command_identify_size;
|
||||||
= "_DECL_COMMAND " __stringify(FUNC) " " __stringify(FLAGS) " " MSG; \
|
= "_DECL_COMMAND " __stringify(FUNC) " " __stringify(FLAGS) " " MSG; \
|
||||||
void __visible FUNC(uint32_t*)
|
void __visible FUNC(uint32_t*)
|
||||||
|
|
||||||
|
#define _DECL_CONSTANT(NAME, VALUE) \
|
||||||
|
char __PASTE(_DECLC_ ## NAME ## _, __LINE__) [] \
|
||||||
|
__visible __section(".compile_time_request") \
|
||||||
|
= "_DECL_CONSTANT " __stringify(NAME) " " __stringify(VALUE)
|
||||||
|
|
||||||
// Create a compile time request and return a unique (incrementing id)
|
// Create a compile time request and return a unique (incrementing id)
|
||||||
// for that request.
|
// for that request.
|
||||||
#define _DECL_REQUEST_ID(REQUEST, ID_SECTION) ({ \
|
#define _DECL_REQUEST_ID(REQUEST, ID_SECTION) ({ \
|
||||||
|
|
|
@ -6,10 +6,6 @@ config BOARD_DIRECTORY
|
||||||
string
|
string
|
||||||
default "sam3x8e"
|
default "sam3x8e"
|
||||||
|
|
||||||
config MCU
|
|
||||||
string
|
|
||||||
default "sam3x8e"
|
|
||||||
|
|
||||||
config CLOCK_FREQ
|
config CLOCK_FREQ
|
||||||
int
|
int
|
||||||
default 42000000 # 84000000/2
|
default 42000000 # 84000000/2
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "board/gpio.h" // gpio_peripheral
|
#include "board/gpio.h" // gpio_peripheral
|
||||||
#include "board/io.h" // readb
|
#include "board/io.h" // readb
|
||||||
#include "board/misc.h" // console_get_input
|
#include "board/misc.h" // console_get_input
|
||||||
|
#include "command.h" // DECL_CONSTANT
|
||||||
#include "sam3x8e.h" // UART
|
#include "sam3x8e.h" // UART
|
||||||
#include "sched.h" // DECL_INIT
|
#include "sched.h" // DECL_INIT
|
||||||
#include "irq.h" // irq_save
|
#include "irq.h" // irq_save
|
||||||
|
@ -24,6 +25,8 @@ static uint32_t transmit_pos, transmit_max;
|
||||||
* Serial hardware
|
* Serial hardware
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
|
DECL_CONSTANT(SERIAL_BAUD, CONFIG_SERIAL_BAUD);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
serial_init(void)
|
serial_init(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
* Low level timer code
|
* Low level timer code
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
|
DECL_CONSTANT(CLOCK_FREQ, CONFIG_CLOCK_FREQ);
|
||||||
|
DECL_CONSTANT(MCU, "sam3x8e");
|
||||||
|
|
||||||
// Return the number of clock ticks for a given number of microseconds
|
// Return the number of clock ticks for a given number of microseconds
|
||||||
uint32_t
|
uint32_t
|
||||||
timer_from_us(uint32_t us)
|
timer_from_us(uint32_t us)
|
||||||
|
|
Loading…
Reference in New Issue