1#include "user_app_exe.h"
2#include "main-header.h"
8#include "command-parser.h"
9#include "sensors/sensor.h"
10#include "ascii_parser.h"
12#include "userconfig.h"
17#include "api_version.h"
20static uint32_t repoid;
21static uint32_t version;
22static struct command *alloc_command_user();
23static int user_serialport_callback(
int mculibhandle,
int portnum, serial_recv_callback cb);
24static int mcu_set_speed(
int mculibhandle,
int speed);
25static void reset_userapp();
26static void led_app_blink(
int colour,
int brightness,
int on,
int off);
31static int register_user_sensor(
struct sensordev *sensor);
32static void free_user_sensors();
34static int unhandled_call();
35static void user_printf(
const char *format, ...);
36static void user_debugf(
const char *format, ...);
37static serial_recv_callback serial_recv_callback_usart3;
38static char userappbuf[500];
39static char *PREFIX =
"userapp";
48 .debugf = &user_debugf,
50 .mculib_serialport_disable = &mculib_serialport_disable,
61 .mculib_has_time_passed = &mculib_has_time_passed,
64 .mculib_spi_send_dma = &mculib_spi_send_dma,
70 .mculib_timer_enable_simple = &mculib_timer_enable_simple,
71 .mculib_timer_disable = &mculib_timer_disable,
72 .mculib_timer_attach_pin_pwm = &mculib_timer_attach_pin_pwm,
73 .mculib_timer_set_pwm = &mculib_timer_set_pwm,
74 .mculib_adc_read_once = &mculib_adc_read_once,
75 .mculib_adc_get_resolution = &mculib_adc_get_resolution,
76 .mculib_adc_enable = &mculib_adc_enable,
77 .mculib_adc_read = &mculib_adc_read,
86 .com_alloc = &alloc_command_user,
91 .sensor_register = ®ister_user_sensor,
96 .vsnprintf = &vsnprintf,
97 .snprintf = &snprintf,
99 .led_blink = &led_app_blink,
100 .get_config_flag = &get_user_config_flag,
106 .sensor_get_runtime_by_index = &get_runtime,
107 .proto_buf_to_struct = &buf_to_struct,
108 .proto_struct_to_buf = &struct_to_buf,
111 .time_get_localtime_as_struct = &get_localtime_as_struct,
112 .timer_softirq = &softirq_timer,
113 .time_get_diff = &diff_time,
114 .time_bcd_to_timestruct = &convert_timestamps_to_time,
119 .hijack_esp32_usart_stop = &unhijack_esp32,
120 .reset_module = &reboot_hard,
122 .unhandled_call1 = &unhandled_call,
123 .unhandled_call2 = &unhandled_call,
124 .unhandled_call3 = &unhandled_call,
125 .unhandled_call4 = &unhandled_call,
126 .unhandled_call5 = &unhandled_call,
127 .unhandled_call6 = &unhandled_call,
128 .unhandled_call7 = &unhandled_call,
129 .unhandled_call8 = &unhandled_call,
135static uint8_t crc_ok = 0;
136static uint8_t do_exe_user_app = 0;
137static uint8_t has_failed = 0;
138static uint8_t start_stop_status = 0;
139static uint32_t myversion = 0;
142#define MCULIB_USERAPP_HANDLE 7
145void set_in_app(uint8_t a) {
146 constants()->in_user_app = a;
150void user_app_exe_init() {
151 memset(&sensordevptr, 0,
sizeof(sensordevptr));
152 start_stop_status = 0;
156 myversion = myapp->version;
162 if ((constants()->in_user_app) && (mculib_get_reset_source() != HAL_RESET_POWER)) {
164 printf(
"Userapp disabled (fail-safe)\r\n");
173static int has_changed() {
176 if (newapp != myapp) {
179 if (newapp == NULL) {
183 if (newapp->version != myversion) {
190static void reset_userapp() {
198int user_app_is_enabled() {
199 return do_exe_user_app;
208void user_app_enable() {
210 if (!user_app_executable()) {
213 if ((has_changed()) && (start_stop_status == 1)) {
218 if (start_stop_status != 1) {
219 invoke_start(MCULIB_USERAPP_HANDLE);
220 mculib_print_mappings(&printf);
224void user_app_disable() {
225 if (!user_app_executable()) {
231 if (start_stop_status == 1) {
237int user_app_checksum_valid() {
244 if (!has_changed()) {
247 }
else if (crc_ok == 2) {
251 if (!user_app_is_valid()) {
254 uint32_t checksum = calc_crc32((
void *)uai, uai->length, 8);
256 if (checksum == uai->checksum) {
261 printf(
"Userapp checksum calculated: %p, reported: %p\r\n", checksum, uai->checksum);
265int user_app_is_valid() {
274 if (uai->magic != 0x53435541) {
282int user_app_executable() {
289 if (!do_exe_user_app) {
292 if (!user_app_is_valid()) {
295 if (!user_app_checksum_valid()) {
302void invoke_start(
int MCULIBHANDLE) {
308 version = ua->version;
309 ua->
start(MCULIBHANDLE, &user_callback_api);
311 start_stop_status = 1;
314 serial_recv_callback_usart3 = NULL;
316 softirqs_removeall();
318 get_user_app()->
stop();
321 start_stop_status = 2;
323 mculib_release_by_handle(MCULIB_USERAPP_HANDLE);
325int invoke_on_command_received(
struct command *com) {
332void invoke_on_new_node(
struct hostroute *host) {
338void invoke_user_loop() {
344void user_app_reset_state() {
351 printf(
"User app state reset\r\n");
355int send_user_app_status() {
356 return user_app_info(NULL);
358static uint32_t user_app_git_repo() {
366static uint32_t user_app_timestamp() {
372 return uac->build_timestamp;
374static uint32_t user_app_apiversion() {
380 return uac->api_version;
382int user_app_info(
struct command *com) {
388 printf(
"Delivering user_app_status\r\n");
389 reply->
target = CLOUD_SERVER;
400 command_add_arg(reply,
"av=%i/%i", user_app_apiversion(), CNW_API_VERSION);
401 reply->
flags = COMFLAGS_SUCCESS;
406 reply->
flags = COMFLAGS_ACK | COMFLAGS_SUCCESS;
411 printf(
"Failed to deliver userapp_status command: %i\r\n", i);
419 int i = userconfig_receive(
com);
443 printf(
"invalid userapp control: %i\r\n", l);
449 uint32_t fl = atoi(x);
450 set_user_config_flags(fl);
456static void led_app_blink(
int colour,
int brightness,
int on,
int off) {
457 led_set_user_managed();
458 led_blink(LED_USER, colour, brightness, on, off);
461static void free_user_sensors() {
462 int max =
sizeof(sensordevptr) /
sizeof(
struct sensordev *);
465 for (i = 0; i < max; i++) {
466 struct sensordev *entry = sensordevptr[i];
470 sensor_deregister(entry);
471 sensordevptr[i] = NULL;
475static int register_user_sensor(
struct sensordev *sensor) {
481 int max =
sizeof(sensordevptr) /
sizeof(
struct sensordev *);
484 for (i = 0; i < max; i++) {
485 struct sensordev *entry = sensordevptr[i];
487 sensordevptr[i] = sd;
494int userapp_checksum_valid(
void *baseadr) {
500 if (uai->magic != 0x53435541) {
504 uint32_t checksum = calc_crc32((
void *)uai, uai->length, 8);
506 if (checksum != uai->checksum) {
512static void user_printf(
const char *format, ...) {
514 int max_size =
sizeof(userappbuf) - 1;
516 snprintf((
char *)&userappbuf, max_size,
"[%s info #%i/%i] ", PREFIX, repoid, version);
518 int l = strlen(userappbuf);
520 va_start(args, format);
521 vsnprintf((
char *)&userappbuf + l, max_size - l, format, args);
523 print((
const char *)&userappbuf);
525static void user_debugf(
const char *format, ...) {
529 snprintf((
char *)&userappbuf, max_size,
"[%s debug #%i/%i] ", PREFIX, repoid, version);
531 int l = strlen(userappbuf);
533 va_start(args, format);
534 vsnprintf((
char *)&userappbuf + l, max_size - l, format, args);
536 print((
const char *)&userappbuf);
539struct command *alloc_command_user() {
540 struct command *
com = alloc_command_with_minfree(10);
545static int unhandled_call() {
546 printf(
"Userapp called a function which is not implemented\r\n");
551int user_serial_callback(
int portnum,
int byte) {
555 if (serial_recv_callback_usart3 == NULL) {
558 serial_recv_callback_usart3(portnum,
byte);
561static int user_serialport_callback(
int mculibhandle,
int portnum, serial_recv_callback cb) {
565 serial_recv_callback_usart3 = cb;
568static int mcu_set_speed(
int mculibhandle,
int speed) {
575 set_mcu_power_mode(speed);
int namedarg_uint16(struct command *com, const char *name, uint16_t *value)
get a named arg (key-value pair), parsed as integer. result in "value". if return value == 0 ,...
int send_command_reply_with_args(struct command *com, byte flags, const char *format,...)
send a reply to a command
int send_command(struct command *com)
send a command to another module (or broadcast)
void free_command(struct command *com)
free a command
int deliver_command(struct command *com, pkt_callback)
deliver a command to a module
void command_add_arg(struct command *com, const char *format,...)
adds an arg to a partially initialised command structure
const char * namedarg(struct command *com, const char *name)
get a named arg (key-value pair) or NULL
void command_add_varg(struct command *com, const char *format, va_list args)
adds a varg list of parameters to a command
int namedarg_uint32(struct command *com, const char *name, uint32_t *value)
get a named arg (key-value pair), parsed as integer. result in "value". if return value == 0 ,...
int send_command_reply(struct command *com, byte flags)
send a reply to a command
struct command * get_data_reply(struct command *com)
allocates and initializes a packet to be send as "data" to the command typically you'd add some data ...
struct command * alloc_command()
allocate a free command
void led_blink(LED_USAGE_TYPE lut, uint32_t colour, uint8_t brightness, uint32_t on, uint32_t off)
will keep blinking until told otherwise will repeat endlessly.
int command_add_binary_arg(struct command *com, const int len, const byte *srcbuf)
adds a binary parameter to command returns 0 if ok otherwise errorcode
struct sensordev * sensor_register(struct sensordev *sensor)
register a new sensor. returns 0 if ok
const char * get_arg(const struct command *com, int index)
given an argument by index[0..n], will return a pointer to the bytearray (excluding the fieldtype) th...
int get_arg_size(const struct command *com, int index)
given an argument by index [0..n], will returns the size of the value in bytes. for a string/array it...
int(* mculib_serialport_write_char)(MCULIB_HANDLE handle, int portnum, uint8_t b)
write to serial port
int(* mculib_pin_in_callback)(MCULIB_HANDLE handle, pin_irq_callback pic)
set a callback to be called whenever a pin irq is triggered
void(* stop)()
last thing to be called. no more userloops or irqs afterwards
int(* mculib_pin_in)(MCULIB_HANDLE handle, int pinnum, int speed, int mode)
configure and enable an IO-Pin as input note: pinnum are sequential 0-99 are PAnn,...
int(* mculib_spi_write_only)(MCULIB_HANDLE handle, int portnum, const uint16_t write)
write a byte, discard the read if a transmission is already in progress wait until transmission is do...
int(* mculib_pin_release)(MCULIB_HANDLE handle, int pinnum)
deconfigure a pin (MCULIB_HANDLE handle,used for a different purpose)
int(* on_command_received)(struct command *com)
this is called for each command we receive
int(* hijack_usb_acm)(void(*receive_hook)(uint8_t *received, int size))
"hijack" the usb port. this means the firmware will neither send bytes through the port nor process i...
long(* mculib_get_seconds_since_boot)(void)
get number of seconds elapsed since boot or power-up this counter is usually ever-increasing and roug...
int(* hijack_esp32_usart)(void(*receive_hook)(uint8_t received))
hijack the esp32 serial port
int(* start)(int MCULIBHANDLE, struct sc_firmware_api *api)
guaranteed to be called by the firmware before any other functions
int(* mculib_spi_master_enable3)(MCULIB_HANDLE handle, int portnum, uint8_t wide, uint8_t clkpol, uint8_t cpha, uint8_t dir, uint32_t baud_in_khz)
enable a spi port as master and set clkpol, cpha and width (wide=0 8bit, wide=1 16bit)(dir == 0=RW,...
uint32_t(* userconfig_size)()
the userconfig: this is a little unstructured piece of flash set aside for configuration of userapps....
void(* printf)(const char *format,...)
print a message on console and possibly forward to server into logfile as well (uses radio - expensiv...
int(* mculib_serialport_enable)(MCULIB_HANDLE handle, int portnum, int baudrate)
configure a serial port with specified parameters num == 1..n (depending on mcu) baudrate == ....
int(* user_serialport_callback)(MCULIB_HANDLE handle, int portnum, serial_recv_callback cb)
set callback for serialport receive irq
int(* userconfig_copy)(uint8_t *buf, uint16_t bufsize, uint16_t *actual_size)
this copies the userconfig into a ram buffer, IF the version has been updated and IF the destination ...
int(* mculib_pin_set)(MCULIB_HANDLE handle, int pinnum, int highlow)
set IOPin to high or low
int(* mculib_spi_disable)(MCULIB_HANDLE handle, int portnum)
disable the spi port
int(* send_via_usb_acm)(uint8_t *buf, int size)
once a usb_acm is "hijacked", the userapp can send bytes through the usb_acm port with this function ...
int(* mculib_spi_write_and_read)(MCULIB_HANDLE handle, int portnum, const uint16_t write, uint16_t *read)
write a byte and read from spi if a transmission is already in progress it waits. this writes and wai...
int(* mculib_spi_read16_only)(MCULIB_HANDLE handle, int portnum, uint16_t *read)
there are weird devices, like tli4970, which aren't really spi. they basically start sending as soon ...
int(* mculib_pin_get)(MCULIB_HANDLE handle, int pinnum)
get current pin level (high or low) this is a bit funny: 0 or 1 indicate the pin level....
int(* userconfig_write)(uint8_t *buf, uint32_t size)
this saves a buf as "userconfig" RETURN VALUE: 0==ok, anything else is an error (same version is not ...
void(* on_new_node)(struct hostroute *host)
called when and if a new node is detected. this may be used, to, for example detect a route to the cl...
void(* user_loop)()
this is called frequently, but with no timing guarantees. essentially, it's called in the "idle-loop"...
void(* pin_pwm)(int MCULIBHANDLE, int pin, uint32_t newstate, int flags)
pwm a pin (mosfets, and some other pins as well)
void(* reset_userapp)(void)
reset the userapp
int(* mculib_serialport_write_string)(MCULIB_HANDLE handle, int port, const char *txt)
write a string to serial port
int(* mculib_pin_out)(MCULIB_HANDLE handle, int pinnum, int speed)
configure and enable an IO-Pin as output note: pinnum are sequential 0-99 are PAnn,...
int(* mcu_set_speed)(int MCULIBHANDLE, int speed)
change cpu speed - sometimes we need to be guaranteed to be fast. speed [1==very fast ....
int(* mculib_pin_out_opendrain)(MCULIB_HANDLE handle, int pinnum, int speed)
configure and enable an IO-Pin as output note: pinnum are sequential 0-99 are PAnn,...
int(* mculib_spi_speed)(MCULIB_HANDLE handle, int portnum, long khz)
set the spi speed (after it's open and running) returns new speed or 0 if failure
void(* proto_release)(void *buf)
release a proto struct
uint32_t(* userconfig_version)()
each time the config is updated, the version is incremented. in other words, unless the version is ch...
these are the callbacks available. the firmware "api". provided to the app on startup
this must be implemented by the userapp, stored in flash at the beginning of the file (offset 0)
user application interface