stm32f4-uart-bootloader

Simple UART bootloader for STM32F4 MCU's
git clone git://git.mdnr.space/stm32f4-uart-bootloader
Log | Files | Refs | Submodules | README | LICENSE

commit e6d10111971a5edb3dac7f484c2773074cee2979
parent a9d297ba567458d1daf880c4b403f1241e25a1c5
Author: mehdi-norouzi <mehdeenoroozi@gmail.com>
Date:   Sun, 23 Feb 2025 01:36:01 +0330

add libopencm3 and freertos as submodules

Diffstat:
M.gitignore | 4----
M.gitmodules | 3+++
Dbootloader/nob.c | 40----------------------------------------
Dbootloader/nob.h | 1160-------------------------------------------------------------------------------
Dbootloader/param.json | 0
Dbootloader/src/bl.c | 123-------------------------------------------------------------------------------
Dbootloader/src/core/comm.c | 536-------------------------------------------------------------------------------
Dbootloader/src/core/comm.h | 18------------------
Dbootloader/src/core/jsmn-helper.h | 114-------------------------------------------------------------------------------
Dbootloader/src/core/jsmn.h | 471-------------------------------------------------------------------------------
Dbootloader/src/core/ser.c | 78------------------------------------------------------------------------------
Dbootloader/src/core/ser.h | 11-----------
Asrc/app/freertos | 1+
13 files changed, 4 insertions(+), 2555 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -10,7 +10,3 @@ build/* globals/version.c tags compile_commands.json -bootloader/ncurses* -bootloader/build* -bootloader/nob -bootloader/nob.old diff --git a/.gitmodules b/.gitmodules @@ -1,3 +1,6 @@ [submodule "src/shared/opencm3"] path = src/shared/opencm3 url = git@github.com:libopencm3/libopencm3.git +[submodule "src/app/freertos"] + path = src/app/freertos + url = git@github.com:FreeRTOS/FreeRTOS-Kernel.git diff --git a/bootloader/nob.c b/bootloader/nob.c @@ -1,40 +0,0 @@ -#define NOB_IMPLEMENTATION -#include "nob.h" - -int main(int argc, char **argv) { - NOB_GO_REBUILD_URSELF(argc, argv); - char *build_target; - char *compiler; - char *header_path; - char *lib_path; - char *output; - char *lflags; - - // skip first argument: program name - nob_shift_args(&argc, &argv); - - Nob_Cmd build_app = {0}; - - if (argc > 0) build_target = nob_shift_args(&argc, &argv); - else build_target = "LINUX"; - - nob_log(NOB_INFO, "build target: %s", build_target); - - if (strcmp(build_target, "LINUX") == 0) { - nob_cmd_append(&build_app, "gcc"); - nob_cmd_append(&build_app, "-Wall", "-Wextra", "-ggdb"); - nob_cmd_append(&build_app, "-D", build_target); - nob_cmd_append(&build_app, "-o", "./build/bl", "./src/bl.c", "./src/core/ser.c", "./src/core/comm.c"); - nob_cmd_append(&build_app, "-I./src/core/", "-I./ncurses-6.3/include/", "-L./ncurses-6.3/lib", "-lncurses"); - } else if (strcmp(build_target, "WIN32") == 0) { - nob_cmd_append(&build_app, "x86_64-w64-mingw32-gcc"); - nob_cmd_append(&build_app, "-Wall", "-Wextra", "-s"); - nob_cmd_append(&build_app, "-D", build_target); - nob_cmd_append(&build_app, "-o", "./build/classifier.exe", "./win-scandir/win-scandir.c", "classifier.c"); - nob_cmd_append(&build_app, "-I./win-scandir", "-I./raylib-win/include", "-L./raylib-win/mylib-opengl-21/", "-lraylib", "-lgdi32", "-lwinmm"); - } - - /*nob_cmd_append(&build_app, "-lm");*/ - if (!nob_cmd_run_sync(build_app)) return 1; - return 0; -} diff --git a/bootloader/nob.h b/bootloader/nob.h @@ -1,1160 +0,0 @@ -// This is a complete backward incompatible rewrite of https://github.com/tsoding/nobuild -// because I'm really unhappy with the direction it is going. It's gonna sit in this repo -// until it's matured enough and then I'll probably extract it to its own repo. - -// Copyright 2023 Alexey Kutepov <reximkut@gmail.com> -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#ifndef NOB_H_ -#define NOB_H_ - -#define NOB_ASSERT assert -#define NOB_REALLOC realloc -#define NOB_FREE free - -#include <assert.h> -#include <stdbool.h> -#include <stdlib.h> -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> - -#ifdef _WIN32 -# define WIN32_LEAN_AND_MEAN -# define _WINUSER_ -# define _WINGDI_ -# define _IMM_ -# define _WINCON_ -# include <windows.h> -# include <direct.h> -# include <shellapi.h> -#else -# include <sys/types.h> -# include <sys/wait.h> -# include <sys/stat.h> -# include <unistd.h> -# include <fcntl.h> -#endif - -#ifdef _WIN32 -# define NOB_LINE_END "\r\n" -#else -# define NOB_LINE_END "\n" -#endif - -#define NOB_ARRAY_LEN(array) (sizeof(array)/sizeof(array[0])) -#define NOB_ARRAY_GET(array, index) \ - (NOB_ASSERT(index >= 0), NOB_ASSERT(index < NOB_ARRAY_LEN(array)), array[index]) - -typedef enum { - NOB_INFO, - NOB_WARNING, - NOB_ERROR, -} Nob_Log_Level; - -void nob_log(Nob_Log_Level level, const char *fmt, ...); - -// It is an equivalent of shift command from bash. It basically pops a command line -// argument from the beginning. -char *nob_shift_args(int *argc, char ***argv); - -typedef struct { - const char **items; - size_t count; - size_t capacity; -} Nob_File_Paths; - -typedef enum { - NOB_FILE_REGULAR = 0, - NOB_FILE_DIRECTORY, - NOB_FILE_SYMLINK, - NOB_FILE_OTHER, -} Nob_File_Type; - -bool nob_mkdir_if_not_exists(const char *path); -bool nob_copy_file(const char *src_path, const char *dst_path); -bool nob_copy_directory_recursively(const char *src_path, const char *dst_path); -bool nob_read_entire_dir(const char *parent, Nob_File_Paths *children); -bool nob_write_entire_file(const char *path, const void *data, size_t size); -Nob_File_Type nob_get_file_type(const char *path); - -#define nob_return_defer(value) do { result = (value); goto defer; } while(0) - -// Initial capacity of a dynamic array -#define NOB_DA_INIT_CAP 256 - -// Append an item to a dynamic array -#define nob_da_append(da, item) \ - do { \ - if ((da)->count >= (da)->capacity) { \ - (da)->capacity = (da)->capacity == 0 ? NOB_DA_INIT_CAP : (da)->capacity*2; \ - (da)->items = NOB_REALLOC((da)->items, (da)->capacity*sizeof(*(da)->items)); \ - NOB_ASSERT((da)->items != NULL && "Buy more RAM lol"); \ - } \ - \ - (da)->items[(da)->count++] = (item); \ - } while (0) - -#define nob_da_free(da) NOB_FREE((da).items) - -// Append several items to a dynamic array -#define nob_da_append_many(da, new_items, new_items_count) \ - do { \ - if ((da)->count + (new_items_count) > (da)->capacity) { \ - if ((da)->capacity == 0) { \ - (da)->capacity = NOB_DA_INIT_CAP; \ - } \ - while ((da)->count + (new_items_count) > (da)->capacity) { \ - (da)->capacity *= 2; \ - } \ - (da)->items = NOB_REALLOC((da)->items, (da)->capacity*sizeof(*(da)->items)); \ - NOB_ASSERT((da)->items != NULL && "Buy more RAM lol"); \ - } \ - memcpy((da)->items + (da)->count, (new_items), (new_items_count)*sizeof(*(da)->items)); \ - (da)->count += (new_items_count); \ - } while (0) - -typedef struct { - char *items; - size_t count; - size_t capacity; -} Nob_String_Builder; - -bool nob_read_entire_file(const char *path, Nob_String_Builder *sb); - -// Append a sized buffer to a string builder -#define nob_sb_append_buf(sb, buf, size) nob_da_append_many(sb, buf, size) - -// Append a NULL-terminated string to a string builder -#define nob_sb_append_cstr(sb, cstr) \ - do { \ - const char *s = (cstr); \ - size_t n = strlen(s); \ - nob_da_append_many(sb, s, n); \ - } while (0) - -// Append a single NULL character at the end of a string builder. So then you can -// use it a NULL-terminated C string -#define nob_sb_append_null(sb) nob_da_append_many(sb, "", 1) - -// Free the memory allocated by a string builder -#define nob_sb_free(sb) NOB_FREE((sb).items) - -// Process handle -#ifdef _WIN32 -typedef HANDLE Nob_Proc; -#define NOB_INVALID_PROC INVALID_HANDLE_VALUE -#else -typedef int Nob_Proc; -#define NOB_INVALID_PROC (-1) -#endif // _WIN32 - -typedef struct { - Nob_Proc *items; - size_t count; - size_t capacity; -} Nob_Procs; - -bool nob_procs_wait(Nob_Procs procs); - -// Wait until the process has finished -bool nob_proc_wait(Nob_Proc proc); - -// A command - the main workhorse of Nob. Nob is all about building commands an running them -typedef struct { - const char **items; - size_t count; - size_t capacity; -} Nob_Cmd; - -// Render a string representation of a command into a string builder. Keep in mind the the -// string builder is not NULL-terminated by default. Use nob_sb_append_null if you plan to -// use it as a C string. -void nob_cmd_render(Nob_Cmd cmd, Nob_String_Builder *render); - -#define nob_cmd_append(cmd, ...) \ - nob_da_append_many(cmd, ((const char*[]){__VA_ARGS__}), (sizeof((const char*[]){__VA_ARGS__})/sizeof(const char*))) - -// Free all the memory allocated by command arguments -#define nob_cmd_free(cmd) NOB_FREE(cmd.items) - -// Run command asynchronously -Nob_Proc nob_cmd_run_async(Nob_Cmd cmd); - -// Run command synchronously -bool nob_cmd_run_sync(Nob_Cmd cmd); - -#ifndef NOB_TEMP_CAPACITY -#define NOB_TEMP_CAPACITY (8*1024*1024) -#endif // NOB_TEMP_CAPACITY -char *nob_temp_strdup(const char *cstr); -void *nob_temp_alloc(size_t size); -char *nob_temp_sprintf(const char *format, ...); -void nob_temp_reset(void); -size_t nob_temp_save(void); -void nob_temp_rewind(size_t checkpoint); - -int is_path1_modified_after_path2(const char *path1, const char *path2); -bool nob_rename(const char *old_path, const char *new_path); -int nob_needs_rebuild(const char *output_path, const char **input_paths, size_t input_paths_count); -int nob_needs_rebuild1(const char *output_path, const char *input_path); -int nob_file_exists(const char *file_path); - -// TODO: add MinGW support for Go Rebuild Urself™ Technology -#ifndef NOB_REBUILD_URSELF -# if _WIN32 -# if defined(__GNUC__) -# define NOB_REBUILD_URSELF(binary_path, source_path) "gcc", "-o", binary_path, source_path -# elif defined(__clang__) -# define NOB_REBUILD_URSELF(binary_path, source_path) "clang", "-o", binary_path, source_path -# elif defined(_MSC_VER) -# define NOB_REBUILD_URSELF(binary_path, source_path) "cl.exe", nob_temp_sprintf("/Fe:%s", (binary_path)), source_path -# endif -# else -# define NOB_REBUILD_URSELF(binary_path, source_path) "cc", "-o", binary_path, source_path -# endif -#endif - -// Go Rebuild Urself™ Technology -// -// How to use it: -// int main(int argc, char** argv) { -// GO_REBUILD_URSELF(argc, argv); -// // actual work -// return 0; -// } -// -// After your added this macro every time you run ./nobuild it will detect -// that you modified its original source code and will try to rebuild itself -// before doing any actual work. So you only need to bootstrap your build system -// once. -// -// The modification is detected by comparing the last modified times of the executable -// and its source code. The same way the make utility usually does it. -// -// The rebuilding is done by using the REBUILD_URSELF macro which you can redefine -// if you need a special way of bootstraping your build system. (which I personally -// do not recommend since the whole idea of nobuild is to keep the process of bootstrapping -// as simple as possible and doing all of the actual work inside of the nobuild) -// -#define NOB_GO_REBUILD_URSELF(argc, argv) \ - do { \ - const char *source_path = __FILE__; \ - assert(argc >= 1); \ - const char *binary_path = argv[0]; \ - \ - int rebuild_is_needed = nob_needs_rebuild(binary_path, &source_path, 1); \ - if (rebuild_is_needed < 0) exit(1); \ - if (rebuild_is_needed) { \ - Nob_String_Builder sb = {0}; \ - nob_sb_append_cstr(&sb, binary_path); \ - nob_sb_append_cstr(&sb, ".old"); \ - nob_sb_append_null(&sb); \ - \ - if (!nob_rename(binary_path, sb.items)) exit(1); \ - Nob_Cmd rebuild = {0}; \ - nob_cmd_append(&rebuild, NOB_REBUILD_URSELF(binary_path, source_path)); \ - bool rebuild_succeeded = nob_cmd_run_sync(rebuild); \ - nob_cmd_free(rebuild); \ - if (!rebuild_succeeded) { \ - nob_rename(sb.items, binary_path); \ - exit(1); \ - } \ - \ - Nob_Cmd cmd = {0}; \ - nob_da_append_many(&cmd, argv, argc); \ - if (!nob_cmd_run_sync(cmd)) exit(1); \ - exit(0); \ - } \ - } while(0) -// The implementation idea is stolen from https://github.com/zhiayang/nabs - -typedef struct { - size_t count; - const char *data; -} Nob_String_View; - -const char *nob_temp_sv_to_cstr(Nob_String_View sv); - -Nob_String_View nob_sv_chop_by_delim(Nob_String_View *sv, char delim); -Nob_String_View nob_sv_trim(Nob_String_View sv); -bool nob_sv_eq(Nob_String_View a, Nob_String_View b); -Nob_String_View nob_sv_from_cstr(const char *cstr); -Nob_String_View nob_sv_from_parts(const char *data, size_t count); - -// printf macros for String_View -#ifndef SV_Fmt -#define SV_Fmt "%.*s" -#endif // SV_Fmt -#ifndef SV_Arg -#define SV_Arg(sv) (int) (sv).count, (sv).data -#endif // SV_Arg -// USAGE: -// String_View name = ...; -// printf("Name: "SV_Fmt"\n", SV_Arg(name)); - - -// minirent.h HEADER BEGIN //////////////////////////////////////// -// Copyright 2021 Alexey Kutepov <reximkut@gmail.com> -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// ============================================================ -// -// minirent — 0.0.1 — A subset of dirent interface for Windows. -// -// https://github.com/tsoding/minirent -// -// ============================================================ -// -// ChangeLog (https://semver.org/ is implied) -// -// 0.0.2 Automatically include dirent.h on non-Windows -// platforms -// 0.0.1 First Official Release - -#ifndef _WIN32 -#include <dirent.h> -#else // _WIN32 - -#define WIN32_LEAN_AND_MEAN -#include "windows.h" - -struct dirent -{ - char d_name[MAX_PATH+1]; -}; - -typedef struct DIR DIR; - -static DIR *opendir(const char *dirpath); -static struct dirent *readdir(DIR *dirp); -static int closedir(DIR *dirp); -#endif // _WIN32 -// minirent.h HEADER END //////////////////////////////////////// - -#endif // NOB_H_ - -#ifdef NOB_IMPLEMENTATION - -static size_t nob_temp_size = 0; -static char nob_temp[NOB_TEMP_CAPACITY] = {0}; - -bool nob_mkdir_if_not_exists(const char *path) -{ -#ifdef _WIN32 - int result = mkdir(path); -#else - int result = mkdir(path, 0755); -#endif - if (result < 0) { - if (errno == EEXIST) { - nob_log(NOB_INFO, "directory `%s` already exists", path); - return true; - } - nob_log(NOB_ERROR, "could not create directory `%s`: %s", path, strerror(errno)); - return false; - } - - nob_log(NOB_INFO, "created directory `%s`", path); - return true; -} - -bool nob_copy_file(const char *src_path, const char *dst_path) -{ - nob_log(NOB_INFO, "copying %s -> %s", src_path, dst_path); -#ifdef _WIN32 - if (!CopyFile(src_path, dst_path, FALSE)) { - nob_log(NOB_ERROR, "Could not copy file: %lu", GetLastError()); - return false; - } - return true; -#else - int src_fd = -1; - int dst_fd = -1; - size_t buf_size = 32*1024; - char *buf = NOB_REALLOC(NULL, buf_size); - NOB_ASSERT(buf != NULL && "Buy more RAM lol!!"); - bool result = true; - - src_fd = open(src_path, O_RDONLY); - if (src_fd < 0) { - nob_log(NOB_ERROR, "Could not open file %s: %s", src_path, strerror(errno)); - nob_return_defer(false); - } - - struct stat src_stat; - if (fstat(src_fd, &src_stat) < 0) { - nob_log(NOB_ERROR, "Could not get mode of file %s: %s", src_path, strerror(errno)); - nob_return_defer(false); - } - - dst_fd = open(dst_path, O_CREAT | O_TRUNC | O_WRONLY, src_stat.st_mode); - if (dst_fd < 0) { - nob_log(NOB_ERROR, "Could not create file %s: %s", dst_path, strerror(errno)); - nob_return_defer(false); - } - - for (;;) { - ssize_t n = read(src_fd, buf, buf_size); - if (n == 0) break; - if (n < 0) { - nob_log(NOB_ERROR, "Could not read from file %s: %s", src_path, strerror(errno)); - nob_return_defer(false); - } - char *buf2 = buf; - while (n > 0) { - ssize_t m = write(dst_fd, buf2, n); - if (m < 0) { - nob_log(NOB_ERROR, "Could not write to file %s: %s", dst_path, strerror(errno)); - nob_return_defer(false); - } - n -= m; - buf2 += m; - } - } - -defer: - free(buf); - close(src_fd); - close(dst_fd); - return result; -#endif -} - -void nob_cmd_render(Nob_Cmd cmd, Nob_String_Builder *render) -{ - for (size_t i = 0; i < cmd.count; ++i) { - const char *arg = cmd.items[i]; - if (arg == NULL) break; - if (i > 0) nob_sb_append_cstr(render, " "); - if (!strchr(arg, ' ')) { - nob_sb_append_cstr(render, arg); - } else { - nob_da_append(render, '\''); - nob_sb_append_cstr(render, arg); - nob_da_append(render, '\''); - } - } -} - -Nob_Proc nob_cmd_run_async(Nob_Cmd cmd) -{ - if (cmd.count < 1) { - nob_log(NOB_ERROR, "Could not run empty command"); - return NOB_INVALID_PROC; - } - - Nob_String_Builder sb = {0}; - nob_cmd_render(cmd, &sb); - nob_sb_append_null(&sb); - nob_log(NOB_INFO, "CMD: %s", sb.items); - nob_sb_free(sb); - memset(&sb, 0, sizeof(sb)); - -#ifdef _WIN32 - // https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output - - STARTUPINFO siStartInfo; - ZeroMemory(&siStartInfo, sizeof(siStartInfo)); - siStartInfo.cb = sizeof(STARTUPINFO); - // NOTE: theoretically setting NULL to std handles should not be a problem - // https://docs.microsoft.com/en-us/windows/console/getstdhandle?redirectedfrom=MSDN#attachdetach-behavior - // TODO: check for errors in GetStdHandle - siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); - siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); - siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - siStartInfo.dwFlags |= STARTF_USESTDHANDLES; - - PROCESS_INFORMATION piProcInfo; - ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); - - // TODO: use a more reliable rendering of the command instead of cmd_render - // cmd_render is for logging primarily - nob_cmd_render(cmd, &sb); - nob_sb_append_null(&sb); - BOOL bSuccess = CreateProcessA(NULL, sb.items, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo); - nob_sb_free(sb); - - if (!bSuccess) { - nob_log(NOB_ERROR, "Could not create child process: %lu", GetLastError()); - return NOB_INVALID_PROC; - } - - CloseHandle(piProcInfo.hThread); - - return piProcInfo.hProcess; -#else - pid_t cpid = fork(); - if (cpid < 0) { - nob_log(NOB_ERROR, "Could not fork child process: %s", strerror(errno)); - return NOB_INVALID_PROC; - } - - if (cpid == 0) { - // NOTE: This leaks a bit of memory in the child process. - // But do we actually care? It's a one off leak anyway... - Nob_Cmd cmd_null = {0}; - nob_da_append_many(&cmd_null, cmd.items, cmd.count); - nob_cmd_append(&cmd_null, NULL); - - if (execvp(cmd.items[0], (char * const*) cmd_null.items) < 0) { - nob_log(NOB_ERROR, "Could not exec child process: %s", strerror(errno)); - exit(1); - } - NOB_ASSERT(0 && "unreachable"); - } - - return cpid; -#endif -} - -bool nob_procs_wait(Nob_Procs procs) -{ - bool success = true; - for (size_t i = 0; i < procs.count; ++i) { - success = nob_proc_wait(procs.items[i]) && success; - } - return success; -} - -bool nob_proc_wait(Nob_Proc proc) -{ - if (proc == NOB_INVALID_PROC) return false; - -#ifdef _WIN32 - DWORD result = WaitForSingleObject( - proc, // HANDLE hHandle, - INFINITE // DWORD dwMilliseconds - ); - - if (result == WAIT_FAILED) { - nob_log(NOB_ERROR, "could not wait on child process: %lu", GetLastError()); - return false; - } - - DWORD exit_status; - if (!GetExitCodeProcess(proc, &exit_status)) { - nob_log(NOB_ERROR, "could not get process exit code: %lu", GetLastError()); - return false; - } - - if (exit_status != 0) { - nob_log(NOB_ERROR, "command exited with exit code %lu", exit_status); - return false; - } - - CloseHandle(proc); - - return true; -#else - for (;;) { - int wstatus = 0; - if (waitpid(proc, &wstatus, 0) < 0) { - nob_log(NOB_ERROR, "could not wait on command (pid %d): %s", proc, strerror(errno)); - return false; - } - - if (WIFEXITED(wstatus)) { - int exit_status = WEXITSTATUS(wstatus); - if (exit_status != 0) { - nob_log(NOB_ERROR, "command exited with exit code %d", exit_status); - return false; - } - - break; - } - - if (WIFSIGNALED(wstatus)) { - nob_log(NOB_ERROR, "command process was terminated by %s", strsignal(WTERMSIG(wstatus))); - return false; - } - } - - return true; -#endif -} - -bool nob_cmd_run_sync(Nob_Cmd cmd) -{ - Nob_Proc p = nob_cmd_run_async(cmd); - if (p == NOB_INVALID_PROC) return false; - return nob_proc_wait(p); -} - -char *nob_shift_args(int *argc, char ***argv) -{ - NOB_ASSERT(*argc > 0); - char *result = **argv; - (*argv) += 1; - (*argc) -= 1; - return result; -} - -void nob_log(Nob_Log_Level level, const char *fmt, ...) -{ - switch (level) { - case NOB_INFO: - fprintf(stderr, "[INFO] "); - break; - case NOB_WARNING: - fprintf(stderr, "[WARNING] "); - break; - case NOB_ERROR: - fprintf(stderr, "[ERROR] "); - break; - default: - NOB_ASSERT(0 && "unreachable"); - } - - va_list args; - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - fprintf(stderr, "\n"); -} - -bool nob_read_entire_dir(const char *parent, Nob_File_Paths *children) -{ - bool result = true; - DIR *dir = NULL; - - dir = opendir(parent); - if (dir == NULL) { - nob_log(NOB_ERROR, "Could not open directory %s: %s", parent, strerror(errno)); - nob_return_defer(false); - } - - errno = 0; - struct dirent *ent = readdir(dir); - while (ent != NULL) { - nob_da_append(children, nob_temp_strdup(ent->d_name)); - ent = readdir(dir); - } - - if (errno != 0) { - nob_log(NOB_ERROR, "Could not read directory %s: %s", parent, strerror(errno)); - nob_return_defer(false); - } - -defer: - if (dir) closedir(dir); - return result; -} - -bool nob_write_entire_file(const char *path, const void *data, size_t size) -{ - bool result = true; - - FILE *f = fopen(path, "wb"); - if (f == NULL) { - nob_log(NOB_ERROR, "Could not open file %s for writing: %s\n", path, strerror(errno)); - nob_return_defer(false); - } - - // len - // v - // aaaaaaaaaa - // ^ - // data - - const char *buf = data; - while (size > 0) { - size_t n = fwrite(buf, 1, size, f); - if (ferror(f)) { - nob_log(NOB_ERROR, "Could not write into file %s: %s\n", path, strerror(errno)); - nob_return_defer(false); - } - size -= n; - buf += n; - } - -defer: - if (f) fclose(f); - return result; -} - -Nob_File_Type nob_get_file_type(const char *path) -{ -#ifdef _WIN32 - DWORD attr = GetFileAttributesA(path); - if (attr == INVALID_FILE_ATTRIBUTES) { - nob_log(NOB_ERROR, "Could not get file attributes of %s: %lu", path, GetLastError()); - return -1; - } - - if (attr & FILE_ATTRIBUTE_DIRECTORY) return NOB_FILE_DIRECTORY; - // TODO: detect symlinks on Windows (whatever that means on Windows anyway) - return NOB_FILE_REGULAR; -#else // _WIN32 - struct stat statbuf; - if (stat(path, &statbuf) < 0) { - nob_log(NOB_ERROR, "Could not get stat of %s: %s", path, strerror(errno)); - return -1; - } - - switch (statbuf.st_mode & S_IFMT) { - case S_IFDIR: return NOB_FILE_DIRECTORY; - case S_IFREG: return NOB_FILE_REGULAR; - case S_IFLNK: return NOB_FILE_SYMLINK; - default: return NOB_FILE_OTHER; - } -#endif // _WIN32 -} - -bool nob_copy_directory_recursively(const char *src_path, const char *dst_path) -{ - bool result = true; - Nob_File_Paths children = {0}; - Nob_String_Builder src_sb = {0}; - Nob_String_Builder dst_sb = {0}; - size_t temp_checkpoint = nob_temp_save(); - - Nob_File_Type type = nob_get_file_type(src_path); - if (type < 0) return false; - - switch (type) { - case NOB_FILE_DIRECTORY: { - if (!nob_mkdir_if_not_exists(dst_path)) nob_return_defer(false); - if (!nob_read_entire_dir(src_path, &children)) nob_return_defer(false); - - for (size_t i = 0; i < children.count; ++i) { - if (strcmp(children.items[i], ".") == 0) continue; - if (strcmp(children.items[i], "..") == 0) continue; - - src_sb.count = 0; - nob_sb_append_cstr(&src_sb, src_path); - nob_sb_append_cstr(&src_sb, "/"); - nob_sb_append_cstr(&src_sb, children.items[i]); - nob_sb_append_null(&src_sb); - - dst_sb.count = 0; - nob_sb_append_cstr(&dst_sb, dst_path); - nob_sb_append_cstr(&dst_sb, "/"); - nob_sb_append_cstr(&dst_sb, children.items[i]); - nob_sb_append_null(&dst_sb); - - if (!nob_copy_directory_recursively(src_sb.items, dst_sb.items)) { - nob_return_defer(false); - } - } - } break; - - case NOB_FILE_REGULAR: { - if (!nob_copy_file(src_path, dst_path)) { - nob_return_defer(false); - } - } break; - - case NOB_FILE_SYMLINK: { - nob_log(NOB_WARNING, "TODO: Copying symlinks is not supported yet"); - } break; - - case NOB_FILE_OTHER: { - nob_log(NOB_ERROR, "Unsupported type of file %s", src_path); - nob_return_defer(false); - } break; - - default: NOB_ASSERT(0 && "unreachable"); - } - -defer: - nob_temp_rewind(temp_checkpoint); - nob_da_free(src_sb); - nob_da_free(dst_sb); - nob_da_free(children); - return result; -} - -char *nob_temp_strdup(const char *cstr) -{ - size_t n = strlen(cstr); - char *result = nob_temp_alloc(n + 1); - NOB_ASSERT(result != NULL && "Increase NOB_TEMP_CAPACITY"); - memcpy(result, cstr, n); - result[n] = '\0'; - return result; -} - -void *nob_temp_alloc(size_t size) -{ - if (nob_temp_size + size > NOB_TEMP_CAPACITY) return NULL; - void *result = &nob_temp[nob_temp_size]; - nob_temp_size += size; - return result; -} - -char *nob_temp_sprintf(const char *format, ...) -{ - va_list args; - va_start(args, format); - int n = vsnprintf(NULL, 0, format, args); - va_end(args); - - NOB_ASSERT(n >= 0); - char *result = nob_temp_alloc(n + 1); - NOB_ASSERT(result != NULL && "Extend the size of the temporary allocator"); - // TODO: use proper arenas for the temporary allocator; - va_start(args, format); - vsnprintf(result, n + 1, format, args); - va_end(args); - - return result; -} - -void nob_temp_reset(void) -{ - nob_temp_size = 0; -} - -size_t nob_temp_save(void) -{ - return nob_temp_size; -} - -void nob_temp_rewind(size_t checkpoint) -{ - nob_temp_size = checkpoint; -} - -const char *nob_temp_sv_to_cstr(Nob_String_View sv) -{ - char *result = nob_temp_alloc(sv.count + 1); - NOB_ASSERT(result != NULL && "Extend the size of the temporary allocator"); - memcpy(result, sv.data, sv.count); - result[sv.count] = '\0'; - return result; -} - -int nob_needs_rebuild(const char *output_path, const char **input_paths, size_t input_paths_count) -{ -#ifdef _WIN32 - BOOL bSuccess; - - HANDLE output_path_fd = CreateFile(output_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); - if (output_path_fd == INVALID_HANDLE_VALUE) { - // NOTE: if output does not exist it 100% must be rebuilt - if (GetLastError() == ERROR_FILE_NOT_FOUND) return 1; - nob_log(NOB_ERROR, "Could not open file %s: %lu", output_path, GetLastError()); - return -1; - } - FILETIME output_path_time; - bSuccess = GetFileTime(output_path_fd, NULL, NULL, &output_path_time); - CloseHandle(output_path_fd); - if (!bSuccess) { - nob_log(NOB_ERROR, "Could not get time of %s: %lu", output_path, GetLastError()); - return -1; - } - - for (size_t i = 0; i < input_paths_count; ++i) { - const char *input_path = input_paths[i]; - HANDLE input_path_fd = CreateFile(input_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); - if (input_path_fd == INVALID_HANDLE_VALUE) { - // NOTE: non-existing input is an error cause it is needed for building in the first place - nob_log(NOB_ERROR, "Could not open file %s: %lu", input_path, GetLastError()); - return -1; - } - FILETIME input_path_time; - bSuccess = GetFileTime(input_path_fd, NULL, NULL, &input_path_time); - CloseHandle(input_path_fd); - if (!bSuccess) { - nob_log(NOB_ERROR, "Could not get time of %s: %lu", input_path, GetLastError()); - return -1; - } - - // NOTE: if even a single input_path is fresher than output_path that's 100% rebuild - if (CompareFileTime(&input_path_time, &output_path_time) == 1) return 1; - } - - return 0; -#else - struct stat statbuf = {0}; - - if (stat(output_path, &statbuf) < 0) { - // NOTE: if output does not exist it 100% must be rebuilt - if (errno == ENOENT) return 1; - nob_log(NOB_ERROR, "could not stat %s: %s", output_path, strerror(errno)); - return -1; - } - int output_path_time = statbuf.st_mtime; - - for (size_t i = 0; i < input_paths_count; ++i) { - const char *input_path = input_paths[i]; - if (stat(input_path, &statbuf) < 0) { - // NOTE: non-existing input is an error cause it is needed for building in the first place - nob_log(NOB_ERROR, "could not stat %s: %s", input_path, strerror(errno)); - return -1; - } - int input_path_time = statbuf.st_mtime; - // NOTE: if even a single input_path is fresher than output_path that's 100% rebuild - if (input_path_time > output_path_time) return 1; - } - - return 0; -#endif -} - -int nob_needs_rebuild1(const char *output_path, const char *input_path) -{ - return nob_needs_rebuild(output_path, &input_path, 1); -} - -bool nob_rename(const char *old_path, const char *new_path) -{ - nob_log(NOB_INFO, "renaming %s -> %s", old_path, new_path); -#ifdef _WIN32 - if (!MoveFileEx(old_path, new_path, MOVEFILE_REPLACE_EXISTING)) { - nob_log(NOB_ERROR, "could not rename %s to %s: %lu", old_path, new_path, GetLastError()); - return false; - } -#else - if (rename(old_path, new_path) < 0) { - nob_log(NOB_ERROR, "could not rename %s to %s: %s", old_path, new_path, strerror(errno)); - return false; - } -#endif // _WIN32 - return true; -} - -bool nob_read_entire_file(const char *path, Nob_String_Builder *sb) -{ - bool result = true; - - FILE *f = fopen(path, "rb"); - if (f == NULL) nob_return_defer(false); - if (fseek(f, 0, SEEK_END) < 0) nob_return_defer(false); - long m = ftell(f); - if (m < 0) nob_return_defer(false); - if (fseek(f, 0, SEEK_SET) < 0) nob_return_defer(false); - - size_t new_count = sb->count + m; - if (new_count > sb->capacity) { - sb->items = realloc(sb->items, new_count); - NOB_ASSERT(sb->items != NULL && "Buy more RAM lool!!"); - sb->capacity = new_count; - } - - fread(sb->items + sb->count, m, 1, f); - if (ferror(f)) { - // TODO: Afaik, ferror does not set errno. So the error reporting in defer is not correct in this case. - nob_return_defer(false); - } - sb->count = new_count; - -defer: - if (!result) nob_log(NOB_ERROR, "Could not read file %s: %s", path, strerror(errno)); - if (f) fclose(f); - return result; -} - -Nob_String_View nob_sv_chop_by_delim(Nob_String_View *sv, char delim) -{ - size_t i = 0; - while (i < sv->count && sv->data[i] != delim) { - i += 1; - } - - Nob_String_View result = nob_sv_from_parts(sv->data, i); - - if (i < sv->count) { - sv->count -= i + 1; - sv->data += i + 1; - } else { - sv->count -= i; - sv->data += i; - } - - return result; -} - -Nob_String_View nob_sv_from_parts(const char *data, size_t count) -{ - Nob_String_View sv; - sv.count = count; - sv.data = data; - return sv; -} - -Nob_String_View nob_sv_trim_left(Nob_String_View sv) -{ - size_t i = 0; - while (i < sv.count && isspace(sv.data[i])) { - i += 1; - } - - return nob_sv_from_parts(sv.data + i, sv.count - i); -} - -Nob_String_View nob_sv_trim_right(Nob_String_View sv) -{ - size_t i = 0; - while (i < sv.count && isspace(sv.data[sv.count - 1 - i])) { - i += 1; - } - - return nob_sv_from_parts(sv.data, sv.count - i); -} - -Nob_String_View nob_sv_trim(Nob_String_View sv) -{ - return nob_sv_trim_right(nob_sv_trim_left(sv)); -} - -Nob_String_View nob_sv_from_cstr(const char *cstr) -{ - return nob_sv_from_parts(cstr, strlen(cstr)); -} - -bool nob_sv_eq(Nob_String_View a, Nob_String_View b) -{ - if (a.count != b.count) { - return false; - } else { - return memcmp(a.data, b.data, a.count) == 0; - } -} - -// RETURNS: -// 0 - file does not exists -// 1 - file exists -// -1 - error while checking if file exists. The error is logged -int nob_file_exists(const char *file_path) -{ -#if _WIN32 - // TODO: distinguish between "does not exists" and other errors - DWORD dwAttrib = GetFileAttributesA(file_path); - return dwAttrib != INVALID_FILE_ATTRIBUTES; -#else - struct stat statbuf; - if (stat(file_path, &statbuf) < 0) { - if (errno == ENOENT) return 0; - nob_log(NOB_ERROR, "Could not check if file %s exists: %s", file_path, strerror(errno)); - return -1; - } - return 1; -#endif -} - -// minirent.h SOURCE BEGIN //////////////////////////////////////// -#ifdef _WIN32 -struct DIR -{ - HANDLE hFind; - WIN32_FIND_DATA data; - struct dirent *dirent; -}; - -DIR *opendir(const char *dirpath) -{ - assert(dirpath); - - char buffer[MAX_PATH]; - snprintf(buffer, MAX_PATH, "%s\\*", dirpath); - - DIR *dir = (DIR*)calloc(1, sizeof(DIR)); - - dir->hFind = FindFirstFile(buffer, &dir->data); - if (dir->hFind == INVALID_HANDLE_VALUE) { - // TODO: opendir should set errno accordingly on FindFirstFile fail - // https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror - errno = ENOSYS; - goto fail; - } - - return dir; - -fail: - if (dir) { - free(dir); - } - - return NULL; -} - -struct dirent *readdir(DIR *dirp) -{ - assert(dirp); - - if (dirp->dirent == NULL) { - dirp->dirent = (struct dirent*)calloc(1, sizeof(struct dirent)); - } else { - if(!FindNextFile(dirp->hFind, &dirp->data)) { - if (GetLastError() != ERROR_NO_MORE_FILES) { - // TODO: readdir should set errno accordingly on FindNextFile fail - // https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror - errno = ENOSYS; - } - - return NULL; - } - } - - memset(dirp->dirent->d_name, 0, sizeof(dirp->dirent->d_name)); - - strncpy( - dirp->dirent->d_name, - dirp->data.cFileName, - sizeof(dirp->dirent->d_name) - 1); - - return dirp->dirent; -} - -int closedir(DIR *dirp) -{ - assert(dirp); - - if(!FindClose(dirp->hFind)) { - // TODO: closedir should set errno accordingly on FindClose fail - // https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror - errno = ENOSYS; - return -1; - } - - if (dirp->dirent) { - free(dirp->dirent); - } - free(dirp); - - return 0; -} -#endif // _WIN32 -// minirent.h SOURCE END //////////////////////////////////////// - -#endif diff --git a/bootloader/param.json b/bootloader/param.json diff --git a/bootloader/src/bl.c b/bootloader/src/bl.c @@ -1,123 +0,0 @@ -#include <stdio.h> -#include "ncurses.h" -#include "comm.h" -#include <fcntl.h> -#include <string.h> -#include <errno.h> -#include <stdlib.h> - -int main_cols, main_lines; -int main_cols_cur, main_lines_cur; -WINDOW *mainwin; -WINDOW *menuwin; -WINDOW *infowin; - -static void redraw(void) -{ - mainwin = initscr(); - getmaxyx(stdscr, main_lines, main_cols); - int menu_win_cols = main_cols /3; - int menu_win_lines = 2 * main_lines / 3; - menuwin = subwin(mainwin, menu_win_lines, menu_win_cols, main_lines/2 - menu_win_lines/2, main_cols/4 - menu_win_cols/2); - infowin = subwin(mainwin, menu_win_lines, menu_win_cols, main_lines/2 - menu_win_lines/2, 3*main_cols/4 - menu_win_cols/2); - box(mainwin, 0, 0); - box(menuwin, 0, 0); - wprintw(mainwin, " Bootloader "); - wprintw(menuwin, " Watcha wanna do? "); - - keypad(menuwin, true); - -} - -typedef struct { - uint8_t number; - char *desc; -} Menu_t; - -#define item_no 8 - -Menu_t mainmenu[item_no] = { - {.number = COMMAND_PR, .desc = "- Read parameters [1]" } , - {.number = COMMAND_PU, .desc = "- Update parameters [2]" } , - {.number = COMMAND_RFI, .desc = "- Read firmware info [3]" } , - {.number = COMMAND_RST, .desc = "- Update the firmware [4]" } , - {.number = COMMAND_LOCK, .desc = "- Lock serial line [5]" } , - {.number = COMMAND_UNLOCK, .desc = "- Unlock serial line [6]" } , - {.number = COMMAND_RDIAG, .desc = "- Read diagnostics [7]" } , - {.number = COMMAND_QUIT, .desc = "- Quit [0]" } , -}; - -int main(int argc, char **argv) -{ - char *serialPort = "/dev/ttyUSB0"; - char response[1024] = {0}; - redraw(); - comm_open_serial_port(serialPort, response); - mvwprintw(infowin, 3, 0, response); - wrefresh(infowin); - wrefresh(mainwin); - - (void)argc; - (void)argv; - - redraw(); - - int choice = 1; - uint8_t highlight = 0; - uint8_t option = 0; - - while (option != item_no - 1) { - - getmaxyx(stdscr, main_lines_cur, main_cols_cur); - if (main_lines_cur != main_lines || main_cols_cur != main_cols) { - werase(mainwin); - werase(infowin); - werase(menuwin); - redraw(); - main_lines = main_lines_cur; - main_cols = main_cols_cur; - } - for(uint8_t i = 0; i < item_no; i++) { - if (i == highlight) wattron(menuwin, A_REVERSE); - mvwprintw(menuwin, i + 2, 2, mainmenu[i].desc); - wattroff(menuwin, A_REVERSE); - } - wrefresh(menuwin); - wrefresh(mainwin); - wrefresh(infowin); - choice = wgetch(menuwin); - switch(choice) { - case KEY_UP: - highlight--; - if (highlight == 0xff) highlight = item_no - 1; - break; - case KEY_DOWN: - highlight = (highlight + 1) % item_no; - break; - default: - break; - } - if (choice == 10) { - option = highlight; - wclear(infowin); - char buffer[255]; - sprintf(buffer, "Command: %s", mainmenu[highlight].desc); - mvwprintw(infowin, 1, 0, buffer); - if (mainmenu[highlight].number == COMMAND_RST) { - sprintf(buffer, "Update in progress ... "); - mvwprintw(infowin, 2, 1, buffer); - } - wrefresh(infowin); - uint16_t len = execute_command(mainmenu[highlight].number, response); - response[len] = '\0'; - mvwprintw(infowin, 3, 0, response); - wrefresh(infowin); - wrefresh(mainwin); - } - } - - comm_close_serial_port(); - - endwin(); - return 0; -} diff --git a/bootloader/src/core/comm.c b/bootloader/src/core/comm.c @@ -1,536 +0,0 @@ -#include <stdio.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdlib.h> -#include "comm.h" -#include "ser.h" -#include <string.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/stat.h> -#include <unistd.h> -#include <inttypes.h> -#include "jsmn-helper.h" - -#define DMA_RX_BUFFER_SIZE = 128 -#define PACKET_MAX_DATA_LEN = DMA_RX_BUFFER_SIZE - 1 - -#define PACK_TAG_INDEX = 0 -#define PACK_LENGTH_INDEX = 1 - -static int port_fd; - -typedef enum __attribute__((packed)) { - PR = 0, - PW = 1, - FIR = 2, - RST = 3, - ACK = 4, - NACK = 5, - LOCK = 6, - UNLOCK = 7, - DIAG = 8, - SYNC = 9, - UPDATE_REQ = 10, - DEV_ID_CHECK = 11, - UPDATE_SIZE = 12, - ERASE_REQ = 13, - FW_NEW = 14, - FW_REP = 15, -} Tag_t; - -enum results { - SUCCESS, - TIMEOUT, - TX_CORRUPT, - RX_CORRUPT, -}; - -typedef struct { - uint8_t code; - char *desc; -} Result_t; - -Result_t resultTable[4] = { - { .code = SUCCESS, .desc = "Success" }, - { .code = TIMEOUT, .desc = "Timeout" }, - { .code = TX_CORRUPT, .desc = "NACK received" }, - { .code = RX_CORRUPT, .desc = "RX packet Corruption" }, -}; - - -typedef struct { - uint8_t major; - uint8_t minor; - uint8_t patch; - uint8_t sha1[5]; -} FWVersion_t; - -typedef struct __attribute__((packed)) { - uint32_t sentinel; - uint32_t devID; - FWVersion_t fwVersion; - uint32_t fwLength; - uint32_t crc32; -} FWInfo_t; - -typedef enum { - BOOTLOADER, - APPLICATION, -} CurrentInstance_t; - -typedef struct { - uint8_t active; - uint8_t ch[2]; -} Lane_t; - -typedef struct __attribute__((packed)) { - bool switchingActive; - uint32_t TB_SW_frequency; -} CaptureConfig_t; - -typedef struct { - Lane_t lane0; - Lane_t lane1; - Lane_t lane2; - Lane_t lane3; -} Layout_t; - -typedef struct __attribute__((packed)) { - CurrentInstance_t currentInstance; - float entranceTh; - float exitTh; - uint32_t entranceDB; - uint32_t exitDB; - Layout_t layout; - CaptureConfig_t captureConfig; - uint8_t filterAvgWindow; -} Param_t; - -typedef struct { - Tag_t tag; - char desc[30]; -} TagDesc_t; - -static uint16_t crc16_calculate(const uint8_t *data, uint16_t size) { -#define POLY16 (uint16_t)0x8005 - uint16_t out = 0; - int bits_read = 0, bit_flag; - /* Sanity check: */ - if (data == NULL) - return 0; - while (size > 0) { - bit_flag = out >> 15; - /* Get next bit: */ - out <<= 1; - out |= (*data >> (7 - bits_read)) & 1; - /* Increment bit counter: */ - bits_read++; - if (bits_read > 7) { - bits_read = 0; - data++; - size--; - } - /* Cycle check: */ - if (bit_flag) { - out ^= POLY16; - } - } - return out; -} - -static uint32_t crc32_calculate(const uint8_t *data, uint16_t size) { -#define POLY32 (uint32_t)0xEDB88320 - uint32_t out = 0; - int bits_read = 0, bit_flag; - /* Sanity check: */ - if (data == NULL) - return 0; - while (size > 0) { - bit_flag = out >> 31; - /* Get next bit: */ - out <<= 1; - out |= (*data >> (7 - bits_read)) & 1; - /* Increment bit counter: */ - bits_read++; - if (bits_read > 7) { - bits_read = 0; - data++; - size--; - } - /* Cycle check: */ - if (bit_flag) { - out ^= POLY32; - } - } - return out; -} - -static int load_param_from_json(Param_t *prm) -{ - - if (jsmn_load_json_to_memory("param.json") == -1) return -1; - Value_t value = {0}; - value = jsmn_get_value(UINT, "currentInstance", NULL); - prm->currentInstance = value.uvalue; - value = jsmn_get_value(FLOAT, "entranceTh", NULL); - prm->entranceTh = value.fvalue; - value = jsmn_get_value(FLOAT, "exitTh", NULL); - prm->exitTh = value.fvalue; - value = jsmn_get_value(UINT, "entranceDB", NULL); - prm->entranceDB = value.uvalue; - value = jsmn_get_value(UINT, "exitDB", NULL); - prm->exitDB = value.uvalue; - value = jsmn_get_value(UINT, "layout", "lane0", "active", NULL); - prm->layout.lane0.active = value.uvalue; - value = jsmn_get_value(UINT, "layout", "lane1", "active", NULL); - prm->layout.lane1.active = value.uvalue; - value = jsmn_get_value(UINT, "layout", "lane2", "active", NULL); - prm->layout.lane2.active = value.uvalue; - value = jsmn_get_value(UINT, "layout", "lane3", "active", NULL); - prm->layout.lane3.active = value.uvalue; - value = jsmn_get_value(ARRAY, "layout", "lane0", "ch", 0, NULL); - prm->layout.lane0.ch[0] = value.uvalue; - value = jsmn_get_value(ARRAY, "layout", "lane0", "ch", 1, NULL); - prm->layout.lane0.ch[1] = value.uvalue; - value = jsmn_get_value(ARRAY, "layout", "lane1", "ch", 0, NULL); - prm->layout.lane1.ch[0] = value.uvalue; - value = jsmn_get_value(ARRAY, "layout", "lane1", "ch", 1, NULL); - prm->layout.lane1.ch[1] = value.uvalue; - value = jsmn_get_value(ARRAY, "layout", "lane2", "ch", 0, NULL); - prm->layout.lane2.ch[0] = value.uvalue; - value = jsmn_get_value(ARRAY, "layout", "lane2", "ch", 1, NULL); - prm->layout.lane2.ch[1] = value.uvalue; - value = jsmn_get_value(ARRAY, "layout", "lane3", "ch", 0, NULL); - prm->layout.lane3.ch[0] = value.uvalue; - value = jsmn_get_value(ARRAY, "layout", "lane3", "ch", 1, NULL); - prm->layout.lane3.ch[1] = value.uvalue; - value = jsmn_get_value(UINT, "captureConfig", "switchingActive", NULL); - prm->captureConfig.switchingActive = value.uvalue; - value = jsmn_get_value(UINT, "captureConfig", "TB_SW_frequency", NULL); - prm->captureConfig.TB_SW_frequency = value.uvalue; - value = jsmn_get_value(UINT, "filterAvgWindow", NULL); - prm->filterAvgWindow = value.uvalue; - return 0; -} - -void create_packet(uint8_t *packet, Tag_t tag, uint8_t *data, uint16_t data_sz) -{ - memset(packet, 0, 1024); - uint8_t packetSize = data_sz + 4; - packet[0] = tag; - packet[1] = data_sz; - if (data != NULL) memcpy(&packet[2], data, data_sz); - uint16_t crc = crc16_calculate(packet, packetSize); - packet[2+data_sz] = (crc >> 8) & 0xFF; - packet[3+data_sz] = crc & 0xFF; -} - -static void create_fw_packet(uint8_t *packet, Tag_t tag, uint8_t *data, size_t data_sz) -{ - memset(packet, 0, 1024); - uint8_t packetSize = data_sz + 6; - packet[0] = tag; - packet[1] = data_sz; - if (data != NULL) memcpy(&packet[2], data, data_sz); - uint32_t crc = crc32_calculate(packet, packetSize); - packet[2+data_sz] = (crc >> 24) & 0xFF; - packet[3+data_sz] = (crc >> 16) & 0xFF; - packet[4+data_sz] = (crc >> 8) & 0xFF; - packet[5+data_sz] = crc & 0xFF; -} - -void parse_parameters(uint8_t *raw, char *response) -{ - Param_t *params = (Param_t *)(raw + 2); - sprintf(response, "current instance = %u\nentranceTh = %.0f\nexitTh = %.0f\nentranceDB = %u\nexitDB = %u\nlane0: {active: %u, ch = [%u, %u]}\nlane1: {active: %u, ch = [%u, %u]}\nlane2: {active: %u, ch = [%u, %u]}\nlane3: {active: %u, ch = [%u, %u]}\nswitching: %u, frequency: %u\nfilterAvgWindow: %u\n" - , params->currentInstance, params->entranceTh, params->exitTh - , params->entranceDB , params->exitDB - , params->layout.lane0.active, params->layout.lane0.ch[0], params->layout.lane0.ch[1] - , params->layout.lane1.active, params->layout.lane1.ch[0], params->layout.lane1.ch[1] - , params->layout.lane2.active, params->layout.lane2.ch[0], params->layout.lane2.ch[1] - , params->layout.lane3.active, params->layout.lane3.ch[0], params->layout.lane3.ch[1] - , params->captureConfig.switchingActive, params->captureConfig.TB_SW_frequency - , params->filterAvgWindow); -} - -void parse_fw_info(uint8_t *raw, char *response) -{ - FWInfo_t *info = (FWInfo_t *)(raw + 2); - sprintf(response, "sentinel = 0x%x\ndevice ID = %u\nVersion = v%u.%u-%x-%c%c%c%c%c\nFirmware Size = %u\nCRC32 = 0x%x", - info->sentinel, info->devID, info->fwVersion.major, info->fwVersion.minor, - info->fwVersion.patch, info->fwVersion.sha1[0], info->fwVersion.sha1[1], - info->fwVersion.sha1[2], info->fwVersion.sha1[3], info->fwVersion.sha1[4], - info->fwLength, info->crc32); -} - -static Result_t update_check_response(uint8_t *rx_buffer, size_t len) -{ - if (len == 0) return resultTable[TIMEOUT]; - if (crc16_calculate(rx_buffer, len) != 0) return resultTable[RX_CORRUPT]; - if (rx_buffer[0] == NACK) return resultTable[TX_CORRUPT]; - return resultTable[SUCCESS]; -} - -static void update_state_machine(char *response) -{ - sleep(1); - uint8_t packet[1024] = {0}; - uint8_t rx_buffer[1024] = {0}; - uint8_t retry = 0; - uint8_t state = SYNC; - struct stat fwStat; - memset(response, 0, 1024); - while (state != 0) { - if (retry > 0) { - if (retry >= 5) state = 0; - } - switch(state) { - case SYNC: - { - create_packet(packet, SYNC, NULL, 0); - ser_send_packet(port_fd, packet, 4); - int len = ser_listen_and_receive_packet(port_fd, rx_buffer, 4, 10); - Result_t result = update_check_response(rx_buffer, len); - if (result.code == resultTable[SUCCESS].code) { - sleep(1); - state++; - } else { - sprintf(response, "\nFailed at Level SYNC: %s", result.desc); - retry++; - } - } break; - case UPDATE_REQ: - { - create_packet(packet, UPDATE_REQ, NULL, 0); - ser_send_packet(port_fd, packet, 4); - int len = ser_listen_and_receive_packet(port_fd, rx_buffer, 4, 10); - Result_t result = update_check_response(rx_buffer, len); - if (result.code == resultTable[SUCCESS].code) { - sleep(1); - state++; - } else { - sprintf(response, "\nFailed at Level UPDATE_REQ: %s", result.desc); - retry++; - } - } break; - case DEV_ID_CHECK: - { - FILE *devidFile = fopen("devID", "r"); - if (devidFile == NULL) { - sprintf(response, "\nFailed at level DEV_ID_CHECK: opening devID file: %s", strerror(errno)); - state = 0; - break; - } - char buffer[7]; // 0x[dddd][\n] - fgets(buffer, 7, devidFile); - uint32_t devid = (uint32_t)strtoul(buffer, NULL, 16); - create_packet(packet, DEV_ID_CHECK, (uint8_t *)&devid, 4); - ser_send_packet(port_fd, packet, 8); - int len = ser_listen_and_receive_packet(port_fd, rx_buffer, 4, 10); - Result_t result = update_check_response(rx_buffer, len); - if (result.code == resultTable[SUCCESS].code) { - state++; - } else { - sprintf(response, "\nFailed at Level DEV_ID_CHECK: %s", result.desc); - retry++; - } - } break; - case UPDATE_SIZE: - { - if (stat("fw.bin", &fwStat) != 0) { - sprintf(response, "\nFailed at level UPDATE_SIZE: Getting fw.bin file: %s", strerror(errno)); - state = 0; - break; - } - uint32_t fwSize = (uint32_t)fwStat.st_size; - create_packet(packet, UPDATE_SIZE, (uint8_t *)&fwSize, 4); - ser_send_packet(port_fd, packet, 8); - int len = ser_listen_and_receive_packet(port_fd, rx_buffer, 4, 10); - Result_t result = update_check_response(rx_buffer, len); - if (result.code == resultTable[SUCCESS].code) { - state++; - } else { - sprintf(response, "\nFailed at Level UPDATE_SIZE: %s", result.desc); - retry++; - } - } break; - case ERASE_REQ: - { - create_packet(packet, ERASE_REQ, NULL, 0); - ser_send_packet(port_fd, packet, 4); - int len = ser_listen_and_receive_packet(port_fd, rx_buffer, 4, 10); - Result_t result = update_check_response(rx_buffer, len); - if (result.code == resultTable[SUCCESS].code) { - state++; - } else { - sprintf(response, "\nFailed at Level ERASE_REQ: %s", result.desc); - retry++; - } - } break; - case FW_NEW: - { - uint8_t chunk[128] = {0}; - uint16_t pack = 0; - uint8_t bytes_read_into_chunk = 0; - FILE *fwFile = fopen("fw.bin", "rb"); - if (fwFile == NULL) { - sprintf(response, "\nFailed at level FW_NEW: Opening fw.bin file: %s", strerror(errno)); - state = 0; - break; - } - uint32_t totalChunk = (fwStat.st_size / 128) + 1; - pack = 1; - retry = 0; - while (retry <= 5) { - if (retry == 0) bytes_read_into_chunk = fread(chunk, 1, 128, fwFile); - if (bytes_read_into_chunk == 0) { - break; - } - if (retry == 0) { - pack++; - create_fw_packet(packet, FW_NEW, chunk, bytes_read_into_chunk); - } else create_fw_packet(packet, FW_REP, chunk, bytes_read_into_chunk); - ser_send_packet(port_fd, packet, bytes_read_into_chunk + 6); - int len = ser_listen_and_receive_packet(port_fd, rx_buffer, 4, 1); - if (len != 0 && crc16_calculate(rx_buffer, len) == 0) { - if (rx_buffer[0] == ACK) retry = 0; - else retry++; - } else retry++; - } - fclose(fwFile); - if (pack == totalChunk + 1) sprintf(response + strlen(response), "\nAll good!"); - else sprintf(response + strlen(response), "\nFailed at level FW_NEW: chunks: %u/%u", pack, totalChunk); - state = 0; - } break; - } - } -} -static void protocol_state_machine(uint8_t *rx_buffer, size_t len, Command_t command, char *response) -{ - memset(response, 0, 1024); - if (crc16_calculate(rx_buffer, len) != 0) { - sprintf(response, "CRC Error\n"); - } - switch(rx_buffer[0]) { - case ACK: - { - if (command == COMMAND_RFI) { - parse_fw_info(rx_buffer, response); - } else if (command == COMMAND_PR) { - parse_parameters(rx_buffer, response); - } else if (command == COMMAND_PU) { - sprintf(response, "Parameters updated successfully."); - } else if (command == COMMAND_RST) { - sprintf(response, "Core rebooted. Sending Sync command ..."); - update_state_machine(response); - } else if (command == COMMAND_LOCK || command == COMMAND_UNLOCK) { - sprintf(response, "Process successfull"); - } else if (command == COMMAND_PU) { - sprintf(response, "Not implemented"); - } else if (command == COMMAND_RDIAG) { - if (rx_buffer[1] == 0) sprintf(response, "No diagnostics saved"); - else { - sprintf(response, "Diagnostics:\n"); - for (uint16_t i = 0; i < len; i++) { - sprintf(response + strlen(response), "%u -> %x\n", i+1, rx_buffer[i+2]); - } - } - } - } break; - case NACK: - { - sprintf(response, "Nack received"); - } break; - } -} - -uint16_t execute_command(uint8_t command, char *response) -{ - uint8_t packet[1024]; - uint8_t rx_size = 0; - switch(command) { - case COMMAND_PR: - { - uint8_t data[2] = {0, sizeof(Param_t)}; - create_packet(packet, PR, data, sizeof(data)/sizeof(data[0])); - ser_send_packet(port_fd, packet, 6); - rx_size = sizeof(Param_t) + 4; - } break; - case COMMAND_PU: - { - Param_t prm = {0}; - if (load_param_from_json(&prm) == -1) { - sprintf(response, "Loading param.json: %s", strerror(errno)); - return strlen(response); - } - create_packet(packet, PW, (uint8_t *)&prm, sizeof(Param_t)); - ser_send_packet(port_fd, packet, sizeof(Param_t) + 4); - rx_size = 4; - } break; - case COMMAND_RFI: - { - uint8_t data[2] = {0, sizeof(FWInfo_t)}; - create_packet(packet, FIR, data, sizeof(data) / sizeof(data[0])); - ser_send_packet(port_fd, packet, 6); - rx_size = sizeof(FWInfo_t) + 4; - } break; - case COMMAND_RST: - { - create_packet(packet, RST, NULL, 0); - ser_send_packet(port_fd, packet, 4); - rx_size = 4; - } break; - case COMMAND_LOCK: - { - create_packet(packet, LOCK, NULL, 0); - ser_send_packet(port_fd, packet, 4); - rx_size = 4; - } break; - - case COMMAND_UNLOCK: - { - create_packet(packet, UNLOCK, NULL, 0); - ser_send_packet(port_fd, packet, 4); - rx_size = 4; - } break; - - case COMMAND_RDIAG: - { - create_packet(packet, DIAG, NULL, 0); - ser_send_packet(port_fd, packet, 4); - rx_size = 4; - } break; - default: return 0;; - } - uint8_t rx_buffer[1024] = {0}; - int len = ser_listen_and_receive_packet(port_fd, rx_buffer, rx_size, 2); - if (len > 0) { - protocol_state_machine(rx_buffer, len, command, response); - return strlen(response); - } else if (len == 0) { - sprintf(response, "Timeout\n"); - return strlen(response); - } - sprintf(response, "Error reading from serial port: %s\nProbably disconnected USB-Serial converter", strerror(errno)); - return strlen(response); -} - -int comm_open_serial_port(char *addr, char *response) -{ - port_fd = open(addr, O_RDWR | O_NOCTTY); - if (port_fd == -1) { - sprintf(response, "Error openning port %s: %s\n", addr, strerror(errno)); - return port_fd; - } - if (configure_serial_port(port_fd) == -1) { - sprintf(response, "Error configuring port %s: %s\n", addr, strerror(errno)); - return port_fd; - } - return port_fd; -} - -void comm_close_serial_port(void) -{ - close(port_fd); -} diff --git a/bootloader/src/core/comm.h b/bootloader/src/core/comm.h @@ -1,18 +0,0 @@ -#ifndef __COMM_H__ -#define __COMM_H__ - -typedef enum { - COMMAND_PR, - COMMAND_PU, - COMMAND_RFI, - COMMAND_RST, - COMMAND_LOCK, - COMMAND_UNLOCK, - COMMAND_RDIAG, - COMMAND_QUIT, -} Command_t; - -uint16_t execute_command(uint8_t command, char *response); -int comm_open_serial_port(char *addr, char *response); -void comm_close_serial_port(void); -#endif // __COMM_H__ diff --git a/bootloader/src/core/jsmn-helper.h b/bootloader/src/core/jsmn-helper.h @@ -1,114 +0,0 @@ -#include "jsmn.h" -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <stdarg.h> - -#define MAX_TOKENS 128 -#define MAX_FILE_SZ 1024 -jsmn_parser parser; -jsmntok_t tokens[MAX_TOKENS]; -int parsed_tokens_cnt; -char json_str[MAX_FILE_SZ]; - -typedef union { - float fvalue; - uint32_t uvalue; -} Value_t; - -typedef enum { - UINT, - FLOAT, - ARRAY, -} Type_t; - -typedef struct { - size_t idx; - jsmntok_t value; -} Key_t; - -static Key_t jsmn_find_object(char *js, jsmntok_t *toks, size_t cnt, char *name) -{ - Key_t key = {0}; - size_t i = 0; - for (i = 0; i < cnt; i++) { - if (toks[i].type == JSMN_STRING) { - if (strncmp(&js[toks[i].start], name, strlen(name)) == 0) break; - } - } - key.idx = i; - key.value = toks[i+1]; - return key; -} - -static Value_t jsmn_get_value(Type_t type, ...) -{ - va_list args; - va_start(args, type); - char *arg = va_arg(args, char *); - jsmntok_t *tokensptr = tokens; - jsmn_parser new_parser; - Key_t key = {0}; - jsmntok_t new_tokens[MAX_TOKENS]; - int new_tok_cnt = parsed_tokens_cnt; - Value_t result; - char *js_start = json_str + key.value.start; - while(arg != NULL) { - key = jsmn_find_object(js_start, tokensptr, new_tok_cnt, arg); - if (key.value.type == JSMN_OBJECT) { - jsmn_init(&new_parser); - js_start += key.value.start; - memset(new_tokens, 0, MAX_TOKENS * sizeof(jsmntok_t)); - new_tok_cnt = jsmn_parse(&new_parser, js_start, key.value.end - key.value.start, new_tokens, MAX_TOKENS); - tokensptr = new_tokens; - } else if (key.value.type == JSMN_PRIMITIVE) { - size_t len = key.value.end - key.value.start + 1; - char *buffer = calloc(len + 1, 1); - snprintf(buffer, len, "%s", js_start+key.value.start); - if (type == UINT) result.uvalue = strtoul(buffer, NULL, 10); - else result.fvalue = strtof(buffer, NULL); - } else if (key.value.type == JSMN_ARRAY && type == ARRAY) { - uint8_t idx = (uint8_t)va_arg(args, int); - if (idx >= key.value.size) { - result.uvalue = -1; - goto end; - } - else { - jsmntok_t ret = new_tokens[key.idx+idx+2]; - size_t len = ret.end - ret.start + 1; - char *buffer = calloc(len + 1, 1); - snprintf(buffer, len, "%s", js_start+ret.start); - result.uvalue = strtoul(buffer, NULL, 10); - } - } - arg = va_arg(args, char *); - } -end: - va_end(args); - return result; -} - -int jsmn_load_json_to_memory(char *path) -{ - FILE *fp = fopen(path, "r"); - if (fp == NULL) return -1; - fread(json_str, sizeof(json_str), 1, fp); - fclose(fp); - jsmn_init(&parser); - parsed_tokens_cnt = jsmn_parse(&parser, json_str, strlen(json_str), tokens, MAX_TOKENS); - return 0; -} -// int main(void) -// { -// FILE *fp = fopen("param.json", "r"); -// fread(json_str, sizeof(json_str), 1, fp); -// fclose(fp); -// -// jsmn_init(&parser); -// parsed_tokens_cnt = jsmn_parse(&parser, json_str, strlen(json_str), tokens, MAX_TOKENS); -// -// Value_t ac = jsmn_get_value(ARRAY, "layout", "lane3", "ch", 2, NULL); -// printf("active = %x\n", ac.uvalue); -// return 0; -// } diff --git a/bootloader/src/core/jsmn.h b/bootloader/src/core/jsmn.h @@ -1,471 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2010 Serge Zaitsev - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef JSMN_H -#define JSMN_H - -#include <stddef.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef JSMN_STATIC -#define JSMN_API static -#else -#define JSMN_API extern -#endif - -/** - * JSON type identifier. Basic types are: - * o Object - * o Array - * o String - * o Other primitive: number, boolean (true/false) or null - */ -typedef enum { - JSMN_UNDEFINED = 0, - JSMN_OBJECT = 1 << 0, - JSMN_ARRAY = 1 << 1, - JSMN_STRING = 1 << 2, - JSMN_PRIMITIVE = 1 << 3 -} jsmntype_t; - -enum jsmnerr { - /* Not enough tokens were provided */ - JSMN_ERROR_NOMEM = -1, - /* Invalid character inside JSON string */ - JSMN_ERROR_INVAL = -2, - /* The string is not a full JSON packet, more bytes expected */ - JSMN_ERROR_PART = -3 -}; - -/** - * JSON token description. - * type type (object, array, string etc.) - * start start position in JSON data string - * end end position in JSON data string - */ -typedef struct jsmntok { - jsmntype_t type; - int start; - int end; - int size; -#ifdef JSMN_PARENT_LINKS - int parent; -#endif -} jsmntok_t; - -/** - * JSON parser. Contains an array of token blocks available. Also stores - * the string being parsed now and current position in that string. - */ -typedef struct jsmn_parser { - unsigned int pos; /* offset in the JSON string */ - unsigned int toknext; /* next token to allocate */ - int toksuper; /* superior token node, e.g. parent object or array */ -} jsmn_parser; - -/** - * Create JSON parser over an array of tokens - */ -JSMN_API void jsmn_init(jsmn_parser *parser); - -/** - * Run JSON parser. It parses a JSON data string into and array of tokens, each - * describing - * a single JSON object. - */ -JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, - jsmntok_t *tokens, const unsigned int num_tokens); - -#ifndef JSMN_HEADER -/** - * Allocates a fresh unused token from the token pool. - */ -static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, - const size_t num_tokens) { - jsmntok_t *tok; - if (parser->toknext >= num_tokens) { - return NULL; - } - tok = &tokens[parser->toknext++]; - tok->start = tok->end = -1; - tok->size = 0; -#ifdef JSMN_PARENT_LINKS - tok->parent = -1; -#endif - return tok; -} - -/** - * Fills token type and boundaries. - */ -static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type, - const int start, const int end) { - token->type = type; - token->start = start; - token->end = end; - token->size = 0; -} - -/** - * Fills next available token with JSON primitive. - */ -static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, - const size_t len, jsmntok_t *tokens, - const size_t num_tokens) { - jsmntok_t *token; - int start; - - start = parser->pos; - - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - switch (js[parser->pos]) { -#ifndef JSMN_STRICT - /* In strict mode primitive must be followed by "," or "}" or "]" */ - case ':': -#endif - case '\t': - case '\r': - case '\n': - case ' ': - case ',': - case ']': - case '}': - goto found; - default: - /* to quiet a warning from gcc*/ - break; - } - if (js[parser->pos] < 32 || js[parser->pos] >= 127) { - parser->pos = start; - return JSMN_ERROR_INVAL; - } - } -#ifdef JSMN_STRICT - /* In strict mode primitive must be followed by a comma/object/array */ - parser->pos = start; - return JSMN_ERROR_PART; -#endif - -found: - if (tokens == NULL) { - parser->pos--; - return 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - parser->pos--; - return 0; -} - -/** - * Fills next token with JSON string. - */ -static int jsmn_parse_string(jsmn_parser *parser, const char *js, - const size_t len, jsmntok_t *tokens, - const size_t num_tokens) { - jsmntok_t *token; - - int start = parser->pos; - - /* Skip starting quote */ - parser->pos++; - - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c = js[parser->pos]; - - /* Quote: end of string */ - if (c == '\"') { - if (tokens == NULL) { - return 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos); -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - return 0; - } - - /* Backslash: Quoted symbol expected */ - if (c == '\\' && parser->pos + 1 < len) { - int i; - parser->pos++; - switch (js[parser->pos]) { - /* Allowed escaped symbols */ - case '\"': - case '/': - case '\\': - case 'b': - case 'f': - case 'r': - case 'n': - case 't': - break; - /* Allows escaped symbol \uXXXX */ - case 'u': - parser->pos++; - for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; - i++) { - /* If it isn't a hex character we have an error */ - if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ - (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ - (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ - parser->pos = start; - return JSMN_ERROR_INVAL; - } - parser->pos++; - } - parser->pos--; - break; - /* Unexpected symbol */ - default: - parser->pos = start; - return JSMN_ERROR_INVAL; - } - } - } - parser->pos = start; - return JSMN_ERROR_PART; -} - -/** - * Parse JSON string and fill tokens. - */ -JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, - jsmntok_t *tokens, const unsigned int num_tokens) { - int r; - int i; - jsmntok_t *token; - int count = parser->toknext; - - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c; - jsmntype_t type; - - c = js[parser->pos]; - switch (c) { - case '{': - case '[': - count++; - if (tokens == NULL) { - break; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - return JSMN_ERROR_NOMEM; - } - if (parser->toksuper != -1) { - jsmntok_t *t = &tokens[parser->toksuper]; -#ifdef JSMN_STRICT - /* In strict mode an object or array can't become a key */ - if (t->type == JSMN_OBJECT) { - return JSMN_ERROR_INVAL; - } -#endif - t->size++; -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - } - token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); - token->start = parser->pos; - parser->toksuper = parser->toknext - 1; - break; - case '}': - case ']': - if (tokens == NULL) { - break; - } - type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); -#ifdef JSMN_PARENT_LINKS - if (parser->toknext < 1) { - return JSMN_ERROR_INVAL; - } - token = &tokens[parser->toknext - 1]; - for (;;) { - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - token->end = parser->pos + 1; - parser->toksuper = token->parent; - break; - } - if (token->parent == -1) { - if (token->type != type || parser->toksuper == -1) { - return JSMN_ERROR_INVAL; - } - break; - } - token = &tokens[token->parent]; - } -#else - for (i = parser->toknext - 1; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - parser->toksuper = -1; - token->end = parser->pos + 1; - break; - } - } - /* Error if unmatched closing bracket */ - if (i == -1) { - return JSMN_ERROR_INVAL; - } - for (; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - parser->toksuper = i; - break; - } - } -#endif - break; - case '\"': - r = jsmn_parse_string(parser, js, len, tokens, num_tokens); - if (r < 0) { - return r; - } - count++; - if (parser->toksuper != -1 && tokens != NULL) { - tokens[parser->toksuper].size++; - } - break; - case '\t': - case '\r': - case '\n': - case ' ': - break; - case ':': - parser->toksuper = parser->toknext - 1; - break; - case ',': - if (tokens != NULL && parser->toksuper != -1 && - tokens[parser->toksuper].type != JSMN_ARRAY && - tokens[parser->toksuper].type != JSMN_OBJECT) { -#ifdef JSMN_PARENT_LINKS - parser->toksuper = tokens[parser->toksuper].parent; -#else - for (i = parser->toknext - 1; i >= 0; i--) { - if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { - if (tokens[i].start != -1 && tokens[i].end == -1) { - parser->toksuper = i; - break; - } - } - } -#endif - } - break; -#ifdef JSMN_STRICT - /* In strict mode primitives are: numbers and booleans */ - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case 't': - case 'f': - case 'n': - /* And they must not be keys of the object */ - if (tokens != NULL && parser->toksuper != -1) { - const jsmntok_t *t = &tokens[parser->toksuper]; - if (t->type == JSMN_OBJECT || - (t->type == JSMN_STRING && t->size != 0)) { - return JSMN_ERROR_INVAL; - } - } -#else - /* In non-strict mode every unquoted value is a primitive */ - default: -#endif - r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); - if (r < 0) { - return r; - } - count++; - if (parser->toksuper != -1 && tokens != NULL) { - tokens[parser->toksuper].size++; - } - break; - -#ifdef JSMN_STRICT - /* Unexpected char in strict mode */ - default: - return JSMN_ERROR_INVAL; -#endif - } - } - - if (tokens != NULL) { - for (i = parser->toknext - 1; i >= 0; i--) { - /* Unmatched opened object or array */ - if (tokens[i].start != -1 && tokens[i].end == -1) { - return JSMN_ERROR_PART; - } - } - } - - return count; -} - -/** - * Creates a new parser based over a given buffer with an array of tokens - * available. - */ -JSMN_API void jsmn_init(jsmn_parser *parser) { - parser->pos = 0; - parser->toknext = 0; - parser->toksuper = -1; -} - -#endif /* JSMN_HEADER */ - -#ifdef __cplusplus -} -#endif - -#endif /* JSMN_H */ diff --git a/bootloader/src/core/ser.c b/bootloader/src/core/ser.c @@ -1,78 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <unistd.h> -#include <termios.h> -#include <sys/epoll.h> -#include <string.h> -#include <errno.h> - -#define SERIAL_PORT "/dev/ttyUSB0" -#define BAUD_RATE B921600 - -struct termios tty; - -int configure_serial_port(int fd) { - - if (tcgetattr(fd, &tty) != 0) { - return -1; - } - - // Set baud rate - cfsetospeed(&tty, BAUD_RATE); - cfsetispeed(&tty, BAUD_RATE); - - // Configure 8N1 mode (8 data bits, no parity, 1 stop bit) - tty.c_cflag &= ~PARENB; // No parity bit - tty.c_cflag &= ~CSTOPB; // Only one stop bit - tty.c_cflag &= ~CSIZE; // Clear current data bit setting - tty.c_cflag |= CS8; // 8 data bits - - // Disable hardware flow control - tty.c_cflag &= ~CRTSCTS; - - // Enable the receiver and set local mode - tty.c_cflag |= (CLOCAL | CREAD); - - // Disable canonical mode, echo, and signal chars - tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); - - // Disable XON/XOFF flow control on input and output - tty.c_iflag &= ~(IXON | IXOFF | IXANY); - - // Set raw output mode - tty.c_oflag &= ~OPOST; - - // Set timeout to return immediately if no data is available - tty.c_cc[VMIN] = 0; - tty.c_cc[VTIME] = 0x05; - - tcflush(fd, TCIOFLUSH); - tcdrain(fd); - if (tcsetattr(fd, TCSANOW, &tty) != 0) { - return -1; - } - - return 0; -} - -int ser_send_packet(int port_fd, uint8_t *data, size_t len) -{ - return write(port_fd, data, len); -} - -int ser_listen_and_receive_packet(int port_fd, uint8_t *rx_buffer, uint8_t len, int timeout_ds) -{ - tty.c_cc[VMIN] = 0; - tty.c_cc[VTIME] = timeout_ds; - if (tcsetattr(port_fd, TCSANOW, &tty) != 0) { - return -1; - } - int read_cnt = read(port_fd, rx_buffer, len); - if (read_cnt == 0 || read_cnt == len) return read_cnt; - tty.c_cc[VMIN] = len - read_cnt; - if (tcsetattr(port_fd, TCSANOW, &tty) != 0) { - return -1; - } - return read(port_fd, rx_buffer + read_cnt, len - read_cnt); -} diff --git a/bootloader/src/core/ser.h b/bootloader/src/core/ser.h @@ -1,11 +0,0 @@ -#ifndef __SER_H__ -#define __SER_H__ - -#include <stdint.h> - - -int configure_serial_port(int fd); -int ser_send_packet(int port_fd, uint8_t *data, size_t len); -int ser_listen_and_receive_packet(int fd, uint8_t *rx_buffer, uint8_t len, int timeout_ms); - -#endif // __SER_H__ diff --git a/src/app/freertos b/src/app/freertos @@ -0,0 +1 @@ +Subproject commit 1a1ae36f9aa4e3c474e55d6404238898003dfc47