Ver código fonte

sysvars: move to common

Move the sysvars to common, to make it easy to forward
configuration from esp32 to rv32.
H. Peter Anvin 1 ano atrás
pai
commit
8c862390d1

+ 3 - 3
Makefile

@@ -1,7 +1,7 @@
 MAKEFLAGS += -R -r
 
 PROJECT   := max80
-SUBDIRS   := esp32 tools rv32 fpga
+SUBDIRS   := common esp32 tools rv32 fpga
 REVISIONS := v1 v2 bypass
 
 GIT_DIR   ?= .git
@@ -49,9 +49,9 @@ version: version.mk version.h version.vh
 
 $(SUBDIRS): version.mk
 
-esp32: version.h
+esp32: version.h | common
 
-rv32: version.h | tools
+rv32: version.h | common tools
 
 fpga: version.vh | rv32 esp32
 

+ 0 - 0
esp32/max80/sysvars.c → common/sysvars.c


+ 0 - 0
esp32/max80/sysvars.h → common/sysvars.h


+ 0 - 0
esp32/sysvars.vars → common/sysvars.vars


+ 10 - 6
esp32/Makefile

@@ -6,11 +6,12 @@ PERL	      = perl
 
 SKETCH	      = max80
 TARGET	      = output/$(SKETCH).ino.bin
-GENFILES      = www.zip $(SKETCH)/sysvars_gen.c $(SKETCH)/sysvars_gen.h
+fromcommon   := $(patsubst ../common/%,$(SKETCH)/src/common/%,$(wildcard ../common/*.[ch]))
+GENFILES      = www.zip
 WWW	      = www
 PORT	     ?= /dev/ttyACM0
 
-build_defines = -DBOARD_HAS_PSRAM -I$(realpath ../common)
+build_defines = -DBOARD_HAS_PSRAM -I. -Isrc/common
 
 BOARD	      = esp32:esp32:esp32s2usb
 ARDUINO_OPTS  = -b $(BOARD) \
@@ -31,13 +32,16 @@ properties:
 	cd $(SKETCH) && \
 		$(ARDUINO_CLI) compile --show-properties $(ARDUINO_OPTS)
 
-$(TARGET): $(shell find $(SKETCH) -type f) $(GENFILES)
+$(TARGET): $(shell find $(SKETCH) -type f) $(GENFILES) $(fromcommon)
 	mkdir -p build output cache
 	cd $(SKETCH) && \
 		$(ARDUINO_CLI) compile $(ARDUINO_OPTS)
 
-$(SKETCH)/%_gen.c $(SKETCH)/%_gen.h: %.vars sysvars.pl
-	$(PERL) sysvars.pl $< $(SKETCH)/$*_gen.h $(SKETCH)/$*_gen.c
+common_dir:
+	mkdir -p $(SKETCH)/src/common
+
+$(SKETCH)/src/common/%: ../common/% | common_dir
+	cp -f $< $@
 
 .PHONY: zip
 zip: zipexclude
@@ -60,7 +64,7 @@ upload: $(TARGET)
 	$(ARDUINO_CLI) upload -i $(TARGET) -p $(PORT) -b $(BOARD) $(SKETCH)
 
 clean:
-	rm -rf build cache zip $(GENFILES)
+	rm -rf build cache zip $(GENFILES) $(SKETCH)/src/common
 
 spotless: clean
 	rm -rf output

+ 0 - 1
esp32/max80/matchver_esp.c

@@ -1 +0,0 @@
-#include "matchver.c"

BIN
esp32/output/max80.ino.bin


BIN
fpga/output/max80.fw


BIN
fpga/output/v1.fw


BIN
fpga/output/v2.fw


+ 419 - 0
sysvars.c

@@ -0,0 +1,419 @@
+#include "common.h"
+#include "sysvars.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+
+#define DEBUG 1
+
+#ifndef DEBUG
+# define DEBUG 0
+#endif
+
+static const char *sysvar_bool_tostr(sysvar_t from, char *buf)
+{
+    buf[0] = '0' + from.v_bool;
+    buf[1] = '\0';
+    return buf;
+}
+
+static bool sysvar_bool_fromstr(sysvar_t *to, const char *from)
+{
+    char c = from[0] | 0x20;
+    switch (c) {
+    case '1':
+    case 't':
+    case 'y':
+    case 'j':
+    case 's':
+	to->v_bool = true;
+	return true;
+    case ' ':			/* Blank or null */
+    case '0':
+    case 'f':
+    case 'n':
+	to->v_bool = false;
+	return true;
+    default:
+	return false;
+    }
+}
+
+const struct sysvar_ops sysvar_bool_ops = {
+    .tostr = sysvar_bool_tostr,
+    .fromstr = sysvar_bool_fromstr,
+    .buflen = BOOL_BUFLEN
+};
+
+static const char *sysvar_int_tostr(sysvar_t from, char *buf)
+{
+    snprintf(buf, INT_BUFLEN, "%ld", from.v_int);
+    return buf;
+}
+
+static bool sysvar_int_fromstr(sysvar_t *to, const char *from)
+{
+    char *ep;
+    long v = strtol(from, &ep, 0);
+    if (ep == from || *ep)
+	return false;
+    to->v_int = v;
+    return true;
+}
+
+const struct sysvar_ops sysvar_int_ops = {
+    .tostr = sysvar_int_tostr,
+    .fromstr = sysvar_int_fromstr,
+    .buflen = INT_BUFLEN
+};
+
+static const char *sysvar_uint_tostr(sysvar_t from, char *buf)
+{
+    snprintf(buf, UINT_BUFLEN, "%lu", from.v_uint);
+    return buf;
+}
+
+static bool sysvar_uint_fromstr(sysvar_t *to, const char *from)
+{
+    char *ep;
+    unsigned long v = strtoul(from, &ep, 0);
+    if (ep == from || *ep)
+	return false;
+    to->v_uint = v;
+    return true;
+}
+
+const struct sysvar_ops sysvar_uint_ops = {
+    .tostr = sysvar_uint_tostr,
+    .fromstr = sysvar_uint_fromstr,
+    .buflen = UINT_BUFLEN
+};
+
+static const char *sysvar_str_tostr(sysvar_t from, char *buf)
+{
+    (void)buf;
+    return from.v_str;
+}
+
+static bool sysvar_str_fromstr(sysvar_t *to, const char *from)
+{
+    char *ns;
+
+    if (!from) {
+	ns = NULL;
+    } else {
+	ns = strdup(from);
+	if (!ns)
+	    return false;
+    }
+    to->v_str = ns;
+    return true;
+}
+
+static bool sysvar_str_set(sysvar_t *to, sysvar_t from)
+{
+    return sysvar_str_fromstr(to, from.v_str);
+}
+
+static size_t sysvar_str_datasize(sysvar_t val)
+{
+    return (val.v_str ? strlen(val.v_str) : 0) + 1;
+}
+
+const struct sysvar_ops sysvar_str_ops = {
+    .set = sysvar_str_set,
+    .tostr = sysvar_str_tostr,
+    .fromstr = sysvar_str_fromstr,
+    .datasize = sysvar_str_datasize
+};
+
+static void sysvar_tz_update(sysvar_t val, bool isset)
+{
+    if (isset)
+	setenv("TZ", val.v_tz, 1);
+    else
+	unsetenv("TZ");
+    tzset();
+}
+
+const struct sysvar_ops sysvar_tz_ops = {
+    .set = sysvar_str_set,
+    .tostr = sysvar_str_tostr,
+    .fromstr = sysvar_str_fromstr,
+    .update = sysvar_tz_update,
+    .datasize = sysvar_str_datasize
+};
+
+static const char *sysvar_ip_tostr(sysvar_t from, char *buf)
+{
+    union ip_bytes {
+	uint8_t b[4];
+	uint32_t l;
+    } ip;
+
+    ip.l = from.v_ip;
+    snprintf(buf, IP_BUFLEN,
+	     "%u.%u.%u.%u", ip.b[0], ip.b[1], ip.b[2], ip.b[3]);
+    return buf;
+}
+
+static bool sysvar_ip_fromstr(sysvar_t *to, const char *str)
+{
+    union ip_bytes {
+	uint8_t b[4];
+	uint32_t l;
+    } ip;
+
+    ip.l = 0;
+    for (int i = 0; i < 4; i++) {
+	char *ep;
+	unsigned long v = strtoul(str, &ep, 10);
+	if (ep == str || *ep != (i == 3) ? '\0' : '.' || v > 255)
+	    return false;
+	str = ep + 1;
+	ip.b[i] = v;
+    }
+
+    to->v_ip = ip.l;
+    return true;
+}
+
+const struct sysvar_ops sysvar_ip_ops = {
+    .tostr = sysvar_ip_tostr,
+    .fromstr = sysvar_ip_fromstr,
+    .buflen = IP_BUFLEN
+};
+
+static bool sysvar_mac_set(sysvar_t *to, sysvar_t from)
+{
+    uint8_t *buf;
+
+    if (!from.v_mac) {
+	buf = NULL;
+    } else {
+	buf = malloc(6);
+	if (!buf)
+	    return false;
+
+	memcpy(buf, from.v_mac, 6);
+    }
+    to->v_mac = buf;
+    return true;
+}
+
+static const char *sysvar_mac_tostr(sysvar_t from, char *buf)
+{
+    const uint8_t *m = from.v_mac;
+    if (!m)
+	return NULL;
+
+    snprintf(buf, MAC_BUFLEN, "%x:%x:%x:%x:%x:%x",
+	     m[0], m[1], m[2], m[3], m[4], m[5]);
+    return buf;
+}
+
+static bool sysvar_mac_fromstr(sysvar_t *to, const char *str)
+{
+    sysvar_t from;
+    uint8_t m[6];
+
+    if (!str) {
+	from.v_mac = NULL;
+    } else {
+	for (int i = 0; i < 6; i++) {
+	    char *ep;
+	    unsigned long v = strtoul(str, &ep, 16);
+	    if (ep == str || *ep != (i == 5) ? '\0' : ':' || v > 255)
+		return false;
+	    str = ep + 1;
+	    m[i] = v;
+	}
+
+	from.v_mac = m;
+    }
+
+    return sysvar_mac_set(to, from);
+}
+
+static size_t sysvar_mac_datasize(sysvar_t val)
+{
+    (void)val;
+    return 6;
+}
+
+const struct sysvar_ops sysvar_mac_ops = {
+    .set = sysvar_mac_set,
+    .tostr = sysvar_mac_tostr,
+    .fromstr = sysvar_mac_fromstr,
+    .buflen = MAC_BUFLEN,
+    .datasize = sysvar_mac_datasize
+};
+
+/* --- Generic getters/setters --- */
+
+/* Contains the lowest numbered sysvar changed; or sysvar_count if nothing */
+enum sysvar_enum sysvar_changed;
+
+sysvar_t getvar(size_t var)
+{
+    if (var >= (size_t)sysvar_count)
+	return sysvar_defval[sysvar_null];
+
+    return sysvar_val[var];
+}
+
+static bool do_setvar(size_t var, sysvar_t val, bool is_set)
+{
+    const struct sysvar_ops *type = sysvar_types[var];
+    sysvar_t *to = &sysvar_val[var];
+    void *free_ptr = NULL;
+
+    if (type->datasize)
+	free_ptr = to->v_ptr;
+
+    if (DEBUG) {
+	char tostr_buf[SYSVAR_BUFLEN];
+	printf("%ssetvar %zu %s <- %s\n", is_set ? "" : "un",
+	       var, sysvar_name[var],
+	       notempty(type->tostr(val, tostr_buf)));
+    }
+
+    if (!type->set || (type->datasize && !val.v_ptr)) {
+	sysvar_val[var] = val;
+    } else {
+	if (!type->set(to, val))
+	    return false;
+    }
+
+    if (free_ptr)
+	free(free_ptr);
+
+    if (var < (size_t)sysvar_changed)
+	sysvar_changed = (enum sysvar_enum)var;
+
+    sysvar_isset[var] = is_set;
+    if (type->update)
+	type->update(*to, is_set);
+
+    return true;
+}
+
+bool setvar(size_t var, sysvar_t val)
+{
+    if (var >= (size_t)sysvar_count)
+	return false;
+
+    return do_setvar(var, val, true);
+}
+
+bool unsetvar(size_t var)
+{
+    if (var >= (size_t)sysvar_count)
+	return false;
+
+    return do_setvar(var, sysvar_defval[var], false);
+}
+
+/* --- Getters/setters converting to/from strings --- */
+
+const char *getvar_tostr(size_t var)
+{
+    static char buf[SYSVAR_BUFLEN];
+    return getvar_tostr_r(var, buf);
+}
+
+const char *getvar_tostr_r(size_t var, char *buf)
+{
+    if (var >= (size_t)sysvar_count)
+	return NULL;
+
+    const struct sysvar_ops *type = sysvar_types[var];
+
+    /* A tostr method is required */
+    return type->tostr(sysvar_val[var], buf);
+}
+
+bool setvar_fromstr(size_t var, const char *str)
+{
+    if (var >= (size_t)sysvar_count)
+	return NULL;
+
+    if (!str)
+	return unsetvar(var);
+
+    const struct sysvar_ops *type = sysvar_types[var];
+    sysvar_t *to = &sysvar_val[var];
+    void *free_ptr = NULL;
+
+    if (type->datasize)
+	free_ptr = to->v_ptr;
+
+    if (DEBUG) {
+	printf("setvar_fromstr %zu %s <- %s\n", var, sysvar_name[var], str);
+    }
+
+    /* A fromstr method is required */
+    if (!type->fromstr(to, str))
+	return false;
+
+    if (var < (size_t)sysvar_changed)
+	sysvar_changed = (enum sysvar_enum)var;
+
+    if (free_ptr)
+	free(free_ptr);
+
+    sysvar_isset[var] = true;
+    return true;
+}
+
+/* --- Find the index of a specific variable --- */
+
+static int string_ptr_compare(const void *a, const void *b)
+{
+    const char * const *aa = a;
+    const char * const *bb = b;
+    return strcmp(*aa, *bb);
+}
+
+size_t sysvar_find(size_t ns, const char *name)
+{
+    if (ns >= (size_t)sysvar_nscount)
+	return 0;
+
+    const sysvar_ns_t *nsi = &sysvar_ns[ns];
+    const char * const *varname;
+    const size_t count = nsi[1].first - nsi->first;
+
+    varname = bsearch(&name, sysvar_name + nsi->first,
+		      count, sizeof *sysvar_name,
+		      string_ptr_compare);
+    if (!varname)
+	return 0;
+
+    return varname - sysvar_name;
+}
+
+/* --- Initialization/reset to defaults --- */
+
+void sysvar_reset(size_t ns)
+{
+    if (ns >= (size_t)sysvar_nscount)
+	return;
+
+    enum sysvar_enum i;
+    for (i = sysvar_ns[ns].first; i < sysvar_ns[ns+1].first; i++)
+	unsetvar(i);
+
+    if (sysvar_changed < i)
+	sysvar_changed = i;
+}
+
+void sysvar_init(void)
+{
+    for (enum sysvar_enum i = sysvar_null+1; i < sysvar_count; i++)
+	unsetvar(i);
+
+    sysvar_changed = sysvar_count;
+}

+ 120 - 0
sysvars.h

@@ -0,0 +1,120 @@
+#ifndef SYSVARS_H
+#define SYSVARS_H
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+#ifndef extern_c
+# ifdef __cplusplus
+#  define extern_c extern "C"
+# else
+#  define extern_c extern
+# endif
+#endif
+
+typedef union sysvar_value {
+    bool v_bool;
+    long int v_int;
+    unsigned long int v_uint;
+    const char *v_str;
+    const char *v_tz;		/* Timezone */
+    uint32_t v_ip;		/* IPv4 address */
+    const uint8_t *v_mac;	/* MAC address */
+    void *v_ptr;
+} sysvar_t;
+
+struct sysvar_ops {
+    bool (*set)(sysvar_t *, sysvar_t);
+    /* bool (*unset)(sysvar_t *); - not used */
+    const char * (*tostr)(sysvar_t, char *);
+    bool (*fromstr)(sysvar_t *, const char *);
+    void (*update)(sysvar_t, bool); /* Called after set or fromstr; bool = isset */
+    size_t (*datasize)(sysvar_t);   /* If pointer, return size of data */
+    size_t buflen;		/* Minimal buffer size for string if needed */
+};
+
+typedef const struct sysvar_ops *sysvar_type_t;
+
+extern_c const struct sysvar_ops sysvar_bool_ops;
+extern_c const struct sysvar_ops sysvar_int_ops;
+extern_c const struct sysvar_ops sysvar_uint_ops;
+extern_c const struct sysvar_ops sysvar_str_ops;
+extern_c const struct sysvar_ops sysvar_tz_ops;
+extern_c const struct sysvar_ops sysvar_ip_ops;
+extern_c const struct sysvar_ops sysvar_mac_ops;
+
+#define SYSVAR_NULLTYPE NULL
+#define SYSVAR_TYPE(x) (&sysvar ## x ## _ops)
+
+#include "sysvars_gen.h"
+
+typedef struct sysvar_namespace {
+    const char *name;
+    enum sysvar_enum first;
+} sysvar_ns_t;
+
+extern_c const sysvar_ns_t sysvar_ns[(size_t)sysvar_nscount+1];
+extern_c enum sysvar_enum sysvar_changed;
+
+/* Buffer size needed to represent some data types */
+#define BOOL_BUFLEN 2
+#define INT_BUFLEN  (3*sizeof(unsigned int)+2)
+#define UINT_BUFLEN INT_BUFLEN
+#define IP_BUFLEN   (4*4)
+#define MAC_BUFLEN  (3*6)
+
+#define SYSVAR_BUFLEN	32	/* Conservative minimum */
+
+extern_c sysvar_t getvar(size_t var);
+extern_c bool setvar(size_t var, sysvar_t val);
+extern_c bool unsetvar(size_t var);
+extern_c const char *getvar_tostr(size_t var);
+extern_c const char *getvar_tostr_r(size_t var, char *buf);
+extern_c bool setvar_fromstr(size_t var, const char *str);
+extern_c void sysvar_init(void);
+extern_c void sysvar_reset(size_t ns);
+extern_c size_t sysvar_find(size_t ns, const char *name);
+extern_c size_t sysvar_marshall(enum sysvar_enum first, size_t count,
+				void *buf, size_t *buflen, uintptr_t extaddr);
+
+/* Type-specific definitions/getters/setters */
+/* Note that t contains a leading underscore to avoid bool/_Bool issues */
+
+#define const_assert(cond, str)					     \
+    do {							     \
+	extern void fail(void) __attribute__((error(str)));	     \
+	if (__builtin_constant_p(cond) && !(cond))		     \
+	    fail();						     \
+    } while (0)
+
+#define TRY_ASSERT_TYPE(var,t)						\
+    const_assert(sysvar_type(var) == SYSVAR_TYPE(t),			\
+	"invalid type for sysvar " #var)
+
+#define SYSVAR_MKTYPE(t,c_type)						\
+    static inline c_type getvar ## t (size_t var)			\
+    {									\
+	TRY_ASSERT_TYPE(var,t);						\
+	/* If var is constant and >= sysvar_count, TRY_ASSERT_TYPE() fails */ \
+	if (__builtin_constant_p(var < (size_t)sysvar_count))		\
+	    return sysvar_val[var].v ## t;				\
+	return getvar(var).v ## t ;					\
+    }									\
+    static inline bool setvar ## t (size_t var, c_type v)		\
+    {									\
+	sysvar_t vv;							\
+	TRY_ASSERT_TYPE(var,t);						\
+	vv.v ## t = v;							\
+	return setvar(var, vv);						\
+    }
+
+SYSVAR_MKTYPE(_bool, bool);
+SYSVAR_MKTYPE(_int, long int);
+SYSVAR_MKTYPE(_uint, unsigned long int);
+SYSVAR_MKTYPE(_str, const char *);
+SYSVAR_MKTYPE(_tz, const char *);
+SYSVAR_MKTYPE(_ip, uint32_t);
+SYSVAR_MKTYPE(_mac, const uint8_t *);
+
+#endif /* SYSVARS_H */

+ 0 - 0
esp32/sysvars.pl → tools/sysvars.pl