├── .clang-format ├── .github ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE │ ├── BUG_REPORT.md │ └── FEATURE_REQUEST.md ├── PULL_REQUEST_TEMPLATE.md ├── README.md └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── docs ├── CONTRIBUTING.md ├── Doxyfile ├── STRUCTURE.md ├── STYLEGUIDE.md └── assets │ └── contributing │ ├── clone.png │ ├── contribute.png │ └── create-fork.png ├── include ├── api.h ├── common │ ├── cobs.h │ ├── gid.h │ ├── linkedlist.h │ ├── result.hpp │ ├── set.h │ └── string2.h ├── kapi.h ├── main.h ├── pros │ ├── apix.hpp │ ├── competition.hpp │ ├── devices │ │ ├── adi_expander.hpp │ │ ├── battery.hpp │ │ ├── brain.hpp │ │ ├── devices.hpp │ │ └── port.hpp │ ├── rtos.h │ └── rtos.hpp ├── rtos │ ├── FreeRTOS.h │ ├── FreeRTOSConfig.h │ ├── StackMacros.h │ ├── list.h │ ├── message_buffer.h │ ├── portable.h │ ├── portmacro.h │ ├── projdefs.h │ ├── queue.h │ ├── semphr.h │ ├── stack_macros.h │ ├── stream_buffer.h │ ├── task.h │ ├── tcb.h │ └── timers.h └── system │ ├── dev │ ├── banners.h │ ├── dev.h │ ├── ser.h │ ├── usd.h │ └── vfs.h │ └── optimizers.h ├── meson.build ├── scripts ├── .clangd ├── get_files.py ├── patch_clangd.py ├── v5.ini └── v5.ld ├── src ├── common │ ├── README.md │ ├── cobs.c │ ├── gid.c │ ├── linkedlist.c │ ├── set.c │ └── string2.c ├── competition.cpp ├── devices │ ├── battery.cpp │ └── brain.cpp ├── rtos │ ├── LICENSE │ ├── README.md │ ├── heap_4.c │ ├── list.c │ ├── port.c │ ├── portASM.S │ ├── portmacro.h │ ├── queue.c │ ├── rtos.cpp │ ├── semphr.c │ ├── stream_buffer.c │ ├── task_notify_when_deleting.c │ ├── tasks.c │ └── timers.c └── system │ ├── cpp_support.cpp │ ├── dev │ ├── file_system_stubs.c │ ├── ser_daemon.c │ ├── ser_driver.c │ ├── usd_driver.c │ └── vfs.c │ ├── envlock.c │ ├── mlock.c │ ├── rtos_hooks.c │ ├── startup.cpp │ ├── stubs.cpp │ ├── system_daemon.cpp │ ├── unwind.c │ └── xilinx_vectors.s ├── subprojects └── v5.wrap └── tests ├── competition_task.cpp ├── errno_reentrancy.c ├── examples └── basic.cpp ├── exceptions.cpp ├── mutexes.c ├── result.cpp ├── rtos_function_linking.c ├── segfault.cpp ├── static_tast_states.c ├── task_notify_when_deleting.c └── unwind.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | # inspired by rustfmt's default style 3 | # implemented for clang-format 19 4 | Language: Cpp 5 | Standard: Latest 6 | AccessModifierOffset: -2 7 | AlignAfterOpenBracket: BlockIndent 8 | AllowAllArgumentsOnNextLine: false 9 | AllowAllParametersOfDeclarationOnNextLine: false 10 | AlignConsecutiveAssignments: None 11 | AllowBreakBeforeNoexceptSpecifier: Always 12 | AllowShortBlocksOnASingleLine: Empty 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortCompoundRequirementOnASingleLine: false 15 | AllowShortEnumsOnASingleLine: false 16 | AllowShortFunctionsOnASingleLine: Empty 17 | AllowShortIfStatementsOnASingleLine: Never 18 | AllowShortLambdasOnASingleLine: Empty 19 | AllowShortLoopsOnASingleLine: false 20 | AlwaysBreakAfterDefinitionReturnType: None 21 | AlwaysBreakBeforeMultilineStrings: true # auto formatting gets nasty otherwise 22 | BinPackArguments: false 23 | BinPackParameters: false 24 | BitFieldColonSpacing: Both 25 | BreakAdjacentStringLiterals: true 26 | BreakAfterAttributes: Always 27 | BreakAfterReturnType: Automatic 28 | PenaltyReturnTypeOnItsOwnLine: 100 # we really don't want to ever do this 29 | BreakBeforeBinaryOperators: NonAssignment 30 | BreakBeforeBraces: Attach 31 | BreakBeforeConceptDeclarations: Always 32 | BreakBeforeInlineASMColon: Always 33 | BreakBeforeTernaryOperators: true 34 | BreakConstructorInitializers: BeforeColon 35 | BreakInheritanceList: AfterColon 36 | BreakStringLiterals: true # this *could* produce really wacky results if autoformatting 37 | # we keep this to let the developer know that they've exceeded 38 | # the column limit. It can be manually formatted in a way that 39 | # won't trigger clang-format 40 | BreakTemplateDeclarations: Yes 41 | ColumnLimit: 100 42 | CompactNamespaces: false 43 | Cpp11BracedListStyle: true 44 | EmptyLineAfterAccessModifier: Never 45 | EmptyLineBeforeAccessModifier: Always 46 | FixNamespaceComments: true 47 | IndentAccessModifiers: false 48 | IndentCaseBlocks: false 49 | IndentCaseLabels: true 50 | IndentExternBlock: NoIndent 51 | IndentGotoLabels: false 52 | IndentPPDirectives: BeforeHash 53 | IndentRequiresClause: true 54 | IndentWidth: 4 55 | IndentWrappedFunctionNames: false 56 | InsertBraces: false # can produce incorrect code if set to true 57 | InsertNewlineAtEOF: false 58 | InsertTrailingCommas: Wrapped 59 | KeepEmptyLines: 60 | AtEndOfFile: false 61 | AtStartOfBlock: false 62 | AtStartOfFile: false 63 | LambdaBodyIndentation: OuterScope # can get really ugly otherwise 64 | MaxEmptyLinesToKeep: 1 65 | NamespaceIndentation: None 66 | PackConstructorInitializers: Never 67 | PointerAlignment: Left # its type info, so it goes on the left 68 | QualifierAlignment: Leave # can produce incorrect code if set to anything other than Leave 69 | ReferenceAlignment: Pointer 70 | ReflowComments: true 71 | RequiresClausePosition: OwnLine 72 | RequiresExpressionIndentation: OuterScope # can get really ugly otherwise 73 | SeparateDefinitionBlocks: Always 74 | ShortNamespaceLines: 0 # disable short namespaces essentially 75 | SortIncludes: true 76 | IncludeBlocks: Regroup 77 | IncludeCategories: 78 | - Regex: '^"' # Group 1: Quote includes. 79 | Priority: 1 80 | - Regex: '^<' # Group 2: Angle-bracket includes. 81 | Priority: 2 82 | SortUsingDeclarations: Lexicographic 83 | SpaceAfterCStyleCast: false 84 | SpaceAfterLogicalNot: false 85 | SpaceAfterTemplateKeyword: false 86 | SpaceAroundPointerQualifiers: Default 87 | SpaceBeforeAssignmentOperators: true 88 | SpaceBeforeCaseColon: false 89 | SpaceBeforeCpp11BracedList: false 90 | SpaceBeforeCtorInitializerColon: true 91 | SpaceBeforeInheritanceColon: true 92 | SpaceBeforeParens: ControlStatementsExceptControlMacros 93 | SpaceBeforeRangeBasedForLoopColon: true 94 | SpaceBeforeSquareBrackets: false 95 | SpaceInEmptyBlock: false 96 | SpacesBeforeTrailingComments: 1 97 | SpacesInAngles: Never 98 | SpacesInLineCommentPrefix: 99 | Minimum: 1 100 | Maximum: 1 101 | SpacesInParens: Never 102 | SpacesInSquareBrackets: false 103 | UseTab: Never -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | Discord (Tag: SizzlinSeal#8682). 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG_REPORT.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Report a bug in the project 4 | title: ":bug: " 5 | labels: "triage" 6 | assignees: "" 7 | --- 8 | 9 | #### Expected Behavior 10 | 11 | 12 | #### Observed Behavior 13 | 14 | 15 | #### Steps to Reproduce 16 | 17 | 18 | #### Environment 19 | 20 | 21 | - LemLib Version: 22 | - PROS Kernel Version: 23 | - PROS CLI Version: 24 | - Additional Templates: 25 | 26 | #### Additional Information 27 | 28 | 29 | 30 | #### Expected Behavior: 31 | 32 | 33 | #### Actual Behavior: 34 | 35 | 36 | #### Steps to reproduce: 37 | 38 | 39 | #### Additional Information 40 | 41 | 42 | #### Screenshots/Output Dumps/Stack Traces 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Suggest an idea for the project 4 | title: ":sparkles: " 5 | labels: "triage" 6 | assignees: "" 7 | --- 8 | 9 | #### Overview 10 | 11 | 12 | #### Motivation 13 | 14 | 15 | #### Additional Information 16 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | #### Overview 2 | 3 | 4 | #### Motivation 5 | 6 | 7 | #### References (optional) 8 | 9 | 10 | #### Implementation Details (optional) 11 | 12 | 13 | #### Test Plan: 14 | 15 | 16 | - [ ] example test A 17 | - [X] example test B 18 | -------------------------------------------------------------------------------- /.github/README.md: -------------------------------------------------------------------------------- 1 | # ZestCode 2 | 3 | > [!IMPORTANT] 4 | > ZestCode is under heavy development, and we'd greatly appreciate any contributors! Consider joining our [Discord Server](https://discord.gg/vNMXCvVwdY) if you are interested. 5 | 6 | ZestCode is a truly open-source framework for the VEX V5. It's a PROS fork, and exists to address some PROS issues, particularly in reliability, tooling, and community input. 7 | 8 | ### (WIP) Why ZestCode? 9 | 10 | - [X] designed to be easy to contribute to 11 | - [X] can be built from source 12 | - [X] public development discussions and decision making 13 | - [ ] superior contributor documentation 14 | - [ ] superior build system 15 | - [ ] more understandable compiler errors/warnings 16 | - [ ] faster build times 17 | - [ ] smarter package management 18 | - [ ] deterministic builds 19 | 20 | ### FAQ 21 | 22 | > Is ZestCode legal? 23 | 24 | Yup, 100% legal. It is not prohibited in the V5RC, VURC, or VAIRC game manual, and it's legal from a copyright standpoint. 25 | 26 | > Why can ZestCode be compiled from source, but PROS can't? 27 | 28 | PROS depends on `libv5rts`, which is a private version of the VEX SDK. ZestCode depends on `libv5rt.a`, which is public. 29 | 30 | ### License 31 | 32 | ZestCode is licensed under the [Mozilla Public License 2.0](../LICENSE) 33 | 34 | ### Contributing 35 | 36 | Want to contribute? Check out [CONTRIBUTING.md](../docs/CONTRIBUTING.md) 37 | 38 | ### Acknowledgements 39 | 40 | The authors of ZestCode would like to thank the developers of PROS for their years of service, and for paving the way for alternatives like ZestCode to even exist in the first place. We'd also like to thank the developers of vexide, ZestCode wouldn't exist if not for their feats. 41 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build Action 2 | 3 | on: 4 | push: 5 | branches: "**" 6 | pull_request: 7 | branches: "**" 8 | 9 | workflow_dispatch: 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | 18 | - name: Build Project 19 | id: build 20 | uses: ZestCommunity/build-action@v0.1.2 21 | 22 | - name: Upload Artifact 23 | uses: actions/upload-artifact@v4 24 | continue-on-error: true # The main point of this is to build the monolith file, not to try and upload it. Therefore, the action shouldn't fail if something were to be changed in the future that would cause this step to fail. (Especially considering ZestCode is still in development and this may very well change. 25 | with: 26 | name: ${{ steps.build.outputs.name }} 27 | path: ${{ github.workspace }}/build/program.bin 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDEs 2 | .vscode/ 3 | .idea/ 4 | # OS 5 | .DS_Store 6 | # Meson 7 | subprojects/*/ 8 | # clangd 9 | /.clangd 10 | .cache/ -------------------------------------------------------------------------------- /docs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributor's Guide 2 | 3 | > [!TIP] 4 | > Consider joining our [Discord Server](https://discord.gg/vNMXCvVwdY), it's the best place to discuss use/development of ZestCode. 5 | 6 | First off, thanks for taking the time to contribute! ZestCode relies on people like **YOU** to stay bug-free and updated. 7 | 8 | ## Ways to contribute 9 | 10 | ### Bug Reports & Feature Requests 11 | 12 | [Click Here](https://github.com/ZestCommunity/ZestCode/issues/new/choose) to submit a bug report, feature request, or privately report a security concern. 13 | 14 | ### Discussion 15 | 16 | Discussion and decision making regarding the development of ZestCode happens mostly on the [ZestCode Discord server](https://discord.gg/vNMXCvVwdY). 17 | Just asking questions, proposing new ideas, and sharing your thoughts make a positive impact. 18 | 19 | ### Pull Requests 20 | 21 | Pull Requests (short form: "PRs") are used to make changes to ZestCode. The rest of this guide is dedicated to submitting a PR. 22 | 23 | ## Your First PR: a step-by-step guide 24 | 25 | ### Step 0: Choose what to work on 26 | 27 | First, head on over to the [ZestCode Issues Tab](https://github.com/ZestCommunity/ZestCode/issues). Each title is prefixed with an emoji, which indicates the type of issue (see [Gitmoji](https://gitmoji.dev/)). 28 | 29 | Each issue has a tag: 30 | - **triage** - waiting on a maintainer to assign a tag 31 | - **sub-issue** - this issue is part of a larger one 32 | - **blocked** - this issue can't be worked on until other issue(s) are resolved 33 | - **in-progress** - this issue is actively being worked on 34 | - **ready** - this issue is ready to be worked on 35 | 36 | You'll want to either submit a new issue which you might be able to work on, or you can select an existing issue marked "ready". [Click Here](https://github.com/ZestCommunity/ZestCode/labels/ready) for a list of all issues marked as "ready". Choose one you want to work on, we recommend something that doesn't sound too big or complicated for your first contribution. 37 | 38 | ### Step 1: Fork 39 | 40 | > [!IMPORTANT] 41 | > You'll need a GitHub account for this step. 42 | 43 | [Click here](https://github.com/ZestCommunity/ZestCode/fork), then click the green button on the bottom right to create your fork, as shown in the image below. 44 | 45 | ![fork creation screen](./assets/contributing/create-fork.png) 46 | 47 | After waiting a couple of seconds, you'll be redirected to your fork of ZestCode on GitHub. 48 | 49 | ### Step 2: Clone 50 | 51 | > [!IMPORTANT] 52 | > You'll need git, and [Visual Studio Code](https://code.visualstudio.com/) for this step. 53 | 54 | In Visual Studio Code, open the command palette with (`ctrl+shift+p` or `command+shift+p`). Type `Git: Clone`, and hit enter. Select `Clone from GitHub`, and then click `/ZestCode`. 55 | 56 | ![VSC repo selection](./assets/contributing/clone.png) 57 | 58 | ### Step 3: Compile 59 | 60 | > [!IMPORTANT] 61 | > You'll need [Meson](https://mesonbuild.com/Getting-meson.html), and [arm-none-eabi-gcc](https://learn.arm.com/install-guides/gcc/arm-gnu/) for this step. 62 | 63 | In your project, open your terminal to set up and configure meson with this command: 64 | 65 | ``` 66 | meson setup --wipe --cross-file scripts/v5.ini build 67 | ``` 68 | 69 | Then, you can compile the project with this command: 70 | 71 | ``` 72 | meson compile -C build 73 | ``` 74 | 75 | > [!TIP] 76 | > You might have to restart your editor before Clangd starts working properly 77 | 78 | ### Step 4: Make your changes 79 | 80 | > [!IMPORTANT] 81 | > If you add any new source files, you will need to add them to [meson.build](../meson.build) 82 | 83 | The project file structure is explained in [STRUCTURE.md](../STRUCTURE.md). Read through it so you know where you should make your changes. 84 | Details on the code style can be found in [STYLEGUIDE.md](./STYLEGUIDE.md). 85 | 86 | You should commit changes regularly. This isn't a requirement, but it will make your life easier, especially for more complex PRs. 87 | You should also be testing your code regularly, and write tests for it in the `src/tests` folder if needed. 88 | 89 | ### Step 5: Open a PR 90 | 91 | Once you think your PR is ready to be reviewed, go to your fork on GitHub, and click the "contribute" button, as shown below. 92 | 93 | ![contribute button](./assets/contributing/contribute.png) 94 | 95 | Then, fill out the PR description template, and remember to prefix the title with a [Gitmoji](https://gitmoji.dev/). Your PR might receive a review within a minutes, or hours. The longest you'll spend waiting is a week but this is rare. 96 | 97 | Reviewers might request changes to the PR before it's merged. In fact, your PR might need several review cycles as we hold our code to a high standard. 98 | Once your PR is approved though, it will be merged shortly. 99 | 100 | And that's it! thanks again for taking the time to contribute. -------------------------------------------------------------------------------- /docs/STRUCTURE.md: -------------------------------------------------------------------------------- 1 | # Project Structure 2 | 3 | Looking at the file structure of a project like this can feel intimidating. This document describes the structure of this project, so you know where to find stuff. 4 | 5 | - `.github` contains files used by GitHub to perform some actions 6 | - `.github/ISSUE_TEMPLATE` contains the templates that are used for new [issues](https://github.com/ZestCommunity/ZestCode/issues) 7 | 8 | - `docs` contains documentation and documentation generation config files 9 | 10 | - `include` contains the header files 11 | - `include/common` headers used in various parts of the project 12 | - `include/pros` headers that are distributed to user projects 13 | - `include/pros/devices` headers containing api for interacting with V5 devices 14 | - `include/rtos` headers for the scheduler (FreeRTOS) 15 | - `include/system` headers for low-level system functionality 16 | - `include/system/dev` headers for serial I/O and file management 17 | 18 | - `scripts` contains scripts used for building ZestCode and projects that use ZestCode 19 | 20 | - `src` contains the source files 21 | - `src/common` sources defining symbols used throughout the project 22 | - `src/devices` implementations of VEX device abstractions 23 | - `src/rtos` sources, build scripts, and misc files of FreeRTOS 24 | - `src/system` sources for low-level system functionality 25 | - `src/system/dev` sources for serial I/O and file management 26 | 27 | - `subprojects` contains wrap files for dependencies 28 | 29 | - `tests` contains unit tests 30 | - `tests/examples` contains example code -------------------------------------------------------------------------------- /docs/STYLEGUIDE.md: -------------------------------------------------------------------------------- 1 | # ZestCode Styleguide 2 | 3 | > [!TIP] 4 | > ZestCode is in the process of migrating to this new style; some older code may not yet be using this new style. 5 | 6 | Maintaining a consistent coding style is important. It helps make the code more readable. ZestCode's style guide is largely inspired by [rustfmt](https://doc.rust-lang.org/stable/style-guide/). 7 | 8 | ## General Rules 9 | 10 | > [!TIP] 11 | > The [clangd VSCode extension](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd) can be used to automatically format your code using the ZestCode styleguide 12 | 13 | Some basic rules are as follows: 14 | 15 | - use [fixed width integer types](https://en.cppreference.com/w/cpp/types/integer) instead of `int` or `unsigned int` 16 | - don't use `int_fast_t` or `int_smallest_t` unless you document why its necessary 17 | - indent using 4 spaces, not tabs 18 | - no more than 100 columns per line 19 | - write tests for your code 20 | - always use `enum class` over `enum` 21 | - a `struct` should have only public member variables and no methods 22 | - don't use `typedef`, use `using` instead 23 | - use [C++11 attributes](https://en.cppreference.com/w/cpp/language/attributes) instead of the older GCC attribute syntax: `__attribute__((...))` 24 | - only use macros as a last resort 25 | 26 | For more details, see [.clang-format](../.clang-format). 27 | 28 | ## File extensions 29 | 30 | > [!IMPORTANT] 31 | > ZestCode is being rewritten in C++. No C files or headers may be added, but existing ones can be modified. 32 | 33 | - C source files will have the extension `.c` 34 | - C++ source files will have the extension `.cpp` 35 | - C header files will have the extension `.h` 36 | - C++ header files will have the extension `.hpp` 37 | - Assembly source files will have the extension `.s` 38 | - Linkerscripts will have the extension `.ld` 39 | - Markdown documents will have the extension `.md` 40 | - Python files will have the extension `.py` 41 | 42 | ## Naming Conventions 43 | 44 | - **files, folders** - snake_case 45 | - **classes, structs, enums, unions, concepts, etc** - PascalCase 46 | - **enum members** - PascalCase 47 | - **edge case** - names like `HTTPRequest` should be `HttpRequst` 48 | - **functions** - snake_case 49 | - **variables** - snake_case 50 | - **member variables** - m_snake_case (The `m_` is intentional) 51 | - **macros** - SCREAMING_SNAKE_CASE 52 | - **constexpr constants** - SCREAMING_SNAKE_CASE 53 | 54 | ## Documentation 55 | 56 | Use Doxygen-style comments as shown in the sections below. 57 | 58 | ### Enum-Level Comments 59 | 60 | These should be placed immediately before the declaration of the enum. 61 | 62 | ```c++ 63 | /* 64 | * @brief Short description of the enum 65 | * 66 | * Extended description of the enum goes here. This should explain general usage 67 | * patterns for the enum. 68 | */ 69 | enum class MyEnum { 70 | member_0, ///< short description of member 0 goes here. 71 | member_1, ///< these can be omitted if it's painfully obvious 72 | member_2, ///< what each is for, or if there are just so many of 73 | member_3, ///< them it doesn't make practical sense to 74 | member_4, ///< document them all. 75 | } 76 | ``` 77 | 78 | > [!TIP] 79 | > In the above example, the comments describing each member of the `enum` run together and form complete sentences for effect. 80 | > Please do not do this in your code! 81 | 82 | ### Function-Level Comments 83 | 84 | These should be placed immediately before the function prototype they are describing in a header file. 85 | 86 | ```c++ 87 | /** 88 | * @brief Brief description of the function. 89 | * 90 | * An extended description of the function (if applicable). 91 | * 92 | * This function uses the following values of errno when an error state is 93 | * reached: 94 | * ERRNO_VALUE - Description of what causes this error 95 | * 96 | * @tparam T the type of the parameters 97 | * 98 | * @param parameter_name The parameter description 99 | * @param other_parameter_name The parameter description 100 | * 101 | * @return The description of the return value, if this is longer than one line 102 | * then it will wrap around under the return statement 103 | * 104 | * @code 105 | * // example code here 106 | * @endcode 107 | * 108 | * @see src/referenced_file.cpp 109 | */ 110 | ``` 111 | 112 | ### Implementation Comments 113 | 114 | Sometimes it is necessary to explain statement or series of statements. 115 | In this case, comment it! Prefer adding comments before the offending code, 116 | rather than next to it. 117 | Add as much documentation as you think is necessary, rather too much than too little. 118 | 119 | For example: 120 | 121 | ```c++ 122 | // Program entrypoint. This is the first function that is run. 123 | // It sets up memory, initializes libc, and then calls main 124 | extern "C" [[gnu::section(".boot")]] 125 | void _start() { 126 | // Symbols provided by the linker script 127 | extern uint32_t __bss_start; 128 | extern uint32_t __bss_end; 129 | extern uint32_t __sbss_start; 130 | extern uint32_t __sbss_end; 131 | // Don't try refactoring this code with stuff like std::fill or std::span. 132 | // It's been tried before, and it causes UB. 133 | // It's suspected that this is due to libc not being initialized yet. 134 | for (uint32_t* bss = &__bss_start; bss < &__bss_end; bss++) 135 | *bss = 0; 136 | for (uint32_t* sbss = &__sbss_start; sbss < &__sbss_end; sbss++) 137 | *sbss = 0; 138 | 139 | // Initialize libc 140 | __libc_init_array(); 141 | 142 | // call the main function, which sets up the scheduler 143 | main(); 144 | } 145 | ``` 146 | 147 | > [!TIP] 148 | > commenting out lines is fine during testing, but should be removed when you mark your PR as ready for review! 149 | 150 | #### Notes to Other Developers (Or Yourself) 151 | 152 | When writing code, it can sometimes be useful to leave notes to other developers or to yourself in the future. Examples of these include: 153 | 154 | - `// TODO: something that should be done` 155 | - `// HACK: used to describe a particularly nasty way of solving a problem-- could be improved, but it works for now` 156 | 157 | While it is not strictly necessary to use these keywords in comments, they can be helpful - modern editors either highlight some of these keywords by default or have extensions that do. 158 | This can make certain comments stand out even more when developers are "grepping" the codebase (visually or otherwise). 159 | -------------------------------------------------------------------------------- /docs/assets/contributing/clone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZestCommunity/ZestCode/0a6c0e822abf9b339ef088ec8cc2bbdb0e070d31/docs/assets/contributing/clone.png -------------------------------------------------------------------------------- /docs/assets/contributing/contribute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZestCommunity/ZestCode/0a6c0e822abf9b339ef088ec8cc2bbdb0e070d31/docs/assets/contributing/contribute.png -------------------------------------------------------------------------------- /docs/assets/contributing/create-fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZestCommunity/ZestCode/0a6c0e822abf9b339ef088ec8cc2bbdb0e070d31/docs/assets/contributing/create-fork.png -------------------------------------------------------------------------------- /include/api.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file api.h 3 | * 4 | * PROS API header provides high-level user functionality 5 | * 6 | * Contains declarations for use by typical VEX programmers using PROS. 7 | * 8 | * This file should not be modified by users, since it gets replaced whenever 9 | * a kernel upgrade occurs. 10 | * 11 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 12 | * All rights reserved. 13 | * 14 | * This Source Code Form is subject to the terms of the Mozilla Public 15 | * License, v. 2.0. If a copy of the MPL was not distributed with this 16 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 17 | */ 18 | 19 | #ifndef _PROS_API_H_ 20 | #define _PROS_API_H_ 21 | 22 | #ifdef __cplusplus 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #else /* (not) __cplusplus */ 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #endif /* __cplusplus */ 41 | 42 | #include "pros/rtos.h" 43 | 44 | #ifdef __cplusplus 45 | #include "pros/rtos.hpp" 46 | #endif 47 | 48 | #endif // _PROS_API_H_ 49 | -------------------------------------------------------------------------------- /include/common/cobs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file common/cobs.h 3 | * 4 | * Consistent Overhead Byte Stuffing header 5 | * 6 | * See common/cobs.c for discussion 7 | * 8 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 9 | * All rights reserved. 10 | * 11 | * This Source Code Form is subject to the terms of the Mozilla Public 12 | * License, v. 2.0. If a copy of the MPL was not distributed with this 13 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 | */ 15 | 16 | #pragma once 17 | 18 | #include 19 | #include 20 | 21 | 22 | #define COBS_ENCODE_MEASURE_MAX(src_len) ((src_len) + (((src_len) + 253) / 254)) 23 | 24 | /** 25 | * Encodes src in the Consistent Overhead Byte Stuffing algorithm, and writes 26 | * the result to dest. dest must be sufficiently long. use cobs_encode_measure() 27 | * to compute the size of the buff or use COBS_ENCODE_MEASURE_MAX(src_len) macro 28 | * to get the max buffer size needed (e.g. for static allocation) 29 | * 30 | * \param[out] dest 31 | * The location to write the stuffed data to 32 | * \param[in] src 33 | * The location of the incoming data 34 | * \param src_len 35 | * The length of the source data 36 | * \param prefix 37 | * The four character stream identifier 38 | * 39 | * \return The number of bytes written 40 | */ 41 | int cobs_encode( 42 | uint8_t* restrict dest, 43 | const uint8_t* restrict src, 44 | const size_t src_len, 45 | const uint32_t prefix 46 | ); 47 | 48 | /** 49 | * Same as cobs_encode() but doesn't write to an output buffer. Used to 50 | * determine how much space is needed for src. 51 | * 52 | * \param[in] src 53 | * The location of the incoming data 54 | * \param src_len 55 | * The length of the source data 56 | * \param prefix 57 | * The four character stream identifier 58 | * 59 | * \return The size of src when encoded 60 | */ 61 | size_t 62 | cobs_encode_measure(const uint8_t* restrict src, const size_t src_len, const uint32_t prefix); 63 | -------------------------------------------------------------------------------- /include/common/gid.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file common/gid.h 3 | * 4 | * Globally unique Identifer facility header 5 | * 6 | * See common/gid.c for discussion 7 | * 8 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 9 | * All rights reserved. 10 | * 11 | * This Source Code Form is subject to the terms of the Mozilla Public 12 | * License, v. 2.0. If a copy of the MPL was not distributed with this 13 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 | */ 15 | 16 | #pragma once 17 | 18 | #include "api.h" 19 | 20 | #include 21 | 22 | 23 | struct gid_metadata { 24 | uint32_t* const bitmap; // a constant pointer to a bitmap 25 | const size_t max; // Maximum gid value 26 | const size_t reserved; // first n GIDs may be reserved, at most 32, but at least 1 27 | const size_t bitmap_size; // Cached number of uint32_t's used to map gid_max. 28 | // Use gid_size_to_words to compute 29 | 30 | // internal usage to ensure that GIDs get delegated linearly before wrapping 31 | // around back to 0 32 | size_t _cur_val; 33 | mutex_t _lock; 34 | }; 35 | 36 | #ifndef UINT32_WIDTH 37 | #define UINT32_WIDTH 32 38 | #endif 39 | 40 | /** 41 | * convert the maximum number of gids into a number of words needed to store the 42 | * bitmap 43 | */ 44 | #define gid_size_to_words(size) (((size) + UINT32_WIDTH - 1) / UINT32_WIDTH) 45 | 46 | /** 47 | * Initializes a gid_metadata structure by "freeing" all IDs in the bitmap 48 | * 49 | * \param[in] metadata 50 | * The gid_metadata structure to initialize 51 | */ 52 | void gid_init(struct gid_metadata* const metadata); 53 | 54 | /** 55 | * Allocates a gid from the gid structure and returns it. 56 | * 57 | * \param[in] metadata 58 | * The gid_metadata to record to the gid structure 59 | * 60 | * \return The gid, or 0 if there are no more gids left. 61 | */ 62 | uint32_t gid_alloc(struct gid_metadata* const metadata); 63 | 64 | /** 65 | * Frees the gid specified from the structure. 66 | * 67 | * \param[in] metadata 68 | * The gid_metadata to free from the gid structure 69 | * \param id 70 | * The gid value indicating the metadata's position in the gid structure 71 | */ 72 | void gid_free(struct gid_metadata* const metadata, uint32_t id); 73 | 74 | /** 75 | * Checks if the gid specified is allocated. 76 | * 77 | * \param[in] metadata 78 | * The gid_metadata to check 79 | * \param id 80 | * The gid value indicating the metadata's position in the gid structure 81 | * 82 | * \return True if the given metadata/id combo is present in the gid structure, 83 | * false otherwise. 84 | */ 85 | bool gid_check(struct gid_metadata* metadata, uint32_t id); 86 | -------------------------------------------------------------------------------- /include/common/linkedlist.h: -------------------------------------------------------------------------------- 1 | /* 2 | * \file common/linkedlist.h 3 | * 4 | * Linked list implementation for internal use 5 | * 6 | * This file defines a linked list implementation that operates on the FreeRTOS 7 | * heap, and is able to generically store function pointers and data 8 | * 9 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 10 | * 11 | * This Source Code Form is subject to the terms of the Mozilla Public 12 | * License, v. 2.0. If a copy of the MPL was not distributed with this 13 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 | */ 15 | 16 | #pragma once 17 | 18 | typedef void (*generic_fn_t)(void); 19 | 20 | typedef struct ll_node_s { 21 | union { 22 | generic_fn_t func; // Note: a list should not contain both data/funcs 23 | void* data; 24 | } payload; 25 | struct ll_node_s* next; 26 | } ll_node_s_t; 27 | 28 | typedef struct { 29 | ll_node_s_t* head; 30 | } linked_list_s_t; 31 | 32 | /** 33 | * Initialize a linked list node storing an arbitrary function pointer 34 | * 35 | * \param func 36 | * Function pointer to store in the node 37 | * 38 | * \return A linked list node that stores a function pointer 39 | */ 40 | ll_node_s_t* linked_list_init_func_node(generic_fn_t func); 41 | 42 | /** 43 | * Initialize a linked list node storing a pointer to arbitrary data 44 | * 45 | * \param[in] data 46 | * Pointer to data 47 | * 48 | * \return A linked list node that stores some data 49 | */ 50 | ll_node_s_t* linked_list_init_data_node(void* data); 51 | 52 | /** 53 | * Initialize a linked list 54 | * 55 | * \return An initialized linked list 56 | */ 57 | linked_list_s_t* linked_list_init(); 58 | 59 | /** 60 | * Prepend a node containing a function pointer to a linked list 61 | * 62 | * If the provided linked list is NULL, it will be initialized first. 63 | * 64 | * \param[in, out] list 65 | * Linked list to which the node will be prepended 66 | * \param func 67 | * Function pointer with which to initialize the node 68 | */ 69 | void linked_list_prepend_func(linked_list_s_t* list, generic_fn_t func); 70 | 71 | /** 72 | * Prepend a node containing some data to a linked list 73 | * 74 | * If the provided linked list is NULL, it will be initialized first. 75 | * 76 | * \param[in, out] list 77 | * Linked list to which the node will be prepended 78 | * \param[in] data 79 | * Data with which to initialize the node 80 | */ 81 | void linked_list_prepend_data(linked_list_s_t* list, void* data); 82 | 83 | /** 84 | * Append a node containing a function pointer to a linked list 85 | * 86 | * If the provided linked list is NULL, it will be initialized first. 87 | * 88 | * \param[in, out] list 89 | * Linked list to which the node will be appended 90 | * \param func 91 | * Function pointer with which to initialize the node 92 | */ 93 | void linked_list_append_func(linked_list_s_t* list, generic_fn_t func); 94 | 95 | /** 96 | * Removes the node containing the given function pointer from the linked list 97 | * 98 | * \param[in, out] list 99 | * Linked list from which the node will be removed 100 | * \param func 101 | * Function pointer to be removed 102 | */ 103 | void linked_list_remove_func(linked_list_s_t* list, generic_fn_t func); 104 | 105 | /** 106 | * Append a node containing some data to a linked list 107 | * 108 | * If the provided linked list is NULL, it will be initialized first. 109 | * 110 | * \param[in, out] list 111 | * Linked list to which the node will be appended 112 | * \param data 113 | * Data with which to initialize the node 114 | */ 115 | void linked_list_append_data(linked_list_s_t* list, void* data); 116 | 117 | /** 118 | * Remove the node containing the given data from the linked list 119 | * 120 | * \param[in, out] list 121 | * Linked list from which the node will be removed 122 | * \param data 123 | * Data to be removed 124 | */ 125 | void linked_list_remove_data(linked_list_s_t* list, void* data); 126 | 127 | typedef void (*linked_list_foreach_fn_t)(ll_node_s_t*, void*); 128 | 129 | /** 130 | * Perform a function on every node in a linked list 131 | * 132 | * If the provided linked list is NULL, the function will terminate. 133 | * 134 | * \param list 135 | * Linked list upon which to perform the function 136 | * \param cb 137 | * Pointer to a callback function that will be provided the current node 138 | * as well as some extra data 139 | * \param extra_data 140 | * Extra data to pass to the callback function 141 | */ 142 | void linked_list_foreach(linked_list_s_t* list, linked_list_foreach_fn_t, void* extra_data); 143 | 144 | /** 145 | * Frees a linked_list_s_t, making it no longer a valid list. This does not free any 146 | * internal data, only the linekd_list structure. 147 | * 148 | * \param list 149 | * List to free 150 | */ 151 | void linked_list_free(linked_list_s_t* list); 152 | -------------------------------------------------------------------------------- /include/common/set.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file common/set.h 3 | * 4 | * Kernel-allocated thread-safe simple sets header 5 | * 6 | * See common/set.c for discussion 7 | * 8 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 9 | * All rights reserved. 10 | * 11 | * This Source Code Form is subject to the terms of the Mozilla Public 12 | * License, v. 2.0. If a copy of the MPL was not distributed with this 13 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 | */ 15 | 16 | #pragma once 17 | 18 | #include "kapi.h" 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | 25 | struct set { 26 | uint32_t* arr; 27 | size_t used; 28 | size_t size; 29 | static_sem_s_t mtx_buf; 30 | mutex_t mtx; 31 | }; 32 | 33 | /** 34 | * Initializes a a set. 35 | * 36 | * \param set 37 | * A pointer to a set structure 38 | */ 39 | void set_initialize(struct set* const set); 40 | 41 | /** 42 | * Adds item to the set if it didn't already exist 43 | * 44 | * \param set 45 | * A pointer to the set structure 46 | * \param item 47 | * Item to add to the set 48 | * 49 | * \return Ttrue if the item was added to the set or was already present 50 | */ 51 | bool set_add(struct set* const set, uint32_t item); 52 | 53 | /** 54 | * Removes an item from the set 55 | * 56 | * \param set 57 | * A pointer to the set structure 58 | * \param item 59 | * The item to remove 60 | * 61 | * \return True if the item was removed (or was already not present) 62 | */ 63 | bool set_rm(struct set* const set, uint32_t item); 64 | 65 | /** 66 | * Checks if the set contains an item 67 | * 68 | * \param set 69 | * A pointer to the set structure 70 | * \param item 71 | * The item to check 72 | * 73 | * \return True if the item is in the set 74 | */ 75 | bool set_contains(struct set* set, uint32_t item); 76 | 77 | /** 78 | * Checks if the list contains an item 79 | * 80 | * \param list 81 | * A pointer to a list of words 82 | * \param size 83 | * The number of items in the list 84 | * \param item 85 | * The item to check 86 | * 87 | * \return True if the item is in the list 88 | */ 89 | bool list_contains(uint32_t const* const list, const size_t size, const uint32_t item); 90 | -------------------------------------------------------------------------------- /include/common/string2.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file common/string.h 3 | * 4 | * Extra string functions header 5 | * 6 | * See common/string.c for discussion 7 | * 8 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 9 | * All rights reserved. 10 | * 11 | * This Source Code Form is subject to the terms of the Mozilla Public 12 | * License, v. 2.0. If a copy of the MPL was not distributed with this 13 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 | */ 15 | 16 | #pragma once 17 | 18 | /** 19 | * strdup but uses the kernel heap 20 | * 21 | * \param s 22 | * Pointer to the string to duplicate 23 | * 24 | * \return The duplicate string 25 | */ 26 | #include 27 | char* kstrdup(const char* s); 28 | 29 | /** 30 | * strndup but uses the kernel heap 31 | * 32 | * \param s 33 | * Pointer to the string to duplicate 34 | * \param n 35 | * The number of characters to duplicate 36 | * 37 | * \return The duplicate string 38 | */ 39 | char* kstrndup(const char* s, size_t n); 40 | -------------------------------------------------------------------------------- /include/kapi.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file kapi.h 3 | * 4 | * Kernel API header 5 | * 6 | * Contains additional declarations for use internally within kernel 7 | * development. This file includes the FreeRTOS header, which allows for 8 | * creation of statically allocated FreeRTOS primitives like tasks, semaphores, 9 | * and queues. 10 | * 11 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 12 | * All rights reserved. 13 | * 14 | * This Source Code Form is subject to the terms of the Mozilla Public 15 | * License, v. 2.0. If a copy of the MPL was not distributed with this 16 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "api.h" 22 | #include "pros/apix.hpp" 23 | #include "rtos/FreeRTOS.h" 24 | #include "rtos/stream_buffer.h" 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #define task_t pros::task_t 29 | #define task_fn_t pros::task_fn_t 30 | #define mutex_t pros::mutex_t 31 | #define sem_t pros::c::sem_t 32 | #define queue_t pros::c::queue_t 33 | #endif 34 | 35 | #define KDBG_FILENO 3 36 | 37 | #define warn_printf(fmt, ...) \ 38 | dprintf(STDERR_FILENO, "%s:%d -- " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__) 39 | #define warn_wprint(str) wprintf("%s", str) 40 | 41 | #define kprintf(fmt, ...) \ 42 | dprintf(KDBG_FILENO, "%s:%d -- " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__) 43 | #define kprint(str) kprintf("%s", str) 44 | 45 | #ifndef PROS_RELEASING 46 | #define kassert(cond) \ 47 | do { \ 48 | if (!(cond)) { \ 49 | kprint("Assertion failed: " #cond); \ 50 | } \ 51 | } while (0) 52 | #else 53 | #define kassert(cond) 54 | #endif 55 | 56 | typedef uint32_t task_stack_t; 57 | 58 | /** 59 | * Suspends the scheduler without disabling interrupts. context switches will 60 | * not occur while the scheduler is suspended. RTOS ticks that occur while the 61 | * scheduler is suspended will be held pending until the scheduler has been 62 | * unsuspended with rtos_resume_all() 63 | * 64 | * When used correctly, this function ensures that operations occur atomically 65 | * w.r.t. multitasking. Functions like task_delay, queue_send, and other 66 | * functions MUST NOT be called while the scheduler is disabled. 67 | */ 68 | void rtos_suspend_all(void); 69 | 70 | /** 71 | * Resumes the scheduler. It does not resume unsuspended tasks that were 72 | * previously suspended by task_suspend. 73 | * 74 | * if(rtos_resume_all()) { 75 | * task_delay(0); // force context switch 76 | * } 77 | * \return True if a context switch is necessary. 78 | */ 79 | int32_t rtos_resume_all(void); 80 | 81 | /** 82 | * Creates a task using statically allocated buffers. All tasks used by the PROS 83 | * system must use statically allocated buffers. 84 | * This function uses the following values of errno when an error state is 85 | * reached: 86 | * ENOMEM - The stack cannot be used as the TCB was not created. 87 | * 88 | * \param function 89 | * Pointer to the task entry function 90 | * \param parameters 91 | * Pointer to memory that will be used as a parameter for the task being 92 | * created. This memory should not typically come from stack, but rather 93 | * from dynamically (i.e., malloc'd) or statically allocated memory. 94 | * \param prio 95 | * The priority at which the task should run. 96 | * TASK_PRIO_DEFAULT plus/minus 1 or 2 is typically used. 97 | * \param stack_depth 98 | * The number of words (i.e. 4 * stack_depth) available on the task's 99 | * stack. TASK_STACK_DEPTH_DEFAULT is typically sufficient. 100 | * \param name 101 | * A descriptive name for the task. This is mainly used to facilitate 102 | * debugging. The name may be up to 32 characters long. 103 | * 104 | * \return A handle by which the newly created task can be referenced. If an 105 | * error occurred, NULL will be returned and errno can be checked for hints as 106 | * to why task_create failed. 107 | */ 108 | task_t task_create_static( 109 | task_fn_t task_code, 110 | void* const param, 111 | uint32_t priority, 112 | const size_t stack_size, 113 | const char* const name, 114 | task_stack_t* const stack_buffer, 115 | static_task_s_t* const task_buffer 116 | ); 117 | 118 | /** 119 | * Creates a statically allocated mutex. 120 | * 121 | * All FreeRTOS primitives must be created statically if they are required for 122 | * operation of the kernel. 123 | * 124 | * \param[out] mutex_buffer 125 | * A buffer to store the mutex in 126 | * 127 | * \return A handle to a newly created mutex. If an error occurred, NULL will be 128 | * returned and errno can be checked for hints as to why mutex_create failed. 129 | */ 130 | mutex_t mutex_create_static(static_sem_s_t* mutex_buffer); 131 | 132 | /** 133 | * Creates a statically allocated semaphore. 134 | * 135 | * All FreeRTOS primitives must be created statically if they are required for 136 | * operation of the kernel. 137 | * 138 | * \param max_count 139 | * The maximum count value that can be reached. 140 | * \param init_count 141 | * The initial count value assigned to the new semaphore. 142 | * \param[out] semaphore_buffer 143 | * A buffer to store the semaphore in 144 | * 145 | * \return A newly created semaphore. If an error occurred, NULL will be 146 | * returned and errno can be checked for hints as to why sem_create failed. 147 | */ 148 | sem_t sem_create_static(uint32_t max_count, uint32_t init_count, static_sem_s_t* semaphore_buffer); 149 | 150 | /** 151 | * Creates a statically allocated queue. 152 | * 153 | * All FreeRTOS primitives must be created statically if they are required for 154 | * operation of the kernel. 155 | * 156 | * \param length 157 | * The maximum number of items that the queue can contain. 158 | * \param item_size 159 | * The number of bytes each item in the queue will require. 160 | * \param[out] storage_buffer 161 | * A memory location for data storage 162 | * \param[out] queue_buffer 163 | * A buffer to store the queue in 164 | * 165 | * \return A handle to a newly created queue, or NULL if the queue cannot be 166 | * created. 167 | */ 168 | queue_t queue_create_static( 169 | uint32_t length, 170 | uint32_t item_size, 171 | uint8_t* storage_buffer, 172 | static_queue_s_t* queue_buffer 173 | ); 174 | 175 | /** 176 | * Display a fatal error to the built-in LCD/touch screen. 177 | * 178 | * This function is intended to be used when the integrity of the RTOS cannot be 179 | * trusted. No thread-safety mechanisms are used and this function only relies 180 | * on the use of the libv5rts. 181 | * 182 | * \param[in] text 183 | * The text string to display to the screen 184 | */ 185 | void display_fatal_error(const char* text); 186 | 187 | /** 188 | * Prints hex characters to the terminal. 189 | * 190 | * \param[in] s 191 | * The array of hex characters to print 192 | * \param len 193 | * The number of hex characters to print 194 | */ 195 | void kprint_hex(uint8_t* s, size_t len); 196 | 197 | int32_t xTaskGetSchedulerState(); 198 | #define taskSCHEDULER_SUSPENDED ((int32_t)0) 199 | #define taskSCHEDULER_NOT_STARTED ((int32_t)1) 200 | #define taskSCHEDULER_RUNNING ((int32_t)2) 201 | 202 | #ifdef __cplusplus 203 | #undef task_t 204 | #undef task_fn_t 205 | #undef mutex_t 206 | } 207 | #endif 208 | -------------------------------------------------------------------------------- /include/main.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file main.h 3 | * 4 | * Contains common definitions and header files used throughout your PROS 5 | * project. 6 | * 7 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 8 | * All rights reserved. 9 | * 10 | * This Source Code Form is subject to the terms of the Mozilla Public 11 | * License, v. 2.0. If a copy of the MPL was not distributed with this 12 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 13 | */ 14 | 15 | #ifndef _PROS_MAIN_H_ 16 | #define _PROS_MAIN_H_ 17 | 18 | /** 19 | * If defined, some commonly used enums will have preprocessor macros which give 20 | * a shorter, more convenient naming pattern. If this isn't desired, simply 21 | * comment the following line out. 22 | * 23 | * For instance, E_CONTROLLER_MASTER has a shorter name: CONTROLLER_MASTER. 24 | * E_CONTROLLER_MASTER is pedantically correct within the PROS styleguide, but 25 | * not convenient for most student programmers. 26 | */ 27 | #define PROS_USE_SIMPLE_NAMES 28 | 29 | /** 30 | * If defined, C++ literals will be available for use. All literals are in the 31 | * pros::literals namespace. 32 | * 33 | * For instance, you can do `4_mtr = 50` to set motor 4's target velocity to 50 34 | */ 35 | #define PROS_USE_LITERALS 36 | 37 | #include "api.h" 38 | 39 | /** 40 | * You should add more #includes here 41 | */ 42 | // #include "okapi/api.hpp" 43 | 44 | /** 45 | * If you find doing pros::Motor() to be tedious and you'd prefer just to do 46 | * Motor, you can use the namespace with the following commented out line. 47 | * 48 | * IMPORTANT: Only the okapi or pros namespace may be used, not both 49 | * concurrently! The okapi namespace will export all symbols inside the pros 50 | * namespace. 51 | */ 52 | // using namespace pros; 53 | // using namespace pros::literals; 54 | // using namespace okapi; 55 | 56 | /** 57 | * Prototypes for the competition control tasks are redefined here to ensure 58 | * that they can be called from user code (i.e. calling autonomous from a 59 | * button press in opcontrol() for testing purposes). 60 | */ 61 | #ifdef __cplusplus 62 | extern "C" { 63 | #endif 64 | void autonomous(void); 65 | void initialize(void); 66 | void disabled(void); 67 | void competition_initialize(void); 68 | void opcontrol(void); 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | 73 | #ifdef __cplusplus 74 | /** 75 | * You can add C++-only headers here 76 | */ 77 | // #include 78 | #endif 79 | 80 | #endif // _PROS_MAIN_H_ 81 | -------------------------------------------------------------------------------- /include/pros/competition.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace zest::competition { 6 | /** 7 | * @brief the competition mode (disabled, driver control, autonomous) 8 | * 9 | */ 10 | enum class Mode { 11 | Disabled, 12 | DriverControl, 13 | Autonomous, 14 | }; 15 | 16 | /** 17 | * @brief the competition system being used 18 | * 19 | */ 20 | enum class System { 21 | FieldControl, 22 | CompetitionSwitch, 23 | None, 24 | }; 25 | 26 | /** 27 | * @brief Get the competition mode (disabled, driver control, autonomous) 28 | * 29 | * @return Status 30 | */ 31 | Mode get_mode(); 32 | 33 | /** 34 | * @brief Get the system type being used (field control, competition switch, or none) 35 | * 36 | * @return System 37 | */ 38 | System get_system(); 39 | 40 | /** 41 | * @brief Whether field control or a competition switch is connected 42 | * 43 | * @return true 44 | * @return false 45 | */ 46 | bool is_connected(); 47 | 48 | /** 49 | * @brief register the callable that will be called when the autonomous period starts. 50 | * 51 | * The callable is called whenever the competition state changes to autonomous. The task that runs 52 | * it is killed as soon as the competition state changes to driver control or disabled. 53 | * 54 | * @param callable 55 | */ 56 | void register_autonomous(std::function callable); 57 | 58 | /** 59 | * @brief register the callable that will be called when the driver control period starts. 60 | * 61 | * The callable is called whenever the competition state changes to autonomous. The task that runs 62 | * it is killed as soon as the competition state changes to driver control or disabled. 63 | * 64 | * @param callable 65 | */ 66 | void register_driver_control(std::function callable); 67 | 68 | /** 69 | * @brief register the callable that will be called when the disabled period starts. 70 | * 71 | * The callable is called whenever the competition state changes to autonomous. The task that 72 | * runs it is killed as soon as the competition state changes to driver control or disabled. 73 | * 74 | * @param callable 75 | */ 76 | void register_disabled(std::function callable); 77 | 78 | /** 79 | * @brief initialize the competition control task 80 | * 81 | * TODO: figure out how to hide this from the user 82 | * 83 | * This function is called after `int main` is called. 84 | */ 85 | void initialize(); 86 | } // namespace zest::competition -------------------------------------------------------------------------------- /include/pros/devices/adi_expander.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "port.hpp" 4 | #include "pros/devices/port.hpp" 5 | 6 | namespace zest { 7 | 8 | /** 9 | * @brief ADI Expander class. Used to control access to ADI ports 10 | * 11 | */ 12 | class AdiExpander { 13 | public: 14 | /** 15 | * @brief Construct a new ADI Expander object 16 | * 17 | * @param port the smart port the ADI expander is connected to 18 | */ 19 | constexpr AdiExpander(SmartPort port) 20 | : port_a(port, 'A'), 21 | port_b(port, 'B'), 22 | port_c(port, 'C'), 23 | port_d(port, 'D'), 24 | port_e(port, 'E'), 25 | port_f(port, 'F'), 26 | port_g(port, 'G'), 27 | port_h(port, 'H'), 28 | port_invalid(port, 'J'), 29 | smart_port(port) {} 30 | 31 | AdiPort port_a; 32 | AdiPort port_b; 33 | AdiPort port_c; 34 | AdiPort port_d; 35 | AdiPort port_e; 36 | AdiPort port_f; 37 | AdiPort port_g; 38 | AdiPort port_h; 39 | // users may use port_invalid as a placeholder or temporary port 40 | AdiPort port_invalid; 41 | 42 | SmartPort smart_port; 43 | }; 44 | }; // namespace zest -------------------------------------------------------------------------------- /include/pros/devices/battery.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace zest { 4 | 5 | class Battery { 6 | public: 7 | /** 8 | * @brief Get the remaining capacity of the robot battery 9 | * 10 | * TODO: document how the returned value should be interpreted (e.g 0-1 or 0-100) 11 | * 12 | * @return double 13 | */ 14 | static double get_capacity(); 15 | /** 16 | * @brief Get the current drawn from the robot battery 17 | * 18 | * TODO: document how the returned value should be interpreted (e.g amps or milliamps) 19 | * 20 | * @return double 21 | */ 22 | static double get_current(); 23 | /** 24 | * @brief Get the temperature of the robot battery 25 | * 26 | * TODO: document how the returned value should be interpreted (e.g celsius or fahrenheit) 27 | * 28 | * @return double 29 | */ 30 | static double get_temperature(); 31 | /** 32 | * @brief Get the voltage of the robot battery 33 | * 34 | * TODO: document how the returned value should be interpreted (e.g celsius or fahrenheit) 35 | * 36 | * @return double 37 | */ 38 | static double get_voltage(); 39 | }; 40 | 41 | } // namespace zest -------------------------------------------------------------------------------- /include/pros/devices/brain.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "pros/devices/adi_expander.hpp" 4 | #include "pros/rtos.hpp" 5 | 6 | namespace zest { 7 | /** 8 | * @brief 9 | * 10 | */ 11 | class Brain { 12 | public: 13 | // physical smart ports 14 | static constexpr SmartPort PORT_1 = SmartPort(1); 15 | static constexpr SmartPort PORT_2 = SmartPort(2); 16 | static constexpr SmartPort PORT_3 = SmartPort(3); 17 | static constexpr SmartPort PORT_4 = SmartPort(4); 18 | static constexpr SmartPort PORT_5 = SmartPort(5); 19 | static constexpr SmartPort PORT_6 = SmartPort(6); 20 | static constexpr SmartPort PORT_7 = SmartPort(7); 21 | static constexpr SmartPort PORT_8 = SmartPort(8); 22 | static constexpr SmartPort PORT_9 = SmartPort(9); 23 | static constexpr SmartPort PORT_10 = SmartPort(10); 24 | static constexpr SmartPort PORT_11 = SmartPort(11); 25 | static constexpr SmartPort PORT_12 = SmartPort(12); 26 | static constexpr SmartPort PORT_13 = SmartPort(13); 27 | static constexpr SmartPort PORT_14 = SmartPort(14); 28 | static constexpr SmartPort PORT_15 = SmartPort(15); 29 | static constexpr SmartPort PORT_16 = SmartPort(16); 30 | static constexpr SmartPort PORT_17 = SmartPort(17); 31 | static constexpr SmartPort PORT_18 = SmartPort(18); 32 | static constexpr SmartPort PORT_19 = SmartPort(19); 33 | static constexpr SmartPort PORT_20 = SmartPort(20); 34 | static constexpr SmartPort PORT_21 = SmartPort(21); 35 | 36 | // virtual smart ports 37 | static constexpr SmartPort INTEGRATED_ADI_PORT = SmartPort(22); 38 | static constexpr SmartPort BATTERY_PORT = SmartPort(25); 39 | // users may use port_invalid as a placeholder or temporary port 40 | static constexpr SmartPort INVALID_PORT = SmartPort(33); 41 | 42 | // all adi ports on the brain 43 | static constexpr AdiExpander adi = AdiExpander(INTEGRATED_ADI_PORT); 44 | 45 | // TODO: conditionally declare functions below, to prevent users accidentally calling them 46 | // TODO: replace lock_all and unlock_all with a single function that returns an std::scoped_lock 47 | 48 | /** 49 | * @brief Get the mutex of a smart port 50 | * 51 | * @warning this function should not be used by typical users 52 | * 53 | * @param smart_port the smart port to get the mutex of 54 | * @return pros::RecursiveMutex& 55 | */ 56 | static pros::RecursiveMutex& get_smart_port_mutex(SmartPort smart_port); 57 | 58 | /** 59 | * @brief lock all smart port mutexes 60 | * 61 | * uses std::lock to prevent deadlocks 62 | */ 63 | static void smart_port_mutex_lock_all(); 64 | 65 | /** 66 | * @brief unlock all smart port mutexes 67 | * 68 | */ 69 | static void smart_port_mutex_unlock_all(); 70 | 71 | private: 72 | static constinit std::array m_mutexes; 73 | }; 74 | }; // namespace zest -------------------------------------------------------------------------------- /include/pros/devices/devices.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/result.hpp" 4 | 5 | namespace zest { 6 | 7 | enum class DeviceType { 8 | Battery, 9 | }; 10 | 11 | /** 12 | * @brief V5 Port Mismatch Error 13 | * 14 | */ 15 | class V5PortMismatchError : public ResultError { 16 | public: 17 | /** 18 | * @brief Construct a new V5 Port Mismatch Error object 19 | * 20 | * @param expected the device expected to be on the port 21 | * @param actual the device that is actually on the port 22 | */ 23 | V5PortMismatchError(DeviceType expected, DeviceType actual) 24 | : expected(expected), 25 | actual(actual) {} 26 | 27 | DeviceType expected; 28 | DeviceType actual; 29 | }; 30 | } // namespace zest -------------------------------------------------------------------------------- /include/pros/devices/port.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace zest { 6 | 7 | // forward-declare friend classes 8 | class Brain; 9 | class AdiExpander; 10 | 11 | /** 12 | * @brief Smart Port class. Represents a Smart Port on the V5 brain. 13 | * 14 | */ 15 | class SmartPort { 16 | // SmartPort instances can only be constructed by the Brain class 17 | friend class Brain; 18 | 19 | public: 20 | /** 21 | * @brief Get the Smart Port as a number (1-indexed) 22 | * 23 | * @return constexpr uint8_t 24 | */ 25 | constexpr uint8_t as_number() const { 26 | return m_number; 27 | } 28 | 29 | /** 30 | * @brief Get the Smart Port as an index (0-indexed) 31 | * 32 | * @return constexpr uint8_t 33 | */ 34 | constexpr uint8_t as_index() const { 35 | return m_number - 1; 36 | } 37 | 38 | private: 39 | /** 40 | * @brief construct a Smart Port from a number 41 | * 42 | */ 43 | constexpr SmartPort(uint8_t port_number) 44 | : m_number(port_number) {} 45 | 46 | uint8_t m_number; 47 | }; 48 | 49 | /** 50 | * @brief ADI Port class. Represents an ADI Port on a the brain or on a 3-wire expander. 51 | * 52 | * ADI Ports may be represented as a 0-indexed number, or a letter (e.g 'A' or 'C'). This class 53 | * provides an interface so the developer doesn't have to worry about conversions. 54 | */ 55 | class AdiPort { 56 | // AdiPort instances can only be constructed by the AdiExpander class 57 | friend class AdiExpander; 58 | 59 | public: 60 | /** 61 | * @brief Get the ADI Port as an uppercase letter ('A' to 'H') 62 | * 63 | * @return constexpr char 64 | */ 65 | constexpr char as_letter() const { 66 | return m_letter; 67 | } 68 | 69 | /** 70 | * @brief Get the ADI Port as a 0-indexed number (0-7) 71 | * 72 | * @return constexpr uint8_t 73 | */ 74 | constexpr uint8_t as_index() const { 75 | return m_letter - 'A'; 76 | } 77 | 78 | SmartPort host_port; 79 | 80 | private: 81 | /** 82 | * @brief Create an ADI Port using its character 83 | * 84 | * @param host_port the smart port of the ADI hub this adi port belongs to 85 | * @param port must be uppercase, 'A' - 'H' 86 | * @return constexpr AdiPort 87 | */ 88 | constexpr AdiPort(SmartPort host_port, char port) 89 | : host_port(host_port), 90 | m_letter(port) {} 91 | 92 | char m_letter; 93 | }; 94 | 95 | } // namespace zest -------------------------------------------------------------------------------- /include/rtos/StackMacros.h: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeRTOS Kernel V10.0.1 3 | * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | * http://www.FreeRTOS.org 23 | * http://aws.amazon.com/freertos 24 | * 25 | * 1 tab == 4 spaces! 26 | */ 27 | 28 | #ifndef STACK_MACROS_H 29 | #define STACK_MACROS_H 30 | 31 | #ifndef _MSC_VER /* Visual Studio doesn't support #warning. */ 32 | #warning The name of this file has changed to stack_macros.h. Please update your code accordingly. This source file (which has the original name) will be removed in future released. 33 | #endif 34 | 35 | /* 36 | * Call the stack overflow hook function if the stack of the task being swapped 37 | * out is currently overflowed, or looks like it might have overflowed in the 38 | * past. 39 | * 40 | * Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check 41 | * the current stack state only - comparing the current top of stack value to 42 | * the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1 43 | * will also cause the last few stack bytes to be checked to ensure the value 44 | * to which the bytes were set when the task was created have not been 45 | * overwritten. Note this second test does not guarantee that an overflowed 46 | * stack will always be recognised. 47 | */ 48 | 49 | /*-----------------------------------------------------------*/ 50 | 51 | #if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) ) 52 | 53 | /* Only the current stack state is to be checked. */ 54 | #define taskCHECK_FOR_STACK_OVERFLOW() \ 55 | { \ 56 | /* Is the currently saved stack pointer within the stack limit? */ \ 57 | if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \ 58 | { \ 59 | vApplicationStackOverflowHook( ( task_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ 60 | } \ 61 | } 62 | 63 | #endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */ 64 | /*-----------------------------------------------------------*/ 65 | 66 | #if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH > 0 ) ) 67 | 68 | /* Only the current stack state is to be checked. */ 69 | #define taskCHECK_FOR_STACK_OVERFLOW() \ 70 | { \ 71 | \ 72 | /* Is the currently saved stack pointer within the stack limit? */ \ 73 | if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack ) \ 74 | { \ 75 | vApplicationStackOverflowHook( ( task_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ 76 | } \ 77 | } 78 | 79 | #endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */ 80 | /*-----------------------------------------------------------*/ 81 | 82 | #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) ) 83 | 84 | #define taskCHECK_FOR_STACK_OVERFLOW() \ 85 | { \ 86 | const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \ 87 | const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \ 88 | \ 89 | if( ( pulStack[ 0 ] != ulCheckValue ) || \ 90 | ( pulStack[ 1 ] != ulCheckValue ) || \ 91 | ( pulStack[ 2 ] != ulCheckValue ) || \ 92 | ( pulStack[ 3 ] != ulCheckValue ) ) \ 93 | { \ 94 | vApplicationStackOverflowHook( ( task_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ 95 | } \ 96 | } 97 | 98 | #endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ 99 | /*-----------------------------------------------------------*/ 100 | 101 | #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) ) 102 | 103 | #define taskCHECK_FOR_STACK_OVERFLOW() \ 104 | { \ 105 | int8_t *pcEndOfStack = ( int8_t * ) pxCurrentTCB->pxEndOfStack; \ 106 | static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ 107 | tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ 108 | tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ 109 | tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ 110 | tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \ 111 | \ 112 | \ 113 | pcEndOfStack -= sizeof( ucExpectedStackBytes ); \ 114 | \ 115 | /* Has the extremity of the task stack ever been written over? */ \ 116 | if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \ 117 | { \ 118 | vApplicationStackOverflowHook( ( task_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ 119 | } \ 120 | } 121 | 122 | #endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ 123 | /*-----------------------------------------------------------*/ 124 | 125 | /* Remove stack overflow macro if not being used. */ 126 | #ifndef taskCHECK_FOR_STACK_OVERFLOW 127 | #define taskCHECK_FOR_STACK_OVERFLOW() 128 | #endif 129 | 130 | 131 | 132 | #endif /* STACK_MACROS_H */ 133 | 134 | -------------------------------------------------------------------------------- /include/rtos/portable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeRTOS Kernel V10.0.1 3 | * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | * http://www.FreeRTOS.org 23 | * http://aws.amazon.com/freertos 24 | * 25 | * 1 tab == 4 spaces! 26 | */ 27 | 28 | /*----------------------------------------------------------- 29 | * Portable layer API. Each function must be defined for each port. 30 | *----------------------------------------------------------*/ 31 | 32 | #ifndef PORTABLE_H 33 | #define PORTABLE_H 34 | 35 | /* If portENTER_CRITICAL is not defined then including deprecated_definitions.h 36 | did not result in a portmacro.h header file being included - and it should be 37 | included here. In this case the path to the correct portmacro.h header file 38 | must be set in the compiler's include path. */ 39 | #ifndef portENTER_CRITICAL 40 | #include "portmacro.h" 41 | #endif 42 | 43 | #if portBYTE_ALIGNMENT == 32 44 | #define portBYTE_ALIGNMENT_MASK ( 0x001f ) 45 | #endif 46 | 47 | #if portBYTE_ALIGNMENT == 16 48 | #define portBYTE_ALIGNMENT_MASK ( 0x000f ) 49 | #endif 50 | 51 | #if portBYTE_ALIGNMENT == 8 52 | #define portBYTE_ALIGNMENT_MASK ( 0x0007 ) 53 | #endif 54 | 55 | #if portBYTE_ALIGNMENT == 4 56 | #define portBYTE_ALIGNMENT_MASK ( 0x0003 ) 57 | #endif 58 | 59 | #if portBYTE_ALIGNMENT == 2 60 | #define portBYTE_ALIGNMENT_MASK ( 0x0001 ) 61 | #endif 62 | 63 | #if portBYTE_ALIGNMENT == 1 64 | #define portBYTE_ALIGNMENT_MASK ( 0x0000 ) 65 | #endif 66 | 67 | #ifndef portBYTE_ALIGNMENT_MASK 68 | #error "Invalid portBYTE_ALIGNMENT definition" 69 | #endif 70 | 71 | #ifndef portNUM_CONFIGURABLE_REGIONS 72 | #define portNUM_CONFIGURABLE_REGIONS 1 73 | #endif 74 | 75 | #ifdef __cplusplus 76 | extern "C" { 77 | #endif 78 | 79 | /* 80 | * Setup the stack of a new task so it is ready to be placed under the 81 | * scheduler control. The registers have to be placed on the stack in 82 | * the order that the port expects to find them. 83 | * 84 | */ 85 | task_stack_t *pxPortInitialiseStack( task_stack_t *pxTopOfStack, task_fn_t pxCode, void *pvParameters ) ; 86 | 87 | /* Used by heap_5.c. */ 88 | typedef struct HeapRegion 89 | { 90 | uint8_t *pucStartAddress; 91 | size_t xSizeInBytes; 92 | } HeapRegion_t; 93 | 94 | /* 95 | * Used to define multiple heap regions for use by heap_5.c. This function 96 | * must be called before any calls to kmalloc() - not creating a task, 97 | * queue, semaphore, mutex, software timer, event group, etc. will result in 98 | * kmalloc being called. 99 | * 100 | * pxHeapRegions passes in an array of HeapRegion_t structures - each of which 101 | * defines a region of memory that can be used as the heap. The array is 102 | * terminated by a HeapRegions_t structure that has a size of 0. The region 103 | * with the lowest start address must appear first in the array. 104 | */ 105 | void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) ; 106 | 107 | 108 | /* 109 | * Map to the memory management routines required for the port. 110 | */ 111 | void *kmalloc( size_t xSize ) ; 112 | void kfree( void *pv ) ; 113 | void vPortInitialiseBlocks( void ) ; 114 | size_t xPortGetFreeHeapSize( void ) ; 115 | size_t xPortGetMinimumEverFreeHeapSize( void ) ; 116 | 117 | /* 118 | * Setup the hardware ready for the scheduler to take control. This generally 119 | * sets up a tick interrupt and sets timers for the correct tick frequency. 120 | */ 121 | int32_t xPortStartScheduler( void ) ; 122 | 123 | /* 124 | * Undo any hardware/ISR setup that was performed by xPortStartScheduler() so 125 | * the hardware is left in its original condition after the scheduler stops 126 | * executing. 127 | */ 128 | void vPortEndScheduler( void ) ; 129 | 130 | #ifdef __cplusplus 131 | } 132 | #endif 133 | 134 | #endif /* PORTABLE_H */ 135 | -------------------------------------------------------------------------------- /include/rtos/projdefs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeRTOS Kernel V10.0.1 3 | * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | * http://www.FreeRTOS.org 23 | * http://aws.amazon.com/freertos 24 | * 25 | * 1 tab == 4 spaces! 26 | */ 27 | 28 | #ifndef PROJDEFS_H 29 | #define PROJDEFS_H 30 | 31 | /* 32 | * Defines the prototype to which task functions must conform. Defined in this 33 | * file to ensure the type is known before portable.h is included. 34 | */ 35 | typedef void (*task_fn_t)( void * ); 36 | 37 | /* Converts a time in milliseconds to a time in ticks. This macro can be 38 | overridden by a macro of the same name defined in FreeRTOSConfig.h in case the 39 | definition here is not suitable for your application. */ 40 | #ifndef pdMS_TO_TICKS 41 | #define pdMS_TO_TICKS( xTimeInMs ) ( ( uint32_t ) ( ( ( uint32_t ) ( xTimeInMs ) * ( uint32_t ) configTICK_RATE_HZ ) / ( uint32_t ) 1000 ) ) 42 | #endif 43 | 44 | #define pdFALSE ( ( int32_t ) 0 ) 45 | #define pdTRUE ( ( int32_t ) 1 ) 46 | 47 | #define pdPASS ( pdTRUE ) 48 | #define pdFAIL ( pdFALSE ) 49 | #define errQUEUE_EMPTY ( ( int32_t ) 0 ) 50 | #define errQUEUE_FULL ( ( int32_t ) 0 ) 51 | 52 | /* FreeRTOS error definitions. */ 53 | #define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 ) 54 | #define errQUEUE_BLOCKED ( -4 ) 55 | #define errQUEUE_YIELD ( -5 ) 56 | 57 | /* Macros used for basic data corruption checks. */ 58 | #ifndef configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 59 | #define configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 0 60 | #endif 61 | 62 | #if( configUSE_16_BIT_TICKS == 1 ) 63 | #define pdINTEGRITY_CHECK_VALUE 0x5a5a 64 | #else 65 | #define pdINTEGRITY_CHECK_VALUE 0x5a5a5a5aUL 66 | #endif 67 | 68 | /* The following errno values are used by FreeRTOS+ components, not FreeRTOS 69 | itself. */ 70 | #define pdFREERTOS_ERRNO_NONE 0 /* No errors */ 71 | #define pdFREERTOS_ERRNO_ENOENT 2 /* No such file or directory */ 72 | #define pdFREERTOS_ERRNO_EINTR 4 /* Interrupted system call */ 73 | #define pdFREERTOS_ERRNO_EIO 5 /* I/O error */ 74 | #define pdFREERTOS_ERRNO_ENXIO 6 /* No such device or address */ 75 | #define pdFREERTOS_ERRNO_EBADF 9 /* Bad file number */ 76 | #define pdFREERTOS_ERRNO_EAGAIN 11 /* No more processes */ 77 | #define pdFREERTOS_ERRNO_EWOULDBLOCK 11 /* Operation would block */ 78 | #define pdFREERTOS_ERRNO_ENOMEM 12 /* Not enough memory */ 79 | #define pdFREERTOS_ERRNO_EACCES 13 /* Permission denied */ 80 | #define pdFREERTOS_ERRNO_EFAULT 14 /* Bad address */ 81 | #define pdFREERTOS_ERRNO_EBUSY 16 /* Mount device busy */ 82 | #define pdFREERTOS_ERRNO_EEXIST 17 /* File exists */ 83 | #define pdFREERTOS_ERRNO_EXDEV 18 /* Cross-device link */ 84 | #define pdFREERTOS_ERRNO_ENODEV 19 /* No such device */ 85 | #define pdFREERTOS_ERRNO_ENOTDIR 20 /* Not a directory */ 86 | #define pdFREERTOS_ERRNO_EISDIR 21 /* Is a directory */ 87 | #define pdFREERTOS_ERRNO_EINVAL 22 /* Invalid argument */ 88 | #define pdFREERTOS_ERRNO_ENOSPC 28 /* No space left on device */ 89 | #define pdFREERTOS_ERRNO_ESPIPE 29 /* Illegal seek */ 90 | #define pdFREERTOS_ERRNO_EROFS 30 /* Read only file system */ 91 | #define pdFREERTOS_ERRNO_EUNATCH 42 /* Protocol driver not attached */ 92 | #define pdFREERTOS_ERRNO_EBADE 50 /* Invalid exchange */ 93 | #define pdFREERTOS_ERRNO_EFTYPE 79 /* Inappropriate file type or format */ 94 | #define pdFREERTOS_ERRNO_ENMFILE 89 /* No more files */ 95 | #define pdFREERTOS_ERRNO_ENOTEMPTY 90 /* Directory not empty */ 96 | #define pdFREERTOS_ERRNO_ENAMETOOLONG 91 /* File or path name too long */ 97 | #define pdFREERTOS_ERRNO_EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ 98 | #define pdFREERTOS_ERRNO_ENOBUFS 105 /* No buffer space available */ 99 | #define pdFREERTOS_ERRNO_ENOPROTOOPT 109 /* Protocol not available */ 100 | #define pdFREERTOS_ERRNO_EADDRINUSE 112 /* Address already in use */ 101 | #define pdFREERTOS_ERRNO_ETIMEDOUT 116 /* Connection timed out */ 102 | #define pdFREERTOS_ERRNO_EINPROGRESS 119 /* Connection already in progress */ 103 | #define pdFREERTOS_ERRNO_EALREADY 120 /* Socket already connected */ 104 | #define pdFREERTOS_ERRNO_EADDRNOTAVAIL 125 /* Address not available */ 105 | #define pdFREERTOS_ERRNO_EISCONN 127 /* Socket is already connected */ 106 | #define pdFREERTOS_ERRNO_ENOTCONN 128 /* Socket is not connected */ 107 | #define pdFREERTOS_ERRNO_ENOMEDIUM 135 /* No medium inserted */ 108 | #define pdFREERTOS_ERRNO_EILSEQ 138 /* An invalid UTF-16 sequence was encountered. */ 109 | #define pdFREERTOS_ERRNO_ECANCELED 140 /* Operation canceled. */ 110 | 111 | /* The following endian values are used by FreeRTOS+ components, not FreeRTOS 112 | itself. */ 113 | #define pdFREERTOS_LITTLE_ENDIAN 0 114 | #define pdFREERTOS_BIG_ENDIAN 1 115 | 116 | /* Re-defining endian values for generic naming. */ 117 | #define pdLITTLE_ENDIAN pdFREERTOS_LITTLE_ENDIAN 118 | #define pdBIG_ENDIAN pdFREERTOS_BIG_ENDIAN 119 | 120 | 121 | #endif /* PROJDEFS_H */ 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /include/rtos/stack_macros.h: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeRTOS Kernel V10.0.1 3 | * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | * http://www.FreeRTOS.org 23 | * http://aws.amazon.com/freertos 24 | * 25 | * 1 tab == 4 spaces! 26 | */ 27 | 28 | #ifndef STACK_MACROS_H 29 | #define STACK_MACROS_H 30 | 31 | /* 32 | * Call the stack overflow hook function if the stack of the task being swapped 33 | * out is currently overflowed, or looks like it might have overflowed in the 34 | * past. 35 | * 36 | * Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check 37 | * the current stack state only - comparing the current top of stack value to 38 | * the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1 39 | * will also cause the last few stack bytes to be checked to ensure the value 40 | * to which the bytes were set when the task was created have not been 41 | * overwritten. Note this second test does not guarantee that an overflowed 42 | * stack will always be recognised. 43 | */ 44 | 45 | /*-----------------------------------------------------------*/ 46 | 47 | #if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) ) 48 | 49 | /* Only the current stack state is to be checked. */ 50 | #define taskCHECK_FOR_STACK_OVERFLOW() \ 51 | { \ 52 | /* Is the currently saved stack pointer within the stack limit? */ \ 53 | if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \ 54 | { \ 55 | vApplicationStackOverflowHook( ( task_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ 56 | } \ 57 | } 58 | 59 | #endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */ 60 | /*-----------------------------------------------------------*/ 61 | 62 | #if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH > 0 ) ) 63 | 64 | /* Only the current stack state is to be checked. */ 65 | #define taskCHECK_FOR_STACK_OVERFLOW() \ 66 | { \ 67 | \ 68 | /* Is the currently saved stack pointer within the stack limit? */ \ 69 | if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack ) \ 70 | { \ 71 | vApplicationStackOverflowHook( ( task_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ 72 | } \ 73 | } 74 | 75 | #endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */ 76 | /*-----------------------------------------------------------*/ 77 | 78 | #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) ) 79 | 80 | #define taskCHECK_FOR_STACK_OVERFLOW() \ 81 | { \ 82 | const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \ 83 | const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \ 84 | \ 85 | if( ( pulStack[ 0 ] != ulCheckValue ) || \ 86 | ( pulStack[ 1 ] != ulCheckValue ) || \ 87 | ( pulStack[ 2 ] != ulCheckValue ) || \ 88 | ( pulStack[ 3 ] != ulCheckValue ) ) \ 89 | { \ 90 | vApplicationStackOverflowHook( ( task_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ 91 | } \ 92 | } 93 | 94 | #endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ 95 | /*-----------------------------------------------------------*/ 96 | 97 | #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) ) 98 | 99 | #define taskCHECK_FOR_STACK_OVERFLOW() \ 100 | { \ 101 | int8_t *pcEndOfStack = ( int8_t * ) pxCurrentTCB->pxEndOfStack; \ 102 | static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ 103 | tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ 104 | tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ 105 | tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ 106 | tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \ 107 | \ 108 | \ 109 | pcEndOfStack -= sizeof( ucExpectedStackBytes ); \ 110 | \ 111 | /* Has the extremity of the task stack ever been written over? */ \ 112 | if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \ 113 | { \ 114 | vApplicationStackOverflowHook( ( task_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ 115 | } \ 116 | } 117 | 118 | #endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ 119 | /*-----------------------------------------------------------*/ 120 | 121 | /* Remove stack overflow macro if not being used. */ 122 | #ifndef taskCHECK_FOR_STACK_OVERFLOW 123 | #define taskCHECK_FOR_STACK_OVERFLOW() 124 | #endif 125 | 126 | 127 | 128 | #endif /* STACK_MACROS_H */ 129 | 130 | -------------------------------------------------------------------------------- /include/rtos/tcb.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "rtos/FreeRTOS.h" 4 | #include "rtos/list.h" 5 | 6 | /* 7 | * Task control block. A task control block (TCB) is allocated for each task, 8 | * and stores task state information, including a pointer to the task's context 9 | * (the task's run time environment, including register values) 10 | */ 11 | typedef struct tskTaskControlBlock 12 | { 13 | volatile task_stack_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */ 14 | 15 | 16 | list_item_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ 17 | list_item_t xEventListItem; /*< Used to reference a task from an event list. */ 18 | uint32_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */ 19 | task_stack_t *pxStack; /*< Points to the start of the stack. */ 20 | char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ 21 | 22 | #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) ) 23 | task_stack_t *pxEndOfStack; /*< Points to the highest valid address for the stack. */ 24 | #endif 25 | 26 | #if ( portCRITICAL_NESTING_IN_TCB == 1 ) 27 | uint32_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */ 28 | #endif 29 | 30 | #if ( configUSE_TRACE_FACILITY == 1 ) 31 | uint32_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */ 32 | uint32_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */ 33 | #endif 34 | 35 | #if ( configUSE_MUTEXES == 1 ) 36 | uint32_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */ 37 | uint32_t uxMutexesHeld; 38 | #endif 39 | 40 | #if ( configUSE_APPLICATION_TASK_TAG == 1 ) 41 | TaskHookFunction_t pxTaskTag; 42 | #endif 43 | 44 | #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) 45 | void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; 46 | #endif 47 | 48 | #if( configGENERATE_RUN_TIME_STATS == 1 ) 49 | uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */ 50 | #endif 51 | 52 | #if ( configUSE_NEWLIB_REENTRANT == 1 ) 53 | /* Allocate a Newlib reent structure that is specific to this task. 54 | Note Newlib support has been included by popular demand, but is not 55 | used by the FreeRTOS maintainers themselves. FreeRTOS is not 56 | responsible for resulting newlib operation. User must be familiar with 57 | newlib and must provide system-wide implementations of the necessary 58 | stubs. Be warned that (at the time of writing) the current newlib design 59 | implements a system-wide malloc() that must be provided with locks. */ 60 | struct _reent xNewLib_reent; 61 | #endif 62 | 63 | #if( configUSE_TASK_NOTIFICATIONS == 1 ) 64 | volatile uint32_t ulNotifiedValue; 65 | volatile uint8_t ucNotifyState; 66 | #endif 67 | 68 | /* See the comments above the definition of 69 | tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */ 70 | #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */ 71 | uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */ 72 | #endif 73 | 74 | #if( INCLUDE_xTaskAbortDelay == 1 ) 75 | uint8_t ucDelayAborted; 76 | #endif 77 | 78 | } tskTCB; 79 | 80 | /* The old tskTCB name is maintained above then typedefed to the new TCB_t name 81 | below to enable the use of older kernel aware debuggers. */ 82 | typedef tskTCB TCB_t; 83 | 84 | /*lint -save -e956 A manual analysis and inspection has been used to determine 85 | which static variables must be declared volatile. */ 86 | 87 | extern TCB_t * volatile pxCurrentTCB; -------------------------------------------------------------------------------- /include/system/dev/banners.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file system/dev/banners.h 3 | * 4 | * PROS banners printed over serial line 5 | * 6 | * This file should only be included ONCE (in system/dev/serial_daemon.c) 7 | * 8 | * See system/dev/serial_daemon.c for discussion 9 | * 10 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 11 | * All rights reserved. 12 | * 13 | * This Source Code Form is subject to the terms of the Mozilla Public 14 | * License, v. 2.0. If a copy of the MPL was not distributed with this 15 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 16 | */ 17 | 18 | #pragma once 19 | // The banners look extra messed up due to the ANSI escape sequences and needing 20 | // to escape backslashes and quotes 21 | static char const* const short_banner = 22 | "\n\n\n" 23 | "  _____ _____ ____ _____ \n" 24 | " | __ \\| __ \\ / __ \\ / ____| Powered by " 25 | "PROS for VEX V5\n" 26 | " | |__) | |__) | | | | (___  Version: %29s\n" 27 | " | ___/| _ /| | | |\\___ \\  Uptime: %23lu.%03lu " 28 | "s\n" 29 | " | | | | \\ \\| |__| |____) | Compiled: %29s\n" 30 | " |_| |_| \\_\\\\____/|_____/  Directory:%29s\n" 31 | "\n\n"; 32 | 33 | static char const* const large_banner = 34 | "\n\n\n" 35 | " _+=+_\n" 36 | "  .-` . `-.  8888888b. 8888888b. .d88888b. " 37 | ".d8888b.\n" 38 | "  _+` \" `+_  888 Y88b 888 Y88b d88P\" " 39 | "\"Y88b d88P Y88b\n" 40 | " \\\\\\sssssssssssss/// 888 888 888 888 888 " 41 | "888 Y88b.\n" 42 | " .ss\\ * /ss. 888 d88P 888 d88P " 43 | "888 888 \"Y888b.\n" 44 | " .+bm .s * s. md+. " 45 | "8888888P\" 8888888P\" 888 888 " 46 | "\"Y88b.\n" 47 | ".hMMMMs . * . sMMMMh. 888 " 48 | " 888 T88b 888 888 " 49 | "\"888\n" 50 | " `\\hMMMb \\ | / dMMMh: " 51 | "888 888 T88b Y88b. .d88P Y88b " 52 | "d88P\n" 53 | " -SNMNo - oNMNs- 888 " 54 | "888 T88b \"Y88888P\" \"Y8888P\"\n" 55 | " `+dMh\\./dMd/\n" 56 | " `:yNy:` Powered by PROS " 57 | "for VEX V5\n" 58 | " \" Copyright (c) Purdue University " 59 | "ACM SIGBots\n" 60 | "Version:%13s Platform: V%d.%d.%d (b%d) " 61 | "Uptime:%5lu.%03lu s\n" 62 | "Compiled: %20s Directory: %22s\n" 63 | "\n\n"; 64 | -------------------------------------------------------------------------------- /include/system/dev/dev.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file system/dev/dev.h 3 | * 4 | * Generic Serial Device driver header 5 | * 6 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 7 | * All rights reserved. 8 | * 9 | * This Source Code Form is subject to the terms of the Mozilla Public 10 | * License, v. 2.0. If a copy of the MPL was not distributed with this 11 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "vfs.h" 17 | 18 | extern const struct fs_driver* const dev_driver; 19 | int dev_open_r(struct _reent* r, const char* path, int flags, int mode); 20 | void dev_initialize(void); 21 | -------------------------------------------------------------------------------- /include/system/dev/ser.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file system/dev/ser.h 3 | * 4 | * Serial driver header 5 | * 6 | * See system/dev/ser_driver.c and system/dev/ser_daemon.c for discussion 7 | * 8 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 9 | * All rights reserved. 10 | * 11 | * This Source Code Form is subject to the terms of the Mozilla Public 12 | * License, v. 2.0. If a copy of the MPL was not distributed with this 13 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 | */ 15 | 16 | #pragma once 17 | 18 | #include "vfs.h" 19 | 20 | extern const struct fs_driver* const ser_driver; 21 | int ser_open_r(struct _reent* r, const char* path, int flags, int mode); 22 | void ser_initialize(void); 23 | -------------------------------------------------------------------------------- /include/system/dev/usd.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file system/dev/usd.h 3 | * 4 | * microSD card driver header 5 | * 6 | * See system/dev/usd_driver.c for discussion 7 | * 8 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 9 | * All rights reserved. 10 | * 11 | * This Source Code Form is subject to the terms of the Mozilla Public 12 | * License, v. 2.0. If a copy of the MPL was not distributed with this 13 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 | */ 15 | 16 | #pragma once 17 | 18 | #include "vfs.h" 19 | 20 | extern const struct fs_driver* const usd_driver; 21 | int usd_open_r(struct _reent* r, const char* path, int flags, int mode); 22 | void usd_initialize(void); 23 | -------------------------------------------------------------------------------- /include/system/dev/vfs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file system/dev/vfs.h 3 | * 4 | * Virtual File System header 5 | * 6 | * See system/dev/vfs.c for discussion 7 | * 8 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 9 | * All rights reserved. 10 | * 11 | * This Source Code Form is subject to the terms of the Mozilla Public 12 | * License, v. 2.0. If a copy of the MPL was not distributed with this 13 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 | */ 15 | 16 | #pragma once 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | struct fs_driver { 24 | ssize_t (*read_r)(struct _reent*, void* const, uint8_t*, const size_t); 25 | int (*write_r)(struct _reent*, void* const, const uint8_t*, const size_t); 26 | int (*close_r)(struct _reent*, void* const); 27 | int (*fstat_r)(struct _reent*, void* const, struct stat*); 28 | int (*isatty_r)(struct _reent*, void* const); 29 | off_t (*lseek_r)(struct _reent*, void* const, off_t, int); 30 | int (*ctl)(void* const, const uint32_t, void* const); 31 | }; 32 | 33 | struct file_entry { 34 | struct fs_driver const* driver; 35 | void* arg; 36 | }; 37 | 38 | // adds an entry to the file table 39 | int vfs_add_entry_r(struct _reent* r, struct fs_driver const* const driver, void* arg); 40 | 41 | // update an entry to the file table. Returns -1 if there was an error. 42 | // If driver is NULL, then the driver isn't updated. If arg is (void*)-1, then 43 | // the arg isn't updated. 44 | int vfs_update_entry(int file, struct fs_driver const* const driver, void* arg); 45 | -------------------------------------------------------------------------------- /include/system/optimizers.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file system/optimizers.h 3 | * 4 | * Optimizers for the kernel 5 | * 6 | * Probably shouldn't use anything from this header 7 | * 8 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 9 | * All rights reserved. 10 | * 11 | * This Source Code Form is subject to the terms of the Mozilla Public 12 | * License, v. 2.0. If a copy of the MPL was not distributed with this 13 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 | */ 15 | 16 | #pragma once 17 | 18 | // See https://stackoverflow.com/q/109710 for discussion 19 | #define likely(cond) __builtin_expect(!!(cond), 1) 20 | #define unlikely(cond) __builtin_expect(!!(cond), 0) 21 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | # This is the main build script. 2 | # This is where we configure how ZestCode is built. 3 | # It's used in combination with scripts/v5.ini, which tells Meson (the build system) 4 | # what tools to use and what platform the program is built for. 5 | 6 | # project configuration 7 | project( 8 | 'zestcode', # project name (zestcode) 9 | ['c', 'cpp'], # written in both C and C++ (for now) 10 | version : '0.0.0', 11 | meson_version: '>= 1.2.0', # we use splitlines which was introduced in meson v1.2.0 12 | default_options: [ 13 | 'c_std=gnu2x', # latest c standard supported in gcc v13 14 | 'cpp_std=gnu++23', # latest c++ standard supported in gcc v13 15 | 'warning_level=3', # 0, 1, 2, 3, or everything. Higher means more warnings 16 | 'optimization=s', # minimize binary size to minimize upload times. We have a ton of performance overhead 17 | 'debug=true', # debug symbols are not included in the final .bin file, so they don't increase upload time at all 18 | 'force_fallback_for=v5, v5_header' 19 | ], 20 | ) 21 | 22 | # patches the .clangd file so the system includes work. 23 | # runs whenever meson is configured 24 | python = find_program('python3') 25 | patch_clangd = files('scripts' / 'patch_clangd.py') 26 | run_command(python, patch_clangd, meson.get_compiler('c'), check: true) 27 | 28 | # possible source file extensions 29 | file_exts = [ 30 | '*.s', # assembly 31 | '*.S', # assembly 32 | '*.c', # C 33 | '*.h', # C 34 | '*.cpp', # C++ 35 | '*.hpp' # C++ 36 | ] 37 | get_files = files('scripts' / 'get_files.py') 38 | # get all source files 39 | get_files_result = run_command(python, get_files, 'src', file_exts, check: true) 40 | source = get_files_result.stdout().strip().splitlines() 41 | 42 | # optimization flags passed to the compiler 43 | optimization_flags = [ 44 | '-ffunction-sections', # used in combination with --gc-sections to reduce binary size 45 | '-fdata-sections', # used in combination with --gc-sections to reduce binary size 46 | '-fno-strict-aliasing', # needed due to bad coding practices in the FreeRTOS source 47 | ] 48 | 49 | # formatting flags passed to the compiler and linker 50 | formatting_flags = [ 51 | '-fdiagnostics-color', # makes the compiler output easier to read, by using colors! 52 | ] 53 | add_global_arguments(formatting_flags, language: 'c') 54 | add_global_arguments(formatting_flags, language: 'cpp') 55 | add_global_link_arguments(formatting_flags, language: 'c') 56 | add_global_link_arguments(formatting_flags, language: 'cpp') 57 | 58 | # miscellaneous flags passed to the linker 59 | linker_flags = [ 60 | '-Wl,--gc-sections', # used in combination with -ffunction-sections and -fdata-sections to reduce binary size 61 | '-Wl,--no-warn-rwx-segments' # silences a warning that does not make a difference for our use case 62 | ] 63 | 64 | # system libraries we depend on 65 | system_deps = [ 66 | '-nostartfiles', # we still need to implement some newlib stubs 67 | '-lstdc++exp', 68 | ] 69 | add_global_link_arguments( system_deps, language: 'c') 70 | add_global_link_arguments(system_deps, language: 'cpp') 71 | 72 | # configuration of the standard library 73 | stdlib_conf = [ 74 | '-D_POSIX_MONOTONIC_CLOCK', # enable the POSIX monotonic clock 75 | ] 76 | 77 | # warning flags 78 | warning_flags = [ 79 | '-Wno-psabi' # all libraries (except libv5) are compiled from source, making this warning useless 80 | ] 81 | 82 | # apply all these flags and configs 83 | add_global_arguments(optimization_flags, formatting_flags, warning_flags, stdlib_conf, language: 'c') 84 | add_global_arguments(optimization_flags, formatting_flags, warning_flags, stdlib_conf, language: 'cpp') 85 | add_global_link_arguments(optimization_flags, linker_flags, formatting_flags, warning_flags, system_deps, language: 'c') 86 | add_global_link_arguments(optimization_flags, linker_flags, formatting_flags, warning_flags, system_deps, language: 'cpp') 87 | 88 | # include directories. 89 | # we only specify the top level in order to enforce paths in include directives. 90 | include = include_directories('./include') 91 | 92 | # this is what user projects will link against, so we use declare_dependency instead of static_library 93 | zestcode = static_library( 94 | 'zestcode', 95 | sources: source, 96 | include_directories: include, 97 | dependencies: dependency('v5_header'), 98 | ) 99 | 100 | # TODO: figure out a better way to do this in a future Tests PR 101 | elf = executable( 102 | 'program.elf', 103 | sources: './tests/examples/basic.cpp', 104 | include_directories: include, 105 | dependencies: [ 106 | dependency('v5'), 107 | ], 108 | link_whole: zestcode 109 | ) 110 | 111 | # meson won't create the binary file for uploading, so we have to do it ourselves 112 | objcopy = find_program('arm-none-eabi-objcopy') 113 | custom_target( 114 | 'program.bin', 115 | output: 'program.bin', 116 | input: elf, 117 | build_by_default: true, # otherwise it won't be built 118 | command: [objcopy, ['-O', 'binary', '-S', '@INPUT@', '@OUTPUT@']], 119 | ) -------------------------------------------------------------------------------- /scripts/.clangd: -------------------------------------------------------------------------------- 1 | CompileFlags: 2 | CompilationDatabase: build # this is where meson generates compile_commands.json 3 | Add: [ 4 | # system include paths will be inserted, making them the first 6 elements of the array 5 | ] 6 | Index: 7 | StandardLibrary: No # we use headers from arm-none-eabi. We can turn this off with no downside. 8 | Diagnostics: 9 | Suppress: 10 | - redefinition_different_typedef # TODO: remove if possible once FreeRTOS has been updated 11 | - language-extension-token # for asm calls in .c files -------------------------------------------------------------------------------- /scripts/get_files.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | Meson Build Source File Collector 5 | 6 | This script recursively searches a directory for source files matching specified extensions 7 | and outputs their absolute paths. Intended for integration with Meson build system, so 8 | you don't have to list every single one of your source files. 9 | """ 10 | 11 | import sys 12 | from pathlib import Path 13 | 14 | def main(): 15 | """ 16 | Main function handling command-line arguments and file discovery. 17 | 18 | Process flow: 19 | 1. Validate command-line arguments 20 | 2. Resolve source directory path 21 | 3. Recursively search for files matching patterns 22 | 4. Deduplicate and sort results 23 | 5. Output absolute file paths 24 | """ 25 | if len(sys.argv) < 3: 26 | print(f"Usage: {sys.argv[0]} ...", file=sys.stderr) 27 | sys.exit(1) 28 | 29 | # Resolve source directory to absolute path 30 | source_dir = Path(sys.argv[1]).resolve() 31 | 32 | # Extract file extension patterns from arguments (supports glob patterns like *.c) 33 | patterns = sys.argv[2:] 34 | 35 | # Verify source directory exists 36 | if not source_dir.is_dir(): 37 | print(f"Error: Source directory '{source_dir}' does not exist.", file=sys.stderr) 38 | sys.exit(1) 39 | 40 | # Use set to avoid duplicate entries from overlapping patterns 41 | files = set() 42 | 43 | # Process each file pattern 44 | for pattern in patterns: 45 | # Recursive glob search (rglob) through directory tree 46 | for path in source_dir.rglob(pattern): 47 | # Skip directories that might match pattern (e.g., 'some.dir' matching *.h) 48 | if path.is_file(): 49 | # Add resolved absolute path to ensure consistency 50 | files.add(path.resolve()) 51 | 52 | # Sort files for deterministic output order 53 | sorted_files = sorted(files) 54 | 55 | # Print results in format Meson can consume (one absolute path per line) 56 | for file_path in sorted_files: 57 | print(file_path) 58 | 59 | if __name__ == '__main__': 60 | # Entry point when executed directly 61 | main() -------------------------------------------------------------------------------- /scripts/patch_clangd.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Generates a .clangd file from the template .clangd found in the scripts folder, and places it in the project root. 4 | # Necessary to automatically determine and tell clangd where to find system includes. 5 | 6 | import sys 7 | import os 8 | import subprocess 9 | import re 10 | import shutil 11 | 12 | def main(): 13 | if len(sys.argv) != 2: 14 | print(f"Usage: python3 {sys.argv[0]} ") 15 | sys.exit(1) 16 | 17 | gcc_executable = sys.argv[1] 18 | 19 | # Obtain sysroot by calling `arm-none-eabi-gcc --print-sysroot` 20 | try: 21 | output = subprocess.check_output([gcc_executable, "--print-sysroot"], universal_newlines=True) 22 | sysroot = output.strip() 23 | except Exception as e: 24 | print(f"Error: Unable to run '{gcc_executable} --print-sysroot': {e}") 25 | sys.exit(1) 26 | 27 | # The base directory is the parent of the sysroot. 28 | base_dir = os.path.dirname(sysroot) 29 | 30 | # Automatically detect the gcc version folder inside lib/gcc/arm-none-eabi. 31 | gcc_dir = os.path.join(base_dir, "lib", "gcc", "arm-none-eabi") 32 | if not os.path.isdir(gcc_dir): 33 | print(f"Error: {gcc_dir} is not a valid directory") 34 | sys.exit(1) 35 | 36 | # List all subdirectories in gcc_dir. 37 | subdirs = [d for d in os.listdir(gcc_dir) if os.path.isdir(os.path.join(gcc_dir, d))] 38 | if not subdirs: 39 | print(f"Error: No directories found in {gcc_dir}") 40 | sys.exit(1) 41 | 42 | # Choose the directory with the highest semantic version. 43 | try: 44 | gcc_version = max(subdirs, key=lambda v: tuple(map(int, v.split(".")))) 45 | except Exception as e: 46 | print(f"Error: Could not determine highest semantic version in {gcc_dir}: {e}") 47 | sys.exit(1) 48 | 49 | # Construct the six include strings. 50 | outputs = [ 51 | f"-isystem{base_dir}/lib/gcc/arm-none-eabi/{gcc_version}/../../../../arm-none-eabi/include/c++/{gcc_version}", 52 | f"-isystem{base_dir}/lib/gcc/arm-none-eabi/{gcc_version}/../../../../arm-none-eabi/include/c++/{gcc_version}/arm-none-eabi/thumb/v7-a+simd/hard", 53 | f"-isystem{base_dir}/lib/gcc/arm-none-eabi/{gcc_version}/../../../../arm-none-eabi/include/c++/{gcc_version}/backward", 54 | f"-isystem{base_dir}/lib/gcc/arm-none-eabi/{gcc_version}/include", 55 | f"-isystem{base_dir}/lib/gcc/arm-none-eabi/{gcc_version}/include-fixed", 56 | f"-isystem{base_dir}/lib/gcc/arm-none-eabi/{gcc_version}/../../../../arm-none-eabi/include" 57 | ] 58 | # Normalize paths to use forward slashes. 59 | outputs = [s.replace(os.sep, '/') for s in outputs] 60 | 61 | # Determine the script's directory and its parent. 62 | script_dir = os.path.dirname(os.path.abspath(__file__)) 63 | parent_dir = os.path.dirname(script_dir) 64 | 65 | # Source .clangd file in the same directory as the script. 66 | source_clangd_path = os.path.join(script_dir, ".clangd") 67 | if not os.path.isfile(source_clangd_path): 68 | print(f"Error: {source_clangd_path} does not exist.") 69 | sys.exit(1) 70 | 71 | # Destination .clangd file in the parent directory. 72 | dest_clangd_path = os.path.join(parent_dir, ".clangd") 73 | try: 74 | shutil.copy2(source_clangd_path, dest_clangd_path) 75 | print(f"Copied {source_clangd_path} to {dest_clangd_path}") 76 | except Exception as e: 77 | print(f"Error copying .clangd: {e}") 78 | sys.exit(1) 79 | 80 | # Read the content of the copied .clangd file. 81 | with open(dest_clangd_path, 'r') as f: 82 | content = f.read() 83 | 84 | # Locate the "Add" section using regex. 85 | # This pattern captures the block starting with "Add:" and an opening bracket, 86 | # then captures its contents until the closing bracket. 87 | pattern = r"(Add:\s*\[\s*\n)(.*?)(\n\s*\])" 88 | match = re.search(pattern, content, flags=re.DOTALL) 89 | if not match: 90 | print("Error: Failed to find the 'Add' section in the .clangd file.") 91 | sys.exit(1) 92 | 93 | prefix = match.group(1) # e.g., "Add: [\n" with indentation 94 | block_content = match.group(2) 95 | suffix = match.group(3) # e.g., "\n ]" (closing bracket with indentation) 96 | 97 | # Split the block into lines. 98 | lines = block_content.splitlines() 99 | 100 | # Determine the indentation from the first non-empty line, or default to 4 spaces. 101 | indent = " " 102 | for line in lines: 103 | stripped = line.lstrip() 104 | if stripped: 105 | indent = line[:len(line)-len(stripped)] 106 | break 107 | 108 | # Build new lines for the computed strings. 109 | new_inserts = [f'{indent}"{item}",' for item in outputs] 110 | 111 | # Insert the new lines at the beginning of the existing block. 112 | new_block_lines = new_inserts + lines 113 | new_block = prefix + "\n".join(new_block_lines) + suffix 114 | 115 | # Replace the original Add block with the new block. 116 | new_content = "# If you want to edit this file, edit scripts/.clangd and reconfigure meson\n" + content[:match.start()] + new_block + content[match.end():] 117 | 118 | # Write the updated content back to the destination .clangd file. 119 | with open(dest_clangd_path, 'w') as f: 120 | f.write(new_content) 121 | 122 | print(f"Successfully updated {dest_clangd_path}.") 123 | 124 | if __name__ == "__main__": 125 | main() 126 | -------------------------------------------------------------------------------- /scripts/v5.ini: -------------------------------------------------------------------------------- 1 | # Cross-compile configuration for the VEX V5. 2 | # Essentially, it tells meson what tools to use and what flags 3 | # to use so it can compile code that can run on the V5 4 | 5 | # compiler flags 6 | [constants] 7 | arch_flags = ['-mcpu=cortex-a9', '-mfpu=neon-fp16', '-mfloat-abi=hard'] # the fastest arch flags possible for the A9 in the v5 8 | linkerscript = ['-T../scripts/v5.ld'] 9 | 10 | # build options 11 | [built-in options] 12 | default_library = 'static' # the v5 does not support shared objects 13 | prefer_static = 'true' 14 | c_args = arch_flags 15 | cpp_args = arch_flags 16 | c_link_args = arch_flags + linkerscript 17 | cpp_link_args = arch_flags + linkerscript 18 | 19 | # what executables to use to compile ZestCode 20 | [binaries] 21 | c = 'arm-none-eabi-gcc' 22 | cpp = 'arm-none-eabi-g++' 23 | ar = 'arm-none-eabi-ar' 24 | objcopy = 'arm-none-eabi-objcopy' 25 | objdump = 'arm-none-eabi-objdump' 26 | strip = 'arm-none-eabi-strip' 27 | size = 'arm-none-eabi-size' 28 | 29 | # specs of the v5 brain 30 | [host_machine] 31 | system = 'none' 32 | kernel = 'none' 33 | cpu_family = 'arm' 34 | cpu = 'cortex-a9' 35 | endian = 'little' -------------------------------------------------------------------------------- /scripts/v5.ld: -------------------------------------------------------------------------------- 1 | /* Linkerscript for the VEX V5. 2 | * This script tells the compiler how to structure the program binary, 3 | * and where it should be stored in RAM. 4 | */ 5 | 6 | /* This stack is used during initialization, but FreeRTOS tasks have their own 7 | stack allocated in BSS or Heap (kernel tasks in FreeRTOS .bss heap; user tasks 8 | in standard heap) */ 9 | _STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000; 10 | 11 | _ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024; 12 | _SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048; 13 | _IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024; 14 | _FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024; 15 | _UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024; 16 | 17 | _HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x02E00000; /* ~48 MB */ 18 | 19 | /* Define Memories in the system */ 20 | start_of_cold_mem = 0x03800000; 21 | _COLD_MEM_SIZE = 0x04800000; 22 | end_of_cold_mem = start_of_cold_mem + _COLD_MEM_SIZE; 23 | 24 | start_of_hot_mem = 0x07800000; 25 | _HOT_MEM_SIZE = 0x00800000; 26 | end_of_hot_mem = start_of_hot_mem + _HOT_MEM_SIZE; 27 | 28 | MEMORY 29 | { 30 | /* user code 72M */ 31 | COLD_MEMORY : ORIGIN = start_of_cold_mem, LENGTH = _COLD_MEM_SIZE /* Just under 19 MB */ 32 | HEAP : ORIGIN = 0x04A00000, LENGTH = _HEAP_SIZE 33 | HOT_MEMORY : ORIGIN = start_of_hot_mem, LENGTH = _HOT_MEM_SIZE /* Just over 8 MB */ 34 | } 35 | 36 | /* used in _sbrk implementation */ 37 | _HEAP_START = ORIGIN(HEAP); 38 | _HEAP_END = ORIGIN(HEAP) + LENGTH(HEAP); 39 | 40 | REGION_ALIAS("RAM", COLD_MEMORY); 41 | 42 | ENTRY(_start) 43 | 44 | /* Define the sections, and where they are mapped in memory */ 45 | SECTIONS 46 | { 47 | .text : { 48 | KEEP (*(.vectors)) 49 | /* boot data should be exactly 32 bytes long */ 50 | *(.boot_data) 51 | . = 0x20; 52 | *(.boot) 53 | . = ALIGN(64); 54 | *(.freertos_vectors) 55 | *(.text) 56 | *(.text.*) 57 | *(.gnu.linkonce.t.*) 58 | *(.plt) 59 | *(.gnu_warning) 60 | *(.gcc_except_table) 61 | *(.glue_7) 62 | *(.glue_7t) 63 | *(.vfp11_veneer) 64 | *(.ARM.extab) 65 | *(.gnu.linkonce.armextab.*) 66 | } > RAM 67 | 68 | .init : { 69 | KEEP (*(.init)) 70 | } > RAM 71 | 72 | .fini : { 73 | KEEP (*(.fini)) 74 | } > RAM 75 | 76 | .rodata : { 77 | __rodata_start = .; 78 | *(.rodata) 79 | *(.rodata.*) 80 | *(.gnu.linkonce.r.*) 81 | __rodata_end = .; 82 | } > RAM 83 | 84 | .rodata1 : { 85 | __rodata1_start = .; 86 | *(.rodata1) 87 | *(.rodata1.*) 88 | __rodata1_end = .; 89 | } > RAM 90 | 91 | .sdata2 : { 92 | __sdata2_start = .; 93 | *(.sdata2) 94 | *(.sdata2.*) 95 | *(.gnu.linkonce.s2.*) 96 | __sdata2_end = .; 97 | } > RAM 98 | 99 | .sbss2 : { 100 | __sbss2_start = .; 101 | *(.sbss2) 102 | *(.sbss2.*) 103 | *(.gnu.linkonce.sb2.*) 104 | __sbss2_end = .; 105 | } > RAM 106 | 107 | .data : { 108 | __data_start = .; 109 | *(.data) 110 | *(.data.*) 111 | *(.gnu.linkonce.d.*) 112 | *(.jcr) 113 | *(.got) 114 | *(.got.plt) 115 | __data_end = .; 116 | } > RAM 117 | 118 | .data1 : { 119 | __data1_start = .; 120 | *(.data1) 121 | *(.data1.*) 122 | __data1_end = .; 123 | } > RAM 124 | 125 | .got : { 126 | *(.got) 127 | } > RAM 128 | 129 | .ctors : { 130 | __CTOR_LIST__ = .; 131 | ___CTORS_LIST___ = .; 132 | KEEP (*crtbegin.o(.ctors)) 133 | KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors)) 134 | KEEP (*(SORT(.ctors.*))) 135 | KEEP (*(.ctors)) 136 | __CTOR_END__ = .; 137 | ___CTORS_END___ = .; 138 | } > RAM 139 | 140 | .dtors : { 141 | __DTOR_LIST__ = .; 142 | ___DTORS_LIST___ = .; 143 | KEEP (*crtbegin.o(.dtors)) 144 | KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors)) 145 | KEEP (*(SORT(.dtors.*))) 146 | KEEP (*(.dtors)) 147 | __DTOR_END__ = .; 148 | ___DTORS_END___ = .; 149 | } > RAM 150 | 151 | .fixup : { 152 | __fixup_start = .; 153 | *(.fixup) 154 | __fixup_end = .; 155 | } > RAM 156 | 157 | .eh_frame : { 158 | *(.eh_frame) 159 | } > RAM 160 | 161 | .eh_framehdr : { 162 | __eh_framehdr_start = .; 163 | *(.eh_framehdr) 164 | __eh_framehdr_end = .; 165 | } > RAM 166 | 167 | .gcc_except_table : { 168 | *(.gcc_except_table) 169 | } > RAM 170 | 171 | .mmu_tbl (ALIGN(16384)) : { 172 | __mmu_tbl_start = .; 173 | *(.mmu_tbl) 174 | __mmu_tbl_end = .; 175 | } > RAM 176 | 177 | .ARM.exidx : { 178 | __exidx_start = .; 179 | *(.ARM.exidx*) 180 | *(.gnu.linkonce.armexidix.*.*) 181 | __exidx_end = .; 182 | } > RAM 183 | 184 | .preinit_array : { 185 | __preinit_array_start = .; 186 | KEEP (*(SORT(.preinit_array.*))) 187 | KEEP (*(.preinit_array)) 188 | __preinit_array_end = .; 189 | } > RAM 190 | 191 | .init_array : { 192 | __init_array_start = .; 193 | KEEP (*(SORT(.init_array.*))) 194 | KEEP (*(.init_array)) 195 | __init_array_end = .; 196 | } > RAM 197 | 198 | .fini_array : { 199 | __fini_array_start = .; 200 | KEEP (*(SORT(.fini_array.*))) 201 | KEEP (*(.fini_array)) 202 | __fini_array_end = .; 203 | } > RAM 204 | 205 | .ARM.attributes : { 206 | __ARM.attributes_start = .; 207 | *(.ARM.attributes) 208 | __ARM.attributes_end = .; 209 | } > RAM 210 | 211 | .sdata : { 212 | __sdata_start = .; 213 | *(.sdata) 214 | *(.sdata.*) 215 | *(.gnu.linkonce.s.*) 216 | __sdata_end = .; 217 | } > RAM 218 | 219 | .sbss (NOLOAD) : { 220 | __sbss_start = .; 221 | *(.sbss) 222 | *(.sbss.*) 223 | *(.gnu.linkonce.sb.*) 224 | __sbss_end = .; 225 | } > RAM 226 | 227 | .tdata : { 228 | __tdata_start = .; 229 | *(.tdata) 230 | *(.tdata.*) 231 | *(.gnu.linkonce.td.*) 232 | __tdata_end = .; 233 | } > RAM 234 | 235 | .tbss : { 236 | __tbss_start = .; 237 | *(.tbss) 238 | *(.tbss.*) 239 | *(.gnu.linkonce.tb.*) 240 | __tbss_end = .; 241 | } > RAM 242 | 243 | .bss (NOLOAD) : { 244 | __bss_start = .; 245 | *(.bss) 246 | *(.bss.*) 247 | *(.gnu.linkonce.b.*) 248 | *(COMMON) 249 | __bss_end = .; 250 | } > RAM 251 | 252 | _SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 ); 253 | 254 | _SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 ); 255 | 256 | /* Generate Stack and Heap definitions */ 257 | 258 | .heap (NOLOAD) : { 259 | . = ALIGN(16); 260 | _heap = .; 261 | HeapBase = .; 262 | _heap_start = .; 263 | . += _HEAP_SIZE; 264 | _heap_end = .; 265 | HeapLimit = .; 266 | } > HEAP 267 | 268 | .stack (NOLOAD) : { 269 | . = ALIGN(16); 270 | _stack_end = .; 271 | . += _STACK_SIZE; 272 | . = ALIGN(16); 273 | _stack = .; 274 | __stack = _stack; 275 | . = ALIGN(16); 276 | _irq_stack_end = .; 277 | . += _IRQ_STACK_SIZE; 278 | . = ALIGN(16); 279 | __irq_stack = .; 280 | _supervisor_stack_end = .; 281 | . += _SUPERVISOR_STACK_SIZE; 282 | . = ALIGN(16); 283 | __supervisor_stack = .; 284 | _abort_stack_end = .; 285 | . += _ABORT_STACK_SIZE; 286 | . = ALIGN(16); 287 | __abort_stack = .; 288 | _fiq_stack_end = .; 289 | . += _FIQ_STACK_SIZE; 290 | . = ALIGN(16); 291 | __fiq_stack = .; 292 | _undef_stack_end = .; 293 | . += _UNDEF_STACK_SIZE; 294 | . = ALIGN(16); 295 | __undef_stack = .; 296 | } > COLD_MEMORY 297 | 298 | _end = .; 299 | } 300 | -------------------------------------------------------------------------------- /src/common/README.md: -------------------------------------------------------------------------------- 1 | # Common Facilities 2 | 3 | This folder contains common facilities used throughout the PROS 3 kernel, such 4 | as JSON parsing. 5 | -------------------------------------------------------------------------------- /src/common/cobs.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file common/cobs.c 3 | * 4 | * Consistent Overhead Byte Stuffing 5 | * 6 | * Contains an implementation of Consistent Overhead Byte Stuffing, adapted from 7 | * https://github.com/jacquesf/COBS-Consistent-Overhead-Byte-Stuffing 8 | * 9 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 10 | * All rights reserved. 11 | * 12 | * This Source Code Form is subject to the terms of the Mozilla Public 13 | * License, v. 2.0. If a copy of the MPL was not distributed with this 14 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 15 | */ 16 | 17 | #include 18 | 19 | #include "common/cobs.h" 20 | 21 | size_t cobs_encode_measure(const uint8_t* restrict src, const size_t src_len, const uint32_t prefix) { 22 | size_t read_idx = 0; 23 | size_t write_idx = 1; 24 | uint8_t code = 1; 25 | 26 | uint8_t* prefix_bytes = (uint8_t*)&(prefix); 27 | for (read_idx = 0; read_idx < 4; read_idx++) { 28 | if (prefix_bytes[read_idx] == 0) { 29 | code = 1; 30 | write_idx++; 31 | } else { 32 | write_idx++; 33 | code++; 34 | // code will never be 0xff since the length will always be 4 35 | } 36 | } 37 | read_idx = 0; 38 | 39 | while (read_idx < src_len) { 40 | if (src[read_idx] == 0) { 41 | code = 1; 42 | write_idx++; 43 | read_idx++; 44 | } else { 45 | write_idx++; 46 | read_idx++; 47 | code++; 48 | if (code == 0xff) { 49 | code = 1; 50 | write_idx++; 51 | } 52 | } 53 | } 54 | 55 | return write_idx; 56 | } 57 | 58 | int cobs_encode(uint8_t* restrict dest, const uint8_t* restrict src, const size_t src_len, const uint32_t prefix) { 59 | size_t read_idx = 0; 60 | size_t write_idx = 1; 61 | size_t code_idx = 0; 62 | uint8_t code = 1; 63 | 64 | uint8_t* prefix_bytes = (uint8_t*)&prefix; 65 | for (read_idx = 0; read_idx < 4;) { 66 | if (prefix_bytes[read_idx] == 0) { 67 | dest[code_idx] = code; 68 | code = 1; 69 | code_idx = write_idx++; 70 | read_idx++; 71 | } else { 72 | dest[write_idx++] = prefix_bytes[read_idx++]; 73 | code++; 74 | // code will never be 0xff since the length of the prefix is 4 75 | } 76 | } 77 | read_idx = 0; 78 | 79 | while (read_idx < src_len) { 80 | if (src[read_idx] == 0) { 81 | dest[code_idx] = code; 82 | code = 1; 83 | code_idx = write_idx++; 84 | read_idx++; 85 | } else { 86 | dest[write_idx++] = src[read_idx++]; 87 | code++; 88 | if (code == 0xff) { 89 | dest[code_idx] = code; 90 | code = 1; 91 | code_idx = write_idx++; 92 | } 93 | } 94 | } 95 | 96 | dest[code_idx] = code; 97 | 98 | return write_idx; 99 | } 100 | -------------------------------------------------------------------------------- /src/common/gid.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file gid.c 3 | * 4 | * Globally Unique Identifiers Map 5 | * 6 | * Contains an implementation to efficiently assign globally unique IDs 7 | * e.g. to assign entries in a global table 8 | * 9 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 10 | * All rights reserved. 11 | * 12 | * This Source Code Form is subject to the terms of the Mozilla Public 13 | * License, v. 2.0. If a copy of the MPL was not distributed with this 14 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 15 | */ 16 | 17 | #include "common/gid.h" 18 | 19 | #include 20 | #include 21 | 22 | 23 | // Note: the V5 is a 32-bit architecture, so we'll use 32-bit integers 24 | 25 | void gid_init(struct gid_metadata* const metadata) { 26 | // metadata arguments aren't checked for correctness since this is an 27 | // internal data structure 28 | size_t i; 29 | for (i = 0; i < metadata->bitmap_size; i++) { 30 | metadata->bitmap[i] = ~0; 31 | } 32 | 33 | metadata->bitmap[0] = (~0 << (metadata->reserved)); 34 | 35 | metadata->_lock = mutex_create(); 36 | return; 37 | } 38 | 39 | uint32_t gid_alloc(struct gid_metadata* const metadata) { 40 | if (mutex_take(metadata->_lock, TIMEOUT_MAX)) { 41 | size_t i; 42 | uint32_t gid = 0; 43 | uint32_t* gid_word = NULL; 44 | uint32_t gid_idx = 0; 45 | // check if the _cur_val + 1 is free 46 | if (!gid_check(metadata, (metadata->_cur_val + 1) % metadata->max)) { 47 | // that gid was free! so allocate it 48 | gid = metadata->_cur_val = (metadata->_cur_val + 1) % metadata->max; 49 | gid_word = metadata->bitmap + (gid / UINT32_WIDTH); 50 | gid_idx = gid % UINT32_WIDTH; 51 | goto return_gid; 52 | } else { 53 | for (i = 0; i < metadata->bitmap_size; i++) { 54 | gid_word = metadata->bitmap + i; 55 | if (*gid_word == 0) { // all GIDs in this word are assigned 56 | continue; 57 | } 58 | // __builtin_ctz counts trailing zeros. This effectively returns the 59 | // position of the first unassigned gid withing the word 60 | gid_idx = __builtin_ctz(*gid_word); 61 | gid = gid_idx + (i * UINT32_WIDTH); 62 | // mark the id as allocated 63 | goto return_gid; 64 | } 65 | } 66 | return_gid: 67 | if (gid > metadata->max || gid == 0) { 68 | mutex_give(metadata->_lock); 69 | return 0; 70 | } 71 | *gid_word &= ~(1 << gid_idx); 72 | metadata->_cur_val = gid; 73 | mutex_give(metadata->_lock); 74 | return gid; 75 | } 76 | return 0; 77 | } 78 | 79 | void gid_free(struct gid_metadata* const metadata, uint32_t id) { 80 | if (id > metadata->max || id == 0) { 81 | return; 82 | } 83 | 84 | size_t word_idx = id / UINT32_WIDTH; 85 | metadata->bitmap[word_idx] |= 1 << (id % UINT32_WIDTH); 86 | } 87 | 88 | bool gid_check(struct gid_metadata* metadata, uint32_t id) { 89 | if (id > metadata->max) { 90 | return false; 91 | } 92 | 93 | size_t word_idx = id / UINT32_WIDTH; 94 | return (metadata->bitmap[word_idx] & (1 << (id % UINT32_WIDTH))) ? false : true; 95 | } 96 | -------------------------------------------------------------------------------- /src/common/linkedlist.c: -------------------------------------------------------------------------------- 1 | /* 2 | * \file common/linkedlist.c 3 | * 4 | * Linked list implementation for internal use 5 | * 6 | * This file defines a linked list implementation that operates on the FreeRTOS 7 | * heap, and is able to generically store function pointers and data 8 | * 9 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 10 | * 11 | * This Source Code Form is subject to the terms of the Mozilla Public 12 | * License, v. 2.0. If a copy of the MPL was not distributed with this 13 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 | */ 15 | 16 | #include "common/linkedlist.h" 17 | 18 | #include "kapi.h" // IWYU pragma: keep 19 | 20 | #include // NULL 21 | 22 | // NOTE: Do not intermix data and function payloads. This may cause data to be 23 | // re-evaluated as a pointer to an area in memory and a false free or add. 24 | 25 | ll_node_s_t* linked_list_init_func_node(generic_fn_t func) { 26 | ll_node_s_t* node = (ll_node_s_t*)kmalloc(sizeof *node); 27 | node->payload.func = func; 28 | node->next = NULL; 29 | 30 | return node; 31 | } 32 | 33 | ll_node_s_t* linked_list_init_data_node(void* data) { 34 | ll_node_s_t* node = (ll_node_s_t*)kmalloc(sizeof *node); 35 | node->payload.data = data; 36 | node->next = NULL; 37 | 38 | return node; 39 | } 40 | 41 | linked_list_s_t* linked_list_init() { 42 | linked_list_s_t* list = (linked_list_s_t*)kmalloc(sizeof *list); 43 | list->head = NULL; 44 | 45 | return list; 46 | } 47 | 48 | void linked_list_prepend_func(linked_list_s_t* list, generic_fn_t func) { 49 | if (list == NULL) 50 | list = linked_list_init(); 51 | 52 | ll_node_s_t* n = linked_list_init_func_node(func); 53 | 54 | n->next = list->head; 55 | list->head = n; 56 | } 57 | 58 | void linked_list_prepend_data(linked_list_s_t* list, void* data) { 59 | if (list == NULL) 60 | list = linked_list_init(); 61 | 62 | ll_node_s_t* n = linked_list_init_data_node(data); 63 | 64 | n->next = list->head; 65 | list->head = n; 66 | } 67 | 68 | void linked_list_append_func(linked_list_s_t* list, generic_fn_t func) { 69 | if (list == NULL) 70 | list = linked_list_init(); 71 | 72 | ll_node_s_t* n = linked_list_init_func_node(func); 73 | 74 | if (list->head == NULL) { 75 | list->head = n; 76 | return; 77 | } 78 | 79 | ll_node_s_t* it = list->head; 80 | while (it->next != NULL) 81 | it = it->next; 82 | 83 | it->next = n; 84 | } 85 | 86 | void linked_list_remove_func(linked_list_s_t* list, generic_fn_t func) { 87 | if (list == NULL || list->head == NULL) 88 | return; 89 | 90 | ll_node_s_t* it = list->head; 91 | ll_node_s_t* p = NULL; 92 | while (it != NULL) { 93 | if (it->payload.func == func) { 94 | if (p == NULL) 95 | list->head = it->next; 96 | else 97 | p->next = it->next; 98 | kfree(it); 99 | break; 100 | } 101 | 102 | p = it; 103 | it = it->next; 104 | } 105 | } 106 | 107 | void linked_list_append_data(linked_list_s_t* list, void* data) { 108 | if (list == NULL) 109 | list = linked_list_init(); 110 | 111 | ll_node_s_t* n = linked_list_init_data_node(data); 112 | 113 | if (list->head == NULL) { 114 | list->head = n; 115 | return; 116 | } 117 | 118 | ll_node_s_t* it = list->head; 119 | while (it->next != NULL) 120 | it = it->next; 121 | 122 | it->next = n; 123 | } 124 | 125 | void linked_list_remove_data(linked_list_s_t* list, void* data) { 126 | if (list == NULL || list->head == NULL) 127 | return; 128 | 129 | ll_node_s_t* it = list->head; 130 | ll_node_s_t* p = NULL; 131 | while (it != NULL) { 132 | if (it->payload.data == data) { 133 | if (p == NULL) 134 | list->head = it->next; 135 | else 136 | p->next = it->next; 137 | kfree(it); 138 | break; 139 | } 140 | 141 | p = it; 142 | it = it->next; 143 | } 144 | } 145 | 146 | void linked_list_foreach(linked_list_s_t* list, linked_list_foreach_fn_t cb, void* extra_data) { 147 | if (list == NULL || list->head == NULL) 148 | return; 149 | 150 | ll_node_s_t* it = list->head; 151 | while (it != NULL) { 152 | cb(it, extra_data); 153 | it = it->next; 154 | } 155 | } 156 | 157 | void linked_list_free(linked_list_s_t* list) { 158 | if (list == NULL || list->head == NULL) 159 | return; 160 | 161 | while (list->head != NULL) { 162 | ll_node_s_t* node = list->head; 163 | list->head = node->next; 164 | kfree(node); 165 | } 166 | kfree(list); 167 | } 168 | -------------------------------------------------------------------------------- /src/common/set.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file common/set.c 3 | * 4 | * Contains an implementation of a thread-safe basic set in the kernel heap. 5 | * It's used to check which streams are enabled in ser_driver for the moment, 6 | * but also has list_contains which may be useful in other contexts. 7 | * 8 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 9 | * All rights reserved. 10 | * 11 | * This Source Code Form is subject to the terms of the Mozilla Public 12 | * License, v. 2.0. If a copy of the MPL was not distributed with this 13 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 | */ 15 | 16 | #include 17 | 18 | #include "common/set.h" 19 | #include "kapi.h" 20 | #include "system/optimizers.h" 21 | 22 | void set_initialize(struct set* const set) { 23 | set->arr = kmalloc(8 * sizeof(*(set->arr))); 24 | set->used = 0; 25 | set->size = 8; 26 | set->mtx = mutex_create_static(&(set->mtx_buf)); 27 | } 28 | 29 | bool set_add(struct set* const set, uint32_t item) { 30 | size_t i = 0; 31 | if (!mutex_take(set->mtx, TIMEOUT_MAX)) { 32 | return false; 33 | } 34 | for (i = 0; i < set->used; i++) { 35 | if (set->arr[i] == item) { 36 | mutex_give(set->mtx); 37 | return true; 38 | } 39 | } 40 | if (set->used == set->size) { 41 | uint32_t* temp = set->arr; 42 | set->arr = kmalloc((set->size + 8) * sizeof(*(set->arr))); 43 | if (unlikely(set->arr == NULL)) { 44 | set->arr = temp; 45 | mutex_give(set->mtx); 46 | return false; 47 | } 48 | memcpy(set->arr, temp, set->size * sizeof(*(set->arr))); 49 | set->size += 8; 50 | } 51 | set->arr[set->used] = item; 52 | set->used++; 53 | mutex_give(set->mtx); 54 | return true; 55 | } 56 | 57 | bool set_rm(struct set* set, uint32_t item) { 58 | size_t i = 0; 59 | if (!mutex_take(set->mtx, TIMEOUT_MAX)) { 60 | return false; 61 | } 62 | for (i = 0; i < set->used - 1; i++) { 63 | if (set->arr[i] == item) { 64 | memcpy(set->arr + i, set->arr + i + 1, set->used - i - 1); 65 | set->used--; 66 | mutex_give(set->mtx); 67 | return true; 68 | } 69 | } 70 | if (set->arr[set->used] == item) { 71 | // this is the last item, no need to do memcpy, just decrement the counter 72 | set->used--; 73 | } 74 | mutex_give(set->mtx); 75 | return true; 76 | } 77 | 78 | bool set_contains(struct set* set, uint32_t item) { 79 | if (!mutex_take(set->mtx, TIMEOUT_MAX)) { 80 | return false; 81 | } 82 | bool ret = list_contains(set->arr, set->used, item); 83 | mutex_give(set->mtx); 84 | return ret; 85 | } 86 | 87 | bool list_contains(uint32_t const* list, const size_t size, const uint32_t item) { 88 | uint32_t const* const end = list + size; 89 | while (list <= end) { 90 | if (*list == item) { 91 | return true; 92 | } 93 | list++; 94 | } 95 | return false; 96 | } 97 | -------------------------------------------------------------------------------- /src/common/string2.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file common/string.c 3 | * 4 | * Contains extra string functions useful for PROS and kstrdup/kstrndup which 5 | * use the kernel heap instead of the user heap 6 | * 7 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 8 | * All rights reserved. 9 | * 10 | * This Source Code Form is subject to the terms of the Mozilla Public 11 | * License, v. 2.0. If a copy of the MPL was not distributed with this 12 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 13 | */ 14 | 15 | #include "kapi.h" 16 | 17 | #include 18 | 19 | char* kstrndup(const char* s, size_t n) { 20 | size_t copy_len = strnlen(s, n); // strlen max'd out at n 21 | char* dupstr = kmalloc(n + 1); 22 | if (!dupstr) { 23 | return NULL; 24 | } 25 | memset(dupstr, 0, n + 1); 26 | memcpy(dupstr, s, copy_len); 27 | return dupstr; 28 | } 29 | 30 | char* kstrdup(const char* s) { 31 | return kstrndup(s, strlen(s)); 32 | } 33 | 34 | void kprint_hex(uint8_t* s, size_t len) { 35 | for (size_t i = 0; i < len; i++) { 36 | if (i % 16 == 0) { 37 | printf("\n%u:\t", i); 38 | } 39 | printf("0x%02x ", s[i]); 40 | } 41 | printf("\n"); 42 | } 43 | -------------------------------------------------------------------------------- /src/competition.cpp: -------------------------------------------------------------------------------- 1 | #include "pros/competition.hpp" 2 | 3 | #include "pros/rtos.h" 4 | #include "pros/rtos.hpp" 5 | #include "v5_api_patched.h" 6 | 7 | #include 8 | 9 | namespace zest::competition { 10 | 11 | // bitmask constants 12 | constexpr uint32_t DISABLED_MASK = 1U << 0; 13 | constexpr uint32_t AUTONOMOUS_MASK = 1U << 1; 14 | constexpr uint32_t CONNECTED_MASK = 1U << 2; 15 | constexpr uint32_t SYSTEM_MASK = 1U << 3; 16 | 17 | // competition task 18 | static std::optional competition_task; 19 | 20 | // callbacks 21 | static std::optional> autonomous_func; 22 | static std::optional> driver_control_func; 23 | static std::optional> disabled_func; 24 | 25 | /** 26 | * @brief kill the current competition task, and spawn a new one that calls the given function 27 | * 28 | * @param f the new function that should be run 29 | */ 30 | static void switch_task(std::optional> f) { 31 | // kill the current competition task if it's still running 32 | if (competition_task) { 33 | const uint32_t competition_task_state = competition_task->get_state(); 34 | if (competition_task_state != pros::E_TASK_STATE_DELETED 35 | && competition_task_state != pros::E_TASK_STATE_INVALID) { 36 | competition_task->remove(); 37 | } 38 | } 39 | 40 | // spawn the new task, if the given function is valid 41 | if (f) { 42 | competition_task = pros::Task::create(*f); 43 | } 44 | } 45 | 46 | // This task controls the competition task. Runs for the lifetime of the program. 47 | // Runs at second highest priority, updates every 2 milliseconds. 48 | static std::optional control_task; 49 | 50 | void initialize() { 51 | control_task = pros::Task::create([]() { 52 | std::optional prev_mode; 53 | 54 | // only run if the mutex is available 55 | while (true) { 56 | const Mode mode = get_mode(); 57 | 58 | // if the competition state changed, or the control task has been notified, 59 | // the competition task should be changed 60 | if (mode != prev_mode) { 61 | prev_mode = mode; 62 | 63 | switch (mode) { 64 | case Mode::Disabled: { 65 | switch_task(disabled_func); 66 | break; 67 | } 68 | case Mode::Autonomous: { 69 | switch_task(autonomous_func); 70 | break; 71 | } 72 | case Mode::DriverControl: { 73 | switch_task(driver_control_func); 74 | break; 75 | } 76 | } 77 | } 78 | 79 | // delay to save resources 80 | pros::delay(2); 81 | } 82 | }, TASK_PRIORITY_MAX - 1); 83 | } 84 | 85 | Mode get_mode() { 86 | const uint32_t status = vexCompetitionStatus(); 87 | 88 | if ((status & DISABLED_MASK) != 0) { 89 | return Mode::Disabled; 90 | } else if ((status & AUTONOMOUS_MASK) != 0) { 91 | return Mode::Autonomous; 92 | } else { 93 | return Mode::DriverControl; 94 | } 95 | } 96 | 97 | System get_system() { 98 | if (!is_connected()) { 99 | return System::None; 100 | } else if ((vexCompetitionStatus() & SYSTEM_MASK) != 0) { 101 | return System::FieldControl; 102 | } else { 103 | return System::CompetitionSwitch; 104 | } 105 | }; 106 | 107 | bool is_connected() { 108 | return (vexCompetitionStatus() & CONNECTED_MASK) != 0; 109 | } 110 | 111 | void register_autonomous(std::function callable) { 112 | autonomous_func = callable; 113 | } 114 | 115 | void register_driver_control(std::function callable) { 116 | driver_control_func = callable; 117 | } 118 | 119 | void register_disabled(std::function callable) { 120 | disabled_func = callable; 121 | } 122 | }; // namespace zest::competition -------------------------------------------------------------------------------- /src/devices/battery.cpp: -------------------------------------------------------------------------------- 1 | #include "pros/devices/battery.hpp" 2 | 3 | #include "pros/devices/brain.hpp" 4 | #include "v5_api_patched.h" 5 | 6 | #include 7 | 8 | namespace zest { 9 | double Battery::get_capacity() { 10 | std::lock_guard lock(Brain::get_smart_port_mutex(Brain::BATTERY_PORT)); 11 | return vexBatteryCapacityGet(); 12 | } 13 | 14 | double Battery::get_current() { 15 | std::lock_guard lock(Brain::get_smart_port_mutex(Brain::BATTERY_PORT)); 16 | return vexBatteryCurrentGet(); 17 | } 18 | 19 | double Battery::get_temperature() { 20 | std::lock_guard lock(Brain::get_smart_port_mutex(Brain::BATTERY_PORT)); 21 | return vexBatteryTemperatureGet(); 22 | } 23 | 24 | double Battery::get_voltage() { 25 | std::lock_guard lock(Brain::get_smart_port_mutex(Brain::BATTERY_PORT)); 26 | return vexBatteryVoltageGet(); 27 | } 28 | } // namespace zest -------------------------------------------------------------------------------- /src/devices/brain.cpp: -------------------------------------------------------------------------------- 1 | #include "pros/devices/brain.hpp" 2 | 3 | #include 4 | 5 | namespace zest { 6 | 7 | pros::RecursiveMutex& Brain::get_smart_port_mutex(SmartPort smart_port) { 8 | // If the port is invalid, return the invalid port mutex. 9 | // Otherwise, return the respective mutex 10 | if (smart_port.as_number() > 32) { 11 | return m_mutexes.at(Brain::INVALID_PORT.as_index()); 12 | } else { 13 | return m_mutexes.at(smart_port.as_index()); 14 | } 15 | } 16 | 17 | void Brain::smart_port_mutex_lock_all() { 18 | std::apply([&](auto&... args) { 19 | std::lock(args...); 20 | }, Brain::m_mutexes); 21 | } 22 | 23 | void Brain::smart_port_mutex_unlock_all() { 24 | for (auto& mutex : Brain::m_mutexes) { 25 | mutex.unlock(); 26 | } 27 | } 28 | 29 | // The VEX SDK has 32 virtual smart ports. 30 | // 21 of these ports represent physical smart ports, 31 | // the rest represent things like the battery, the controller, etc. 32 | // This array has 33 mutexes. The extra mutex is used for invalid ports. 33 | constinit std::array Brain::m_mutexes; 34 | 35 | } // namespace zest -------------------------------------------------------------------------------- /src/rtos/LICENSE: -------------------------------------------------------------------------------- 1 | The FreeRTOS kernel is released under the MIT open source license, the text of 2 | which is provided below. 3 | 4 | This license covers the FreeRTOS kernel source files, which are located in the 5 | /FreeRTOS/Source directory of the official FreeRTOS kernel download. It also 6 | covers most of the source files in the demo application projects, which are 7 | located in the /FreeRTOS/Demo directory of the official FreeRTOS download. The 8 | demo projects may also include third party software that is not part of FreeRTOS 9 | and is licensed separately to FreeRTOS. Examples of third party software 10 | includes header files provided by chip or tools vendors, linker scripts, 11 | peripheral drivers, etc. All the software in subdirectories of the /FreeRTOS 12 | directory is either open source or distributed with permission, and is free for 13 | use. For the avoidance of doubt, refer to the comments at the top of each 14 | source file. 15 | 16 | 17 | License text: 18 | ------------- 19 | 20 | Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 21 | Permission is hereby granted, free of charge, to any person obtaining a copy of 22 | this software and associated documentation files (the "Software"), to deal in 23 | the Software without restriction, including without limitation the rights to 24 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 25 | the Software, and to permit persons to whom the Software is furnished to do so, 26 | subject to the following conditions: 27 | 28 | The above copyright notice and this permission notice shall be included in all 29 | copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 33 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 34 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 35 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 36 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 37 | 38 | -------------------------------------------------------------------------------- /src/rtos/README.md: -------------------------------------------------------------------------------- 1 | ## The FreeRTOS Kernel Library 2 | 3 | __Note: modifiying these files may break PROS or make PROS unstable__ 4 | 5 | _This file serves as an introduction to how PROS uses FreeRTOS if you're just_ 6 | _getting started with development of the PROS kernel. It also contains some_ 7 | _notes from configuring FreeRTOS to work with the V5._ 8 | 9 | PROS 3 uses FreeRTOS 9.0.0 to implement scheduling, queues, and lists - the 10 | barebones of an operating system. In some respects, FreeRTOS could be thought of 11 | as a C library that we have ported to the V5. It of course does more significant 12 | work that a typical application library. 13 | Since computer architectures are different and FreeRTOS aims to work with many 14 | embedded architectures, some work must be done to let FreeRTOS work with the 15 | hardware. 16 | 17 | FreeRTOS provides many demo projects and the developers recommend modifying one 18 | of the projects to suit the needs of the project. Since the V5 is Zynq-7000 board, 19 | we're modifying the Cortex\_A9\_Zynq\_ZC702 demo. 20 | 21 | You should read some of FreeRTOS's documentation and/or take an equivalent of 22 | Purdue's CS250 (Computer Architecture) and CS354 (Operating Systems) for 23 | requisite background knowledge. For more info about the Zynq/A9 port, see 24 | FreeRTOS's documentation on [Zynq](http://www.freertos.org/RTOS-Xilinx-Zynq.html) 25 | and the [A9](http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html). 26 | 27 | ## Modifications to FreeRTOS 28 | We've somewhat significantly refactored the FreeRTOS kernel so that any FreeRTOS 29 | functions used within PROS align with the PROS coding style. See refactor.tsv in 30 | this directory. 31 | 32 | We've removed the use of `int32_t` and `uint32_t` from any public facing 33 | API since we felt it unnecessary. Additionally, all variables pertaining to ticks 34 | on the PROS internal or public facing APIs have become millisecond precision, and 35 | the conversion done immediately upon entering the functiion. 36 | 37 | -------------------------------------------------------------------------------- /src/rtos/list.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeRTOS Kernel V10.0.1 3 | * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | * http://www.FreeRTOS.org 23 | * http://aws.amazon.com/freertos 24 | * 25 | * 1 tab == 4 spaces! 26 | */ 27 | 28 | 29 | #include 30 | #include "rtos/FreeRTOS.h" 31 | #include "rtos/list.h" 32 | 33 | /*----------------------------------------------------------- 34 | * PUBLIC LIST API documented in list.h 35 | *----------------------------------------------------------*/ 36 | 37 | void vListInitialise( List_t * const pxList ) 38 | { 39 | /* The list structure contains a list item which is used to mark the 40 | end of the list. To initialise the list the list end is inserted 41 | as the only list entry. */ 42 | pxList->pxIndex = ( list_item_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ 43 | 44 | /* The list end value is the highest possible value in the list to 45 | ensure it remains at the end of the list. */ 46 | pxList->xListEnd.xItemValue = portMAX_DELAY; 47 | 48 | /* The list end next and previous pointers point to itself so we know 49 | when the list is empty. */ 50 | pxList->xListEnd.pxNext = ( list_item_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ 51 | pxList->xListEnd.pxPrevious = ( list_item_t * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ 52 | 53 | pxList->uxNumberOfItems = ( uint32_t ) 0U; 54 | 55 | /* Write known values into the list if 56 | configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ 57 | listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ); 58 | listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ); 59 | } 60 | /*-----------------------------------------------------------*/ 61 | 62 | void vListInitialiseItem( list_item_t * const pxItem ) 63 | { 64 | /* Make sure the list item is not recorded as being on a list. */ 65 | pxItem->pvContainer = NULL; 66 | 67 | /* Write known values into the list item if 68 | configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ 69 | listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ); 70 | listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ); 71 | } 72 | /*-----------------------------------------------------------*/ 73 | 74 | void vListInsertEnd( List_t * const pxList, list_item_t * const pxNewListItem ) 75 | { 76 | list_item_t * const pxIndex = pxList->pxIndex; 77 | 78 | /* Only effective when configASSERT() is also defined, these tests may catch 79 | the list data structures being overwritten in memory. They will not catch 80 | data errors caused by incorrect configuration or use of FreeRTOS. */ 81 | listTEST_LIST_INTEGRITY( pxList ); 82 | listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ); 83 | 84 | /* Insert a new list item into pxList, but rather than sort the list, 85 | makes the new list item the last item to be removed by a call to 86 | listGET_OWNER_OF_NEXT_ENTRY(). */ 87 | pxNewListItem->pxNext = pxIndex; 88 | pxNewListItem->pxPrevious = pxIndex->pxPrevious; 89 | 90 | /* Only used during decision coverage testing. */ 91 | mtCOVERAGE_TEST_DELAY(); 92 | 93 | pxIndex->pxPrevious->pxNext = pxNewListItem; 94 | pxIndex->pxPrevious = pxNewListItem; 95 | 96 | /* Remember which list the item is in. */ 97 | pxNewListItem->pvContainer = ( void * ) pxList; 98 | 99 | ( pxList->uxNumberOfItems )++; 100 | } 101 | /*-----------------------------------------------------------*/ 102 | 103 | void vListInsert( List_t * const pxList, list_item_t * const pxNewListItem ) 104 | { 105 | list_item_t *pxIterator; 106 | const uint32_t xValueOfInsertion = pxNewListItem->xItemValue; 107 | 108 | /* Only effective when configASSERT() is also defined, these tests may catch 109 | the list data structures being overwritten in memory. They will not catch 110 | data errors caused by incorrect configuration or use of FreeRTOS. */ 111 | listTEST_LIST_INTEGRITY( pxList ); 112 | listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ); 113 | 114 | /* Insert the new list item into the list, sorted in xItemValue order. 115 | 116 | If the list already contains a list item with the same item value then the 117 | new list item should be placed after it. This ensures that TCB's which are 118 | stored in ready lists (all of which have the same xItemValue value) get a 119 | share of the CPU. However, if the xItemValue is the same as the back marker 120 | the iteration loop below will not end. Therefore the value is checked 121 | first, and the algorithm slightly modified if necessary. */ 122 | if( xValueOfInsertion == portMAX_DELAY ) 123 | { 124 | pxIterator = pxList->xListEnd.pxPrevious; 125 | } 126 | else 127 | { 128 | /* *** NOTE *********************************************************** 129 | If you find your application is crashing here then likely causes are 130 | listed below. In addition see http://www.freertos.org/FAQHelp.html for 131 | more tips, and ensure configASSERT() is defined! 132 | http://www.freertos.org/a00110.html#configASSERT 133 | 134 | 1) Stack overflow - 135 | see http://www.freertos.org/Stacks-and-stack-overflow-checking.html 136 | 2) Incorrect interrupt priority assignment, especially on Cortex-M 137 | parts where numerically high priority values denote low actual 138 | interrupt priorities, which can seem counter intuitive. See 139 | http://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition 140 | of configMAX_SYSCALL_INTERRUPT_PRIORITY on 141 | http://www.freertos.org/a00110.html 142 | 3) Calling an API function from within a critical section or when 143 | the scheduler is suspended, or calling an API function that does 144 | not end in "FromISR" from an interrupt. 145 | 4) Using a queue or semaphore before it has been initialised or 146 | before the scheduler has been started (are interrupts firing 147 | before rtos_sched_start() has been called?). 148 | **********************************************************************/ 149 | 150 | for( pxIterator = ( list_item_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ 151 | { 152 | /* There is nothing to do here, just iterating to the wanted 153 | insertion position. */ 154 | } 155 | } 156 | 157 | pxNewListItem->pxNext = pxIterator->pxNext; 158 | pxNewListItem->pxNext->pxPrevious = pxNewListItem; 159 | pxNewListItem->pxPrevious = pxIterator; 160 | pxIterator->pxNext = pxNewListItem; 161 | 162 | /* Remember which list the item is in. This allows fast removal of the 163 | item later. */ 164 | pxNewListItem->pvContainer = ( void * ) pxList; 165 | 166 | ( pxList->uxNumberOfItems )++; 167 | } 168 | /*-----------------------------------------------------------*/ 169 | 170 | uint32_t uxListRemove( list_item_t * const pxItemToRemove ) 171 | { 172 | /* The list item knows which list it is in. Obtain the list from the list 173 | item. */ 174 | List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer; 175 | 176 | pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious; 177 | pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext; 178 | 179 | /* Only used during decision coverage testing. */ 180 | mtCOVERAGE_TEST_DELAY(); 181 | 182 | /* Make sure the index is left pointing to a valid item. */ 183 | if( pxList->pxIndex == pxItemToRemove ) 184 | { 185 | pxList->pxIndex = pxItemToRemove->pxPrevious; 186 | } 187 | else 188 | { 189 | mtCOVERAGE_TEST_MARKER(); 190 | } 191 | 192 | pxItemToRemove->pvContainer = NULL; 193 | ( pxList->uxNumberOfItems )--; 194 | 195 | return pxList->uxNumberOfItems; 196 | } 197 | /*-----------------------------------------------------------*/ 198 | 199 | -------------------------------------------------------------------------------- /src/rtos/rtos.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file rtos/rtos.cpp 3 | * 4 | * Contains functions for the PROS RTOS kernel for use by typical 5 | * VEX programmers. 6 | * 7 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 8 | * All rights reserved. 9 | * 10 | * This Source Code Form is subject to the terms of the Mozilla Public 11 | * License, v. 2.0. If a copy of the MPL was not distributed with this 12 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 13 | */ 14 | 15 | #include "pros/rtos.hpp" 16 | 17 | #include 18 | #include 19 | 20 | #include "kapi.h" 21 | #include "rtos/task.h" 22 | #include "system/optimizers.h" 23 | 24 | namespace pros { 25 | using namespace pros::c; 26 | 27 | Task::Task(task_fn_t function, void* parameters, std::uint32_t prio, std::uint16_t stack_depth, const char* name) { 28 | task = task_create(function, parameters, prio, stack_depth, name); 29 | } 30 | 31 | Task::Task(task_fn_t function, void* parameters, const char* name) 32 | : Task(function, parameters, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, name) {} 33 | 34 | Task::Task(task_t task) : task(task) {} 35 | Task& Task::operator=(const task_t in) { 36 | task = in; 37 | return *this; 38 | } 39 | 40 | Task Task::current() { 41 | return Task{task_get_current()}; 42 | } 43 | 44 | void Task::remove() { 45 | return task_delete(task); 46 | } 47 | 48 | std::uint32_t Task::get_priority() { 49 | return task_get_priority(task); 50 | } 51 | 52 | void Task::set_priority(std::uint32_t prio) { 53 | task_set_priority(task, prio); 54 | } 55 | 56 | std::uint32_t Task::get_state() { 57 | return task_get_state(task); 58 | } 59 | 60 | void Task::suspend() { 61 | task_suspend(task); 62 | } 63 | 64 | void Task::resume() { 65 | task_resume(task); 66 | } 67 | 68 | const char* Task::get_name() { 69 | return task_get_name(task); 70 | } 71 | 72 | std::uint32_t Task::notify() { 73 | return task_notify(task); 74 | } 75 | 76 | void Task::join() { 77 | return task_join(task); 78 | } 79 | 80 | std::uint32_t Task::notify_ext(std::uint32_t value, notify_action_e_t action, std::uint32_t* prev_value) { 81 | return task_notify_ext(task, value, action, prev_value); 82 | } 83 | 84 | std::uint32_t Task::notify_take(bool clear_on_exit, std::uint32_t timeout) { 85 | return task_notify_take(clear_on_exit, timeout); 86 | } 87 | 88 | bool Task::notify_clear() { 89 | return task_notify_clear(task); 90 | } 91 | 92 | void Task::delay(const std::uint32_t milliseconds) { 93 | task_delay(milliseconds); 94 | } 95 | 96 | void Task::delay_until(std::uint32_t* const prev_time, const std::uint32_t delta) { 97 | task_delay_until(prev_time, delta); 98 | } 99 | 100 | std::uint32_t Task::get_count() { 101 | return task_get_count(); 102 | } 103 | 104 | Clock::time_point Clock::now() { 105 | return Clock::time_point{Clock::duration{millis()}}; 106 | } 107 | 108 | mutex_t Mutex::lazy_init() { 109 | mutex_t _mutex; 110 | if(unlikely((_mutex = mutex.load(std::memory_order::relaxed)) == nullptr)) { 111 | taskENTER_CRITICAL(); 112 | if(likely((_mutex = mutex.load()) == nullptr)) { 113 | mutex.store((_mutex = pros::c::mutex_create())); 114 | } 115 | taskEXIT_CRITICAL(); 116 | } 117 | return _mutex; 118 | } 119 | 120 | bool Mutex::take() { 121 | return mutex_take(lazy_init(), TIMEOUT_MAX); 122 | } 123 | 124 | bool Mutex::take(std::uint32_t timeout) { 125 | return mutex_take(lazy_init(), timeout); 126 | } 127 | 128 | bool Mutex::give() { 129 | return mutex_give(lazy_init()); 130 | } 131 | 132 | void Mutex::lock() { 133 | if (!take(TIMEOUT_MAX)) { 134 | throw std::system_error(errno, std::system_category(), "Cannot obtain lock!"); 135 | } 136 | } 137 | 138 | void Mutex::unlock() { 139 | give(); 140 | } 141 | 142 | bool Mutex::try_lock() { 143 | return take(0); 144 | } 145 | 146 | Mutex::~Mutex() { 147 | mutex_t _mutex = mutex.exchange(reinterpret_cast(~0)); 148 | pros::c::mutex_delete(_mutex); 149 | } 150 | 151 | mutex_t RecursiveMutex::lazy_init() { 152 | mutex_t _mutex; 153 | if(unlikely((_mutex = mutex.load(std::memory_order::relaxed)) == nullptr)) { 154 | taskENTER_CRITICAL(); 155 | if(likely((_mutex = mutex.load()) == nullptr)) { 156 | mutex.store((_mutex = pros::c::mutex_recursive_create())); 157 | } 158 | taskEXIT_CRITICAL(); 159 | } 160 | return _mutex; 161 | } 162 | 163 | bool RecursiveMutex::take() { 164 | return mutex_recursive_take(lazy_init(), TIMEOUT_MAX); 165 | } 166 | 167 | bool RecursiveMutex::take(std::uint32_t timeout) { 168 | return mutex_recursive_take(lazy_init(), timeout); 169 | } 170 | 171 | bool RecursiveMutex::give() { 172 | return mutex_recursive_give(lazy_init()); 173 | } 174 | 175 | void RecursiveMutex::lock() { 176 | if (!take(TIMEOUT_MAX)) { 177 | throw std::system_error(errno, std::system_category(), "Cannot obtain lock!"); 178 | } 179 | } 180 | 181 | void RecursiveMutex::unlock() { 182 | give(); 183 | } 184 | 185 | bool RecursiveMutex::try_lock() { 186 | return take(0); 187 | } 188 | 189 | RecursiveMutex::~RecursiveMutex() { 190 | mutex_t _mutex = mutex.exchange(reinterpret_cast(~0)); 191 | pros::c::mutex_delete(_mutex); 192 | } 193 | } // namespace pros 194 | -------------------------------------------------------------------------------- /src/rtos/task_notify_when_deleting.c: -------------------------------------------------------------------------------- 1 | #include "kapi.h" 2 | #include "common/linkedlist.h" 3 | 4 | // NOTE: can't just include task.h because of redefinition that goes on in kapi 5 | // include chain, so we just prototype what we need here 6 | void *pvTaskGetThreadLocalStoragePointer( task_t xTaskToQuery, int32_t xIndex ); 7 | void vTaskSetThreadLocalStoragePointer( task_t xTaskToSet, int32_t xIndex, void *pvValue ); 8 | 9 | #include "rtos/tcb.h" 10 | 11 | // This increments configNUM_THREAD_LOCAL_STORAGE_POINTERS by 2 12 | 13 | #define SUBSCRIBERS_TLSP_IDX 0 14 | #define SUBSCRIPTIONS_TLSP_IDX 1 15 | 16 | static static_sem_s_t task_notify_when_deleting_mutex_buf; 17 | static mutex_t task_notify_when_deleting_mutex; 18 | 19 | struct notify_delete_action { 20 | task_t task_to_notify; 21 | uint32_t value; 22 | notify_action_e_t notify_action; 23 | }; 24 | 25 | struct _find_task_args { 26 | task_t task; 27 | struct notify_delete_action* found_action; 28 | }; 29 | 30 | static void _find_task_cb(ll_node_s_t* node, void* extra) { 31 | struct notify_delete_action* action = node->payload.data; 32 | struct _find_task_args* args = extra; 33 | 34 | if(action->task_to_notify == args->task) { 35 | args->found_action = action; 36 | } 37 | } 38 | 39 | static struct notify_delete_action* _find_task(linked_list_s_t* ll, task_t task) { 40 | struct _find_task_args args = { 41 | .task = task, 42 | .found_action = NULL 43 | }; 44 | linked_list_foreach(ll, _find_task_cb, &args); 45 | 46 | return args.found_action; 47 | } 48 | 49 | void task_notify_when_deleting_init() { 50 | task_notify_when_deleting_mutex = mutex_create_static(&task_notify_when_deleting_mutex_buf); 51 | } 52 | 53 | void task_notify_when_deleting(task_t target_task, task_t task_to_notify, 54 | uint32_t value, notify_action_e_t notify_action) { 55 | task_to_notify = (task_to_notify == NULL) ? pxCurrentTCB : task_to_notify; 56 | target_task = (target_task == NULL) ? pxCurrentTCB : target_task; 57 | 58 | // It doesn't make sense for a task to notify itself, and make sure that 59 | // neither task is NULL (implying that scheduler hasn't started yet) 60 | if (task_to_notify == target_task || !task_to_notify || !target_task) { 61 | return; 62 | } 63 | 64 | // Return immediately if the target task is already deleted 65 | if (eTaskStateGet(target_task) == E_TASK_STATE_DELETED) { 66 | return; 67 | } 68 | 69 | mutex_take(task_notify_when_deleting_mutex, TIMEOUT_MAX); 70 | 71 | // task_to_notify maintains a list of the tasks whose deletion it cares about. 72 | // This will allow us to unsubscribe from notification if/when task_to_notify 73 | // is deleted 74 | linked_list_s_t* subscriptions_ll = pvTaskGetThreadLocalStoragePointer(task_to_notify, SUBSCRIPTIONS_TLSP_IDX); 75 | if (subscriptions_ll == NULL) { 76 | subscriptions_ll = linked_list_init(); 77 | vTaskSetThreadLocalStoragePointer(task_to_notify, SUBSCRIPTIONS_TLSP_IDX, subscriptions_ll); 78 | } 79 | if (subscriptions_ll != NULL) { 80 | // check whether task_to_notify is already subscribed to target_task. if so, 81 | // do nothing 82 | ll_node_s_t* it = subscriptions_ll->head; 83 | bool found = false; 84 | while (it != NULL && !found) { 85 | found = it->payload.data == target_task; 86 | it = it->next; 87 | } 88 | if (!found) { 89 | linked_list_prepend_data(subscriptions_ll, target_task); 90 | } 91 | } 92 | 93 | // similarly, target_task maintains a list of the tasks it needs to notify 94 | // when being deleted 95 | linked_list_s_t* target_ll = pvTaskGetThreadLocalStoragePointer(target_task, SUBSCRIBERS_TLSP_IDX); 96 | if (target_ll == NULL) { 97 | target_ll = linked_list_init(); 98 | vTaskSetThreadLocalStoragePointer(target_task, SUBSCRIBERS_TLSP_IDX, target_ll); 99 | } 100 | 101 | if (target_ll != NULL) { 102 | // Try to find the task_to_notify in the target linked list 103 | // i.e., target_task was already configured to notify task_to_notify 104 | struct notify_delete_action* action = _find_task(target_ll, task_to_notify); 105 | 106 | // action wasn't found, so add it to the linked list 107 | if (action == NULL) { 108 | action = (struct notify_delete_action*)kmalloc(sizeof(struct notify_delete_action)); 109 | if (action != NULL) { 110 | linked_list_prepend_data(target_ll, action); 111 | } 112 | } 113 | 114 | // update the action (whether it was found or newly allocated) 115 | if (action != NULL) { 116 | action->task_to_notify = task_to_notify; 117 | action->notify_action = notify_action; 118 | action->value = value; 119 | } 120 | } 121 | mutex_give(task_notify_when_deleting_mutex); 122 | } 123 | 124 | // NOTE: this code is untested, probably works, but also has a terrible name (task_notify_when_deleting_unsubscribe) 125 | // void task_notify_when_deleting_unsubscribe(task_t target_task, task_t task_to_notify) { 126 | // task_to_notify = (task_to_notify == NULL) ? pxCurrentTCB : task_to_notify; 127 | // target_task = (target_task == NULL) ? pxCurrentTCB : target_task; 128 | // 129 | // if (task_to_notify == target_task || !task_to_notify || !target_task) { 130 | // return; 131 | // } 132 | // 133 | // linked_list_s_t* ll = pvTaskGetThreadLocalStoragePointer(target_task, TLSP_IDX); 134 | // if (ll != NULL) { 135 | // struct notify_delete_action* action = _find_task(ll, task_to_notify); 136 | // if (action != NULL) { 137 | // linked_list_remove_data(ll, action); 138 | // kfree(action); 139 | // } 140 | // } 141 | // } 142 | 143 | static void unsubscribe_hook_cb(ll_node_s_t* node, void* task_to_remove) { 144 | task_t subscription = node->payload.data; 145 | 146 | linked_list_s_t* subscriptions_list = pvTaskGetThreadLocalStoragePointer(subscription, SUBSCRIBERS_TLSP_IDX); 147 | if (subscriptions_list != NULL) { 148 | linked_list_remove_data(subscriptions_list, task_to_remove); 149 | } 150 | } 151 | 152 | static void delete_hook_cb(ll_node_s_t* node, void* ignore) { 153 | struct notify_delete_action* action = node->payload.data; 154 | if (action != NULL) { 155 | task_notify_ext(action->task_to_notify, action->value, action->notify_action, NULL); 156 | kfree(action); 157 | node->payload.data = NULL; 158 | } 159 | } 160 | 161 | void task_notify_when_deleting_hook(task_t task) { 162 | mutex_take(task_notify_when_deleting_mutex, TIMEOUT_MAX); 163 | // if this task was subscribed to any other task deletion events, unsubscribe 164 | linked_list_s_t* ll = pvTaskGetThreadLocalStoragePointer(task, SUBSCRIPTIONS_TLSP_IDX); 165 | if (ll != NULL) { 166 | linked_list_foreach(ll, unsubscribe_hook_cb, task); 167 | linked_list_free(ll); 168 | vTaskSetThreadLocalStoragePointer(task, SUBSCRIPTIONS_TLSP_IDX, NULL); 169 | } 170 | // notify subscribed tasks of this task's deletion 171 | ll = pvTaskGetThreadLocalStoragePointer(task, SUBSCRIBERS_TLSP_IDX); 172 | if (ll != NULL) { 173 | linked_list_foreach(ll, delete_hook_cb, NULL); 174 | linked_list_free(ll); 175 | vTaskSetThreadLocalStoragePointer(task, SUBSCRIBERS_TLSP_IDX, NULL); // for good measure 176 | } 177 | mutex_give(task_notify_when_deleting_mutex); 178 | } 179 | -------------------------------------------------------------------------------- /src/system/cpp_support.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file system/cpp_support.cpp 3 | * 4 | * C++ support hooks 5 | * 6 | * \copyright (c) 2017-2024, Purdue University ACM SIGBots. 7 | * All rights reserved. 8 | * 9 | * This Source Code Form is subject to the terms of the Mozilla Public 10 | * License, v. 2.0. If a copy of the MPL was not distributed with this 11 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 12 | */ 13 | 14 | #include "rtos/task.h" 15 | #include "v5_api_patched.h" 16 | 17 | #include 18 | #include 19 | 20 | extern "C" void task_fn_wrapper(task_fn_t fn, void* args) { 21 | #ifdef __cpp_exceptions 22 | try { 23 | #endif 24 | fn(args); 25 | #ifdef __cpp_exceptions 26 | } catch (const std::runtime_error& re) { 27 | fprintf(stderr, "Runtime error: %s \n", re.what()); 28 | vexDisplayString(5, "A runtime error occurred:"); 29 | vexDisplayString(6, "%s", re.what()); 30 | vexDisplayString(7, "Note: open terminal for error message"); 31 | } catch (const std::exception& ex) { 32 | fprintf(stderr, "Exception occurred: %s \n", ex.what()); 33 | vexDisplayString(5, "An exception occurred:"); 34 | vexDisplayString(6, "%s", ex.what()); 35 | vexDisplayString(7, "Note: open terminal for error message"); 36 | } catch (...) { 37 | fprintf(stderr, "Unknown error occurred. \n"); 38 | vexDisplayString(5, "An unknown error occurred"); 39 | } 40 | #endif 41 | } -------------------------------------------------------------------------------- /src/system/dev/file_system_stubs.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file system/dev/dev_driver.c 3 | * 4 | * Generic Serial Device driver 5 | * 6 | * Contains temporary stubs for the file system to allow compilation under gcc 9.2 7 | * This is temporary and should be removed as part of #184 8 | * 9 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 10 | * All rights reserved. 11 | * 12 | * This Source Code Form is subject to the terms of the Mozilla Public 13 | * License, v. 2.0. If a copy of the MPL was not distributed with this 14 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | int chdir(const char* path) { 21 | errno = ENOSYS; 22 | return -1; 23 | } 24 | 25 | int mkdir(const char* pathname, mode_t mode) { 26 | errno = ENOSYS; 27 | return -1; 28 | } 29 | 30 | int chmod(const char* pathname, mode_t mode) { 31 | errno = ENOSYS; 32 | return -1; 33 | } 34 | 35 | int fchmod(int fd, mode_t mode) { 36 | errno = ENOSYS; 37 | return -1; 38 | } 39 | 40 | int fchmodat(int dirfd, const char* pathname, mode_t mode, int flags) { 41 | errno = ENOSYS; 42 | return -1; 43 | } 44 | 45 | long pathconf(const char* path, int name) { 46 | errno = ENOSYS; 47 | return -1; 48 | } 49 | 50 | char* getcwd(char* buf, size_t size) { 51 | errno = ENOSYS; 52 | return NULL; 53 | } 54 | 55 | int _unlink(const char* name) { 56 | errno = ENOSYS; 57 | return -1; 58 | } 59 | 60 | int _link(const char* old, const char* new) { 61 | errno = ENOSYS; 62 | return -1; 63 | } 64 | 65 | int _stat(const char* file, struct stat* st) { 66 | errno = ENOSYS; 67 | return -1; 68 | } 69 | 70 | int symlink(const char* file, const char* linkpath) { 71 | errno = ENOSYS; 72 | return -1; 73 | } 74 | 75 | ssize_t readlink(const char* pathname, char* buf, size_t bufsiz) { 76 | errno = ENOSYS; 77 | return -1; 78 | } 79 | 80 | int truncate(const char* path, off_t length) { 81 | errno = ENOSYS; 82 | return -1; 83 | } 84 | -------------------------------------------------------------------------------- /src/system/dev/ser_daemon.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file system/dev/ser_daemon.c 3 | * 4 | * Serial Input Daemon 5 | * 6 | * The serial input daemon is responsible for polling the serial line for 7 | * characters and responding to any kernel commands (like printing the banner or 8 | * enabling COBS) 9 | * 10 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 11 | * All rights reserved. 12 | * 13 | * This Source Code Form is subject to the terms of the Mozilla Public 14 | * License, v. 2.0. If a copy of the MPL was not distributed with this 15 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 16 | */ 17 | 18 | #include "kapi.h" 19 | #include "system/dev/banners.h" 20 | #include "v5_api_patched.h" 21 | 22 | #define MAX_COMMAND_LENGTH 32 23 | 24 | __attribute__((weak)) char const* const _PROS_COMPILE_TIMESTAMP = "Unknown"; 25 | __attribute__((weak)) char const* const _PROS_COMPILE_DIRECTORY = "Unknown"; 26 | __attribute__((weak)) const int _PROS_COMPILE_TIMESTAMP_INT = 0; 27 | 28 | static bool banner_is_enabled = true; 29 | 30 | void enable_banner(bool enabled) { 31 | banner_is_enabled = enabled; 32 | } 33 | 34 | void print_small_banner(void) { 35 | if (!banner_is_enabled) 36 | return; 37 | uint32_t uptime = millis(); 38 | char const* const timestamp = _PROS_COMPILE_TIMESTAMP; 39 | char const* const directory = _PROS_COMPILE_DIRECTORY; 40 | iprintf( 41 | short_banner, 42 | "0.0.0", // PROS_VERSION_STRING, 43 | uptime / 1000, // clangd is lying to you 44 | uptime % 1000, // clangd is lying to you 45 | timestamp, 46 | directory 47 | ); 48 | } 49 | 50 | void print_large_banner(void) { 51 | if (!banner_is_enabled) 52 | return; 53 | uint8_t version[4]; 54 | uint32_t* sys_ver = (uint32_t*)version; 55 | *sys_ver = vexSystemVersion(); 56 | uint32_t uptime = millis(); 57 | char const* const timestamp = _PROS_COMPILE_TIMESTAMP; 58 | char const* const directory = _PROS_COMPILE_DIRECTORY; 59 | iprintf( 60 | large_banner, 61 | "0.0.0", // PROS_VERSION_STRING, 62 | version[3], 63 | version[2], 64 | version[1], 65 | version[0], 66 | uptime / 1000, // clangd is lying to you 67 | uptime % 1000, // clangd is lying to you 68 | timestamp, 69 | directory 70 | ); 71 | } 72 | 73 | /******************************************************************************/ 74 | /** Input buffer **/ 75 | /** **/ 76 | /** this is what read() reads from. Implemented as a ring buffer **/ 77 | /** TODO: just use a FreeRTOS queue instead of 2 semaphores **/ 78 | /******************************************************************************/ 79 | #define INP_BUFFER_SIZE 0x1000 // 4KB... which is larger than VEX's output buffer -_- 80 | 81 | static static_stream_buf_s_t inp_stream_buf; 82 | static uint8_t inp_buffer[INP_BUFFER_SIZE]; 83 | static stream_buf_t inp_stream; 84 | 85 | static inline void inp_buffer_initialize() { 86 | inp_stream = stream_buf_create_static(INP_BUFFER_SIZE, 1, inp_buffer, &inp_stream_buf); 87 | } 88 | 89 | // if you extern this function you can place characters on the rest of the 90 | // system's input buffer 91 | bool inp_buffer_post(uint8_t b) { 92 | return stream_buf_send(inp_stream, &b, 1, TIMEOUT_MAX); 93 | } 94 | 95 | int32_t inp_buffer_read(uint32_t timeout) { 96 | // polling the semaphore from a higher priority task (as would be normal) will 97 | // starve the ser_daemon_task 98 | if (timeout == 0) { 99 | timeout = 1; 100 | } 101 | uint8_t b; 102 | if (!stream_buf_recv(inp_stream, &b, 1, timeout)) { 103 | return -1; 104 | } 105 | return (int32_t)b; 106 | } 107 | 108 | // returns the number of bytes currently in the stream 109 | int32_t inp_buffer_available() { 110 | return stream_buf_get_used(inp_stream); 111 | } 112 | 113 | /******************************************************************************/ 114 | /** Serial Daemon **/ 115 | /******************************************************************************/ 116 | static task_stack_t ser_daemon_stack[TASK_STACK_DEPTH_MIN]; 117 | static static_task_s_t ser_daemon_task_buffer; 118 | 119 | static inline uint8_t vex_read_char() { 120 | int32_t b = vexSerialReadChar(1); 121 | while (b == -1L) { 122 | task_delay(1); 123 | b = vexSerialReadChar(1); 124 | } 125 | // Don't get rid of the literal type suffix, it ensures optimizations don't 126 | // break this condition 127 | return (uint8_t)b; 128 | } 129 | 130 | static void ser_daemon_task(void* ign) { 131 | uint8_t command_stack[MAX_COMMAND_LENGTH]; 132 | size_t command_stack_idx = 0; 133 | 134 | print_large_banner(); 135 | 136 | while (1) { 137 | uint8_t b = vex_read_char(); 138 | if (b == 'p') { // TODO: make the command prefix not typeable 139 | command_stack[command_stack_idx++] = b; 140 | b = command_stack[command_stack_idx++] = vex_read_char(); 141 | if (b == 'R') { 142 | b = command_stack[command_stack_idx++] = vex_read_char(); 143 | switch (b) { 144 | case 'a': 145 | fprintf(stderr, "I'm alive!\n"); 146 | command_stack_idx = 0; 147 | break; 148 | case 'b': 149 | task_delay(20); 150 | print_small_banner(); 151 | command_stack_idx = 0; 152 | break; 153 | case 'B': 154 | task_delay(20); 155 | print_large_banner(); 156 | command_stack_idx = 0; 157 | break; 158 | case 'e': 159 | // read next 4 bytes 160 | command_stack[command_stack_idx++] = vex_read_char(); 161 | command_stack[command_stack_idx++] = vex_read_char(); 162 | command_stack[command_stack_idx++] = vex_read_char(); 163 | command_stack[command_stack_idx++] = vex_read_char(); 164 | // the parameter expected to serctl is the stream id (a uint32_t), so 165 | // we 166 | // need to cast to a uint32_t pointer, dereference it, and cast to a 167 | // void* to make the compiler happy 168 | serctl(SERCTL_ACTIVATE, (void*)(*(uint32_t*)(command_stack + 3))); 169 | // printf("enabled %s\n", command_stack + 3); 170 | command_stack_idx = 0; 171 | break; 172 | case 'd': 173 | // read next 4 bytes 174 | command_stack[command_stack_idx++] = vex_read_char(); 175 | command_stack[command_stack_idx++] = vex_read_char(); 176 | command_stack[command_stack_idx++] = vex_read_char(); 177 | command_stack[command_stack_idx++] = vex_read_char(); 178 | serctl(SERCTL_DEACTIVATE, (void*)(*(uint32_t*)(command_stack + 3))); 179 | // printf("disabled %s\n", command_stack+3); 180 | command_stack_idx = 0; 181 | break; 182 | case 'c': 183 | serctl(SERCTL_ENABLE_COBS, NULL); 184 | command_stack_idx = 0; 185 | break; 186 | case 'r': 187 | serctl(SERCTL_DISABLE_COBS, NULL); 188 | command_stack_idx = 0; 189 | break; 190 | default: 191 | command_stack_idx = 0; 192 | break; 193 | } 194 | } 195 | 196 | for (size_t i = 0; i < command_stack_idx; i++) { 197 | // empty out the command stack onto the input buffer since something 198 | // wasn't right with the command 199 | inp_buffer_post(command_stack[i]); 200 | } 201 | command_stack_idx = 0; 202 | } else { 203 | inp_buffer_post(b); 204 | } 205 | } 206 | } 207 | 208 | void ser_initialize(void) { 209 | inp_buffer_initialize(); 210 | extern void ser_driver_initialize(void); 211 | ser_driver_initialize(); 212 | 213 | task_create_static( 214 | ser_daemon_task, 215 | NULL, 216 | TASK_PRIORITY_MIN + 1, 217 | TASK_STACK_DEPTH_MIN, 218 | "Serial Daemon (PROS)", 219 | ser_daemon_stack, 220 | &ser_daemon_task_buffer 221 | ); 222 | } 223 | -------------------------------------------------------------------------------- /src/system/dev/usd_driver.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file system/dev/usd_driver.c 3 | * 4 | * Contains the driver for writing files to the microSD card. 5 | * 6 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 7 | * All rights reserved. 8 | * 9 | * This Source Code Form is subject to the terms of the Mozilla Public 10 | * License, v. 2.0. If a copy of the MPL was not distributed with this 11 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 12 | */ 13 | 14 | // the pragma below is needed due to a FreeRTOS oversight 15 | #include "kapi.h" // IWYU pragma: keep 16 | #include "system/dev/usd.h" 17 | #include "system/dev/vfs.h" 18 | #include "v5_api_patched.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | typedef struct usd_file_arg { 27 | FIL* ifi_fptr; 28 | } usd_file_arg_t; 29 | 30 | static const int FRESULTMAP[] = { 31 | 0, 32 | EIO, 33 | EINVAL, 34 | EBUSY, 35 | ENOENT, 36 | ENOENT, 37 | EINVAL, 38 | EACCES, // FR_DENIED 39 | EEXIST, 40 | EINVAL, 41 | EROFS, 42 | ENXIO, 43 | ENOBUFS, 44 | ENXIO, 45 | EIO, 46 | EACCES, // FR_LOCKED 47 | ENOBUFS, 48 | ENFILE, 49 | EINVAL 50 | }; 51 | 52 | enum fa_flags { 53 | FA_READ = 1 << 0, 54 | FA_WRITE = 1 << 1, 55 | FA_CREATE_ALWAYS = 1 << 2, 56 | FA_OPEN_APPEND = 1 << 3, 57 | FA_CREATE_NEW = 1 << 4 58 | }; 59 | 60 | /******************************************************************************/ 61 | /** newlib driver functions **/ 62 | /******************************************************************************/ 63 | int usd_read_r(struct _reent* r, void* const arg, uint8_t* buffer, const size_t len) { 64 | usd_file_arg_t* file_arg = (usd_file_arg_t*)arg; 65 | // TODO: mutex here. Global or file lock? 66 | int32_t result = vexFileRead((char*)buffer, sizeof(*buffer), len, file_arg->ifi_fptr); 67 | return result; 68 | } 69 | 70 | int usd_write_r(struct _reent* r, void* const arg, const uint8_t* buf, const size_t len) { 71 | usd_file_arg_t* file_arg = (usd_file_arg_t*)arg; 72 | // TODO: mutex here. Global or file lock? 73 | int32_t result = vexFileWrite((char*)buf, sizeof(*buf), len, file_arg->ifi_fptr); 74 | // Flush the buffer 75 | vexFileSync(file_arg->ifi_fptr); 76 | return result; 77 | } 78 | 79 | int usd_close_r(struct _reent* r, void* const arg) { 80 | usd_file_arg_t* file_arg = (usd_file_arg_t*)arg; 81 | vexFileClose(file_arg->ifi_fptr); 82 | return 0; 83 | } 84 | 85 | int usd_fstat_r(struct _reent* r, void* const arg, struct stat* st) { 86 | usd_file_arg_t* file_arg = (usd_file_arg_t*)arg; 87 | st->st_size = vexFileSize(file_arg->ifi_fptr); 88 | return 0; 89 | } 90 | 91 | int usd_isatty_r(struct _reent* r, void* const arg) { 92 | return 0; 93 | } 94 | 95 | off_t usd_lseek_r(struct _reent* r, void* const arg, off_t ptr, int dir) { 96 | usd_file_arg_t* file_arg = (usd_file_arg_t*)arg; 97 | // TODO: mutex here. Global or file lock? 98 | FRESULT result = vexFileSeek(file_arg->ifi_fptr, ptr, dir); 99 | if (result != FR_OK) { 100 | r->_errno = FRESULTMAP[result]; 101 | return (off_t)-1; 102 | } 103 | return vexFileTell(file_arg->ifi_fptr); 104 | } 105 | 106 | int usd_ctl(void* const arg, const uint32_t cmd, void* const extra_arg) { 107 | return 0; 108 | } 109 | 110 | /******************************************************************************/ 111 | /** Driver description **/ 112 | /******************************************************************************/ 113 | 114 | const struct fs_driver _usd_driver = { 115 | .close_r = usd_close_r, 116 | .fstat_r = usd_fstat_r, 117 | .isatty_r = usd_isatty_r, 118 | .lseek_r = usd_lseek_r, 119 | .read_r = usd_read_r, 120 | .write_r = usd_write_r, 121 | .ctl = usd_ctl 122 | }; 123 | const struct fs_driver* const usd_driver = &_usd_driver; 124 | 125 | int usd_open_r(struct _reent* r, const char* path, int flags, int mode) { 126 | FRESULT result = vexFileMountSD(); 127 | if (result != F_OK) { 128 | r->_errno = FRESULTMAP[result]; 129 | return -1; 130 | } 131 | 132 | usd_file_arg_t* file_arg = kmalloc(sizeof(*file_arg)); 133 | 134 | switch (flags & O_ACCMODE) { 135 | case O_RDONLY: 136 | file_arg->ifi_fptr = vexFileOpen(path, ""); // mode is ignored 137 | break; 138 | case O_WRONLY: 139 | if (flags & O_APPEND) { 140 | file_arg->ifi_fptr = vexFileOpenWrite(path); 141 | } else { 142 | file_arg->ifi_fptr = vexFileOpenCreate(path); 143 | } 144 | break; 145 | default: 146 | r->_errno = EINVAL; 147 | return -1; 148 | } 149 | 150 | if (!file_arg->ifi_fptr) { 151 | r->_errno = ENFILE; // up to 8 files max as of vexOS 0.7.4b55 152 | return -1; 153 | } 154 | return vfs_add_entry_r(r, usd_driver, file_arg); 155 | } 156 | -------------------------------------------------------------------------------- /src/system/dev/vfs.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file system/dev/vfs.c 3 | * 4 | * Virtual File System 5 | * 6 | * VFS is responsible for maintaining the global file table and routing all 7 | * basic I/O to the appropriate driver. There are three drivers implemented, 8 | * ser, dev, and usd which correspond to the serial driver, generic smart port 9 | * communication, and microSD card, respectively. 10 | * 11 | * VFS implements all of the I/O newlib stubs like open/read/write and delegates 12 | * them to the file's driver. Drivers don't actually have any knowledge of the 13 | * fileno. A file number maps to a driver and driver argument, which would be 14 | * whatever metadata the driver needs to open the file 15 | * 16 | * Copyright (c) 2017-2021, Purdue University ACM SIGBots 17 | * All rights reserved. 18 | * 19 | * This Source Code Form is subject to the terms of the Mozilla Public 20 | * License, v. 2.0. If a copy of the MPL was not distributed with this 21 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 22 | */ 23 | 24 | #include "system/dev/vfs.h" 25 | 26 | #include "common/gid.h" 27 | #include "kapi.h" 28 | #include "system/dev/dev.h" 29 | #include "system/dev/ser.h" 30 | #include "system/dev/usd.h" 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #define MAX_FILELEN 128 37 | #define MAX_FILES_OPEN 31 38 | 39 | #define RESERVED_FILENOS 4 // reserve stdin, stdout, stderr, kdbg 40 | 41 | // gids bitmap buffer 42 | static uint32_t file_table_bmp[gid_size_to_words(MAX_FILES_OPEN)]; 43 | // the gid structure itself 44 | static struct gid_metadata file_table_gids = { 45 | .bitmap = file_table_bmp, 46 | .max = MAX_FILES_OPEN, 47 | .reserved = RESERVED_FILENOS, 48 | .bitmap_size = gid_size_to_words(MAX_FILES_OPEN) 49 | }; 50 | 51 | // file table mapping a file descriptor number to a driver and driver argument 52 | static struct file_entry file_table[MAX_FILES_OPEN]; 53 | 54 | void vfs_initialize(void) { 55 | gid_init(&file_table_gids); 56 | 57 | ser_initialize(); 58 | 59 | // Force _GLOBAL_REENT initialization for C++ stdio to work. See D97 60 | extern void __sinit(struct _reent * s); 61 | if (!_GLOBAL_REENT->__cleanup) 62 | __sinit(_GLOBAL_REENT); 63 | } 64 | 65 | // adds an entry to the the file system 66 | int vfs_add_entry_r(struct _reent* r, struct fs_driver const* const driver, void* arg) { 67 | uint32_t gid = gid_alloc(&file_table_gids); 68 | if (gid == 0) { 69 | r->_errno = ENFILE; 70 | return -1; 71 | } 72 | 73 | file_table[gid].driver = driver; 74 | file_table[gid].arg = arg; 75 | return gid; 76 | } 77 | 78 | // update a given fileno driver and arg. Used by ser_driver_initialize to 79 | // initialize stdout, stdin, stderr, and kdbg 80 | int vfs_update_entry(int file, struct fs_driver const* const driver, void* arg) { 81 | if (file < 0 || !gid_check(&file_table_gids, file)) { 82 | kprintf("BAD vfs update %d", file); 83 | return -1; 84 | } 85 | if (driver != NULL) { 86 | file_table[file].driver = driver; 87 | } 88 | if (arg != (void*)-1) { 89 | file_table[file].arg = arg; 90 | } 91 | return 0; 92 | } 93 | 94 | int _open(const char* file, int flags, int mode) { 95 | struct _reent* r = _REENT; 96 | // Check if the filename is too long or not NULL terminated 97 | size_t i = 0; 98 | for (i = 0; i < MAX_FILELEN; i++) { 99 | if (file[i] == '\0') { 100 | break; 101 | } 102 | } 103 | if (i == MAX_FILELEN) { 104 | r->_errno = ENAMETOOLONG; 105 | return -1; 106 | } 107 | if (strstr(file, "/ser") == file) { 108 | // is a serial pseudofile 109 | return ser_open_r(r, file + strlen("/ser"), flags, mode); 110 | } else if (strstr(file, "/usd") == file) { 111 | return usd_open_r(r, file + strlen("/usd"), flags, mode); 112 | //} else if (strstr(file, "/dev") == file) { 113 | // return dev_open_r(r, file + strlen("/dev"), flags, mode); 114 | } else { 115 | return usd_open_r(r, file, flags, mode); 116 | } 117 | } 118 | 119 | ssize_t _write(int file, const void* buf, size_t len) { 120 | struct _reent* r = _REENT; 121 | if (file < 0 || !gid_check(&file_table_gids, file)) { 122 | r->_errno = EBADF; 123 | kprintf("BAD write %d", file); 124 | return -1; 125 | } 126 | return file_table[file].driver->write_r(r, file_table[file].arg, buf, len); 127 | } 128 | 129 | ssize_t _read(int file, void* buf, size_t len) { 130 | struct _reent* r = _REENT; 131 | if (file < 0 || !gid_check(&file_table_gids, file)) { 132 | r->_errno = EBADF; 133 | kprintf("BAD read %d", file); 134 | return -1; 135 | } 136 | return file_table[file].driver->read_r(r, file_table[file].arg, buf, len); 137 | } 138 | 139 | int _close(int file) { 140 | struct _reent* r = _REENT; 141 | // NOTE: newlib automatically closes all open files for a given task when 142 | // the task is deleted. 143 | if (file > 0 && file < RESERVED_FILENOS) { 144 | // Do not close the reserved file handles 145 | return 0; 146 | } 147 | if (file < 0 || !gid_check(&file_table_gids, file)) { 148 | r->_errno = EBADF; 149 | kprintf("BAD close %d", file); 150 | return -1; 151 | } 152 | int ret = file_table[file].driver->close_r(r, file_table[file].arg); 153 | if (ret == 0) { 154 | gid_free(&file_table_gids, file); 155 | } 156 | return ret; 157 | } 158 | 159 | int _fstat(int file, struct stat* st) { 160 | struct _reent* r = _REENT; 161 | if (file < 0 || !gid_check(&file_table_gids, file)) { 162 | r->_errno = EBADF; 163 | kprintf("BAD fstat %d", file); 164 | return -1; 165 | } 166 | return file_table[file].driver->fstat_r(r, file_table[file].arg, st); 167 | } 168 | 169 | off_t _lseek(int file, off_t ptr, int dir) { 170 | struct _reent* r = _REENT; 171 | if (file < 0 || !gid_check(&file_table_gids, file)) { 172 | r->_errno = EBADF; 173 | kprintf("BAD lseek %d", file); 174 | return -1; 175 | } 176 | return file_table[file].driver->lseek_r(r, file_table[file].arg, ptr, dir); 177 | } 178 | 179 | int _isatty(int file) { 180 | struct _reent* r = _REENT; 181 | if (file < 0 || !gid_check(&file_table_gids, file)) { 182 | r->_errno = EBADF; 183 | kprintf("BAD isatty %d", file); 184 | return -1; 185 | } 186 | return file_table[file].driver->isatty_r(r, file_table[file].arg); 187 | } 188 | 189 | int32_t fdctl(int file, const uint32_t action, void* const extra_arg) { 190 | if (file < 0 || !gid_check(&file_table_gids, file)) { 191 | errno = EBADF; 192 | return -1; 193 | } 194 | return file_table[file].driver->ctl(file_table[file].arg, action, extra_arg); 195 | } 196 | -------------------------------------------------------------------------------- /src/system/envlock.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file system/envlock.c 3 | * 4 | * environment lock newlib stubs 5 | * 6 | * Contains implementations of environment-locking functions for newlib. 7 | * 8 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 9 | * All rights reserved. 10 | * 11 | * This Source Code Form is subject to the terms of the Mozilla Public 12 | * License, v. 2.0. If a copy of the MPL was not distributed with this 13 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 | */ 15 | 16 | #include "rtos/task.h" 17 | 18 | void __env_lock(void) { 19 | rtos_suspend_all(); 20 | } 21 | 22 | void __env_unlock(void) { 23 | rtos_resume_all(); 24 | } 25 | -------------------------------------------------------------------------------- /src/system/mlock.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file system/mlock.c 3 | * 4 | * memory lock newlib stubs 5 | * 6 | * Contains implementations of memory-locking functions for newlib. 7 | * 8 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 9 | * All rights reserved. 10 | * 11 | * This Source Code Form is subject to the terms of the Mozilla Public 12 | * License, v. 2.0. If a copy of the MPL was not distributed with this 13 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 | */ 15 | 16 | #include "rtos/task.h" 17 | 18 | void __malloc_lock(void) { 19 | rtos_suspend_all(); 20 | } 21 | 22 | void __malloc_unlock(void) { 23 | rtos_resume_all(); 24 | } 25 | -------------------------------------------------------------------------------- /src/system/startup.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file system/startup.cpp 3 | * 4 | * Contains the main startup code for PROS 3.0. main is called from vexStartup 5 | * code. Our main() initializes data structures and starts the FreeRTOS 6 | * scheduler. 7 | * 8 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 9 | * All rights reserved. 10 | * 11 | * This Source Code Form is subject to the terms of the Mozilla Public 12 | * License, v. 2.0. If a copy of the MPL was not distributed with this 13 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 | */ 15 | 16 | #include "pros/competition.hpp" 17 | #include "pros/rtos.hpp" 18 | #include "v5_api_patched.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | 26 | extern "C" { 27 | // Initialization routines provided elsewhere 28 | void rtos_initialize(); 29 | void vfs_initialize(); 30 | void rtos_sched_start(); 31 | void __libc_init_array(); 32 | } 33 | 34 | // this goes in the first 32-byte chunk of the user program 35 | // which is why the entrypoint is offset from 0x3800000 by 0x20 36 | // only the first 16 bytes of this chunk is used however 37 | // see the vcodesig definition in the SDK for more details 38 | [[gnu::section(".boot_data")]] 39 | vcodesig boot_data = { 40 | .magic = V5_SIG_MAGIC, 41 | .type = V5_SIG_TYPE_USER, 42 | .owner = V5_SIG_OWNER_PARTNER, 43 | .options = V5_SIG_OPTIONS_NONE, 44 | }; 45 | 46 | // The pros_init function is executed early (via constructor attribute) 47 | [[gnu::constructor(101)]] 48 | static void pros_init() { 49 | rtos_initialize(); 50 | vfs_initialize(); 51 | } 52 | 53 | // forward-declare main function 54 | int main(); 55 | 56 | // Program entrypoint. This is the first function that is run. 57 | // It sets up memory, calls constructors, and starts the scheduler 58 | extern "C" [[gnu::section(".boot")]] 59 | void _start() { 60 | // Symbols provided by the linker script 61 | extern uint32_t __bss_start; 62 | extern uint32_t __bss_end; 63 | extern uint32_t __sbss_start; 64 | extern uint32_t __sbss_end; 65 | // don't try refactoring this code with stuff like std::fill or std::span. 66 | // It's been tried before, and it causes UB. 67 | // It's suspected that this is due to libc not being initialized yet. 68 | for (uint32_t* bss = &__bss_start; bss < &__bss_end; bss++) 69 | *bss = 0; 70 | for (uint32_t* sbss = &__sbss_start; sbss < &__sbss_end; sbss++) 71 | *sbss = 0; 72 | 73 | // call global constructors 74 | __libc_init_array(); 75 | 76 | // start main task 77 | // these pragmas are needed to silence the same warning on clang and gcc 78 | // normally you aren't supposed to reference the main function 79 | #pragma GCC diagnostic push 80 | #pragma GCC diagnostic ignored "-Wpedantic" 81 | #pragma GCC diagnostic ignored "-Wunknown-pragmas" 82 | #pragma clang diagnostic push 83 | #pragma clang diagnostic ignored "-Wmain" 84 | pros::Task main_task([]() { 85 | // run the main function 86 | main(); 87 | // initialize the competition control task 88 | zest::competition::initialize(); 89 | }); 90 | #pragma clang diagnostic pop 91 | #pragma GCC diagnostic pop 92 | 93 | // start the scheduler 94 | rtos_sched_start(); 95 | 96 | // If execution reaches here, the scheduler has failed. 97 | vexDisplayPrintf(10, 60, 1, "failed to start scheduler\n"); 98 | std::printf("Failed to start Scheduler\n"); 99 | _exit(0); // exit with code 0 to stop spinlock 100 | } 101 | -------------------------------------------------------------------------------- /src/system/stubs.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file system/stubs.cpp 3 | * 4 | * Port of newlib to PROS for the V5 5 | * 6 | * Contains the various methods needed to enable standard C library support 7 | * through the use of the Arm-distributed implementation of newlib. 8 | * 9 | * Also implements some VEX SDK functions that need custom functionality 10 | * 11 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 12 | * All rights reserved. 13 | * 14 | * This Source Code Form is subject to the terms of the Mozilla Public 15 | * License, v. 2.0. If a copy of the MPL was not distributed with this 16 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 17 | */ 18 | 19 | #include "pros/competition.hpp" 20 | #include "rtos/task.h" 21 | #include "v5_api_patched.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | constexpr uint32_t SEC_TO_MSEC = 1000; 31 | constexpr uint32_t SEC_TO_MICRO = 1000000; 32 | constexpr uint32_t MICRO_TO_NANO = 1000; 33 | 34 | extern "C" { 35 | 36 | // external functions 37 | void vexTasksRun(); 38 | void __libc_fini_array(); 39 | 40 | // We just need these symbols so the program can link 41 | void _init() {} 42 | 43 | void _fini() {} 44 | 45 | void __vex_function_prolog() {} 46 | 47 | uint32_t __vex_critical_section = 0; 48 | 49 | // There's only ever one process 50 | int _getpid() { 51 | return 1; 52 | } 53 | 54 | // kill a process, but since there's only 55 | // one process, if the ID isn't 1, 56 | // then don't do anything 57 | int _kill(int pid, int sig) { 58 | if (pid == 1) { 59 | _exit(sig); 60 | } 61 | return 0; 62 | } 63 | 64 | caddr_t _sbrk(int incr) { 65 | // these addresses are defined in the v5.ld (the linker script) 66 | extern char _HEAP_START; 67 | extern char _HEAP_END; 68 | 69 | static char* current_heap = &_HEAP_START; 70 | char* prev_heap = current_heap; 71 | 72 | // Check if incrementing current_heap would exceed the HEAP region. 73 | if (current_heap + incr > &_HEAP_END) { 74 | errno = ENOMEM; 75 | return reinterpret_cast(-1); 76 | } 77 | current_heap += incr; 78 | return reinterpret_cast(prev_heap); 79 | } 80 | 81 | // We don't have to deal with shared objects, so this is only here 82 | // so everything links properly. 83 | // See https://stackoverflow.com/questions/34308720/where-is-dso-handle-defined 84 | [[gnu::visibility("hidden")]] 85 | extern const void* const __dso_handle = &__dso_handle; 86 | 87 | // This function is called by functions like std::abort. 88 | // it's not called on a normal program exit, 89 | // even though it probably should. 90 | void _exit(int status) { 91 | // dprintf doesn't work after freeRTOS is suspended 92 | // so it's run first 93 | if (status != 0) 94 | dprintf(3, "FATAL ERROR, status %d", status); // kprintf 95 | 96 | // flush stdio 97 | fflush(stdout); 98 | std::cout.flush(); 99 | // flush intermediary buffers 100 | extern void ser_output_flush(); 101 | ser_output_flush(); 102 | 103 | // suspend all tasks 104 | rtos_suspend_all(); 105 | 106 | // wait for vexos to flush the serial buffers 107 | const uint32_t start_time = millis(); 108 | constexpr uint32_t max_flush_time = 50; 109 | while (vexSerialWriteFree(1) != 2048 || millis() - start_time > max_flush_time) { 110 | vexTasksRun(); 111 | } 112 | 113 | // call libc destructors 114 | __libc_fini_array(); 115 | 116 | // request to exit the program 117 | vexSystemExitRequest(); 118 | // the exit request isn't instant, 119 | // so we poll vexTasksRun() while we wait 120 | while (true) 121 | vexTasksRun(); 122 | } 123 | 124 | // sleep for a number of microseconds 125 | int usleep(useconds_t period) { 126 | // Compromise: If the delay is in microsecond range, it will block threads. 127 | // if not, it will not block threads but not be accurate to the microsecond range. 128 | // This limitation is due to the scheduler quanta being 1 millisecond 129 | if (period >= 1000) { 130 | task_delay(period / SEC_TO_MSEC); 131 | return 0; 132 | } 133 | uint64_t endTime = vexSystemHighResTimeGet() + period; 134 | while (vexSystemHighResTimeGet() < endTime) 135 | asm volatile("nop"); 136 | return 0; 137 | } 138 | 139 | // sleep for a number of seconds 140 | unsigned sleep(unsigned period) { 141 | task_delay(period * SEC_TO_MSEC); 142 | return 1; 143 | } 144 | 145 | // get entropy. ZestCode does not implement this function, but other 146 | // libraries can, which is why this function is marked as weak 147 | [[gnu::weak]] 148 | int getentropy(void* _buffer, size_t _length) { 149 | errno = ENOSYS; 150 | return -1; 151 | } 152 | 153 | // These variables are used to store the user-set time. 154 | // When user_time_set is false, the realtime clock will use the timestamp as the 155 | // base time. When it is true will use user_time_spec as the base time instead. 156 | // set_microseconds stores the value of the microsecond timer when the user set 157 | // the time. 158 | static bool user_time_set = false; 159 | static struct timespec user_time_spec; 160 | static int64_t set_microseconds = 0; 161 | 162 | int clock_settime(clockid_t clock_id, const struct timespec* tp) { 163 | if (tp == NULL) { 164 | errno = EINVAL; 165 | return -1; 166 | } 167 | 168 | int retval = -1; 169 | 170 | switch (clock_id) { 171 | case CLOCK_REALTIME: 172 | user_time_set = true; 173 | user_time_spec = *tp; 174 | set_microseconds = vexSystemHighResTimeGet(); 175 | retval = 0; 176 | default: 177 | errno = EINVAL; 178 | } 179 | 180 | return retval; 181 | } 182 | 183 | int clock_gettime(clockid_t clock_id, struct timespec* tp) { 184 | if (tp == NULL) { 185 | errno = EINVAL; 186 | return -1; 187 | } 188 | 189 | struct timeval tv; 190 | int retval = -1; 191 | 192 | switch (clock_id) { 193 | case CLOCK_REALTIME: 194 | retval = gettimeofday(&tv, NULL); 195 | if (!retval) 196 | TIMEVAL_TO_TIMESPEC(&tv, tp); 197 | break; 198 | case CLOCK_MONOTONIC: { 199 | uint64_t totalTime = vexSystemHighResTimeGet(); 200 | uint64_t secs = totalTime / SEC_TO_MICRO; 201 | uint64_t micros = totalTime - secs * SEC_TO_MICRO; 202 | 203 | tp->tv_sec = secs; 204 | tp->tv_nsec = micros * MICRO_TO_NANO; 205 | break; 206 | } 207 | default: 208 | errno = EINVAL; 209 | break; 210 | } 211 | 212 | return retval; 213 | } 214 | 215 | // HACK: 216 | // 217 | // This function pointer serves as a callback so that _gettimeofday() can call 218 | // a function inside the hot package. Without this, _gettimeofday() cannot 219 | // access any symbols in the hot package (where _PROS_COMPILE_TIMESTAMP_INT 220 | // lives), and linker errors occur. 221 | // 222 | // When the hot package is initialized, it calls set_get_timestamp_int_func() 223 | // and sets the callback to a function that returns the unix timestamp. 224 | // 225 | // Essentially, when the hot process starts: 226 | // 1) Pass the get_timestamp_int_func to the cold package 227 | // 2) When the cold package (this library) needs to access the timestamp, 228 | // call the callback 229 | // 3) Then the cold package 230 | static const int (*get_timestamp_int_func)(void) = NULL; 231 | 232 | void set_get_timestamp_int_func(const int (*func)(void)) { 233 | get_timestamp_int_func = func; 234 | } 235 | 236 | int _gettimeofday(struct timeval* tp, void* tzvp) { 237 | if (get_timestamp_int_func == nullptr) { 238 | return -1; 239 | } 240 | 241 | if (user_time_set) { 242 | tp->tv_sec = user_time_spec.tv_sec; 243 | tp->tv_usec = user_time_spec.tv_nsec * 1000; 244 | tp->tv_usec += vexSystemHighResTimeGet() - set_microseconds; 245 | } else if (zest::competition::is_connected()) { 246 | // TODO: update this to get the date/time through VexOS. Apparently, 247 | // the time is kept properly only when competition controls are 248 | // connected. I haven't had time to check or confirm this. 249 | // https://github.com/purduesigbots/pros/pull/127#issuecomment-1095361338 250 | tp->tv_sec = get_timestamp_int_func(); 251 | tp->tv_usec = vexSystemHighResTimeGet(); 252 | } else { 253 | // When competition isn't connected, the vex's date/time functions do 254 | // not work. Here we use a timestamp compiled into the program and then 255 | // add the number of microseconds the program has been running to get 256 | // the best estimate. 257 | tp->tv_sec = get_timestamp_int_func(); 258 | tp->tv_usec = vexSystemHighResTimeGet(); 259 | } 260 | 261 | return 1; 262 | } 263 | } // extern "C" 264 | -------------------------------------------------------------------------------- /src/system/system_daemon.cpp: -------------------------------------------------------------------------------- 1 | #include "kapi.h" 2 | #include "pros/devices/brain.hpp" 3 | #include "pros/rtos.hpp" 4 | 5 | extern "C" { 6 | void vexTasksRun(); 7 | void ser_output_flush(); 8 | } 9 | 10 | namespace zest { 11 | 12 | // This task runs for the lifetime of the program. 13 | // It periodically calls vexTasksRun, which copies shared memory to/from vexOS. 14 | static pros::Task system_daemon([]() { 15 | while (true) { 16 | // lock all smart port mutexes 17 | Brain::smart_port_mutex_lock_all(); 18 | // flush serial output 19 | ser_output_flush(); 20 | // suspend all tasks 21 | rtos_suspend_all(); 22 | // copy shared memory 23 | vexTasksRun(); 24 | // resume all tasks 25 | rtos_resume_all(); 26 | // unlock all smart port mutexes 27 | zest::Brain::smart_port_mutex_unlock_all(); 28 | 29 | // delay to save resources 30 | pros::delay(2); 31 | } 32 | }, TASK_PRIORITY_MAX); 33 | 34 | } // namespace zest -------------------------------------------------------------------------------- /src/system/xilinx_vectors.s: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * (c) Copyright 2009-13 Xilinx, Inc. All rights reserved. 4 | * 5 | * This file contains confidential and proprietary information of Xilinx, Inc. 6 | * and is protected under U.S. and international copyright and other 7 | * intellectual property laws. 8 | * 9 | * DISCLAIMER 10 | * This disclaimer is not a license and does not grant any rights to the 11 | * materials distributed herewith. Except as otherwise provided in a valid 12 | * license issued to you by Xilinx, and to the maximum extent permitted by 13 | * applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL 14 | * FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, 15 | * IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF 16 | * MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; 17 | * and (2) Xilinx shall not be liable (whether in contract or tort, including 18 | * negligence, or under any other theory of liability) for any loss or damage 19 | * of any kind or nature related to, arising under or in connection with these 20 | * materials, including for any direct, or any indirect, special, incidental, 21 | * or consequential loss or damage (including loss of data, profits, goodwill, 22 | * or any type of loss or damage suffered as a result of any action brought by 23 | * a third party) even if such damage or loss was reasonably foreseeable or 24 | * Xilinx had been advised of the possibility of the same. 25 | * 26 | * CRITICAL APPLICATIONS 27 | * Xilinx products are not designed or intended to be fail-safe, or for use in 28 | * any application requiring fail-safe performance, such as life-support or 29 | * safety devices or systems, Class III medical devices, nuclear facilities, 30 | * applications related to the deployment of airbags, or any other applications 31 | * that could lead to death, personal injury, or severe property or 32 | * environmental damage (individually and collectively, "Critical 33 | * Applications"). Customer assumes the sole risk and liability of any use of 34 | * Xilinx products in Critical Applications, subject only to applicable laws 35 | * and regulations governing limitations on product liability. 36 | * 37 | * THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE 38 | * AT ALL TIMES. 39 | * 40 | ******************************************************************************/ 41 | /*****************************************************************************/ 42 | /** 43 | * @file asm_vectors.s 44 | * 45 | * This file contains the initial vector table for the Cortex A9 processor 46 | * 47 | *
 48 | * MODIFICATION HISTORY:
 49 | *
 50 | * Ver   Who     Date     Changes
 51 | * ----- ------- -------- ---------------------------------------------------
 52 | * 1.00a ecm/sdm 10/20/09 Initial version
 53 | * 3.05a sdm	02/02/12 Save lr when profiling is enabled
 54 | * 3.10a srt     04/18/13 Implemented ARM Erratas. Please refer to file
 55 | *			 'xil_errata.h' for errata description
 56 | * 
57 | * 58 | * @note 59 | * 60 | * None. 61 | * 62 | ******************************************************************************/ 63 | 64 | //#include "xil_errata.h" 65 | #define CONFIG_ARM_ERRATA_775420 1 66 | 67 | .org 0 68 | .text 69 | .arm 70 | 71 | .global _boot 72 | .global _freertos_vector_table 73 | 74 | .global FIQInterrupt 75 | .global DataAbortInterrupt 76 | .global PrefetchAbortInterrupt 77 | .global vPortInstallFreeRTOSVectorTable 78 | 79 | .extern FreeRTOS_IRQ_Handler 80 | .extern FreeRTOS_SWI_Handler 81 | 82 | .section .freertos_vectors 83 | _freertos_vector_table: 84 | B _boot 85 | B FreeRTOS_Undefined 86 | ldr pc, _swi 87 | B FreeRTOS_PrefetchAbortHandler 88 | B FreeRTOS_DataAbortHandler 89 | NOP /* Placeholder for address exception vector*/ 90 | LDR PC, _irq 91 | B FreeRTOS_FIQHandler 92 | 93 | _irq: .word FreeRTOS_IRQ_Handler 94 | _swi: .word FreeRTOS_SWI_Handler 95 | 96 | 97 | .align 4 98 | FreeRTOS_FIQHandler: /* FIQ vector handler */ 99 | stmdb sp!,{r0-r3,r12,lr} /* state save from compiled code */ 100 | FIQLoop: 101 | blx FIQInterrupt /* FIQ vector */ 102 | ldmia sp!,{r0-r3,r12,lr} /* state restore from compiled code */ 103 | subs pc, lr, #4 /* adjust return */ 104 | 105 | .align 4 106 | FreeRTOS_Undefined: /* Undefined handler */ 107 | b . 108 | 109 | .align 4 110 | FreeRTOS_DataAbortHandler: /* Data Abort handler */ 111 | #ifdef CONFIG_ARM_ERRATA_775420 112 | dsb 113 | #endif 114 | stmdb sp!,{r0-r3,r12,lr} /* state save from compiled code */ 115 | blx DataAbortInterrupt /*DataAbortInterrupt :call C function here */ 116 | ldmia sp!,{r0-r3,r12,lr} /* state restore from compiled code */ 117 | subs pc, lr, #4 /* adjust return */ 118 | 119 | .align 4 120 | FreeRTOS_PrefetchAbortHandler: /* Prefetch Abort handler */ 121 | #ifdef CONFIG_ARM_ERRATA_775420 122 | dsb 123 | #endif 124 | stmdb sp!,{r0-r3,r12,lr} /* state save from compiled code */ 125 | blx PrefetchAbortInterrupt /* PrefetchAbortInterrupt: call C function here */ 126 | ldmia sp!,{r0-r3,r12,lr} /* state restore from compiled code */ 127 | subs pc, lr, #4 /* adjust return */ 128 | 129 | .align 4 130 | .type vPortInstallFreeRTOSVectorTable, %function 131 | vPortInstallFreeRTOSVectorTable: 132 | 133 | /* Set VBAR to the vector table that contains the FreeRTOS handlers. */ 134 | ldr r0, =_freertos_vector_table 135 | mcr p15, 0, r0, c12, c0, 0 136 | dsb 137 | isb 138 | bx lr 139 | 140 | 141 | .end 142 | -------------------------------------------------------------------------------- /subprojects/v5.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | url = https://github.com/ZestCommunity/libv5rt-meson.git 3 | revision = v1.2 4 | depth = 1 5 | 6 | [provide] 7 | v5 = v5_lib_dep 8 | v5_header = v5_header_dep -------------------------------------------------------------------------------- /tests/competition_task.cpp: -------------------------------------------------------------------------------- 1 | #include "pros/competition.hpp" 2 | #include "pros/rtos.hpp" 3 | 4 | #include 5 | 6 | extern "C" { 7 | void vexDisplayPrintf(int32_t xpos, int32_t ypos, uint32_t bOpaque, const char* format, ...); 8 | void vexDisplayErase(); 9 | } 10 | 11 | int main() { 12 | zest::competition::register_driver_control([]() { 13 | vexDisplayErase(); 14 | vexDisplayPrintf(10, 100, 1, "Driver Control Running\n"); 15 | vexDisplayPrintf(10, 60, 1, "num tasks: %u\n", pros::Task::get_count()); 16 | // infinite loop to test task priorities. If everything is working correctly, the 17 | // competition task will still switch when the competition state changes 18 | while (true) { 19 | asm("nop"); 20 | } 21 | }); 22 | zest::competition::register_autonomous([]() { 23 | vexDisplayErase(); 24 | vexDisplayPrintf(10, 100, 1, "Autonomous Running\n"); 25 | vexDisplayPrintf(10, 60, 1, "num tasks: %u\n", pros::Task::get_count()); 26 | // infinite loop to test task priorities. If everything is working correctly, the 27 | // competition task will still switch when the competition state changes 28 | while (true) { 29 | asm("nop"); 30 | } 31 | }); 32 | zest::competition::register_disabled([]() { 33 | vexDisplayErase(); 34 | vexDisplayPrintf(10, 100, 1, "Disabled Running\n"); 35 | vexDisplayPrintf(10, 60, 1, "num tasks: %u\n", pros::Task::get_count()); 36 | // infinite loop to test task priorities. If everything is working correctly, the 37 | // competition task will still switch when the competition state changes 38 | while (true) { 39 | asm("nop"); 40 | } 41 | }); 42 | 43 | vexDisplayPrintf(10, 60, 1, "demonstrating that tasks are run after main returns\n"); 44 | pros::delay(3000); 45 | vexDisplayErase(); 46 | } -------------------------------------------------------------------------------- /tests/errno_reentrancy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "api.h" 3 | #include "v5_api_patched.h" 4 | 5 | void task_a_fn(void* ign) { 6 | vexDisplayString(2, "Errno from A is: %d\n", errno); 7 | task_delay(1000); 8 | errno = ENOEXEC; 9 | while (1) { 10 | vexDisplayString(2, "Errno from A is: %d\n", errno); 11 | task_delay(10); 12 | } 13 | } 14 | 15 | void task_b_fn(void* ign) { 16 | while (1) { 17 | vexDisplayString(3, "Errno from B is: %d\n", errno); 18 | task_delay(10); 19 | } 20 | } 21 | 22 | void test_errno_reentrancy() { 23 | task_create(task_a_fn, NULL, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "Task A"); 24 | task_create(task_b_fn, NULL, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "Task B"); 25 | } 26 | -------------------------------------------------------------------------------- /tests/examples/basic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" { 4 | void vexDisplayPrintf(int32_t xpos, int32_t ypos, uint32_t bOpaque, const char* format, ...); 5 | } 6 | 7 | int main() { 8 | vexDisplayPrintf(10, 60, 1, "Hello World!\n"); 9 | } -------------------------------------------------------------------------------- /tests/exceptions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "v5_api_patched.h" 5 | 6 | #include "rtos/FreeRTOS.h" 7 | #include "rtos/task.h" 8 | 9 | extern "C" void throw_it() { 10 | throw std::runtime_error("RT err in function"); 11 | } 12 | 13 | extern "C" void test_exceptions() { 14 | vexDisplayErase(); 15 | vexDisplayString(0, "Starting test"); 16 | throw_it(); 17 | vexDisplayString(3, "it didn't work"); 18 | } 19 | -------------------------------------------------------------------------------- /tests/mutexes.c: -------------------------------------------------------------------------------- 1 | void test_mutex() { 2 | mutex_t mut = mutex_create(); 3 | 4 | mutex_take(mut, TIMEOUT_MAX); 5 | 6 | mutex_give(mut); 7 | } 8 | -------------------------------------------------------------------------------- /tests/result.cpp: -------------------------------------------------------------------------------- 1 | #include "common/result.hpp" 2 | 3 | #include 4 | #include 5 | 6 | // there'll be a lot of unused variables, since we just want to see if it compiles 7 | #pragma GCC diagnostic ignored "-Wunused-variable" 8 | 9 | class MyError : public zest::ResultError {}; 10 | 11 | class MyError2 : public zest::ResultError {}; 12 | 13 | zest::Result test_function_1() { 14 | // return nothing 15 | return {}; 16 | // return MyError 17 | return MyError(); 18 | } 19 | 20 | zest::Result test_function_2() { 21 | // return an integer 22 | return 1; 23 | // return MyError 24 | return MyError(); 25 | } 26 | 27 | constexpr void compile_time_tests() { 28 | // test sentinel values 29 | static_assert(zest::sentinel_v == INT32_MAX); 30 | static_assert(zest::sentinel_v == std::numeric_limits::infinity()); 31 | 32 | { 33 | // test comparison operator 34 | static_assert(zest::Result(2) == zest::Result(2)); 35 | static_assert(zest::Result(3) == zest::Result(3)); 36 | static_assert(zest::Result(0) == 0); 37 | static_assert(0 == zest::Result(0)); 38 | static_assert(0.0 == zest::Result(0)); 39 | static_assert(zest::Result(0) == 0.0); 40 | } 41 | 42 | { 43 | // test conversion operators 44 | zest::Result a = 2; 45 | int& b = a; 46 | const int& c = a; 47 | int&& d = zest::Result(2); 48 | const int&& e = zest::Result(2); 49 | int f = a; 50 | } 51 | 52 | { 53 | // test error getting 54 | static_assert(zest::Result(MyError()).get()); 55 | static_assert(!zest::Result(1).get()); 56 | static_assert(zest::Result(1).get()); 57 | static_assert(zest::Result(1).get()); 58 | } 59 | } 60 | 61 | void runtime_tests() {} 62 | -------------------------------------------------------------------------------- /tests/rtos_function_linking.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file tests/rtos_function_linking.c 3 | * 4 | * Test that all the FreeRTOS functions link correctly. 5 | * 6 | * Do not actually run this test - just make sure it compiles 7 | * 8 | * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. 9 | * All rights reserved. 10 | * 11 | * This Source Code Form is subject to the terms of the Mozilla Public 12 | * License, v. 2.0. If a copy of the MPL was not distributed with this 13 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 | */ 15 | 16 | #include "api.h" 17 | 18 | void x(void* ign) {} 19 | void test_all() { 20 | task_delete(task_create(x, NULL, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "no name")); 21 | task_delay(1); 22 | 23 | task_delay_until(NULL, 3); 24 | 25 | task_get_priority(NULL); 26 | 27 | task_set_priority(NULL, 4); 28 | 29 | task_get_state(NULL); 30 | 31 | task_suspend(NULL); 32 | task_resume(NULL); 33 | 34 | task_get_count(); 35 | 36 | task_get_name(NULL); 37 | 38 | task_get_by_name("Hello"); 39 | 40 | task_notify(NULL); 41 | 42 | task_notify_ext(NULL, 4, E_NOTIFY_ACTION_NONE, NULL); 43 | 44 | task_notify_take(false, MAX_TIMEOUT); 45 | 46 | task_notify_clear(NULL); 47 | 48 | mutex_t mutex = mutex_create(); 49 | mutex_take(mutex, MAX_TIMEOUT); 50 | mutex_give(mutex); 51 | 52 | sem_t sem = sem_create(4, 0); 53 | sem_wait(sem, MAX_TIMEOUT); 54 | sem_post(sem); 55 | } 56 | -------------------------------------------------------------------------------- /tests/segfault.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | [[gnu::noinline]] static void thing_1(uint8_t i) { 4 | printf("thing_1(%i)\n", i); 5 | if (i == 0) { 6 | asm volatile("mov r0, #0 \n\tSTR sp, [r0]\n\t"); 7 | } else { 8 | thing_1(i - 1); 9 | printf("%s", "Never prints!"); 10 | } 11 | } 12 | 13 | 14 | 15 | /** 16 | * Runs initialization code. This occurs as soon as the program is started. 17 | * 18 | * All other competition modes are blocked by initialize; it is recommended 19 | * to keep execution time for this mode under a few seconds. 20 | */ 21 | void initialize() { 22 | printf("%s", "Hello world!"); 23 | thing_1(10); 24 | } 25 | 26 | void disabled() {} 27 | 28 | void competition_initialize() {} 29 | 30 | void autonomous() {} 31 | 32 | void opcontrol() {} -------------------------------------------------------------------------------- /tests/static_tast_states.c: -------------------------------------------------------------------------------- 1 | // This test is mostly verifying that the idle task isn't being starved 2 | 3 | #include 4 | 5 | #include "rtos/FreeRTOS.h" 6 | #include "rtos/task.h" 7 | 8 | #define STACK_SIZE 0x2000 9 | 10 | task_stack_t staticTaskStack[STACK_SIZE]; 11 | static_task_s_t staticTaskTask; 12 | task_t staticTaskHandle; 13 | 14 | void myStaticTask(void*); 15 | // the task_delay(5) SHOULD NOT BE REQUIRED but FreeRTOS is buggy af 16 | void myTask(void* ign) { 17 | printf("myTask %d task_notify_take\n", __LINE__); 18 | task_delay(10); 19 | task_notify_take(true, 0xffffffffUL); 20 | printf("myTask %d task_create_static\n", __LINE__); 21 | task_delay(10); 22 | task_create_static(myStaticTask, NULL, 8, STACK_SIZE, "My Static Task", staticTaskStack, &staticTaskTask); 23 | printf("myTask %d task_delete\n", __LINE__); 24 | task_delay(10); 25 | task_delete(NULL); 26 | } 27 | 28 | void myStaticTask(void* ign) { 29 | printf("myStaticTask %d task_create\n", __LINE__); 30 | task_delay(10); 31 | task_t task = task_create(myTask, NULL, 8, STACK_SIZE, "My Task"); 32 | printf("myStaticTask %d task_notify %p\n", __LINE__, task); 33 | task_delay(10); 34 | task_notify(task); 35 | printf("myStaticTask %d task_delete\n", __LINE__); 36 | task_delay(10); 37 | task_delete(NULL); 38 | } 39 | 40 | void opcontrol() { 41 | task_create_static(myStaticTask, NULL, 8, STACK_SIZE, "My Static Task", staticTaskStack, &staticTaskTask); 42 | } 43 | -------------------------------------------------------------------------------- /tests/task_notify_when_deleting.c: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "pros/apix.h" 3 | 4 | void target_task(void* ignore) { 5 | lcd_print(0, "%s says hello", task_get_name(NULL)); 6 | task_delay(1000); 7 | lcd_print(0, "I don't feel so good - %s", task_get_name(NULL)); 8 | } 9 | 10 | void notify_task(void* ignore) { 11 | lcd_set_text(2, "I don't know - I don't know what's happening"); 12 | task_notify_take(true, TIMEOUT_MAX); 13 | lcd_set_text(4, "God damn you all to hell!"); 14 | } 15 | 16 | void opcontrol() { 17 | task_t peter = task_create(target_task, NULL, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "Peter Parker"); 18 | task_notify_when_deleting(peter, NULL, 1, E_NOTIFY_ACTION_BITS); 19 | 20 | task_notify_take(true, TIMEOUT_MAX); 21 | lcd_set_text(1, "Are you alright?"); 22 | 23 | task_t peter2 = task_create(notify_task, NULL, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "Peter Parker's Son"); 24 | // task_delay(1000); 25 | task_notify_when_deleting(NULL, peter2, 1, E_NOTIFY_ACTION_INCR); 26 | // task_delay(1000); 27 | lcd_set_text(3, "Goodbye, cruel world!"); 28 | // task_delay(1000); 29 | } 30 | -------------------------------------------------------------------------------- /tests/unwind.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | class RaiiPrint { 4 | public: 5 | ~RaiiPrint() { 6 | std::cout << "unwinding works" << std::endl; 7 | } 8 | }; 9 | 10 | void initialize() { 11 | RaiiPrint raii_print; 12 | // time for the terminal to boot up 13 | pros::delay(3000); 14 | // cause a data abort exception. 15 | // if stack unwinding works, then the RaiiPrint destructor will be called. 16 | // we'll know it has been called because it will print to the terminal. 17 | throw ""; 18 | } --------------------------------------------------------------------------------