From 6ca34b43935992af9b102ea4a4e7a036951fc120 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sun, 1 Jun 2025 16:04:51 -0700 Subject: [PATCH 1/9] add zestcode lib build target --- meson.build | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index c666f6a5..725fa7b6 100644 --- a/meson.build +++ b/meson.build @@ -90,7 +90,8 @@ add_global_link_arguments(optimization_flags, linker_flags, formatting_flags, wa include = include_directories('./include') # this is what user projects will link against, so we use declare_dependency instead of static_library -zestcode_dep = declare_dependency( +zestcode = static_library( + 'zestcode', sources: source, include_directories: include, dependencies: dependency('v5_header'), @@ -103,8 +104,8 @@ elf = executable( include_directories: include, dependencies: [ dependency('v5'), - zestcode_dep.as_link_whole() # link whole so libc symbols are overridden - ] + ], + link_whole: zestcode ) # meson won't create the binary file for uploading, so we have to do it ourselves @@ -115,4 +116,4 @@ custom_target( input: elf, build_by_default: true, # otherwise it won't be built command: [objcopy, ['-O', 'binary', '-S', '@INPUT@', '@OUTPUT@']], -) +) \ No newline at end of file From 7499f08fb22207cc7e4ee4ab3c48f84880c0ca7e Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sun, 1 Jun 2025 16:20:00 -0700 Subject: [PATCH 2/9] remove system daemon --- include/system/user_functions.h | 5 - include/system/user_functions/c_list.h | 9 -- include/system/user_functions/cpp_list.h | 9 -- include/system/user_functions/list.h | 6 - src/system/startup.cpp | 60 ++++----- src/system/system_daemon.cpp | 160 ----------------------- src/system/user_functions.cpp | 40 ------ tests/examples/basic.cpp | 7 +- 8 files changed, 28 insertions(+), 268 deletions(-) delete mode 100644 include/system/user_functions.h delete mode 100644 include/system/user_functions/c_list.h delete mode 100644 include/system/user_functions/cpp_list.h delete mode 100644 include/system/user_functions/list.h delete mode 100644 src/system/system_daemon.cpp delete mode 100644 src/system/user_functions.cpp diff --git a/include/system/user_functions.h b/include/system/user_functions.h deleted file mode 100644 index 57cc248b..00000000 --- a/include/system/user_functions.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#define FUNC(F) void user_##F(); -#include "system/user_functions/list.h" -#undef FUNC diff --git a/include/system/user_functions/c_list.h b/include/system/user_functions/c_list.h deleted file mode 100644 index e66bd823..00000000 --- a/include/system/user_functions/c_list.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef FUNC - #error "FUNC must be defined" -#endif - -FUNC(autonomous) -FUNC(initialize) -FUNC(opcontrol) -FUNC(disabled) -FUNC(competition_initialize) diff --git a/include/system/user_functions/cpp_list.h b/include/system/user_functions/cpp_list.h deleted file mode 100644 index 1373dd2e..00000000 --- a/include/system/user_functions/cpp_list.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef FUNC - #error "FUNC must be defined" -#endif - -FUNC(cpp_autonomous) -FUNC(cpp_initialize) -FUNC(cpp_opcontrol) -FUNC(cpp_disabled) -FUNC(cpp_competition_initialize) diff --git a/include/system/user_functions/list.h b/include/system/user_functions/list.h deleted file mode 100644 index 3c4d70de..00000000 --- a/include/system/user_functions/list.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef FUNC - #error "FUNC must be defined" -#endif - -#include "system/user_functions/c_list.h" -#include "system/user_functions/cpp_list.h" diff --git a/src/system/startup.cpp b/src/system/startup.cpp index b8580733..94eb8798 100644 --- a/src/system/startup.cpp +++ b/src/system/startup.cpp @@ -13,6 +13,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "pros/rtos.hpp" #include "v5_api_patched.h" #include @@ -21,56 +22,37 @@ #include extern "C" { - // Initialization routines provided elsewhere void rtos_initialize(); void vfs_initialize(); - -[[gnu::weak]] -void display_initialize() {} - void rtos_sched_start(); - -// libc initialization void __libc_init_array(); - -// tick vex tasks -void vexTasksRun(); -} // extern "C" - -void system_daemon_initialize(); +} // this goes in the first 32-byte chunk of the user program // which is why the entrypoint is offset from 0x3800000 by 0x20 // only the first 16 bytes of this chunk is used however // see the vcodesig definition in the SDK for more details [[gnu::section(".boot_data")]] -vcodesig vexCodeSig = {V5_SIG_MAGIC, V5_SIG_TYPE_USER, V5_SIG_OWNER_PARTNER, V5_SIG_OPTIONS_NONE}; +vcodesig vexCodeSig = { + .magic = V5_SIG_MAGIC, + .type = V5_SIG_TYPE_USER, + .owner = V5_SIG_OWNER_PARTNER, + .options = V5_SIG_OPTIONS_NONE, +}; // The pros_init function is executed early (via constructor attribute) -// before most global C++ constructors are run. -[[gnu::constructor(102)]] +[[gnu::constructor(101)]] static void pros_init() { rtos_initialize(); vfs_initialize(); - display_initialize(); - // Note: system_daemon_initialize must be called last, per design requirements. - system_daemon_initialize(); } -// the main function, starts the scheduler and ensures the program exits gracefully if it fails -int main() { - // Start freeRTOS - rtos_sched_start(); +// forward-declare main function +int main(); - // If execution reaches here, the scheduler has failed. - vexDisplayPrintf(10, 60, 1, "failed to start scheduler\n"); - std::printf("Failed to start Scheduler\n"); - _exit(0); // exit with code 0 to stop spinlock -} - -// program entrypoint. This is the first function that is run -// it sets up memory, calls constructors, and then calls main +// Program entrypoint. This is the first function that is run. +// It sets up memory, calls constructors, and starts the scheduler extern "C" [[gnu::section(".boot")]] void _start() { // Symbols provided by the linker script @@ -89,15 +71,23 @@ void _start() { // call global constructors __libc_init_array(); - // call the main function - // This GCC warning is a nuisance. - // This is the industry standard +// start main task +// these pragmas are needed to silence the same warning on clang and gcc +// normally you aren't supposed to reference the main function #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #pragma GCC diagnostic ignored "-Wunknown-pragmas" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmain" - main(); + pros::Task task(main); #pragma clang diagnostic pop #pragma GCC diagnostic pop + + // start the scheduler + rtos_sched_start(); + + // If execution reaches here, the scheduler has failed. + vexDisplayPrintf(10, 60, 1, "failed to start scheduler\n"); + std::printf("Failed to start Scheduler\n"); + _exit(0); // exit with code 0 to stop spinlock } diff --git a/src/system/system_daemon.cpp b/src/system/system_daemon.cpp deleted file mode 100644 index 278a5bf0..00000000 --- a/src/system/system_daemon.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/** - * \file system/system_daemon.c - * - * Competition control daemon responsible for invoking the user tasks. - * - * \copyright (c) 2017-2024, Purdue University ACM SIGBots. - * All rights reserved. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#include "kapi.h" -#include "pros/devices/brain.hpp" -#include "pros/rtos.hpp" -#include "system/optimizers.h" -#include "system/user_functions.h" // IWYU pragma: keep - -extern "C" { -void vexTasksRun(); -void ser_output_flush(); -} - -static void _disabled_task(void*); -static void _autonomous_task(void*); -static void _opcontrol_task(void*); -static void _competition_initialize_task(void*); -static void _initialize_task(void*); -static void _system_daemon_task(void*); - -static task_stack_t competition_task_stack[TASK_STACK_DEPTH_DEFAULT]; -static static_task_s_t competition_task_buffer; -static pros::task_t competition_task; - -static task_stack_t system_daemon_task_stack[TASK_STACK_DEPTH_DEFAULT]; -static static_task_s_t system_daemon_task_buffer; -static pros::task_t system_daemon_task; - -enum state_task { - E_OPCONTROL_TASK = 0, - E_AUTON_TASK, - E_DISABLED_TASK, - E_COMP_INIT_TASK -}; - -static const char task_names[4][32] = { - "User Operator Control (PROS)", - "User Autonomous (PROS)", - "User Disabled (PROS)", - "User Comp. Init. (PROS)" -}; - -static task_fn_t task_fns[4] = - {_opcontrol_task, _autonomous_task, _disabled_task, _competition_initialize_task}; - -// does the basic background operations that need to occur every 2ms -static inline void do_background_operations() { - zest::Brain::smart_port_mutex_lock_all(); - ser_output_flush(); - rtos_suspend_all(); - vexTasksRun(); - rtos_resume_all(); - zest::Brain::smart_port_mutex_unlock_all(); -} - -static void _system_daemon_task(void*) { - uint32_t time = pros::millis(); - // Initialize status to an invalid state to force an update the first loop - uint32_t status = (uint32_t)(1 << 8); - uint32_t task_state; - - // start up user initialize task. once the user initialize function completes, - // the _initialize_task will notify us and we can go into normal competition - // monitoring mode - competition_task = task_create_static( - _initialize_task, - NULL, - TASK_PRIORITY_DEFAULT, - TASK_STACK_DEPTH_DEFAULT, - "User Initialization (PROS)", - competition_task_stack, - &competition_task_buffer - ); - - time = pros::millis(); - while (!pros::c::task_notify_take(true, 2)) { - // wait for initialize to finish - do_background_operations(); - } - while (1) { - do_background_operations(); - - if (unlikely(status != pros::c::competition_get_status())) { - // Have a new competition status, need to clean up whatever's running - uint32_t old_status = status; - status = pros::c::competition_get_status(); - enum state_task state = E_OPCONTROL_TASK; - if ((status & COMPETITION_DISABLED) && (old_status & COMPETITION_DISABLED)) { - // Don't restart the disabled task even if other bits have changed (e.g. auton bit) - continue; - } - - // competition initialize runs only when entering disabled and we're - // connected to competition control - if ((status ^ old_status) & COMPETITION_CONNECTED - && (status & (COMPETITION_DISABLED | COMPETITION_CONNECTED)) - == (COMPETITION_DISABLED | COMPETITION_CONNECTED)) { - state = E_COMP_INIT_TASK; - } else if (status & COMPETITION_DISABLED) { - state = E_DISABLED_TASK; - } else if (status & COMPETITION_AUTONOMOUS) { - state = E_AUTON_TASK; - } - - task_state = pros::c::task_get_state(competition_task); - // delete the task only if it's in normal operation (e.g. not deleted) - // The valid task states AREN'T deleted, invalid, or running (running - // means it's the current task, which will never be the case) - if (task_state == pros::E_TASK_STATE_READY || task_state == pros::E_TASK_STATE_BLOCKED - || task_state == pros::E_TASK_STATE_SUSPENDED) { - pros::c::task_delete(competition_task); - } - - competition_task = task_create_static( - task_fns[state], - NULL, - TASK_PRIORITY_DEFAULT, - TASK_STACK_DEPTH_DEFAULT, - task_names[state], - competition_task_stack, - &competition_task_buffer - ); - } - - pros::c::task_delay_until(&time, 2); - } -} - -void system_daemon_initialize() { - system_daemon_task = task_create_static( - _system_daemon_task, - NULL, - TASK_PRIORITY_MAX - 2, - TASK_STACK_DEPTH_DEFAULT, - "PROS System Daemon", - system_daemon_task_stack, - &system_daemon_task_buffer - ); -} - -// these functions are what actually get called by the system daemon, which -// attempt to call whatever the user declares -#define FUNC(NAME) \ - static void _##NAME##_task(void* ign) { \ - user_##NAME(); \ - pros::c::task_notify(system_daemon_task); \ - } -#include "system/user_functions/c_list.h" -#undef FUNC diff --git a/src/system/user_functions.cpp b/src/system/user_functions.cpp deleted file mode 100644 index e2035a19..00000000 --- a/src/system/user_functions.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "system/user_functions.h" - -// how this all works... -// system daemon starts an autonomous task which calls user_autonomous() -// user_autonomous will invoke a hot-linked autonomous if one is available -// The invoked autonomous may actually just invoke user_cpp_autonomous -// which will invoke a C routine which calls C++ autonomous routine - -// Our weak functions call C++ links of these functions, allowing users to only optionally extern -// "C" the task functions these are implemented in cpp_support.cpp FUNC(cpp_autonomous) expands to: -// extern void cpp_autonomous(); -#define FUNC(NAME) extern void NAME(); -#include "system/user_functions/cpp_list.h" -#undef FUNC - -// default implementations of the different competition modes attempt to call -// the C++ linkage version of the function -// FUNC(autonomous) exapnds to: -// __attribute__((weak)) void autonomous() { user_cpp_autonomous(); } -#define FUNC(NAME) \ - __attribute__((weak)) void NAME() { \ - user_cpp_##NAME(); \ - } -#include "system/user_functions/c_list.h" -#undef FUNC - -// FUNC(cpp_autonomous) exapnds to: -// void user_cpp_autonomous() { -// if(HOT_TABLE && HOT_TABLE->functions.cpp_autonomous) { -// HOT_TABLE->functions.cpp_autonomous(); -// } else { -// cpp_autonomous(); -// } -// } -#define FUNC(NAME) \ - void user_##NAME() { \ - NAME(); \ - } -#include "system/user_functions/list.h" -#undef FUNC diff --git a/tests/examples/basic.cpp b/tests/examples/basic.cpp index 48161c21..fcc6702d 100644 --- a/tests/examples/basic.cpp +++ b/tests/examples/basic.cpp @@ -1,6 +1,5 @@ -#include "main.h" +#include "v5_api_patched.h" -void initialize() { - pros::delay(3000); - std::cout << "hello world!" << std::endl; +int main() { + vexDisplayPrintf(10, 60, 1, "Hello World!\n"); } \ No newline at end of file From 3fd4a54c54020173e82e8a3cf82bed0732321f39 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 6 Jun 2025 15:09:01 -0700 Subject: [PATCH 3/9] use vexcode-style competition callbacks --- include/api.h | 2 - include/pros/competition.hpp | 77 ++++++++ include/pros/misc.h | 334 ----------------------------------- include/pros/misc.hpp | 201 --------------------- src/competition.cpp | 122 +++++++++++++ src/devices/competition.cpp | 73 -------- src/system/competition.hpp | 10 ++ src/system/cpp_support.cpp | 35 +--- src/system/startup.cpp | 8 +- src/system/stubs.cpp | 4 +- tests/examples/basic.cpp | 6 +- 11 files changed, 224 insertions(+), 648 deletions(-) create mode 100644 include/pros/competition.hpp delete mode 100644 include/pros/misc.h delete mode 100644 include/pros/misc.hpp create mode 100644 src/competition.cpp delete mode 100644 src/devices/competition.cpp create mode 100644 src/system/competition.hpp diff --git a/include/api.h b/include/api.h index 9bd126c8..205ee89d 100644 --- a/include/api.h +++ b/include/api.h @@ -39,11 +39,9 @@ #include #endif /* __cplusplus */ -#include "pros/misc.h" #include "pros/rtos.h" #ifdef __cplusplus - #include "pros/misc.hpp" #include "pros/rtos.hpp" #endif diff --git a/include/pros/competition.hpp b/include/pros/competition.hpp new file mode 100644 index 00000000..8bd0d39d --- /dev/null +++ b/include/pros/competition.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include + +namespace zest::competition { +/** + * @brief the competition mode (disabled, driver control, autonomous) + * + */ +enum class Mode { + Disabled, + DriverControl, + Autonomous, +}; + +/** + * @brief the competition system being used + * + */ +enum class System { + FieldControl, + CompetitionSwitch, + None, +}; + +/** + * @brief Get the competition mode (disabled, driver control, autonomous) + * + * @return Status + */ +Mode get_mode(); + +/** + * @brief Get the system type being used (field control, competition switch, or none) + * + * @return System + */ +System get_system(); + +/** + * @brief Whether field control or a competition switch is connected + * + * @return true + * @return false + */ +bool is_connected(); + +/** + * @brief register the callable that will be called when the autonomous period starts. + * + * The callable is called whenever the competition state changes to autonomous. The task that runs + * it is killed as soon as the competition state changes to driver control or disabled. + * + * @param callable + */ +void register_autonomous(std::function callable); + +/** + * @brief register the callable that will be called when the driver control period starts. + * + * The callable is called whenever the competition state changes to autonomous. The task that runs + * it is killed as soon as the competition state changes to driver control or disabled. + * + * @param callable + */ +void register_driver_control(std::function callable); + +/** + * @brief register the callable that will be called when the disabled period starts. + * + * The callable is called whenever the competition state changes to autonomous. The task that + * runs it is killed as soon as the competition state changes to driver control or disabled. + * + * @param callable + */ +void register_disabled(std::function callable); +} // namespace zest::competition \ No newline at end of file diff --git a/include/pros/misc.h b/include/pros/misc.h deleted file mode 100644 index 5514a3fd..00000000 --- a/include/pros/misc.h +++ /dev/null @@ -1,334 +0,0 @@ -/** - * \file pros/misc.h - * \ingroup c-misc - * - * Contains prototypes for miscellaneous functions pertaining to the controller, - * battery, and competition control. - * - * This file should not be modified by users, since it gets replaced whenever - * a kernel upgrade occurs. - * - * \copyright (c) 2017-2024, Purdue University ACM SIGBots. - * All rights reservered. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * \defgroup c-misc Miscellaneous C API - * \note Additional example code for this module can be found in its [Tutorial.](@ref controller) - */ - -#ifndef _PROS_MISC_H_ -#define _PROS_MISC_H_ - -#include - -#define NUM_V5_PORTS (22) - -/** - * \ingroup c-misc - */ - -/** - * \addtogroup c-misc - * @{ - */ - -/// \name V5 Competition -//@{ - -/*#define COMPETITION_DISABLED (1 << 0) -#define COMPETITION_AUTONOMOUS (1 << 1) -#define COMPETITION_CONNECTED (1 << 2) -#define COMPETITION_SYSTEM (1 << 3)*/ -typedef enum { - COMPETITION_DISABLED = 1 << 0, - COMPETITION_CONNECTED = 1 << 2, - COMPETITION_AUTONOMOUS = 1 << 1, - COMPETITION_SYSTEM = 1 << 3, -} competition_status; - -#ifdef __cplusplus -extern "C" { -namespace pros { -namespace c { -#endif - -/** - * \fn competition_get_status(void) - * Get the current status of the competition control. - * - * \return The competition control status as a mask of bits with - * COMPETITION_{ENABLED,AUTONOMOUS,CONNECTED}. - * - * \b Example - * \code - * void initialize() { - * if (competition_get_status() & COMPETITION_CONNECTED == true) { - * // Field Control is Connected - * // Run LCD Selector code or similar - * } - * } - * \endcode - */ -uint8_t competition_get_status(void); - -/** - * \fn competition_is_disabled() - * - * \return True if the V5 Brain is disabled, false otherwise. - * - * \b Example - * \code - * void my_task_fn(void* ignore) { - * while (!competition_is_disabled()) { - * // Run competition tasks (like Lift Control or similar) - * } - * } - * - * void initialize() { - * task_t my_task = task_create(my_task_fn, NULL, TASK_PRIO_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "My - * Task"); - * } - * \endcode - */ -uint8_t competition_is_disabled(void); - -/** - * \return True if the V5 Brain is connected to competition control, false otherwise. - * - * \b Example - * \code - * void initialize() { - * if (competition_is_connected()) { - * // Field Control is Connected - * // Run LCD Selector code or similar - * } - * } - * \endcode - */ -uint8_t competition_is_connected(void); - -/** - * \return True if the V5 Brain is in autonomous mode, false otherwise. - * - * \b Example - * \code - * void my_task_fn(void* ignore) { - * while (!competition_is_autonomous()) { - * // Wait to do anything until autonomous starts - * delay(2); - * } - * while (competition_is_autonomous()) { - * // Run whatever code is desired to just execute in autonomous - * } - * } - * - * void initialize() { - * task_t my_task = task_create(my_task_fn, NULL, TASK_PRIO_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "My - * Task"); - * } - * \endcode - */ -uint8_t competition_is_autonomous(void); - -/** - * \return True if the V5 Brain is connected to VEXnet Field Controller, false otherwise. - * - * \b Example - * \code - * void initialize() { - * if (competition_is_field()) { - * // connected to VEXnet Field Controller - * } - * } - * \endcode - */ -uint8_t competition_is_field(void); - -/** - * \return True if the V5 Brain is connected to VEXnet Competition Switch, false otherwise. - * - * \b Example - * \code - * void initialize() { - * if (competition_is_switch()) { - * // connected to VEXnet Competition Switch - * } - * } - */ -uint8_t competition_is_switch(void); - -#ifdef __cplusplus -} -} -} -#endif -///@} - -/// \name V5 Controller -///@{ -#ifdef __cplusplus -extern "C" { -namespace pros { -#endif -/** - * Gets the current voltage of the battery, as reported by VEXos. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCES - Another resource is currently trying to access the battery port. - * - * \return The current voltage of the battery - * - * \b Example - * \code - * void initialize() { - * printf("Battery's Voltage: %d\n", battery_get_voltage()); - * } - * \endcode - */ -int32_t battery_get_voltage(void); - -/** - * Gets the current current of the battery, as reported by VEXos. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCES - Another resource is currently trying to access the battery port. - * - * \return The current current of the battery - * - * \b Example - * \code - * void initialize() { - * printf("Battery Current: %d\n", battery_get_current()); - * } - * \endcode - */ -int32_t battery_get_current(void); - -/** - * Gets the current temperature of the battery, as reported by VEXos. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCES - Another resource is currently trying to access the battery port. - * - * \return The current temperature of the battery - * - * \b Example - * \code - * void initialize() { - * printf("Battery's Temperature: %d\n", battery_get_temperature()); - * } - * \endcode - */ -double battery_get_temperature(void); - -/** - * Gets the current capacity of the battery, as reported by VEXos. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCES - Another resource is currently trying to access the battery port. - * - * \return The current capacity of the battery - * - * \b Example - * \code - * void initialize() { - * printf("Battery Level: %d\n", battery_get_capacity()); - * } - * \endcode - */ -double battery_get_capacity(void); - -/** - * Checks if the SD card is installed. - * - * \return 1 if the SD card is installed, 0 otherwise - * - * \b Example - * \code - * void opcontrol() { - * printf("%i", usd_is_installed()); - * } - * \endcode - */ -int32_t usd_is_installed(void); - -/** - * Lists the files in a directory specified by the path - * Puts the list of file names (NOT DIRECTORIES) into the buffer seperated by newlines - * - * This function uses the following values of errno when an error state is - * reached: - * - * EIO - Hard error occured in the low level disk I/O layer - * EINVAL - file or directory is invalid, or length is invalid - * EBUSY - THe physical drinve cannot work - * ENOENT - cannot find the path or file - * EINVAL - the path name format is invalid - * EACCES - Access denied or directory full - * EEXIST - Access denied - * EROFS - SD card is write protected - * ENXIO - drive number is invalid or not a FAT32 drive - * ENOBUFS - drive has no work area - * ENFILE - too many open files - * - * - * - * \note use a path of "\" to list the files in the main directory NOT "/usd/" - * DO NOT PREPEND YOUR PATHS WITH "/usd/" - * - * \return 1 on success or PROS_ERR on failure setting errno - * - * \b Example - * \code - * void opcontrol() { - * char* test = (char*) malloc(128); - * pros::c::usd_list_files("/", test, 128); - * pros::delay(200); - * printf("%s\n", test); //Prints the file names in the root directory seperated by newlines - * pros::delay(100); - * pros::c::usd_list_files("/test", test, 128); - * pros::delay(200); - * printf("%s\n", test); //Prints the names of files in the folder named test seperated by - *newlines pros::delay(100); - * } - * \endcode - */ -int32_t usd_list_files(const char* path, char* buffer, int32_t len); - -/******************************************************************************/ -/** Date and Time **/ -/******************************************************************************/ - -extern const char* baked_date; -extern const char* baked_time; - -typedef struct { - uint16_t year; // Year - 1980 - uint8_t day; - uint8_t month; // 1 = January -} date_s_t; - -typedef struct { - uint8_t hour; - uint8_t min; - uint8_t sec; - uint8_t sec_hund; // hundredths of a second -} time_s_t; - -///@} - -///@} - -#ifdef __cplusplus -} -} // namespace pros -#endif - -#endif // _PROS_MISC_H_ diff --git a/include/pros/misc.hpp b/include/pros/misc.hpp deleted file mode 100644 index fb8c7f08..00000000 --- a/include/pros/misc.hpp +++ /dev/null @@ -1,201 +0,0 @@ -/** - * \file pros/misc.hpp - * \ingroup cpp-pros - * - * Contains prototypes for miscellaneous functions pertaining to the controller, - * battery, and competition control. - * - * This file should not be modified by users, since it gets replaced whenever - * a kernel upgrade occurs. - * - * \copyright (c) 2017-2024, Purdue University ACM SIGBots. - * All rights reservered. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * \defgroup cpp-misc Miscellaneous C++ API - * \note Additional example code for this module can be found in its [Tutorial.](@ref controller) - */ - -#ifndef _PROS_MISC_HPP_ -#define _PROS_MISC_HPP_ - -#include "pros/misc.h" - -#include -#include - - -namespace pros { -namespace battery { -/** - * \addtogroup cpp-misc - * ///@{ - */ -/** - * Gets the current voltage of the battery, as reported by VEXos. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCES - Another resource is currently trying to access the battery port. - * - * \return The current voltage of the battery - * - * \b Example - * \code - * void initialize() { - * printf("Battery Level: %.2f\n", get_capacity()); - * } - * \endcode - */ -double get_capacity(void); - -/** - * Gets the current current of the battery in milliamps, as reported by VEXos. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCES - Another resource is currently trying to access the battery port. - * - * \return The current current of the battery - * - * \b Example - * \code - * void initialize() { - * printf("Battery Current: %d\n", get_current()); - * } - * \endcode - */ -int32_t get_current(void); - -/** - * Gets the current temperature of the battery, as reported by VEXos. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCES - Another resource is currently trying to access the battery port. - * - * \return The current temperature of the battery - * - * \b Example - * \code - * void initialize() { - * printf("Battery's Temperature: %.2f\n", get_temperature()); - * } - * \endcode - */ -double get_temperature(void); - -/** - * Gets the current capacity of the battery in millivolts, as reported by VEXos. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCES - Another resource is currently trying to access the battery port. - * - * \return The current capacity of the battery - * - * \b Example - * \code - * void initialize() { - * printf("Battery's Voltage: %d\n", get_voltage()); - * } - * \endcode - */ -int32_t get_voltage(void); -///@} -} // namespace battery - -namespace competition { -/** - * Get the current status of the competition control. - * - * \return The competition control status as a mask of bits with - * COMPETITION_{ENABLED,AUTONOMOUS,CONNECTED}. - * - * \b Example - * \code - * void status_display_task(){ - * if(!is_connected()) { - * pros::lcd::print(0, "V5 Brain is not connected!"); - * } - * if(is_autonomous()) { - * pros::lcd::print(0, "V5 Brain is in autonomous mode!"); - * } - * if(!is_disabled()) { - * pros::lcd::print(0, "V5 Brain is disabled!"); - * } - * \endcode - */ -std::uint8_t get_status(void); -std::uint8_t is_autonomous(void); -std::uint8_t is_connected(void); -std::uint8_t is_disabled(void); -std::uint8_t is_field_control(void); -std::uint8_t is_competition_switch(void); -} // namespace competition - -namespace usd { -/** - * Checks if the SD card is installed. - * - * \return 1 if the SD card is installed, 0 otherwise - * - * \b Example - * \code - * void opcontrol() { - * printf("%i", is_installed()); - * } - * \endcode - */ -std::int32_t is_installed(void); -/** - * Lists the files in a directory specified by the path - * Puts the list of file names (NOT DIRECTORIES) into the buffer seperated by newlines - * - * This function uses the following values of errno when an error state is - * reached: - * - * EIO - Hard error occured in the low level disk I/O layer - * EINVAL - file or directory is invalid, or length is invalid - * EBUSY - THe physical drinve cannot work - * ENOENT - cannot find the path or file - * EINVAL - the path name format is invalid - * EACCES - Access denied or directory full - * EEXIST - Access denied - * EROFS - SD card is write protected - * ENXIO - drive number is invalid or not a FAT32 drive - * ENOBUFS - drive has no work area - * ENFILE - too many open files - * - * - * - * \note use a path of "\" to list the files in the main directory NOT "/usd/" - * DO NOT PREPEND YOUR PATHS WITH "/usd/" - * - * \return 1 on success or PROS_ERR on failure setting errno - * - * \b Example - * \code - * void opcontrol() { - * char* test = (char*) malloc(128); - * pros::usd::list_files("/", test, 128); - * pros::delay(200); - * printf("%s\n", test); //Prints the file names in the root directory seperated by newlines - * pros::delay(100); - * pros::list_files("/test", test, 128); - * pros::delay(200); - * printf("%s\n", test); //Prints the names of files in the folder named test seperated by - *newlines pros::delay(100); - * } - * \endcode - */ - -std::int32_t list_files(const char* path, char* buffer, std::int32_t len); -} // namespace usd - -} // namespace pros - -#endif // _PROS_MISC_HPP_ diff --git a/src/competition.cpp b/src/competition.cpp new file mode 100644 index 00000000..f930bd8d --- /dev/null +++ b/src/competition.cpp @@ -0,0 +1,122 @@ +#include "pros/competition.hpp" + +#include "pros/rtos.h" +#include "pros/rtos.hpp" +#include "v5_api_patched.h" + +#include + +namespace zest::competition { + +// bitmask constants +constexpr uint32_t DISABLED_MASK = 1U << 0; +constexpr uint32_t AUTONOMOUS_MASK = 1U << 1; +constexpr uint32_t CONNECTED_MASK = 1U << 2; +constexpr uint32_t SYSTEM_MASK = 1U << 3; + +// competition task +static std::optional competition_task; + +// callbacks +static std::optional> autonomous_func; +static std::optional> driver_control_func; +static std::optional> disabled_func; + +/** + * @brief kill the current competition task, and spawn a new one that calls the given function + * + * @param f the new function that should be run + */ +static void switch_task(std::optional> f) { + // kill the current competition task if it's still running + if (competition_task) { + const uint32_t competition_task_state = competition_task->get_state(); + if (competition_task_state != pros::E_TASK_STATE_DELETED + && competition_task_state != pros::E_TASK_STATE_INVALID) { + competition_task->remove(); + } + } + + // spawn the new task, if the given function is valid + if (f) { + competition_task = pros::Task::create(*f); + } +} + +// This task controls the competition task. Runs for the lifetime of the program. +// Runs at second highest priority, updates every 2 milliseconds. +static std::optional control_task; + +void initialize() { + control_task = pros::Task::create([]() { + std::optional prev_mode; + + // only run if the mutex is available + while (true) { + const Mode mode = get_mode(); + + // if the competition state changed, or the control task has been notified, + // the competition task should be changed + if (mode != prev_mode || pros::Task::notify_take(true, 0)) { + prev_mode = mode; + + switch (mode) { + case Mode::Disabled: { + switch_task(disabled_func); + break; + } + case Mode::Autonomous: { + switch_task(autonomous_func); + break; + } + case Mode::DriverControl: { + switch_task(driver_control_func); + break; + } + } + } + + // delay to save resources + pros::delay(2); + } + }, TASK_PRIORITY_MAX - 1); +} + +Mode get_mode() { + const uint32_t status = vexCompetitionStatus(); + + if ((status & DISABLED_MASK) != 0) { + return Mode::Disabled; + } else if ((status & AUTONOMOUS_MASK) != 0) { + return Mode::Autonomous; + } else { + return Mode::DriverControl; + } +} + +System get_system() { + if (!is_connected()) { + return System::None; + } else if ((vexCompetitionStatus() & SYSTEM_MASK) != 0) { + return System::FieldControl; + } else { + return System::CompetitionSwitch; + } +}; + +bool is_connected() { + return (vexCompetitionStatus() & CONNECTED_MASK) != 0; +} + +void register_autonomous(std::function callable) { + autonomous_func = callable; +} + +void register_driver_control(std::function callable) { + driver_control_func = callable; +} + +void register_disabled(std::function callable) { + disabled_func = callable; +} +}; // namespace zest::competition \ No newline at end of file diff --git a/src/devices/competition.cpp b/src/devices/competition.cpp deleted file mode 100644 index 5e1f7dc6..00000000 --- a/src/devices/competition.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/** - * \file devices/competition.cpp - * - * Contains competition control functions. - * - * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. - * All rights reserved. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#include "pros/misc.h" -#include "v5_api_patched.h" - -// TODO: remove this C API -extern "C" { -uint8_t competition_get_status(void) { - return vexCompetitionStatus(); -} - -uint8_t competition_is_disabled(void) { - return (competition_get_status() & COMPETITION_DISABLED) != 0; -} - -uint8_t competition_is_connected(void) { - return (competition_get_status() & COMPETITION_CONNECTED) != 0; -} - -uint8_t competition_is_autonomous(void) { - return (competition_get_status() & COMPETITION_AUTONOMOUS) != 0; -} - -uint8_t competition_is_field(void) { - return ((competition_get_status() & COMPETITION_SYSTEM) != 0) && competition_is_connected(); -} - -uint8_t competition_is_switch(void) { - return ((competition_get_status() & COMPETITION_SYSTEM) == 0) && competition_is_connected(); -} -} - -namespace pros { -namespace competition { -using namespace pros::c; - -uint8_t get_status(void) { - return competition_get_status(); -} - -uint8_t is_autonomous(void) { - return competition_is_autonomous(); -} - -uint8_t is_connected(void) { - return competition_is_connected(); -} - -uint8_t is_disabled(void) { - return competition_is_disabled(); -} - -uint8_t is_field_control(void) { - return competition_is_field(); -} - -uint8_t is_competition_switch(void) { - return competition_is_switch(); -} - -} // namespace competition -} // namespace pros diff --git a/src/system/competition.hpp b/src/system/competition.hpp new file mode 100644 index 00000000..46eee90a --- /dev/null +++ b/src/system/competition.hpp @@ -0,0 +1,10 @@ +// this file contains private API for the competition control + +#pragma once + +#include "pros/competition.hpp" + +namespace zest::competition { +// initialize the competition control task +void initialize(); +} // namespace zest::competition \ No newline at end of file diff --git a/src/system/cpp_support.cpp b/src/system/cpp_support.cpp index 76c0eb7a..5c0ab017 100644 --- a/src/system/cpp_support.cpp +++ b/src/system/cpp_support.cpp @@ -38,37 +38,4 @@ extern "C" void task_fn_wrapper(task_fn_t fn, void* args) { vexDisplayString(5, "An unknown error occurred"); } #endif -} - -/******************************************************************************/ -/** C++ Linkages for User Tasks **/ -/******************************************************************************/ -__attribute__((weak)) void autonomous() {} - -__attribute__((weak)) void initialize() {} - -__attribute__((weak)) void opcontrol() {} - -__attribute__((weak)) void disabled() {} - -__attribute__((weak)) void competition_initialize() {} - -extern "C" void cpp_autonomous() { - autonomous(); -} - -extern "C" void cpp_initialize() { - initialize(); -} - -extern "C" void cpp_opcontrol() { - opcontrol(); -} - -extern "C" void cpp_disabled() { - disabled(); -} - -extern "C" void cpp_competition_initialize() { - competition_initialize(); -} +} \ No newline at end of file diff --git a/src/system/startup.cpp b/src/system/startup.cpp index 94eb8798..33e6b46b 100644 --- a/src/system/startup.cpp +++ b/src/system/startup.cpp @@ -14,6 +14,7 @@ */ #include "pros/rtos.hpp" +#include "src/system/competition.hpp" #include "v5_api_patched.h" #include @@ -79,7 +80,12 @@ void _start() { #pragma GCC diagnostic ignored "-Wunknown-pragmas" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmain" - pros::Task task(main); + pros::Task task([]() { + // run the main function + main(); + // initialize the competition control task + zest::competition::initialize(); + }); #pragma clang diagnostic pop #pragma GCC diagnostic pop diff --git a/src/system/stubs.cpp b/src/system/stubs.cpp index f464c258..f3f829ff 100644 --- a/src/system/stubs.cpp +++ b/src/system/stubs.cpp @@ -16,7 +16,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "pros/misc.h" +#include "pros/competition.hpp" #include "rtos/task.h" #include "v5_api_patched.h" @@ -242,7 +242,7 @@ int _gettimeofday(struct timeval* tp, void* tzvp) { tp->tv_sec = user_time_spec.tv_sec; tp->tv_usec = user_time_spec.tv_nsec * 1000; tp->tv_usec += vexSystemHighResTimeGet() - set_microseconds; - } else if (pros::c::competition_is_connected()) { + } else if (zest::competition::is_connected()) { // TODO: update this to get the date/time through VexOS. Apparently, // the time is kept properly only when competition controls are // connected. I haven't had time to check or confirm this. diff --git a/tests/examples/basic.cpp b/tests/examples/basic.cpp index fcc6702d..f9fa09f2 100644 --- a/tests/examples/basic.cpp +++ b/tests/examples/basic.cpp @@ -1,4 +1,8 @@ -#include "v5_api_patched.h" +#include + +extern "C" { +void vexDisplayPrintf(int32_t xpos, int32_t ypos, uint32_t bOpaque, const char* format, ...); +} int main() { vexDisplayPrintf(10, 60, 1, "Hello World!\n"); From 7518dbe2fd2ea304e20be1c5b62497838fa8f16a Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 6 Jun 2025 15:29:38 -0700 Subject: [PATCH 4/9] re-add system daemon --- src/competition.cpp | 2 +- src/system/startup.cpp | 10 +++++----- src/system/system_daemon.cpp | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 src/system/system_daemon.cpp diff --git a/src/competition.cpp b/src/competition.cpp index f930bd8d..afa7a051 100644 --- a/src/competition.cpp +++ b/src/competition.cpp @@ -57,7 +57,7 @@ void initialize() { // if the competition state changed, or the control task has been notified, // the competition task should be changed - if (mode != prev_mode || pros::Task::notify_take(true, 0)) { + if (mode != prev_mode) { prev_mode = mode; switch (mode) { diff --git a/src/system/startup.cpp b/src/system/startup.cpp index 33e6b46b..f49a3773 100644 --- a/src/system/startup.cpp +++ b/src/system/startup.cpp @@ -35,7 +35,7 @@ void __libc_init_array(); // only the first 16 bytes of this chunk is used however // see the vcodesig definition in the SDK for more details [[gnu::section(".boot_data")]] -vcodesig vexCodeSig = { +vcodesig boot_data = { .magic = V5_SIG_MAGIC, .type = V5_SIG_TYPE_USER, .owner = V5_SIG_OWNER_PARTNER, @@ -72,15 +72,15 @@ void _start() { // call global constructors __libc_init_array(); -// start main task -// these pragmas are needed to silence the same warning on clang and gcc -// normally you aren't supposed to reference the main function + // start main task + // these pragmas are needed to silence the same warning on clang and gcc + // normally you aren't supposed to reference the main function #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #pragma GCC diagnostic ignored "-Wunknown-pragmas" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmain" - pros::Task task([]() { + pros::Task main_task([]() { // run the main function main(); // initialize the competition control task diff --git a/src/system/system_daemon.cpp b/src/system/system_daemon.cpp new file mode 100644 index 00000000..754dd100 --- /dev/null +++ b/src/system/system_daemon.cpp @@ -0,0 +1,34 @@ +#include "kapi.h" +#include "pros/devices/brain.hpp" +#include "pros/rtos.hpp" + +extern "C" { +void vexTasksRun(); +void ser_output_flush(); +} + +namespace zest { + +// This task runs for the lifetime of the program. +// It periodically calls vexTasksRun, which copies shared memory to/from vexOS. +static pros::Task system_daemon([]() { + while (true) { + // lock all smart port mutexes + Brain::smart_port_mutex_lock_all(); + // flush serial output + ser_output_flush(); + // suspend all tasks + rtos_suspend_all(); + // copy shared memory + vexTasksRun(); + // resume all tasks + rtos_resume_all(); + // unlock all smart port mutexes + zest::Brain::smart_port_mutex_unlock_all(); + + // delay to save resources + pros::delay(2); + } +}, TASK_PRIORITY_MAX); + +} // namespace zest \ No newline at end of file From f1c7985b06894a14f4c1d000e837c0e873802b78 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 6 Jun 2025 15:31:03 -0700 Subject: [PATCH 5/9] move internal competition header file --- src/{system => }/competition.hpp | 0 src/system/startup.cpp | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/{system => }/competition.hpp (100%) diff --git a/src/system/competition.hpp b/src/competition.hpp similarity index 100% rename from src/system/competition.hpp rename to src/competition.hpp diff --git a/src/system/startup.cpp b/src/system/startup.cpp index f49a3773..ce952c73 100644 --- a/src/system/startup.cpp +++ b/src/system/startup.cpp @@ -14,7 +14,7 @@ */ #include "pros/rtos.hpp" -#include "src/system/competition.hpp" +#include "src/competition.hpp" #include "v5_api_patched.h" #include From f9f73558e36ca3a7efc303f073bf92288a9a4f09 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 6 Jun 2025 15:33:16 -0700 Subject: [PATCH 6/9] remove internal competition.hpp header file --- include/pros/competition.hpp | 9 +++++++++ src/competition.hpp | 10 ---------- 2 files changed, 9 insertions(+), 10 deletions(-) delete mode 100644 src/competition.hpp diff --git a/include/pros/competition.hpp b/include/pros/competition.hpp index 8bd0d39d..8d9197e5 100644 --- a/include/pros/competition.hpp +++ b/include/pros/competition.hpp @@ -74,4 +74,13 @@ void register_driver_control(std::function callable); * @param callable */ void register_disabled(std::function callable); + +/** + * @brief initialize the competition control task + * + * TODO: figure out how to hide this from the user + * + * This function is called after `int main` is called. + */ +void initialize(); } // namespace zest::competition \ No newline at end of file diff --git a/src/competition.hpp b/src/competition.hpp deleted file mode 100644 index 46eee90a..00000000 --- a/src/competition.hpp +++ /dev/null @@ -1,10 +0,0 @@ -// this file contains private API for the competition control - -#pragma once - -#include "pros/competition.hpp" - -namespace zest::competition { -// initialize the competition control task -void initialize(); -} // namespace zest::competition \ No newline at end of file From 780d7071421d3ddb9e076d20ba86ef0f417c5614 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 6 Jun 2025 15:35:55 -0700 Subject: [PATCH 7/9] fix compiler errors --- src/system/startup.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/system/startup.cpp b/src/system/startup.cpp index ce952c73..b9264402 100644 --- a/src/system/startup.cpp +++ b/src/system/startup.cpp @@ -13,8 +13,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "pros/competition.hpp" #include "pros/rtos.hpp" -#include "src/competition.hpp" #include "v5_api_patched.h" #include @@ -22,6 +22,7 @@ #include #include + extern "C" { // Initialization routines provided elsewhere void rtos_initialize(); From 3864cf449b81a5c2a591b6f55c5cd5614151aeb2 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 6 Jun 2025 16:00:43 -0700 Subject: [PATCH 8/9] add competition task tests --- tests/competition_task.cpp | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/competition_task.cpp diff --git a/tests/competition_task.cpp b/tests/competition_task.cpp new file mode 100644 index 00000000..d8277185 --- /dev/null +++ b/tests/competition_task.cpp @@ -0,0 +1,46 @@ +#include "pros/competition.hpp" +#include "pros/rtos.hpp" + +#include + +extern "C" { +void vexDisplayPrintf(int32_t xpos, int32_t ypos, uint32_t bOpaque, const char* format, ...); +void vexDisplayErase(); +} + +int main() { + zest::competition::register_driver_control([]() { + vexDisplayErase(); + vexDisplayPrintf(10, 100, 1, "Driver Control Running\n"); + vexDisplayPrintf(10, 60, 1, "num tasks: %u\n", pros::Task::get_count()); + // infinite loop to test task priorities. If everything is working correctly, the + // competition task will still switch when the competition state changes + while (true) { + asm("nop"); + } + }); + zest::competition::register_autonomous([]() { + vexDisplayErase(); + vexDisplayPrintf(10, 100, 1, "Autonomous Running\n"); + vexDisplayPrintf(10, 60, 1, "num tasks: %u\n", pros::Task::get_count()); + // infinite loop to test task priorities. If everything is working correctly, the + // competition task will still switch when the competition state changes + while (true) { + asm("nop"); + } + }); + zest::competition::register_disabled([]() { + vexDisplayErase(); + vexDisplayPrintf(10, 100, 1, "Disabled Running\n"); + vexDisplayPrintf(10, 60, 1, "num tasks: %u\n", pros::Task::get_count()); + // infinite loop to test task priorities. If everything is working correctly, the + // competition task will still switch when the competition state changes + while (true) { + asm("nop"); + } + }); + + vexDisplayPrintf(10, 60, 1, "demonstrating that tasks are run after main returns\n"); + pros::delay(3000); + vexDisplayErase(); +} \ No newline at end of file From b15bde0c06061283ca61a3d6a14f21ab2e350249 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 6 Jun 2025 16:02:25 -0700 Subject: [PATCH 9/9] update STRUCTURE.md --- docs/STRUCTURE.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/STRUCTURE.md b/docs/STRUCTURE.md index 579fa433..f180d6ab 100644 --- a/docs/STRUCTURE.md +++ b/docs/STRUCTURE.md @@ -14,7 +14,6 @@ Looking at the file structure of a project like this can feel intimidating. This - `include/rtos` headers for the scheduler (FreeRTOS) - `include/system` headers for low-level system functionality - `include/system/dev` headers for serial I/O and file management - - `include/system/user_functions` a horrifying mess that should be destroyed - `scripts` contains scripts used for building ZestCode and projects that use ZestCode