├── .clang-format ├── .devcontainer ├── Dockerfile ├── LICENSE ├── devcontainer.json └── packagelist ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── clang-format.yml │ ├── pr-comment.yml │ ├── pros-build-release.yml │ └── pros-build.yml ├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── Makefile ├── README.md ├── common.mk ├── firmware ├── libc.a ├── libm.a ├── libpros.a ├── v5-common.ld ├── v5-hot.ld └── v5.ld ├── include ├── api.h ├── gamepad │ ├── api.hpp │ ├── button.hpp │ ├── event_handler.hpp │ ├── gamepad.hpp │ ├── joystick_transformation.hpp │ ├── recursive_mutex.hpp │ ├── screens │ │ ├── abstractScreen.hpp │ │ ├── alertScreen.hpp │ │ └── defaultScreen.hpp │ └── todo.hpp ├── main.h └── pros │ ├── abstract_motor.hpp │ ├── adi.h │ ├── adi.hpp │ ├── apix.h │ ├── colors.h │ ├── colors.hpp │ ├── device.h │ ├── device.hpp │ ├── distance.h │ ├── distance.hpp │ ├── error.h │ ├── ext_adi.h │ ├── gps.h │ ├── gps.hpp │ ├── imu.h │ ├── imu.hpp │ ├── link.h │ ├── link.hpp │ ├── llemu.h │ ├── llemu.hpp │ ├── misc.h │ ├── misc.hpp │ ├── motor_group.hpp │ ├── motors.h │ ├── motors.hpp │ ├── optical.h │ ├── optical.hpp │ ├── rotation.h │ ├── rotation.hpp │ ├── rtos.h │ ├── rtos.hpp │ ├── screen.h │ ├── screen.hpp │ ├── serial.h │ ├── serial.hpp │ ├── vision.h │ └── vision.hpp ├── project.pros └── src ├── gamepad ├── button.cpp ├── gamepad.cpp ├── joystick_transformation.cpp └── screens │ ├── alertScreen.cpp │ └── defaultScreen.cpp └── main.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | AccessModifierOffset: 0 4 | AlignAfterOpenBracket: Align 5 | AlignArrayOfStructures: None 6 | AlignConsecutiveAssignments: None 7 | AlignConsecutiveBitFields: None 8 | AlignConsecutiveDeclarations: None 9 | AlignConsecutiveMacros: None 10 | AlignEscapedNewlines: Right 11 | AlignOperands: Align 12 | AlignTrailingComments: false 13 | AllowAllArgumentsOnNextLine: false 14 | AllowAllParametersOfDeclarationOnNextLine: false 15 | AllowShortBlocksOnASingleLine: Always 16 | AllowShortCaseLabelsOnASingleLine: true 17 | AllowShortEnumsOnASingleLine: true 18 | AllowShortFunctionsOnASingleLine: All 19 | AllowShortIfStatementsOnASingleLine: AllIfsAndElse 20 | AllowShortLambdasOnASingleLine: All 21 | AllowShortLoopsOnASingleLine: true 22 | AlwaysBreakAfterReturnType: None 23 | AlwaysBreakBeforeMultilineStrings: false 24 | AlwaysBreakTemplateDeclarations: No 25 | BinPackArguments: true 26 | BinPackParameters: true 27 | BitFieldColonSpacing: Both 28 | BreakBeforeBraces: Custom 29 | BraceWrapping: 30 | AfterCaseLabel: false 31 | AfterClass: false 32 | AfterControlStatement: Never 33 | AfterEnum: false 34 | AfterFunction: false 35 | AfterNamespace: false 36 | AfterObjCDeclaration: false 37 | AfterStruct: false 38 | AfterUnion: false 39 | AfterExternBlock: false 40 | BeforeCatch: false 41 | BeforeElse: false 42 | BeforeLambdaBody: false 43 | BeforeWhile: false 44 | IndentBraces: false 45 | SplitEmptyFunction: true 46 | SplitEmptyRecord: true 47 | SplitEmptyNamespace: true 48 | BreakAfterJavaFieldAnnotations: false 49 | BreakBeforeBinaryOperators: None 50 | BreakConstructorInitializers: BeforeColon 51 | BreakInheritanceList: BeforeColon 52 | BreakStringLiterals: true 53 | ColumnLimit: 120 54 | CompactNamespaces: false 55 | ConstructorInitializerIndentWidth: 4 56 | Cpp11BracedListStyle: true 57 | EmptyLineAfterAccessModifier: Never 58 | EmptyLineBeforeAccessModifier: Never 59 | IndentAccessModifiers: true 60 | IndentCaseLabels: true 61 | IndentExternBlock: AfterExternBlock 62 | IndentGotoLabels: true 63 | IndentWidth: 4 64 | IndentWrappedFunctionNames: false 65 | KeepEmptyLinesAtTheStartOfBlocks: false 66 | PackConstructorInitializers: Never 67 | PointerAlignment: Left 68 | ReferenceAlignment: Left 69 | ReflowComments: true 70 | SeparateDefinitionBlocks: Always 71 | SortIncludes: false 72 | SpaceBeforeAssignmentOperators: true 73 | SpaceBeforeCaseColon: false 74 | SpaceBeforeCpp11BracedList: true 75 | SpaceBeforeCtorInitializerColon: true 76 | SpaceBeforeInheritanceColon: true 77 | SpaceBeforeParens: ControlStatements 78 | SpaceBeforeRangeBasedForLoopColon: true 79 | SpaceBeforeSquareBrackets: false 80 | SpaceInEmptyBlock: false 81 | SpaceInEmptyParentheses: false 82 | SpacesInCStyleCastParentheses: false 83 | SpacesInConditionalStatement: false 84 | TabWidth: 4 85 | UseTab: Never -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.84 as builder 2 | 3 | RUN git clone https://github.com/vexide/vex-v5-qemu.git /vex-v5-qemu 4 | 5 | WORKDIR /vex-v5-qemu 6 | RUN cd packages/kernel; cargo build --target-dir /target/kernel 7 | 8 | # FIXME: This should probably be removed in the future since it's very fragile 9 | RUN rustup toolchain install nightly 10 | 11 | RUN cd packages/client-cli; cargo +nightly install --path . --root /target/client-cli 12 | 13 | FROM mcr.microsoft.com/devcontainers/cpp:1-noble 14 | # ------------ 15 | # Install Required Packages 16 | # ------------ 17 | RUN sudo apt-get update 18 | COPY ./.devcontainer/packagelist /packagelist 19 | RUN sudo apt-get -y install $(cat /packagelist | sed 's/\r//') 20 | RUN rm /packagelist # Cleanup image 21 | RUN sudo apt-get clean # Cleanup image 22 | 23 | # ------------ 24 | # Install Clangd 25 | # ------------ 26 | RUN curl -sLo clangd.zip $( \ 27 | curl -s https://api.github.com/repos/clangd/clangd/releases/latest \ 28 | | jq -r '[.assets[] | select(.name | test ("^clangd-linux"))][0].browser_download_url' \ 29 | ) \ 30 | && unzip clangd.zip -d /usr/local/share \ 31 | && mv /usr/local/share/clangd_*/ /usr/local/share/clangd \ 32 | && rm clangd.zip 33 | 34 | ENV PATH="$PATH:/usr/local/share/clangd/bin" 35 | 36 | # ------------ 37 | # Install PROS CLI 38 | # ------------ 39 | RUN pip install --break-system-packages pros-cli 40 | 41 | # ------------ 42 | # Install ARM Toolchain 43 | # ------------ 44 | COPY --from=ghcr.io/lemlib/pros-build:v2.0.2 /gcc-arm-none-eabi-10.3-2021.10 /usr/local/share/arm-none-eabi 45 | ENV PATH="$PATH:/usr/local/share/arm-none-eabi/bin" 46 | 47 | # Copy the simulator binary 48 | COPY --from=builder /target/client-cli/bin/client-cli /usr/local/bin/simulator 49 | 50 | # Clone pros kernel source so we can reference it when debugging 51 | COPY ./project.pros /project.pros 52 | ENV PROS_SOURCE_PATH="$HOME/.pros" 53 | RUN git clone https://github.com/purduesigbots/pros.git $PROS_SOURCE_PATH \ 54 | --depth 1 \ 55 | --branch $(\r\n\r\n`; 26 | 27 | const old_marker = new RegExp(marker.replace("\r\n", "\r?\n")).exec(old_body)?.[0] ?? marker; 28 | 29 | body = (old_body ?? "").split(old_marker)[0] + marker + body; 30 | await github.request('PATCH /repos/{owner}/{repo}/pulls/{pull_number}', { 31 | owner: owner, 32 | repo: repo, 33 | pull_number: issue_number, 34 | body: body, 35 | headers: { 36 | 'X-GitHub-Api-Version': '2022-11-28' 37 | } 38 | }) 39 | } 40 | 41 | const {owner, repo} = context.repo; 42 | const run_id = ${{github.event.workflow_run.id}}; 43 | 44 | const pull_head_sha = '${{github.event.workflow_run.head_sha}}'; 45 | 46 | /** @type {{old_body: string}} */ 47 | const {issue_number, old_body} = await (async () => { 48 | const pulls = await github.rest.pulls.list({owner, repo}); 49 | for await (const {data} of github.paginate.iterator(pulls)) { 50 | for (const pull of data) { 51 | if (pull.head.sha === pull_head_sha) { 52 | return {issue_number: pull.number, old_body: pull.body}; 53 | } 54 | } 55 | } 56 | return {}; 57 | })(); 58 | if (issue_number) { 59 | core.info(`Using pull request ${issue_number}`); 60 | } else { 61 | return core.error(`No matching pull request found`); 62 | } 63 | 64 | let old_sha = /\<\!-- commit-sha: (?[a-z0-9]+) --\>/i.exec(old_body)?.groups?.sha 65 | if (old_sha != undefined && pull_head_sha == old_sha) return core.error("Comment is already up-to-date!") 66 | 67 | const artifacts = await github.paginate( 68 | github.rest.actions.listWorkflowRunArtifacts, {owner, repo, run_id}); 69 | if (!artifacts.length) { 70 | return core.error(`No artifacts found, perhaps Build Template was skipped`); 71 | } 72 | const template = artifacts[0]; 73 | 74 | let body = `\n`; 75 | body +=`## Download the template for this pull request: \n\n`; 76 | body += `> [!NOTE] 77 | > This is auto generated from [\`${{ github.workflow }}\`](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})\n`; 78 | body += `- via manual download: [${template.name}.zip](https://nightly.link/${owner}/${repo}/actions/artifacts/${template.id}.zip)\n`; 79 | body += `- via PROS Integrated Terminal: \n \`\`\` 80 | curl -o ${template.name}.zip https://nightly.link/${owner}/${repo}/actions/artifacts/${template.id}.zip; 81 | pros c fetch ${template.name}.zip; 82 | pros c apply ${template.name}; 83 | rm ${template.name}.zip; 84 | \`\`\``; 85 | 86 | core.info(`Review thread message body: \n${body}`); 87 | 88 | await upsertComment(owner, repo, issue_number, 89 | "nightly-link", old_body, body); 90 | -------------------------------------------------------------------------------- /.github/workflows/pros-build-release.yml: -------------------------------------------------------------------------------- 1 | name: Build Release 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | build-release: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout Code 13 | uses: actions/checkout@v4 14 | - name: Build Template 15 | id: build_step 16 | uses: LemLib/pros-build@v2.0.2 17 | with: 18 | lib_folder_name: "gamepad" 19 | copy_readme_and_license_to_include: true 20 | no_commit_hash: true 21 | - name: Upload Template To Release 22 | uses: svenstaro/upload-release-action@v2 23 | with: 24 | file: ${{ github.workspace }}/${{ steps.build_step.outputs.name }} 25 | -------------------------------------------------------------------------------- /.github/workflows/pros-build.yml: -------------------------------------------------------------------------------- 1 | name: Build Template 2 | 3 | on: 4 | push: 5 | branches: "**" 6 | pull_request: 7 | branches: "**" 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Checkout Code 16 | uses: actions/checkout@v4 17 | - name: Build Template 18 | id: build_step 19 | uses: LemLib/pros-build@v2.0.2 20 | with: 21 | lib_folder_name: "gamepad" 22 | copy_readme_and_license_to_include: true 23 | - name: Upload Artifact 24 | uses: actions/upload-artifact@v4 25 | with: 26 | name: ${{ steps.build_step.outputs.name }} 27 | path: ${{ github.workspace }}/template/* 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.o 3 | *.obj 4 | 5 | # Executables 6 | *.bin 7 | *.elf 8 | 9 | # PROS 10 | bin/ 11 | .vscode/* 12 | .cache/ 13 | compile_commands.json 14 | temp.log 15 | temp.errors 16 | *.ini 17 | .d/ 18 | 19 | # CLion 20 | .idea/ 21 | 22 | # MacOS 23 | .DS_Store 24 | 25 | # Linux 26 | debug.log 27 | 28 | # Always include development settings 29 | !.vscode/settings.json -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "githubPullRequests.ignoredPullRequestBranches": [ 3 | "main" 4 | ], 5 | "conventionalCommits.scopes": [ 6 | "buttons", 7 | "display", 8 | "joysticks" 9 | ] 10 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | All files in this repository are licensed under the MIT license as follows, 2 | unless otherwise noted in another LICENSE file 3 | 4 | ===== BEGIN LICENSE ===== 5 | 6 | MIT License 7 | 8 | Copyright (c) 2024 Jamie Maki-Fern, Ayaan (ion098), and other contributors 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ######################### User configurable parameters ######################### 3 | # filename extensions 4 | CEXTS:=c 5 | ASMEXTS:=s S 6 | CXXEXTS:=cpp c++ cc 7 | 8 | # probably shouldn't modify these, but you may need them below 9 | ROOT=. 10 | FWDIR:=$(ROOT)/firmware 11 | BINDIR=$(ROOT)/bin 12 | SRCDIR=$(ROOT)/src 13 | INCDIR=$(ROOT)/include 14 | 15 | WARNFLAGS+= 16 | EXTRA_CFLAGS= 17 | EXTRA_CXXFLAGS= 18 | 19 | # Set to 1 to enable hot/cold linking 20 | USE_PACKAGE:=1 21 | 22 | # Add libraries you do not wish to include in the cold image here 23 | # EXCLUDE_COLD_LIBRARIES:= $(FWDIR)/your_library.a 24 | EXCLUDE_COLD_LIBRARIES:= 25 | 26 | # Set this to 1 to add additional rules to compile your project as a PROS library template 27 | IS_LIBRARY:=1 28 | LIBNAME:=gamepad 29 | VERSION:=0.3.0 30 | # EXCLUDE_SRC_FROM_LIB= $(SRCDIR)/unpublishedfile.c 31 | # this line excludes opcontrol.c and similar files 32 | EXCLUDE_SRC_FROM_LIB+=$(foreach file, $(SRCDIR)/main,$(foreach cext,$(CEXTS),$(file).$(cext)) $(foreach cxxext,$(CXXEXTS),$(file).$(cxxext))) 33 | 34 | # files that get distributed to every user (beyond your source archive) - add 35 | # whatever files you want here. This line is configured to add all header files 36 | # that are in the the include directory get exported 37 | TEMPLATE_FILES=$(INCDIR)/gamepad/*.h $(INCDIR)/gamepad/*.hpp 38 | 39 | .DEFAULT_GOAL=quick 40 | 41 | ################################################################################ 42 | ################################################################################ 43 | ########## Nothing below this line should be edited by typical users ########### 44 | -include ./common.mk 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gamepad 2 | VEX V5 Controller Utilities 3 | -------------------------------------------------------------------------------- /common.mk: -------------------------------------------------------------------------------- 1 | ARCHTUPLE=arm-none-eabi- 2 | DEVICE=VEX EDR V5 3 | 4 | MFLAGS=-mcpu=cortex-a9 -mfpu=neon-fp16 -mfloat-abi=softfp -Os -g 5 | CPPFLAGS=-D_POSIX_THREADS -D_UNIX98_THREAD_MUTEX_ATTRIBUTES -D_POSIX_TIMERS -D_POSIX_MONOTONIC_CLOCK 6 | GCCFLAGS=-ffunction-sections -fdata-sections -fdiagnostics-color -funwind-tables 7 | 8 | # Check if the llemu files in libvgl exist. If they do, define macros that the 9 | # llemu headers in the kernel repo can use to conditionally include the libvgl 10 | # versions 11 | ifneq (,$(wildcard ./include/liblvgl/llemu.h)) 12 | CPPFLAGS += -D_PROS_INCLUDE_LIBLVGL_LLEMU_H 13 | endif 14 | ifneq (,$(wildcard ./include/liblvgl/llemu.hpp)) 15 | CPPFLAGS += -D_PROS_INCLUDE_LIBLVGL_LLEMU_HPP 16 | endif 17 | 18 | WARNFLAGS+=-Wno-psabi 19 | 20 | SPACE := $() $() 21 | COMMA := , 22 | 23 | C_STANDARD?=gnu11 24 | CXX_STANDARD?=gnu++20 25 | 26 | DEPDIR := .d 27 | $(shell mkdir -p $(DEPDIR)) 28 | DEPFLAGS = -MT $$@ -MMD -MP -MF $(DEPDIR)/$$*.Td 29 | MAKEDEPFOLDER = -$(VV)mkdir -p $(DEPDIR)/$$(dir $$(patsubst $(BINDIR)/%, %, $(ROOT)/$$@)) 30 | RENAMEDEPENDENCYFILE = -$(VV)mv -f $(DEPDIR)/$$*.Td $$(patsubst $(SRCDIR)/%, $(DEPDIR)/%.d, $(ROOT)/$$<) && touch $$@ 31 | 32 | LIBRARIES+=$(wildcard $(FWDIR)/*.a) 33 | # Cannot include newlib and libc because not all of the req'd stubs are implemented 34 | EXCLUDE_COLD_LIBRARIES+=$(FWDIR)/libc.a $(FWDIR)/libm.a 35 | COLD_LIBRARIES=$(filter-out $(EXCLUDE_COLD_LIBRARIES), $(LIBRARIES)) 36 | wlprefix=-Wl,$(subst $(SPACE),$(COMMA),$1) 37 | LNK_FLAGS=--gc-sections --start-group $(strip $(LIBRARIES)) -lgcc -lstdc++ --end-group -T$(FWDIR)/v5-common.ld 38 | 39 | ASMFLAGS=$(MFLAGS) $(WARNFLAGS) 40 | CFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) $(GCCFLAGS) --std=$(C_STANDARD) 41 | CXXFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) $(GCCFLAGS) --std=$(CXX_STANDARD) 42 | LDFLAGS=$(MFLAGS) $(WARNFLAGS) -nostdlib $(GCCFLAGS) 43 | SIZEFLAGS=-d --common 44 | NUMFMTFLAGS=--to=iec --format %.2f --suffix=B 45 | 46 | AR:=$(ARCHTUPLE)ar 47 | # using arm-none-eabi-as generates a listing by default. This produces a super verbose output. 48 | # Using gcc accomplishes the same thing without the extra output 49 | AS:=$(ARCHTUPLE)gcc 50 | CC:=$(ARCHTUPLE)gcc 51 | CXX:=$(ARCHTUPLE)g++ 52 | LD:=$(ARCHTUPLE)g++ 53 | OBJCOPY:=$(ARCHTUPLE)objcopy 54 | SIZETOOL:=$(ARCHTUPLE)size 55 | READELF:=$(ARCHTUPLE)readelf 56 | STRIP:=$(ARCHTUPLE)strip 57 | 58 | ifneq (, $(shell command -v gnumfmt 2> /dev/null)) 59 | SIZES_NUMFMT:=| gnumfmt --field=-4 --header $(NUMFMTFLAGS) 60 | else 61 | ifneq (, $(shell command -v numfmt 2> /dev/null)) 62 | SIZES_NUMFMT:=| numfmt --field=-4 --header $(NUMFMTFLAGS) 63 | else 64 | SIZES_NUMFMT:= 65 | endif 66 | endif 67 | 68 | ifneq (, $(shell command -v sed 2> /dev/null)) 69 | SIZES_SED:=| sed -e 's/ dec/total/' 70 | else 71 | SIZES_SED:= 72 | endif 73 | 74 | rwildcard=$(foreach d,$(filter-out $3,$(wildcard $1*)),$(call rwildcard,$d/,$2,$3)$(filter $(subst *,%,$2),$d)) 75 | 76 | # Colors 77 | NO_COLOR=$(shell printf "%b" "\033[0m") 78 | OK_COLOR=$(shell printf "%b" "\033[32;01m") 79 | ERROR_COLOR=$(shell printf "%b" "\033[31;01m") 80 | WARN_COLOR=$(shell printf "%b" "\033[33;01m") 81 | STEP_COLOR=$(shell printf "%b" "\033[37;01m") 82 | OK_STRING=$(OK_COLOR)[OK]$(NO_COLOR) 83 | DONE_STRING=$(OK_COLOR)[DONE]$(NO_COLOR) 84 | ERROR_STRING=$(ERROR_COLOR)[ERRORS]$(NO_COLOR) 85 | WARN_STRING=$(WARN_COLOR)[WARNINGS]$(NO_COLOR) 86 | ECHO=/bin/printf "%s\n" 87 | echo=@$(ECHO) "$2$1$(NO_COLOR)" 88 | echon=@/bin/printf "%s" "$2$1$(NO_COLOR)" 89 | 90 | define test_output_2 91 | @if test $(BUILD_VERBOSE) -eq $(or $4,1); then printf "%s\n" "$2"; fi; 92 | @output="$$($2 2>&1)"; exit=$$?; \ 93 | if test 0 -ne $$exit; then \ 94 | printf "%s%s\n" "$1" "$(ERROR_STRING)"; \ 95 | printf "%s\n" "$$output"; \ 96 | exit $$exit; \ 97 | elif test -n "$$output"; then \ 98 | printf "%s%s\n" "$1" "$(WARN_STRING)"; \ 99 | printf "%s\n" "$$output"; \ 100 | else \ 101 | printf "%s%s\n" "$1" "$3"; \ 102 | fi; 103 | endef 104 | 105 | define test_output 106 | @output=$$($1 2>&1); exit=$$?; \ 107 | if test 0 -ne $$exit; then \ 108 | printf "%s\n" "$(ERROR_STRING)" $$?; \ 109 | printf "%s\n" $$output; \ 110 | exit $$exit; \ 111 | elif test -n "$$output"; then \ 112 | printf "%s\n" "$(WARN_STRING)"; \ 113 | printf "%s" $$output; \ 114 | else \ 115 | printf "%s\n" "$2"; \ 116 | fi; 117 | endef 118 | 119 | # Makefile Verbosity 120 | ifeq ("$(origin VERBOSE)", "command line") 121 | BUILD_VERBOSE = $(VERBOSE) 122 | endif 123 | ifeq ("$(origin V)", "command line") 124 | BUILD_VERBOSE = $(V) 125 | endif 126 | 127 | ifndef BUILD_VERBOSE 128 | BUILD_VERBOSE = 0 129 | endif 130 | 131 | # R is reduced (default messages) - build verbose = 0 132 | # V is verbose messages - verbosity = 1 133 | # VV is super verbose - verbosity = 2 134 | ifeq ($(BUILD_VERBOSE), 0) 135 | R = @echo 136 | D = @ 137 | VV = @ 138 | endif 139 | ifeq ($(BUILD_VERBOSE), 1) 140 | R = @echo 141 | D = 142 | VV = @ 143 | endif 144 | ifeq ($(BUILD_VERBOSE), 2) 145 | R = 146 | D = 147 | VV = 148 | endif 149 | 150 | INCLUDE=$(foreach dir,$(INCDIR) $(EXTRA_INCDIR),-iquote"$(dir)") 151 | 152 | ASMSRC=$(foreach asmext,$(ASMEXTS),$(call rwildcard, $(SRCDIR),*.$(asmext), $1)) 153 | ASMOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call ASMSRC,$1))) 154 | CSRC=$(foreach cext,$(CEXTS),$(call rwildcard, $(SRCDIR),*.$(cext), $1)) 155 | COBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CSRC, $1))) 156 | CXXSRC=$(foreach cxxext,$(CXXEXTS),$(call rwildcard, $(SRCDIR),*.$(cxxext), $1)) 157 | CXXOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CXXSRC,$1))) 158 | 159 | GETALLOBJ=$(sort $(call ASMOBJ,$1) $(call COBJ,$1) $(call CXXOBJ,$1)) 160 | 161 | ARCHIVE_TEXT_LIST=$(subst $(SPACE),$(COMMA),$(notdir $(basename $(LIBRARIES)))) 162 | 163 | LDTIMEOBJ:=$(BINDIR)/_pros_ld_timestamp.o 164 | 165 | MONOLITH_BIN:=$(BINDIR)/monolith.bin 166 | MONOLITH_ELF:=$(basename $(MONOLITH_BIN)).elf 167 | 168 | HOT_BIN:=$(BINDIR)/hot.package.bin 169 | HOT_ELF:=$(basename $(HOT_BIN)).elf 170 | COLD_BIN:=$(BINDIR)/cold.package.bin 171 | COLD_ELF:=$(basename $(COLD_BIN)).elf 172 | 173 | # Check if USE_PACKAGE is defined to check for migration steps from purduesigbots/pros#87 174 | ifndef USE_PACKAGE 175 | $(error Your Makefile must be migrated! Visit https://pros.cs.purdue.edu/v5/releases/kernel3.1.6.html to learn how) 176 | endif 177 | 178 | DEFAULT_BIN=$(MONOLITH_BIN) 179 | ifeq ($(USE_PACKAGE),1) 180 | DEFAULT_BIN=$(HOT_BIN) 181 | endif 182 | 183 | -include $(wildcard $(FWDIR)/*.mk) 184 | 185 | .PHONY: all clean quick 186 | 187 | quick: $(DEFAULT_BIN) 188 | 189 | all: clean $(DEFAULT_BIN) 190 | 191 | clean: 192 | @echo Cleaning project 193 | -$Drm -rf $(BINDIR) 194 | -$Drm -rf $(DEPDIR) 195 | 196 | ifeq ($(IS_LIBRARY),1) 197 | ifeq ($(LIBNAME),libbest) 198 | $(errror "You should rename your library! libbest is the default library name and should be changed") 199 | endif 200 | 201 | LIBAR=$(BINDIR)/$(LIBNAME).a 202 | TEMPLATE_DIR=$(ROOT)/template 203 | 204 | clean-template: 205 | @echo Cleaning $(TEMPLATE_DIR) 206 | -$Drm -rf $(TEMPLATE_DIR) 207 | 208 | $(LIBAR): $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)) $(EXTRA_LIB_DEPS) 209 | -$Drm -f $@ 210 | $(call test_output_2,Creating $@ ,$(AR) rcs $@ $^, $(DONE_STRING)) 211 | 212 | .PHONY: library 213 | library: $(LIBAR) 214 | 215 | .PHONY: template 216 | template: clean-template $(LIBAR) 217 | $Dpros c create-template . $(LIBNAME) $(VERSION) $(foreach file,$(TEMPLATE_FILES) $(LIBAR),--system "$(file)") --target v5 $(CREATE_TEMPLATE_FLAGS) 218 | endif 219 | 220 | # if project is a library source, compile the archive and link output.elf against the archive rather than source objects 221 | ifeq ($(IS_LIBRARY),1) 222 | ELF_DEPS+=$(filter-out $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)), $(call GETALLOBJ,$(EXCLUDE_SRCDIRS))) 223 | LIBRARIES+=$(LIBAR) 224 | else 225 | ELF_DEPS+=$(call GETALLOBJ,$(EXCLUDE_SRCDIRS)) 226 | endif 227 | 228 | $(MONOLITH_BIN): $(MONOLITH_ELF) $(BINDIR) 229 | $(call test_output_2,Creating $@ for $(DEVICE) ,$(OBJCOPY) $< -O binary -R .hot_init $@,$(DONE_STRING)) 230 | 231 | $(MONOLITH_ELF): $(ELF_DEPS) $(LIBRARIES) 232 | $(call _pros_ld_timestamp) 233 | $(call test_output_2,Linking project with $(ARCHIVE_TEXT_LIST) ,$(LD) $(LDFLAGS) $(ELF_DEPS) $(LDTIMEOBJ) $(call wlprefix,-T$(FWDIR)/v5.ld $(LNK_FLAGS)) -o $@,$(OK_STRING)) 234 | @echo Section sizes: 235 | -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) 236 | 237 | $(COLD_BIN): $(COLD_ELF) 238 | $(call test_output_2,Creating cold package binary for $(DEVICE) ,$(OBJCOPY) $< -O binary -R .hot_init $@,$(DONE_STRING)) 239 | 240 | $(COLD_ELF): $(COLD_LIBRARIES) 241 | $(VV)mkdir -p $(dir $@) 242 | $(call test_output_2,Creating cold package with $(ARCHIVE_TEXT_LIST) ,$(LD) $(LDFLAGS) $(call wlprefix,--gc-keep-exported --whole-archive $^ -lstdc++ --no-whole-archive) $(call wlprefix,-T$(FWDIR)/v5.ld $(LNK_FLAGS) -o $@),$(OK_STRING)) 243 | $(call test_output_2,Stripping cold package ,$(OBJCOPY) --strip-symbol=install_hot_table --strip-symbol=__libc_init_array --strip-symbol=_PROS_COMPILE_DIRECTORY --strip-symbol=_PROS_COMPILE_TIMESTAMP --strip-symbol=_PROS_COMPILE_TIMESTAMP_INT $@ $@, $(DONE_STRING)) 244 | @echo Section sizes: 245 | -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) 246 | 247 | $(HOT_BIN): $(HOT_ELF) $(COLD_BIN) 248 | $(call test_output_2,Creating $@ for $(DEVICE) ,$(OBJCOPY) $< -O binary $@,$(DONE_STRING)) 249 | 250 | $(HOT_ELF): $(COLD_ELF) $(ELF_DEPS) 251 | $(call _pros_ld_timestamp) 252 | $(call test_output_2,Linking hot project with $(COLD_ELF) and $(ARCHIVE_TEXT_LIST) ,$(LD) -nostartfiles $(LDFLAGS) $(call wlprefix,-R $<) $(filter-out $<,$^) $(LDTIMEOBJ) $(LIBRARIES) $(call wlprefix,-T$(FWDIR)/v5-hot.ld $(LNK_FLAGS) -o $@),$(OK_STRING)) 253 | @printf "%s\n" "Section sizes:" 254 | -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) 255 | 256 | define asm_rule 257 | $(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 258 | $(VV)mkdir -p $$(dir $$@) 259 | $$(call test_output_2,Compiled $$< ,$(AS) -c $(ASMFLAGS) -o $$@ $$<,$(OK_STRING)) 260 | endef 261 | $(foreach asmext,$(ASMEXTS),$(eval $(call asm_rule,$(asmext)))) 262 | 263 | define c_rule 264 | $(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 265 | $(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 $(DEPDIR)/$(basename $1).d 266 | $(VV)mkdir -p $$(dir $$@) 267 | $(MAKEDEPFOLDER) 268 | $$(call test_output_2,Compiled $$< ,$(CC) -c $(INCLUDE) -iquote"$(INCDIR)/$$(dir $$*)" $(CFLAGS) $(EXTRA_CFLAGS) $(DEPFLAGS) -o $$@ $$<,$(OK_STRING)) 269 | $(RENAMEDEPENDENCYFILE) 270 | endef 271 | $(foreach cext,$(CEXTS),$(eval $(call c_rule,$(cext)))) 272 | 273 | define cxx_rule 274 | $(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 275 | $(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 $(DEPDIR)/$(basename %).d 276 | $(VV)mkdir -p $$(dir $$@) 277 | $(MAKEDEPFOLDER) 278 | $$(call test_output_2,Compiled $$< ,$(CXX) -c $(INCLUDE) -iquote"$(INCDIR)/$$(dir $$*)" $(CXXFLAGS) $(EXTRA_CXXFLAGS) $(DEPFLAGS) -o $$@ $$<,$(OK_STRING)) 279 | $(RENAMEDEPENDENCYFILE) 280 | endef 281 | $(foreach cxxext,$(CXXEXTS),$(eval $(call cxx_rule,$(cxxext)))) 282 | 283 | define _pros_ld_timestamp 284 | $(VV)mkdir -p $(dir $(LDTIMEOBJ)) 285 | @# Pipe a line of code defining _PROS_COMPILE_TOOLSTAMP and _PROS_COMPILE_DIRECTORY into GCC, 286 | @# which allows compilation from stdin. We define _PROS_COMPILE_DIRECTORY using a command line-defined macro 287 | @# which is the pwd | tail bit, which will truncate the path to the last 23 characters 288 | @# 289 | @# const int _PROS_COMPILE_TIMESTAMP_INT = $(( $(date +%s) - $(date +%z) * 3600 )) 290 | @# char const * const _PROS_COMPILE_TIEMSTAMP = __DATE__ " " __TIME__ 291 | @# char const * const _PROS_COMPILE_DIRECTORY = "$(shell pwd | tail -c 23)"; 292 | @# 293 | @# The shell command $$(($$(date +%s)+($$(date +%-z)/100*3600))) fetches the current 294 | @# unix timestamp, and then adds the UTC timezone offset to account for time zones. 295 | 296 | $(call test_output_2,Adding timestamp ,echo 'const int _PROS_COMPILE_TIMESTAMP_INT = $(shell echo $$(($$(date +%s)+($$(date +%-z)/100*3600)))); char const * const _PROS_COMPILE_TIMESTAMP = __DATE__ " " __TIME__; char const * const _PROS_COMPILE_DIRECTORY = "$(wildcard $(shell pwd | tail -c 23))";' | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) -o $(LDTIMEOBJ) -,$(OK_STRING)) 297 | endef 298 | 299 | # these rules are for build-compile-commands, which just print out sysroot information 300 | cc-sysroot: 301 | @echo | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) --verbose -o /dev/null - 302 | cxx-sysroot: 303 | @echo | $(CXX) -c -x c++ $(CXXFLAGS) $(EXTRA_CXXFLAGS) --verbose -o /dev/null - 304 | 305 | $(DEPDIR)/%.d: ; 306 | .PRECIOUS: $(DEPDIR)/%.d 307 | 308 | include $(wildcard $(patsubst $(SRCDIR)/%,$(DEPDIR)/%.d,$(CSRC) $(CXXSRC))) 309 | -------------------------------------------------------------------------------- /firmware/libc.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LemLib/Gamepad/3a43926f3620b05bf2583817ec2c9b2dfd9b3ba0/firmware/libc.a -------------------------------------------------------------------------------- /firmware/libm.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LemLib/Gamepad/3a43926f3620b05bf2583817ec2c9b2dfd9b3ba0/firmware/libm.a -------------------------------------------------------------------------------- /firmware/libpros.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LemLib/Gamepad/3a43926f3620b05bf2583817ec2c9b2dfd9b3ba0/firmware/libpros.a -------------------------------------------------------------------------------- /firmware/v5-common.ld: -------------------------------------------------------------------------------- 1 | /* Define the sections, and where they are mapped in memory */ 2 | SECTIONS 3 | { 4 | /* This will get stripped out before uploading, but we need to place code 5 | here so we can at least link to it (install_hot_table) */ 6 | .hot_init : { 7 | KEEP (*(.hot_magic)) 8 | KEEP (*(.hot_init)) 9 | } > HOT_MEMORY 10 | 11 | .text : { 12 | KEEP (*(.vectors)) 13 | /* boot data should be exactly 32 bytes long */ 14 | *(.boot_data) 15 | . = 0x20; 16 | *(.boot) 17 | . = ALIGN(64); 18 | *(.freertos_vectors) 19 | *(.text) 20 | *(.text.*) 21 | *(.gnu.linkonce.t.*) 22 | *(.plt) 23 | *(.gnu_warning) 24 | *(.gcc_except_table) 25 | *(.glue_7) 26 | *(.glue_7t) 27 | *(.vfp11_veneer) 28 | *(.ARM.extab) 29 | *(.gnu.linkonce.armextab.*) 30 | } > RAM 31 | 32 | .init : { 33 | KEEP (*(.init)) 34 | } > RAM 35 | 36 | .fini : { 37 | KEEP (*(.fini)) 38 | } > RAM 39 | 40 | .rodata : { 41 | __rodata_start = .; 42 | *(.rodata) 43 | *(.rodata.*) 44 | *(.gnu.linkonce.r.*) 45 | __rodata_end = .; 46 | } > RAM 47 | 48 | .rodata1 : { 49 | __rodata1_start = .; 50 | *(.rodata1) 51 | *(.rodata1.*) 52 | __rodata1_end = .; 53 | } > RAM 54 | 55 | .sdata2 : { 56 | __sdata2_start = .; 57 | *(.sdata2) 58 | *(.sdata2.*) 59 | *(.gnu.linkonce.s2.*) 60 | __sdata2_end = .; 61 | } > RAM 62 | 63 | .sbss2 : { 64 | __sbss2_start = .; 65 | *(.sbss2) 66 | *(.sbss2.*) 67 | *(.gnu.linkonce.sb2.*) 68 | __sbss2_end = .; 69 | } > RAM 70 | 71 | .data : { 72 | __data_start = .; 73 | *(.data) 74 | *(.data.*) 75 | *(.gnu.linkonce.d.*) 76 | *(.jcr) 77 | *(.got) 78 | *(.got.plt) 79 | __data_end = .; 80 | } > RAM 81 | 82 | .data1 : { 83 | __data1_start = .; 84 | *(.data1) 85 | *(.data1.*) 86 | __data1_end = .; 87 | } > RAM 88 | 89 | .got : { 90 | *(.got) 91 | } > RAM 92 | 93 | .ctors : { 94 | __CTOR_LIST__ = .; 95 | ___CTORS_LIST___ = .; 96 | KEEP (*crtbegin.o(.ctors)) 97 | KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors)) 98 | KEEP (*(SORT(.ctors.*))) 99 | KEEP (*(.ctors)) 100 | __CTOR_END__ = .; 101 | ___CTORS_END___ = .; 102 | } > RAM 103 | 104 | .dtors : { 105 | __DTOR_LIST__ = .; 106 | ___DTORS_LIST___ = .; 107 | KEEP (*crtbegin.o(.dtors)) 108 | KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors)) 109 | KEEP (*(SORT(.dtors.*))) 110 | KEEP (*(.dtors)) 111 | __DTOR_END__ = .; 112 | ___DTORS_END___ = .; 113 | } > RAM 114 | 115 | .fixup : { 116 | __fixup_start = .; 117 | *(.fixup) 118 | __fixup_end = .; 119 | } > RAM 120 | 121 | .eh_frame : { 122 | *(.eh_frame) 123 | } > RAM 124 | 125 | .eh_framehdr : { 126 | __eh_framehdr_start = .; 127 | *(.eh_framehdr) 128 | __eh_framehdr_end = .; 129 | } > RAM 130 | 131 | .gcc_except_table : { 132 | *(.gcc_except_table) 133 | } > RAM 134 | 135 | .mmu_tbl (ALIGN(16384)) : { 136 | __mmu_tbl_start = .; 137 | *(.mmu_tbl) 138 | __mmu_tbl_end = .; 139 | } > RAM 140 | 141 | .ARM.exidx : { 142 | __exidx_start = .; 143 | *(.ARM.exidx*) 144 | *(.gnu.linkonce.armexidix.*.*) 145 | __exidx_end = .; 146 | } > RAM 147 | 148 | .preinit_array : { 149 | __preinit_array_start = .; 150 | KEEP (*(SORT(.preinit_array.*))) 151 | KEEP (*(.preinit_array)) 152 | __preinit_array_end = .; 153 | } > RAM 154 | 155 | .init_array : { 156 | __init_array_start = .; 157 | KEEP (*(SORT(.init_array.*))) 158 | KEEP (*(.init_array)) 159 | __init_array_end = .; 160 | } > RAM 161 | 162 | .fini_array : { 163 | __fini_array_start = .; 164 | KEEP (*(SORT(.fini_array.*))) 165 | KEEP (*(.fini_array)) 166 | __fini_array_end = .; 167 | } > RAM 168 | 169 | .ARM.attributes : { 170 | __ARM.attributes_start = .; 171 | *(.ARM.attributes) 172 | __ARM.attributes_end = .; 173 | } > RAM 174 | 175 | .sdata : { 176 | __sdata_start = .; 177 | *(.sdata) 178 | *(.sdata.*) 179 | *(.gnu.linkonce.s.*) 180 | __sdata_end = .; 181 | } > RAM 182 | 183 | .sbss (NOLOAD) : { 184 | __sbss_start = .; 185 | *(.sbss) 186 | *(.sbss.*) 187 | *(.gnu.linkonce.sb.*) 188 | __sbss_end = .; 189 | } > RAM 190 | 191 | .tdata : { 192 | __tdata_start = .; 193 | *(.tdata) 194 | *(.tdata.*) 195 | *(.gnu.linkonce.td.*) 196 | __tdata_end = .; 197 | } > RAM 198 | 199 | .tbss : { 200 | __tbss_start = .; 201 | *(.tbss) 202 | *(.tbss.*) 203 | *(.gnu.linkonce.tb.*) 204 | __tbss_end = .; 205 | } > RAM 206 | 207 | .bss (NOLOAD) : { 208 | __bss_start = .; 209 | *(.bss) 210 | *(.bss.*) 211 | *(.gnu.linkonce.b.*) 212 | *(COMMON) 213 | __bss_end = .; 214 | } > RAM 215 | 216 | _SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 ); 217 | 218 | _SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 ); 219 | 220 | /* Generate Stack and Heap definitions */ 221 | 222 | .heap (NOLOAD) : { 223 | . = ALIGN(16); 224 | _heap = .; 225 | HeapBase = .; 226 | _heap_start = .; 227 | . += _HEAP_SIZE; 228 | _heap_end = .; 229 | HeapLimit = .; 230 | } > HEAP 231 | 232 | .stack (NOLOAD) : { 233 | . = ALIGN(16); 234 | _stack_end = .; 235 | . += _STACK_SIZE; 236 | . = ALIGN(16); 237 | _stack = .; 238 | __stack = _stack; 239 | . = ALIGN(16); 240 | _irq_stack_end = .; 241 | . += _IRQ_STACK_SIZE; 242 | . = ALIGN(16); 243 | __irq_stack = .; 244 | _supervisor_stack_end = .; 245 | . += _SUPERVISOR_STACK_SIZE; 246 | . = ALIGN(16); 247 | __supervisor_stack = .; 248 | _abort_stack_end = .; 249 | . += _ABORT_STACK_SIZE; 250 | . = ALIGN(16); 251 | __abort_stack = .; 252 | _fiq_stack_end = .; 253 | . += _FIQ_STACK_SIZE; 254 | . = ALIGN(16); 255 | __fiq_stack = .; 256 | _undef_stack_end = .; 257 | . += _UNDEF_STACK_SIZE; 258 | . = ALIGN(16); 259 | __undef_stack = .; 260 | } > COLD_MEMORY 261 | 262 | _end = .; 263 | } 264 | -------------------------------------------------------------------------------- /firmware/v5-hot.ld: -------------------------------------------------------------------------------- 1 | /* This stack is used during initialization, but FreeRTOS tasks have their own 2 | stack allocated in BSS or Heap (kernel tasks in FreeRTOS .bss heap; user tasks 3 | in standard heap) */ 4 | _STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000; 5 | 6 | _ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024; 7 | _SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048; 8 | _IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024; 9 | _FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024; 10 | _UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024; 11 | 12 | _HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x02E00000; /* ~48 MB */ 13 | 14 | /* Define Memories in the system */ 15 | start_of_cold_mem = 0x03800000; 16 | _COLD_MEM_SIZE = 0x04800000; 17 | end_of_cold_mem = start_of_cold_mem + _COLD_MEM_SIZE; 18 | 19 | start_of_hot_mem = 0x07800000; 20 | _HOT_MEM_SIZE = 0x00800000; 21 | end_of_hot_mem = start_of_hot_mem + _HOT_MEM_SIZE; 22 | 23 | MEMORY 24 | { 25 | /* user code 72M */ 26 | COLD_MEMORY : ORIGIN = start_of_cold_mem, LENGTH = _COLD_MEM_SIZE /* Just under 19 MB */ 27 | HEAP : ORIGIN = 0x04A00000, LENGTH = _HEAP_SIZE 28 | HOT_MEMORY : ORIGIN = start_of_hot_mem, LENGTH = _HOT_MEM_SIZE /* Just over 8 MB */ 29 | } 30 | 31 | REGION_ALIAS("RAM", HOT_MEMORY); 32 | 33 | ENTRY(install_hot_table) 34 | -------------------------------------------------------------------------------- /firmware/v5.ld: -------------------------------------------------------------------------------- 1 | /* This stack is used during initialization, but FreeRTOS tasks have their own 2 | stack allocated in BSS or Heap (kernel tasks in FreeRTOS .bss heap; user tasks 3 | in standard heap) */ 4 | _STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000; 5 | 6 | _ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024; 7 | _SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048; 8 | _IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024; 9 | _FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024; 10 | _UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024; 11 | 12 | _HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x02E00000; /* ~48 MB */ 13 | 14 | /* Define Memories in the system */ 15 | start_of_cold_mem = 0x03800000; 16 | _COLD_MEM_SIZE = 0x04800000; 17 | end_of_cold_mem = start_of_cold_mem + _COLD_MEM_SIZE; 18 | 19 | start_of_hot_mem = 0x07800000; 20 | _HOT_MEM_SIZE = 0x00800000; 21 | end_of_hot_mem = start_of_hot_mem + _HOT_MEM_SIZE; 22 | 23 | MEMORY 24 | { 25 | /* user code 72M */ 26 | COLD_MEMORY : ORIGIN = start_of_cold_mem, LENGTH = _COLD_MEM_SIZE /* Just under 19 MB */ 27 | HEAP : ORIGIN = 0x04A00000, LENGTH = _HEAP_SIZE 28 | HOT_MEMORY : ORIGIN = start_of_hot_mem, LENGTH = _HOT_MEM_SIZE /* Just over 8 MB */ 29 | } 30 | 31 | REGION_ALIAS("RAM", COLD_MEMORY); 32 | 33 | ENTRY(vexStartup) 34 | -------------------------------------------------------------------------------- /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-2023, 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 | #define PROS_VERSION_MAJOR 4 43 | #define PROS_VERSION_MINOR 0 44 | #define PROS_VERSION_PATCH 7 45 | #define PROS_VERSION_STRING "4.0.7" 46 | 47 | #include "pros/adi.h" 48 | #include "pros/colors.h" 49 | #include "pros/device.h" 50 | #include "pros/distance.h" 51 | #include "pros/error.h" 52 | #include "pros/ext_adi.h" 53 | #include "pros/gps.h" 54 | #include "pros/imu.h" 55 | #include "pros/link.h" 56 | #include "pros/llemu.h" 57 | #include "pros/misc.h" 58 | #include "pros/motors.h" 59 | #include "pros/optical.h" 60 | #include "pros/rotation.h" 61 | #include "pros/rtos.h" 62 | #include "pros/screen.h" 63 | #include "pros/vision.h" 64 | 65 | #ifdef __cplusplus 66 | #include "pros/adi.hpp" 67 | #include "pros/colors.hpp" 68 | #include "pros/device.hpp" 69 | #include "pros/distance.hpp" 70 | #include "pros/gps.hpp" 71 | #include "pros/imu.hpp" 72 | #include "pros/link.hpp" 73 | #include "pros/llemu.hpp" 74 | #include "pros/misc.hpp" 75 | #include "pros/motor_group.hpp" 76 | #include "pros/motors.hpp" 77 | #include "pros/optical.hpp" 78 | #include "pros/rotation.hpp" 79 | #include "pros/rtos.hpp" 80 | #include "pros/screen.hpp" 81 | #include "pros/vision.hpp" 82 | #endif 83 | 84 | #endif // _PROS_API_H_ 85 | -------------------------------------------------------------------------------- /include/gamepad/api.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gamepad/event_handler.hpp" // IWYU pragma: export 4 | #include "gamepad/gamepad.hpp" // IWYU pragma: export 5 | #include "gamepad/screens/alertScreen.hpp" // IWYU pragma: export 6 | -------------------------------------------------------------------------------- /include/gamepad/button.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "event_handler.hpp" 8 | 9 | namespace gamepad { 10 | enum EventType { 11 | ON_PRESS, 12 | ON_LONG_PRESS, 13 | ON_RELEASE, 14 | ON_SHORT_RELEASE, 15 | ON_LONG_RELEASE, 16 | ON_REPEAT_PRESS, 17 | }; 18 | 19 | class Button { 20 | friend class Gamepad; 21 | public: 22 | /// Whether the button has just been pressed 23 | bool rising_edge = false; 24 | /// Whether the button has just been released 25 | bool falling_edge = false; 26 | /// Whether the button is currently held down 27 | bool is_pressed = false; 28 | /// How long the button has been held down 29 | uint32_t time_held = 0; 30 | /// How long the button has been released 31 | uint32_t time_released = 0; 32 | /// How many times the button has been repeat-pressed 33 | uint32_t repeat_iterations = 0; 34 | /** 35 | * @brief Set the time for a press to be considered a long press for the button 36 | * 37 | * @note this is likely to be used with the onLongPress(), onShortRelease(), onLongRelease(), or onRepeatPress() 38 | * events 39 | * 40 | * @param threshold the time in ms that would be considered a long press 41 | * 42 | * @b Example: 43 | * @code {.cpp} 44 | * // change the threshold 45 | * gamepad::master.Left.setLongPressThreshold(5000); 46 | * // then call the function 47 | * gamepad::master.Left.onLongPress("longPress1", []() { 48 | * std::cout << "I was held for 5000ms instead of the 500ms default!" << std::endl; 49 | * }); 50 | * @endcode 51 | */ 52 | void setLongPressThreshold(uint32_t threshold) const; 53 | /** 54 | * @brief Set the interval for the repeatPress event to repeat 55 | * 56 | * @note this is likely to be used with the onRepeatPress() event 57 | * 58 | * @param cooldown the interval in ms 59 | * 60 | * @b Example: 61 | * @code {.cpp} 62 | * // change the threshold 63 | * gamepad::master.Up.setRepeatCooldown(100); 64 | * // then call the function 65 | * gamepad::master.Up.onRepeatPress("repeatPress1", []() { 66 | * std::cout << "I'm being repeated every 100ms instead of the 50ms default!" << std::endl; 67 | * }); 68 | * @endcode 69 | */ 70 | void setRepeatCooldown(uint32_t cooldown) const; 71 | /** 72 | * @brief Register a function to run when the button is pressed. 73 | * 74 | * @param listenerName The name of the listener, this must be a unique name 75 | * @param func The function to run when the button is pressed, the function MUST NOT block 76 | * @return 0 The listener was successfully registered 77 | * @return INT32_MAX The listener was not successfully registered (there is already a listener with this name) 78 | * 79 | * @b Example: 80 | * @code {.cpp} 81 | * // Use a function... 82 | * gamepad::master.Down.onPress("downPress1", downPress1); 83 | * // ...or a lambda 84 | * gamepad::master.Up.onPress("upPress1", []() { std::cout << "I was pressed!" << std::endl; }); 85 | * @endcode 86 | */ 87 | int32_t onPress(std::string listenerName, std::function func) const; 88 | /** 89 | * @brief Register a function to run when the button is long pressed. 90 | * 91 | * By default, onLongPress will fire when the button has been held down for 92 | * 500ms or more, this threshold can be adjusted via the setLongPressThreshold() method. 93 | * 94 | * @warning When using this event along with onPress, both the onPress 95 | * and onLongPress listeners may fire together. 96 | * 97 | * @param listenerName The name of the listener, this must be a unique name 98 | * @param func The function to run when the button is long pressed, the function MUST NOT block 99 | * @return 0 The listener was successfully registered 100 | * @return INT32_MAX The listener was not successfully registered (there is already a listener with this name) 101 | * 102 | * @b Example: 103 | * @code {.cpp} 104 | * // Use a function... 105 | * gamepad::master.Left.onLongPress("fireCatapult", fireCatapult); 106 | * // ...or a lambda 107 | * gamepad::master.Right.onLongPress("print_right", []() { std::cout << "Right button was long pressed!" << 108 | * std::endl; }); 109 | * @endcode 110 | */ 111 | int32_t onLongPress(std::string listenerName, std::function func) const; 112 | /** 113 | * @brief Register a function to run when the button is released. 114 | * 115 | * @param listenerName The name of the listener, this must be a unique name 116 | * @param func The function to run when the button is released, the function MUST NOT block 117 | * @return 0 The listener was successfully registered 118 | * @return INT32_MAX The listener was not successfully registered (there is already a listener with this name) 119 | * 120 | * @b Example: 121 | * @code {.cpp} 122 | * // Use a function... 123 | * gamepad::master.X.onRelease("stopFlywheel", stopFlywheel); 124 | * // ...or a lambda 125 | * gamepad::master.Y.onRelease("stopIntake", []() { intake.move(0); }); 126 | * @endcode 127 | */ 128 | int32_t onRelease(std::string listenerName, std::function func) const; 129 | /** 130 | * @brief Register a function to run when the button is short released. 131 | * 132 | * By default, shortRelease will fire when the button has been released before 500ms, this threshold can be 133 | * adjusted via the setLongPressThreshold() method. 134 | * 135 | * @note This event will most likely be used along with the longPress event. 136 | * 137 | * @param listenerName The name of the listener, this must be a unique name 138 | * @param func The function to run when the button is short released, the function MUST NOT block 139 | * @return 0 The listener was successfully registered 140 | * @return INT32_MAX The listener was not successfully registered (there is already a listener with this name) 141 | * 142 | * @b Example: 143 | * @code {.cpp} 144 | * // Use a function... 145 | * gamepad::master.A.onShortRelease("raiseLiftOneLevel", raiseLiftOneLevel); 146 | * // ...or a lambda 147 | * gamepad::master.B.onShortRelease("intakeOnePiece", []() { intake.move_relative(600, 100); }); 148 | * @endcode 149 | */ 150 | int32_t onShortRelease(std::string listenerName, std::function func) const; 151 | /** 152 | * @brief Register a function to run when the button is long released. 153 | * 154 | * By default, longRelease will fire when the button has been released after 500ms, this threshold can be 155 | * adjusted via the setLongPressThreshold() method. 156 | * 157 | * @param listenerName The name of the listener, this must be a unique name 158 | * @param func The function to run when the button is long released, the function MUST NOT block 159 | * @return 0 The listener was successfully registered 160 | * @return INT32_MAX The listener was not successfully registered (there is already a listener with this name) 161 | * 162 | * @b Example: 163 | * @code {.cpp} 164 | * // Use a function... 165 | * gamepad::master.Up.onLongRelease("moveLiftToGround", moveLiftToGround); 166 | * // ...or a lambda 167 | * gamepad::master.Left.onLongRelease("spinIntake", []() { intake.move(127); }); 168 | * @endcode 169 | * 170 | */ 171 | int32_t onLongRelease(std::string listenerName, std::function func) const; 172 | /** 173 | * @brief Register a function to run periodically after its been held 174 | * 175 | * By default repeatPress will start repeating after 500ms and repeat every 50ms, this can be adjusted via the 176 | * setLongPressThreshold() and setRepeatCooldown() methods respectively 177 | * 178 | * @param listenerName The name of the listener, this must be a unique name 179 | * @param func the function to run periodically when the button is held, the function MUST NOT block 180 | * @return 0 The listener was successfully registered 181 | * @return INT32_MAX The listener was not successfully registered (there is already a listener with this name) 182 | * 183 | * @b Example: 184 | * @code {.cpp} 185 | * // Use a function... 186 | * gamepad::master.X.onRepeatPress("shootDisk", shootOneDisk); 187 | * // ...or a lambda 188 | * gamepad::master.A.onRepeatPress("scoreOneRing", []() { intake.move_relative(200, 100); }); 189 | * @endcode 190 | * 191 | */ 192 | int32_t onRepeatPress(std::string listenerName, std::function func) const; 193 | /** 194 | * @brief Register a function to run for a given event. 195 | * 196 | * @param event Which event to register the listener on. 197 | * @param listenerName The name of the listener, this must be a unique name 198 | * @param func The function to run for the given event, the function MUST NOT block 199 | * @return 0 The listener was successfully registered 200 | * @return INT32_MAX The listener was not successfully registered (there is already a listener with this name) 201 | * 202 | * @b Example: 203 | * @code {.cpp} 204 | * // Use a function... 205 | * gamepad::master.L1.addListener(gamepad::ON_PRESS, "start_spin", startSpin); 206 | * // ...or a lambda 207 | * gamepad::master.L1.addListener(gamepad::ON_RELEASE, "stop_spin", []() { motor1.brake(); }); 208 | * @endcode 209 | */ 210 | int32_t addListener(EventType event, std::string listenerName, std::function func) const; 211 | /** 212 | * @brief Removes a listener from the button 213 | * @warning Usage of this function is discouraged. 214 | * 215 | * @param event the event type of the listener 216 | * @param listenerName The name of the listener to remove 217 | * @return 0 The specified listener was successfully removed 218 | * @return INT32_MAX The specified listener could not be removed 219 | * 220 | * @b Example: 221 | * @code {.cpp} 222 | * // Add an event listener... 223 | * gamepad::master.L1.addListener(gamepad::ON_PRESS, "do_something", doSomething); 224 | * // ...and now get rid of it 225 | * gamepad::master.L1.removeListener(gamepad::ON_PRESS, "do_something"); 226 | * @endcode 227 | */ 228 | int32_t removeListener(EventType event, std::string listenerName) const; 229 | 230 | /** 231 | * @brief Returns a value indicating whether the button is currently being held. 232 | * 233 | * @return true The button is currently pressed 234 | * @return false The button is not currently pressed 235 | */ 236 | explicit operator bool() const { return is_pressed; } 237 | private: 238 | /** 239 | * @brief Updates the button and runs any event handlers, if necessary 240 | * 241 | * @param is_held Whether or not the button is currently held down 242 | */ 243 | void update(bool is_held); 244 | /** 245 | * @brief Get the handler object for the given event type 246 | * 247 | * @param event The desired event type 248 | * @return nullptr The event value is invalid 249 | * @return _impl::EventHandler* A pointer to the given event's handler 250 | */ 251 | _impl::EventHandler* get_handler(EventType event) const; 252 | /// How long the threshold should be for the longPress and shortRelease events 253 | mutable uint32_t m_long_press_threshold = 500; 254 | /// How often repeatPress is called 255 | mutable uint32_t m_repeat_cooldown = 50; 256 | /// The last time the update function was called 257 | uint32_t m_last_update_time = pros::millis(); 258 | /// The last time the long press event was fired 259 | uint32_t m_last_long_press_time = 0; 260 | /// The last time the repeat event was called 261 | uint32_t m_last_repeat_time = 0; 262 | mutable _impl::EventHandler m_on_press_event {}; 263 | mutable _impl::EventHandler m_on_long_press_event {}; 264 | mutable _impl::EventHandler m_on_release_event {}; 265 | mutable _impl::EventHandler m_on_short_release_event {}; 266 | mutable _impl::EventHandler m_on_long_release_event {}; 267 | mutable _impl::EventHandler m_on_repeat_press_event {}; 268 | }; 269 | } // namespace gamepad -------------------------------------------------------------------------------- /include/gamepad/event_handler.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "gamepad/recursive_mutex.hpp" 9 | 10 | namespace gamepad::_impl { 11 | 12 | /** 13 | * @brief Event handling class with thread safety that supports adding, removing, and running listeners 14 | * 15 | * @tparam Key the key type for (un)registering listener (this type MUST support operator== and operator!=) 16 | * @tparam Args the types of the parameters that each listener is passed 17 | */ 18 | template class EventHandler { 19 | public: 20 | using Listener = std::function; 21 | 22 | /** 23 | * @brief Add a listener to the list of listeners 24 | * 25 | * @param key The listener key (this must be a unique key value) 26 | * @param func The function to run when this event is fired 27 | * @return 0 The listener was successfully added 28 | * @return INT32_MAX The listener was NOT successfully added (there is already a listener with the same key) 29 | */ 30 | int32_t addListener(Key key, Listener func) { 31 | std::lock_guard lock(m_mutex); 32 | if (std::find(m_keys.begin(), m_keys.end(), key) != m_keys.end()) return INT32_MAX; 33 | m_keys.push_back(key); 34 | m_listeners.push_back(func); 35 | return 0; 36 | } 37 | 38 | /** 39 | * @brief Remove a listener from the list of listeners 40 | * 41 | * @param key The listener key (this must be a unique key value) 42 | * @return 0 The listener was successfully removed 43 | * @return INT32_MAX The listener was NOT successfully removed (there is no listener with the same key) 44 | */ 45 | int32_t removeListener(Key key) { 46 | std::lock_guard lock(m_mutex); 47 | auto i = std::find(m_keys.begin(), m_keys.end(), key); 48 | if (i != m_keys.end()) { 49 | m_keys.erase(i); 50 | m_listeners.erase(m_listeners.begin() + (i - m_keys.begin())); 51 | return 0; 52 | } 53 | return INT32_MAX; 54 | } 55 | 56 | /** 57 | * @brief Whether or not there are any listeners registered 58 | * 59 | * @return true There are listeners registered 60 | * @return false There are no listeners registered 61 | */ 62 | bool isEmpty() { 63 | std::lock_guard lock(m_mutex); 64 | return m_listeners.empty(); 65 | } 66 | 67 | /** 68 | * @brief Runs each listener registered 69 | * 70 | * @param args The parameters to pass to each listener 71 | */ 72 | void fire(Args... args) { 73 | std::lock_guard lock(m_mutex); 74 | for (auto listener : m_listeners) { listener(args...); } 75 | } 76 | private: 77 | std::vector m_keys {}; 78 | std::vector m_listeners {}; 79 | gamepad::_impl::RecursiveMutex m_mutex {}; 80 | }; 81 | } // namespace gamepad::_impl 82 | -------------------------------------------------------------------------------- /include/gamepad/gamepad.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "joystick_transformation.hpp" 4 | #include "pros/misc.h" 5 | #include "screens/defaultScreen.hpp" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "screens/abstractScreen.hpp" 11 | #include "button.hpp" 12 | #include "pros/misc.hpp" 13 | 14 | namespace gamepad { 15 | class Gamepad { 16 | public: 17 | /** 18 | * @brief Updates the state of the gamepad (all joysticks and buttons), and also runs 19 | * any registered listeners. 20 | * 21 | * @note This function should be called at the beginning of every loop iteration. 22 | * 23 | * @b Example: 24 | * @code {.cpp} 25 | * while (true) { 26 | * gamepad::master.update(); 27 | * // do robot control stuff here... 28 | * pros::delay(25); 29 | * } 30 | * @endcode 31 | * 32 | */ 33 | void update(); 34 | /** 35 | * @brief Add a screen to the screen update loop that can update the controller's screen 36 | * 37 | * @param screen the `AbstractScreen` to add to the screen queue 38 | * 39 | * @b Example: 40 | * @code {.cpp} 41 | * // initialize the alerts screen so we can have alerts on the controller 42 | * std::shared_ptr alerts = std::make_shared(); 43 | * 44 | * gamepad::master.add_screen(alerts); 45 | */ 46 | void addScreen(std::shared_ptr screen); 47 | /** 48 | * @brief print a line to the console like pros (low priority) 49 | * 50 | * @param line the line number to print the string on (0-2) 51 | * @param str the string to print onto the controller (\n to go to the next line) 52 | * 53 | * This function uses the following value(s) of errno when an error state is reached: 54 | * 55 | * EINVAL: The line number is not in the interval [0, 2] 56 | * EMSGSIZE: The string is more than 3 lines long 57 | * 58 | * @b Example: 59 | * @code {.cpp} 60 | * gamepad::master.printLine(1, "This will print on the middle line"); 61 | * gamepad::master.printLine(0, "this will print\n\naround the middle line"); 62 | * @endcode 63 | * 64 | * @return 0 if the line was printed successfully 65 | * @return INT32_MAX if there was an error, setting errno 66 | */ 67 | int32_t printLine(uint8_t line, std::string str); 68 | /** 69 | * @brief clears all lines on the controller, similar to the pros function (low priority) 70 | * 71 | * @b Example: 72 | * @code {.cpp} 73 | * // clears the whole screen on the controller 74 | * gamepad::master.clear() 75 | * @endcode 76 | */ 77 | void clear(); 78 | /** 79 | * @brief clears the specific line on the controller, similar to the pros function clear_line (low priority) 80 | * 81 | * @param line the line to clear (0-2) 82 | * 83 | * This function uses the following value(s) of errno when an error state is reached: 84 | * 85 | * EINVAL: The line number is not in the interval [0, 2] 86 | * 87 | * @b Example: 88 | * @code {.cpp} 89 | * // clears the center line on the controller 90 | * gamepad::master.clear(1); 91 | * @endcode 92 | * 93 | * @return 0 if the line was cleared successfully 94 | * @return INT32_MAX if there was an error, setting errno 95 | */ 96 | int32_t clear(uint8_t line); 97 | /** 98 | * makes the controller rumble like pros (low priority) 99 | * 100 | * @param rumble_pattern A string consisting of the characters '.', '-', and ' ', where dots are short rumbles, 101 | * dashes are long rumbles, and spaces are pauses. Maximum supported length is 8 characters. 102 | * 103 | * This function uses the following value(s) of errno when an error state is reached: 104 | * 105 | * EINVAL: The rumble pattern contains a character other than '.', '-', or ' ' 106 | * EMSGSIZE: The pattern is more than 8 characters long 107 | * 108 | * @b Example: 109 | * @code {.cpp} 110 | * // rumbles in the following pattern: short, pause, long, short short 111 | * gamepad::master.rumble(". -.."); 112 | * @endcode 113 | * 114 | * @return 0 if the rumble was successful 115 | * @return INT32_MAX if there was an error, setting errno 116 | */ 117 | void rumble(std::string rumble_pattern); 118 | /** 119 | * @brief Get the state of a button on the controller. 120 | * 121 | * @param button Which button to return 122 | * 123 | * @b Example: 124 | * @code {.cpp} 125 | * if(gamepad::master[DIGITAL_L1]) { 126 | * // do something here... 127 | * } 128 | * @endcode 129 | * 130 | */ 131 | const Button& operator[](pros::controller_digital_e_t button); 132 | /** 133 | * @brief Get the value of a joystick axis on the controller. 134 | * 135 | * @param joystick Which joystick axis to return 136 | * 137 | * @b Example: 138 | * @code {.cpp} 139 | * // control a motor with a joystick 140 | * intake.move(gamepad::master[ANALOG_RIGHT_Y]); 141 | * @endcode 142 | * 143 | */ 144 | float operator[](pros::controller_analog_e_t joystick); 145 | 146 | /// The L1 button on the top of the controller. 147 | const Button& buttonL1(); 148 | 149 | /// The L2 button on the top of the controller. 150 | const Button& buttonL2(); 151 | 152 | /// The R1 button on the top of the controller. 153 | const Button& buttonR1(); 154 | 155 | /// The R2 button on the top of the controller. 156 | const Button& buttonR2(); 157 | 158 | /// The up arrow button on the front of the controller. 159 | const Button& buttonUp(); 160 | 161 | /// The down arrow button on the front of the controller. 162 | const Button& buttonDown(); 163 | 164 | /// The left arrow button on the front of the controller. 165 | const Button& buttonLeft(); 166 | 167 | /// The right arrow button on the front of the controller. 168 | const Button& buttonRight(); 169 | 170 | /// The X arrow button on the front of the controller. 171 | const Button& buttonX(); 172 | 173 | /// The B arrow button on the front of the controller. 174 | const Button& buttonB(); 175 | 176 | /// The Y arrow button on the front of the controller. 177 | const Button& buttonY(); 178 | 179 | /// The A arrow button on the front of the controller. 180 | const Button& buttonA(); 181 | 182 | /** 183 | * @brief Gets the value of the left joystick's x axis, optionally applying a curve. 184 | * 185 | * @param use_curve (optional) Whether or not to use the curve; defaults to true. 186 | * @return float The value of the left joystick's x-axis, between -1.0 and 1.0. 187 | */ 188 | float axisLeftX(bool use_curve = true); 189 | 190 | /** 191 | * @brief Gets the value of the left joystick's y axis, optionally applying a curve. 192 | * 193 | * @param use_curve (optional) Whether or not to use the curve; defaults to true. 194 | * @return float The value of the left joystick's y-axis, between -1.0 and 1.0. 195 | */ 196 | float axisLeftY(bool use_curve = true); 197 | 198 | /** 199 | * @brief Gets the value of the right joystick's x axis, optionally applying a curve. 200 | * 201 | * @param use_curve (optional) Whether or not to use the curve; defaults to true. 202 | * @return float The value of the right joystick's x-axis, between -1.0 and 1.0. 203 | */ 204 | float axisRightX(bool use_curve = true); 205 | 206 | /** 207 | * @brief Gets the value of the right joystick's y axis, optionally applying a curve. 208 | * 209 | * @param use_curve (optional) Whether or not to use the curve; defaults to true. 210 | * @return float The value of the right joystick's y-axis, between -1.0 and 1.0. 211 | */ 212 | float axisRightY(bool use_curve = true); 213 | 214 | /** 215 | * @brief Set the transformation to be used for the left joystick. 216 | * 217 | * @param left_transformation The transformation to be used 218 | */ 219 | void set_left_transform(Transformation left_transformation); 220 | 221 | /** 222 | * @brief Set the transformation to be used for the right joystick. 223 | * 224 | * @param right_transformation The transformation to be used 225 | */ 226 | void set_right_transform(Transformation right_transformation); 227 | 228 | /// The master controller, same as @ref gamepad::master 229 | static Gamepad master; 230 | /// The partner controller, same as @ref gamepad::partner 231 | static Gamepad partner; 232 | private: 233 | Gamepad(pros::controller_id_e_t id); 234 | 235 | Button m_L1 {}, m_L2 {}, m_R1 {}, m_R2 {}, m_Up {}, m_Down {}, m_Left {}, m_Right {}, m_X {}, m_B {}, m_Y {}, 236 | m_A {}; 237 | float m_LeftX = 0, m_LeftY = 0, m_RightX = 0, m_RightY = 0; 238 | Button Fake {}; 239 | std::optional m_left_transformation {std::nullopt}; 240 | std::optional m_right_transformation {std::nullopt}; 241 | /** 242 | * @brief Gets a unique name for a listener that will not conflict with user listener names. 243 | * 244 | * @important: when using the function, you must register the listener by 245 | * directly calling addListener on the EventHandler, do NOT use onPress/addListener,etc. 246 | * 247 | * @return std::string A unique listener name 248 | */ 249 | static std::string uniqueName(); 250 | static Button Gamepad::* buttonToPtr(pros::controller_digital_e_t button); 251 | void updateButton(pros::controller_digital_e_t button_id); 252 | 253 | void updateScreens(); 254 | 255 | std::shared_ptr m_default_screen = std::make_shared(); 256 | std::vector> m_screens = {}; 257 | ScreenBuffer m_current_screen = {}; 258 | ScreenBuffer m_next_buffer = {}; 259 | pros::Controller m_controller; 260 | 261 | uint8_t m_last_printed_line = 0; 262 | uint32_t m_last_print_time = 0; 263 | uint32_t m_last_update_time = 0; 264 | bool m_screen_cleared = false; 265 | pros::Mutex m_mutex {}; 266 | }; 267 | 268 | inline Gamepad Gamepad::master {pros::E_CONTROLLER_MASTER}; 269 | inline Gamepad Gamepad::partner {pros::E_CONTROLLER_PARTNER}; 270 | /// The master controller 271 | inline Gamepad& master = Gamepad::master; 272 | /// The partner controller 273 | inline Gamepad& partner = Gamepad::partner; 274 | 275 | } // namespace gamepad 276 | -------------------------------------------------------------------------------- /include/gamepad/joystick_transformation.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace gamepad { 9 | 10 | /** 11 | * @brief An abstract class for joystick transformations. 12 | * 13 | * A transformation takes a coordinate representing the value of the joystick, and returns a transformed coordinate 14 | * value 15 | * 16 | */ 17 | class AbstractTransformation { 18 | public: 19 | /** 20 | * @brief Get the transformed coordinate given the original. 21 | * 22 | * @param original The original value of the joystick 23 | * @return std::pair The transformed value 24 | */ 25 | virtual std::pair get_value(std::pair original) = 0; 26 | virtual ~AbstractTransformation() = default; 27 | }; 28 | 29 | /** 30 | * @brief A joystick transformation that applies a deadband to the joystick values 31 | * 32 | * A deadband makes the joystick value zero when the value is close to zero. This helps prevent drifting, since 33 | * joysticks often do not read exactly zero when released. 34 | */ 35 | class Deadband : public AbstractTransformation { 36 | public: 37 | /** 38 | * @brief Construct a new Deadband object 39 | * 40 | * @param x_deadband The deadband to apply for the x axis. 41 | * @param y_deadband The deadband to apply for the x axis. 42 | * @param x_spread How much the deadband for the x axis should widen. 43 | * @param y_spread How much the deadband for the y axis should widen. 44 | */ 45 | Deadband(float x_deadband, float y_deadband, float x_spread, float y_spread) 46 | : m_x_deadband(x_deadband), 47 | m_y_deadband(y_deadband), 48 | m_x_spread(x_spread), 49 | m_y_spread(y_spread) {} 50 | 51 | /** 52 | * @brief Construct a new Deadband object 53 | * 54 | * @param x_deadband The deadband to apply for the x axis. 55 | * @param y_deadband The deadband to apply for the y axis. 56 | */ 57 | Deadband(float x_deadband, float y_deadband) 58 | : Deadband(x_deadband, y_deadband, 0.0, 0.0) {} 59 | 60 | /** 61 | * @brief Get the joystick coordinate after applying the deadband 62 | * 63 | * @param original The value of the joystick before applying the deadband 64 | * @return std::pair The joystick coordinate, with a deadband applied 65 | */ 66 | std::pair get_value(std::pair original) override; 67 | private: 68 | /** 69 | * @brief Applies a deadband to a joystick axis 70 | * 71 | * @param value The value of the joystick axis 72 | * @param deadband The deadband to use 73 | * @return float The joystick axis value with deadband applied 74 | */ 75 | static float apply_deadband(float value, float deadband); 76 | 77 | float m_x_deadband; 78 | float m_y_deadband; 79 | float m_x_spread; 80 | float m_y_spread; 81 | }; 82 | 83 | /** 84 | * @brief A joystick transformation that applies an expo curve to the joystick values 85 | * 86 | * An expo curve allows greater control of the joystick, by reducing the joystick values at low speeds, while still 87 | * allowing you to attain the maximum value of the joysticks. 88 | */ 89 | class ExpoCurve : public AbstractTransformation { 90 | public: 91 | /** 92 | * @brief Construct a new Expo Curve object 93 | * 94 | * @param x_curve How much the x axis should be curved. A higher value curves the joystick value more. 95 | * @param y_curve How much the y axis should be curved. A higher value curves the joystick value more. 96 | */ 97 | ExpoCurve(float x_curve, float y_curve) 98 | : m_x_curve(x_curve), 99 | m_y_curve(y_curve) {} 100 | 101 | /** 102 | * @brief Get the joystick coordinate after applying the curve 103 | * 104 | * @param original The value of the joystick before applying the curve 105 | * @return std::pair The joystick coordinate, with a curve applied 106 | */ 107 | std::pair get_value(std::pair original) override; 108 | private: 109 | float m_x_curve; 110 | float m_y_curve; 111 | }; 112 | 113 | /** 114 | * @brief A joystick transformation that applies a fisheye to the joystick values 115 | * 116 | * The vex controller joysticks don't reach their maximum value in the corners. This can be an issue, especially when 117 | * using single stick arcade. The fisheye "stretches" the joystick values so that they attain their maximum value even 118 | * in the corners of the joysticks. 119 | */ 120 | class Fisheye : public AbstractTransformation { 121 | public: 122 | /** 123 | * @brief Construct a new Fisheye object 124 | * 125 | * @param radius The radius of the rounded circle that forms the corners of the joystick's housing. 126 | */ 127 | Fisheye(float radius) 128 | : m_radius(radius) {} 129 | 130 | /** 131 | * @brief Get the joystick coordinate after applying the fisheye 132 | * 133 | * @param original The value of the joystick before applying the fisheye 134 | * @return std::pair The joystick coordinate, with a fisheye applied 135 | */ 136 | std::pair get_value(std::pair original) override; 137 | private: 138 | float m_radius; 139 | }; 140 | 141 | /** 142 | * @brief A chain of transformations. This class should not be directly used, but should be constructed using the 143 | * TransformationBuilder class. 144 | */ 145 | class Transformation final { 146 | friend class TransformationBuilder; 147 | public: 148 | std::pair get_value(std::pair); 149 | private: 150 | std::vector> m_all_transforms; 151 | }; 152 | 153 | /** 154 | * @brief A class to create a chain of transformations. 155 | * 156 | */ 157 | class TransformationBuilder final { 158 | public: 159 | /** 160 | * @brief Construct a new Transformation Builder object 161 | * 162 | * @param first The transformation that should be used first 163 | */ 164 | template T> TransformationBuilder(T first) { 165 | m_transform.m_all_transforms.push_back(std::make_unique(std::move(first))); 166 | } 167 | 168 | TransformationBuilder() = delete; 169 | 170 | /** 171 | * @brief Add a transformation to the list of transformations to be applied. 172 | * 173 | * @param next The next transformation to be applied after the previous specified transformation 174 | * @return TransformationBuilder& The original Transformation Builder. 175 | */ 176 | template T> TransformationBuilder& and_then(T next) { 177 | m_transform.m_all_transforms.push_back(std::make_unique(std::move(next))); 178 | return *this; 179 | } 180 | 181 | /** 182 | * @brief Generate the final chained transformation 183 | * 184 | * @return Transformation The final chained transformation. This can be passed to 185 | * set_left_transform/set_right_transform 186 | */ 187 | Transformation build() { return std::move(m_transform); } 188 | 189 | /** 190 | * @brief Generate the final chained transformation 191 | * 192 | * @return Transformation The final chained transformation. This can be passed to 193 | * set_left_transform/set_right_transform 194 | */ 195 | operator Transformation() { return std::move(m_transform); } 196 | private: 197 | Transformation m_transform {}; 198 | }; 199 | } // namespace gamepad 200 | -------------------------------------------------------------------------------- /include/gamepad/recursive_mutex.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "pros/apix.h" 4 | #include "pros/rtos.h" 5 | 6 | namespace gamepad::_impl { 7 | 8 | class RecursiveMutex { 9 | public: 10 | /** 11 | * @brief Construct a new recursive mutex 12 | * 13 | */ 14 | RecursiveMutex() 15 | : mutex(pros::c::mutex_recursive_create()) {} 16 | 17 | /** 18 | * @brief Locks the recursive mutex, optionally bailing out after a timeout 19 | * 20 | * @param timeout How long to wait for the mutex before baling out 21 | * @return true The mutex was successfully acquired 22 | * @return false The mutex was not successfully acquired 23 | */ 24 | bool take(std::uint32_t timeout = TIMEOUT_MAX) { return pros::c::mutex_recursive_take(mutex, timeout); } 25 | 26 | /** 27 | * @brief Locks the mutex, waiting indefinitely until the mutex is acquired 28 | * 29 | */ 30 | void lock() { 31 | while (!this->take()) pros::delay(2); 32 | } 33 | 34 | /** 35 | * @brief Attempts to lock the mutex without blocking the current thread 36 | * 37 | * @return true The mutex was successfully acquired 38 | * @return false The mutex was not successfully acquired 39 | */ 40 | bool try_lock() { return this->take(0); } 41 | 42 | /** 43 | * @brief Unlocks the mutex 44 | * 45 | * @return true The mutex was successfully released 46 | * @return false The mutex was not successfully released 47 | */ 48 | bool give() { return pros::c::mutex_recursive_give(mutex); } 49 | 50 | /** 51 | * @brief Unlocks the mutex, equivalent to \ref give() 52 | * 53 | */ 54 | void unlock() { this->give(); } 55 | 56 | /** 57 | * @brief Destroy the recursive mutex and free any allocated memory 58 | */ 59 | ~RecursiveMutex() { pros::c::mutex_delete(mutex); } 60 | private: 61 | pros::mutex_t mutex; 62 | }; 63 | 64 | } // namespace gamepad::_impl -------------------------------------------------------------------------------- /include/gamepad/screens/abstractScreen.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "pros/misc.h" 9 | 10 | namespace gamepad { 11 | 12 | /** 13 | * @brief type for conveying a full screen with the first 3 being the lines 14 | * of text on the controller screen and the last being a rumble pattern 15 | */ 16 | typedef std::array, 4> ScreenBuffer; 17 | 18 | /** 19 | * @brief The abstract class for interacting with the controller screen 20 | * 21 | */ 22 | class AbstractScreen { 23 | public: 24 | AbstractScreen(uint32_t priority) 25 | : m_priority(priority) {} 26 | 27 | /** 28 | * @brief runs every time the controller's update function is called 29 | * use this if you need to update something regardless of if there is an 30 | * available slot in the screen 31 | * 32 | * @param delta_time the time since the last update in milliseconds 33 | */ 34 | virtual void update(uint32_t delta_time) {} 35 | 36 | /** 37 | * @brief runs if there is an empty line that is available to print 38 | * 39 | * @param visible_lines a set that contains the line numbers of all lines that 40 | * are empty and available for printing 41 | * 42 | * @returns a the lines to be printed, any lines that are not available will be ignored 43 | */ 44 | virtual ScreenBuffer getScreen(std::set visible_lines) = 0; 45 | 46 | /** 47 | * @brief a function where button events are pushed, use this to handle button events. 48 | * 49 | * @param button_events a set of the button events that happened this update 50 | */ 51 | virtual void handleEvents(std::set button_events) {} 52 | 53 | /** 54 | * @brief returns the priority of the screen 55 | * 56 | * @warning it is not recommended to override this function 57 | */ 58 | uint32_t getPriority() { return m_priority; } 59 | protected: 60 | const uint32_t m_priority; 61 | }; 62 | 63 | } // namespace gamepad 64 | -------------------------------------------------------------------------------- /include/gamepad/screens/alertScreen.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "abstractScreen.hpp" 8 | #include "pros/rtos.hpp" 9 | #include "gamepad/screens/abstractScreen.hpp" 10 | 11 | namespace gamepad { 12 | 13 | /** 14 | * @brief a screen that sends alerts to the controller, duration of alerts can be customized 15 | * 16 | * @note priority: UINT32_MAX - 100 17 | */ 18 | class AlertScreen : public AbstractScreen { 19 | public: 20 | AlertScreen() 21 | : AbstractScreen(UINT32_MAX - 100) {} 22 | 23 | /** 24 | * @brief updates the alert loop 25 | * 26 | * @param delta_time the time since the last update 27 | */ 28 | void update(uint32_t delta_time); 29 | 30 | /** 31 | * @brief return the next alert to print if there is space for it on the screen 32 | * 33 | * @param visible_lines a set that contains the line numbers of all lines that 34 | * are empty and available for printing 35 | * 36 | * @returns a the lines to be printed, any lines that are not available will be ignored 37 | */ 38 | ScreenBuffer getScreen(std::set visible_lines); 39 | 40 | /** 41 | * @brief add an alert to the alert queue, to be printed as soon as there is an available space 42 | * 43 | * @param line the line number to print the alert at (0-2) 44 | * @param strs the string to print on the controller, "\n" to go to the next line 45 | * lines that go over 2 will be cropped out 46 | * @param duration how long the alert should persist on the screen 47 | * @param rumble A string consisting of the characters '.', '-', and ' ', where dots are short rumbles, 48 | * dashes are long rumbles, and spaces are pauses. Maximum supported length is 8 characters. 49 | * 50 | * This function uses the following value(s) of errno when an error state is reached: 51 | * 52 | * EINVAL: The line number is not in the interval [0, 2] 53 | * EMSGSIZE: The alert is more than 3 lines long 54 | * 55 | * @return 0 if the alert was added successfully 56 | * @return INT32_MAX if there was an error, setting errno 57 | * 58 | */ 59 | int32_t addAlerts(uint8_t line, std::string strs, uint32_t duration, std::string rumble = ""); 60 | private: 61 | struct AlertBuffer { 62 | ScreenBuffer screen; 63 | uint32_t duration; 64 | }; 65 | 66 | std::deque m_screen_buffer {}; 67 | std::optional m_screen_contents {}; 68 | uint32_t m_line_set_time = 0; 69 | pros::Mutex m_mutex {}; 70 | }; 71 | 72 | } // namespace gamepad 73 | -------------------------------------------------------------------------------- /include/gamepad/screens/defaultScreen.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gamepad/screens/abstractScreen.hpp" 4 | #include "pros/rtos.hpp" 5 | 6 | namespace gamepad { 7 | 8 | /** 9 | * @brief A basic screen that allows basic prints, similar to pros controller api 10 | * 11 | * @note The gamepad class has wrappers around this class 12 | * @note priority: 1 13 | */ 14 | class DefaultScreen : public AbstractScreen { 15 | public: 16 | DefaultScreen() 17 | : AbstractScreen(1) {} 18 | 19 | /** 20 | * @brief returns any lines that have space to print on the controller 21 | * 22 | * @param visible_lines a set that contains the line numbers of all lines that 23 | * are empty and available for printing 24 | * 25 | * @returns a the lines to be printed, any lines that are not available will be ignored 26 | */ 27 | ScreenBuffer getScreen(std::set visible_lines); 28 | 29 | /** 30 | * @brief print a line to the console like pros 31 | * 32 | * @param line the line number to print the string on (0-2) 33 | * @param str the string to print onto the controller (\n to go to the next line) 34 | * 35 | * This function uses the following value(s) of errno when an error state is reached: 36 | * 37 | * EINVAL: The line number is not in the interval [0, 2] 38 | * EMSGSIZE: The string is more than 3 lines long 39 | * 40 | * @return 0 if the alert was added successfully 41 | * @return INT32_MAX if there was an error, setting errno 42 | */ 43 | int32_t printLine(uint8_t line, std::string str); 44 | 45 | /** 46 | * makes the controller rumble like pros 47 | * 48 | * @param rumble_pattern A string consisting of the characters '.', '-', and ' ', where dots are short rumbles, 49 | * dashes are long rumbles, and spaces are pauses. Maximum supported length is 8 characters. 50 | * 51 | * This function uses the following value(s) of errno when an error state is reached: 52 | * 53 | * EINVAL: The rumble pattern contains a character other than '.', '-', or ' ' 54 | * EMSGSIZE: The pattern is more than 8 characters long 55 | * 56 | * @return 0 if the alert was added successfully 57 | * @return INT32_MAX if there was an error, setting errno 58 | */ 59 | int32_t rumble(std::string rumble_pattern); 60 | private: 61 | ScreenBuffer m_current_buffer {}; 62 | pros::Mutex m_mutex {}; 63 | }; 64 | 65 | } // namespace gamepad 66 | -------------------------------------------------------------------------------- /include/gamepad/todo.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define DO_PRAGMA(x) _Pragma(#x) 4 | 5 | // We only define the TODO/FIXME macros if the file is being compiled by Microsoft Intellisense 6 | // or clangd. This way, the TODO/FIXME messages don't clutter the compilation messages. 7 | #if defined(_debug) || defined(__clang__) 8 | #define TODO(x) DO_PRAGMA(message("TODO - " x)) 9 | #define FIXME(x) DO_PRAGMA(warning("FIXME - " x)) 10 | #else 11 | #define TODO(x) 12 | #define FIXME(x) 13 | #endif -------------------------------------------------------------------------------- /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-2023, 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 convienent 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 | 55 | /** 56 | * Prototypes for the competition control tasks are redefined here to ensure 57 | * that they can be called from user code (i.e. calling autonomous from a 58 | * button press in opcontrol() for testing purposes). 59 | */ 60 | #ifdef __cplusplus 61 | extern "C" { 62 | #endif 63 | void autonomous(void); 64 | void initialize(void); 65 | void disabled(void); 66 | void competition_initialize(void); 67 | void opcontrol(void); 68 | #ifdef __cplusplus 69 | } 70 | #endif 71 | 72 | #ifdef __cplusplus 73 | /** 74 | * You can add C++-only headers here 75 | */ 76 | //#include 77 | #endif 78 | 79 | #endif // _PROS_MAIN_H_ 80 | -------------------------------------------------------------------------------- /include/pros/colors.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file pros/colors.h 3 | * 4 | * Contains macro definitions of colors (as `uint32_t`) 5 | * 6 | * This file should not be modified by users, since it gets replaced whenever 7 | * a kernel upgrade occurs. 8 | * 9 | * Copyright (c) 2017-2020 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 | * \defgroup c-colors Colors C API 16 | */ 17 | 18 | /** 19 | * \ingroup c-colors 20 | * \note These functions can be used for dynamic device instantiation. 21 | */ 22 | 23 | /** 24 | * \addtogroup c-colors 25 | * @{ 26 | */ 27 | 28 | #ifndef _PROS_COLORS_H_ 29 | #define _PROS_COLORS_H_ 30 | 31 | #define RGB2COLOR(R, G, B) ((R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff)) 32 | #define COLOR2R(COLOR) ((COLOR >> 16) & 0xff) 33 | #define COLOR2G(COLOR) ((COLOR >> 8) & 0xff) 34 | #define COLOR2B(COLOR) (COLOR & 0xff) 35 | 36 | #ifdef __cplusplus 37 | namespace pros { 38 | namespace c { 39 | #endif 40 | 41 | /** 42 | * \enum color_e_t 43 | * @brief 44 | * Enum of possible colors 45 | * 46 | * Contains common colors, all members are self descriptive. 47 | */ 48 | typedef enum color_e { 49 | COLOR_ALICE_BLUE = 0x00F0F8FF, 50 | COLOR_ANTIQUE_WHITE = 0x00FAEBD7, 51 | COLOR_AQUA = 0x0000FFFF, 52 | COLOR_AQUAMARINE = 0x007FFFD4, 53 | COLOR_AZURE = 0x00F0FFFF, 54 | COLOR_BEIGE = 0x00F5F5DC, 55 | COLOR_BISQUE = 0x00FFE4C4, 56 | COLOR_BLACK = 0x00000000, 57 | COLOR_BLANCHED_ALMOND = 0x00FFEBCD, 58 | COLOR_BLUE = 0x000000FF, 59 | COLOR_BLUE_VIOLET = 0x008A2BE2, 60 | COLOR_BROWN = 0x00A52A2A, 61 | COLOR_BURLY_WOOD = 0x00DEB887, 62 | COLOR_CADET_BLUE = 0x005F9EA0, 63 | COLOR_CHARTREUSE = 0x007FFF00, 64 | COLOR_CHOCOLATE = 0x00D2691E, 65 | COLOR_CORAL = 0x00FF7F50, 66 | COLOR_CORNFLOWER_BLUE = 0x006495ED, 67 | COLOR_CORNSILK = 0x00FFF8DC, 68 | COLOR_CRIMSON = 0x00DC143C, 69 | COLOR_CYAN = 0x0000FFFF, 70 | COLOR_DARK_BLUE = 0x0000008B, 71 | COLOR_DARK_CYAN = 0x00008B8B, 72 | COLOR_DARK_GOLDENROD = 0x00B8860B, 73 | COLOR_DARK_GRAY = 0x00A9A9A9, 74 | COLOR_DARK_GREY = COLOR_DARK_GRAY, 75 | COLOR_DARK_GREEN = 0x00006400, 76 | COLOR_DARK_KHAKI = 0x00BDB76B, 77 | COLOR_DARK_MAGENTA = 0x008B008B, 78 | COLOR_DARK_OLIVE_GREEN = 0x00556B2F, 79 | COLOR_DARK_ORANGE = 0x00FF8C00, 80 | COLOR_DARK_ORCHID = 0x009932CC, 81 | COLOR_DARK_RED = 0x008B0000, 82 | COLOR_DARK_SALMON = 0x00E9967A, 83 | COLOR_DARK_SEA_GREEN = 0x008FBC8F, 84 | COLOR_DARK_SLATE_GRAY = 0x002F4F4F, 85 | COLOR_DARK_SLATE_GREY = COLOR_DARK_SLATE_GRAY, 86 | COLOR_DARK_TURQUOISE = 0x0000CED1, 87 | COLOR_DARK_VIOLET = 0x009400D3, 88 | COLOR_DEEP_PINK = 0x00FF1493, 89 | COLOR_DEEP_SKY_BLUE = 0x0000BFFF, 90 | COLOR_DIM_GRAY = 0x00696969, 91 | COLOR_DIM_GREY = COLOR_DIM_GRAY, 92 | COLOR_DODGER_BLUE = 0x001E90FF, 93 | COLOR_FIRE_BRICK = 0x00B22222, 94 | COLOR_FLORAL_WHITE = 0x00FFFAF0, 95 | COLOR_FOREST_GREEN = 0x00228B22, 96 | COLOR_FUCHSIA = 0x00FF00FF, 97 | COLOR_GAINSBORO = 0x00DCDCDC, 98 | COLOR_GHOST_WHITE = 0x00F8F8FF, 99 | COLOR_GOLD = 0x00FFD700, 100 | COLOR_GOLDENROD = 0x00DAA520, 101 | COLOR_GRAY = 0x00808080, 102 | COLOR_GREY = COLOR_GRAY, 103 | COLOR_GREEN = 0x00008000, 104 | COLOR_GREEN_YELLOW = 0x00ADFF2F, 105 | COLOR_HONEYDEW = 0x00F0FFF0, 106 | COLOR_HOT_PINK = 0x00FF69B4, 107 | COLOR_INDIAN_RED = 0x00CD5C5C, 108 | COLOR_INDIGO = 0x004B0082, 109 | COLOR_IVORY = 0x00FFFFF0, 110 | COLOR_KHAKI = 0x00F0E68C, 111 | COLOR_LAVENDER = 0x00E6E6FA, 112 | COLOR_LAVENDER_BLUSH = 0x00FFF0F5, 113 | COLOR_LAWN_GREEN = 0x007CFC00, 114 | COLOR_LEMON_CHIFFON = 0x00FFFACD, 115 | COLOR_LIGHT_BLUE = 0x00ADD8E6, 116 | COLOR_LIGHT_CORAL = 0x00F08080, 117 | COLOR_LIGHT_CYAN = 0x00E0FFFF, 118 | COLOR_LIGHT_GOLDENROD_YELLOW = 0x00FAFAD2, 119 | COLOR_LIGHT_GREEN = 0x0090EE90, 120 | COLOR_LIGHT_GRAY = 0x00D3D3D3, 121 | COLOR_LIGHT_GREY = COLOR_LIGHT_GRAY, 122 | COLOR_LIGHT_PINK = 0x00FFB6C1, 123 | COLOR_LIGHT_SALMON = 0x00FFA07A, 124 | COLOR_LIGHT_SEA_GREEN = 0x0020B2AA, 125 | COLOR_LIGHT_SKY_BLUE = 0x0087CEFA, 126 | COLOR_LIGHT_SLATE_GRAY = 0x00778899, 127 | COLOR_LIGHT_SLATE_GREY = COLOR_LIGHT_SLATE_GRAY, 128 | COLOR_LIGHT_STEEL_BLUE = 0x00B0C4DE, 129 | COLOR_LIGHT_YELLOW = 0x00FFFFE0, 130 | COLOR_LIME = 0x0000FF00, 131 | COLOR_LIME_GREEN = 0x0032CD32, 132 | COLOR_LINEN = 0x00FAF0E6, 133 | COLOR_MAGENTA = 0x00FF00FF, 134 | COLOR_MAROON = 0x00800000, 135 | COLOR_MEDIUM_AQUAMARINE = 0x0066CDAA, 136 | COLOR_MEDIUM_BLUE = 0x000000CD, 137 | COLOR_MEDIUM_ORCHID = 0x00BA55D3, 138 | COLOR_MEDIUM_PURPLE = 0x009370DB, 139 | COLOR_MEDIUM_SEA_GREEN = 0x003CB371, 140 | COLOR_MEDIUM_SLATE_BLUE = 0x007B68EE, 141 | COLOR_MEDIUM_SPRING_GREEN = 0x0000FA9A, 142 | COLOR_MEDIUM_TURQUOISE = 0x0048D1CC, 143 | COLOR_MEDIUM_VIOLET_RED = 0x00C71585, 144 | COLOR_MIDNIGHT_BLUE = 0x00191970, 145 | COLOR_MINT_CREAM = 0x00F5FFFA, 146 | COLOR_MISTY_ROSE = 0x00FFE4E1, 147 | COLOR_MOCCASIN = 0x00FFE4B5, 148 | COLOR_NAVAJO_WHITE = 0x00FFDEAD, 149 | COLOR_NAVY = 0x00000080, 150 | COLOR_OLD_LACE = 0x00FDF5E6, 151 | COLOR_OLIVE = 0x00808000, 152 | COLOR_OLIVE_DRAB = 0x006B8E23, 153 | COLOR_ORANGE = 0x00FFA500, 154 | COLOR_ORANGE_RED = 0x00FF4500, 155 | COLOR_ORCHID = 0x00DA70D6, 156 | COLOR_PALE_GOLDENROD = 0x00EEE8AA, 157 | COLOR_PALE_GREEN = 0x0098FB98, 158 | COLOR_PALE_TURQUOISE = 0x00AFEEEE, 159 | COLOR_PALE_VIOLET_RED = 0x00DB7093, 160 | COLOR_PAPAY_WHIP = 0x00FFEFD5, 161 | COLOR_PEACH_PUFF = 0x00FFDAB9, 162 | COLOR_PERU = 0x00CD853F, 163 | COLOR_PINK = 0x00FFC0CB, 164 | COLOR_PLUM = 0x00DDA0DD, 165 | COLOR_POWDER_BLUE = 0x00B0E0E6, 166 | COLOR_PURPLE = 0x00800080, 167 | COLOR_RED = 0x00FF0000, 168 | COLOR_ROSY_BROWN = 0x00BC8F8F, 169 | COLOR_ROYAL_BLUE = 0x004169E1, 170 | COLOR_SADDLE_BROWN = 0x008B4513, 171 | COLOR_SALMON = 0x00FA8072, 172 | COLOR_SANDY_BROWN = 0x00F4A460, 173 | COLOR_SEA_GREEN = 0x002E8B57, 174 | COLOR_SEASHELL = 0x00FFF5EE, 175 | COLOR_SIENNA = 0x00A0522D, 176 | COLOR_SILVER = 0x00C0C0C0, 177 | COLOR_SKY_BLUE = 0x0087CEEB, 178 | COLOR_SLATE_BLUE = 0x006A5ACD, 179 | COLOR_SLATE_GRAY = 0x00708090, 180 | COLOR_SLATE_GREY = COLOR_SLATE_GRAY, 181 | COLOR_SNOW = 0x00FFFAFA, 182 | COLOR_SPRING_GREEN = 0x0000FF7F, 183 | COLOR_STEEL_BLUE = 0x004682B4, 184 | COLOR_TAN = 0x00D2B48C, 185 | COLOR_TEAL = 0x00008080, 186 | COLOR_THISTLE = 0x00D8BFD8, 187 | COLOR_TOMATO = 0x00FF6347, 188 | COLOR_TURQUOISE = 0x0040E0D0, 189 | COLOR_VIOLET = 0x00EE82EE, 190 | COLOR_WHEAT = 0x00F5DEB3, 191 | COLOR_WHITE = 0x00FFFFFF, 192 | COLOR_WHITE_SMOKE = 0x00F5F5F5, 193 | COLOR_YELLOW = 0x00FFFF00, 194 | COLOR_YELLOW_GREEN = 0x009ACD32, 195 | } color_e_t; 196 | 197 | ///@} 198 | 199 | #ifdef __cplusplus 200 | } // namespace c 201 | } // namespace pros 202 | #endif 203 | 204 | #endif // _PROS_COLORS_H_ 205 | -------------------------------------------------------------------------------- /include/pros/colors.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file pros/colors.hpp 3 | * 4 | * Contains enum class definitions of colors 5 | * 6 | * This file should not be modified by users, since it gets replaced whenever 7 | * a kernel upgrade occurs. 8 | * 9 | * Copyright (c) 2017-2022 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 | * \defgroup cpp-colors C++ Color API 16 | */ 17 | #ifndef _PROS_COLORS_HPP_ 18 | #define _PROS_COLORS_HPP_ 19 | 20 | 21 | namespace pros{ 22 | /** 23 | * \ingroup cpp-colors 24 | */ 25 | 26 | /** 27 | * \addtogroup cpp-colors 28 | * @{ 29 | */ 30 | 31 | /** 32 | * \enum Color 33 | * @brief 34 | * Enum class of possible colors 35 | * 36 | * Contains common colors, all members are self descriptive. 37 | */ 38 | enum class Color { 39 | alice_blue = 0x00F0F8FF, 40 | antique_white = 0x00FAEBD7, 41 | aqua = 0x0000FFFF, 42 | aquamarine = 0x007FFFD4, 43 | azure = 0x00F0FFFF, 44 | beige = 0x00F5F5DC, 45 | bisque = 0x00FFE4C4, 46 | black = 0x00000000, 47 | blanched_almond = 0x00FFEBCD, 48 | blue = 0x000000FF, 49 | blue_violet = 0x008A2BE2, 50 | brown = 0x00A52A2A, 51 | burly_wood = 0x00DEB887, 52 | cadet_blue = 0x005F9EA0, 53 | chartreuse = 0x007FFF00, 54 | chocolate = 0x00D2691E, 55 | coral = 0x00FF7F50, 56 | cornflower_blue = 0x006495ED, 57 | cornsilk = 0x00FFF8DC, 58 | crimson = 0x00DC143C, 59 | cyan = 0x0000FFFF, 60 | dark_blue = 0x0000008B, 61 | dark_cyan = 0x00008B8B, 62 | dark_goldenrod = 0x00B8860B, 63 | dark_gray = 0x00A9A9A9, 64 | dark_grey = dark_gray, 65 | dark_green = 0x00006400, 66 | dark_khaki = 0x00BDB76B, 67 | dark_magenta = 0x008B008B, 68 | dark_olive_green = 0x00556B2F, 69 | dark_orange = 0x00FF8C00, 70 | dark_orchid = 0x009932CC, 71 | dark_red = 0x008B0000, 72 | dark_salmon = 0x00E9967A, 73 | dark_sea_green = 0x008FBC8F, 74 | dark_slate_gray = 0x002F4F4F, 75 | dark_slate_grey = dark_slate_gray, 76 | dark_turquoise = 0x0000CED1, 77 | dark_violet = 0x009400D3, 78 | deep_pink = 0x00FF1493, 79 | deep_sky_blue = 0x0000BFFF, 80 | dim_gray = 0x00696969, 81 | dim_grey = dim_gray, 82 | dodger_blue = 0x001E90FF, 83 | fire_brick = 0x00B22222, 84 | floral_white = 0x00FFFAF0, 85 | forest_green = 0x00228B22, 86 | fuchsia = 0x00FF00FF, 87 | gainsboro = 0x00DCDCDC, 88 | ghost_white = 0x00F8F8FF, 89 | gold = 0x00FFD700, 90 | goldenrod = 0x00DAA520, 91 | gray = 0x00808080, 92 | grey = gray, 93 | green = 0x00008000, 94 | green_yellow = 0x00ADFF2F, 95 | honeydew = 0x00F0FFF0, 96 | hot_pink = 0x00FF69B4, 97 | indian_red = 0x00CD5C5C, 98 | indigo = 0x004B0082, 99 | ivory = 0x00FFFFF0, 100 | khaki = 0x00F0E68C, 101 | lavender = 0x00E6E6FA, 102 | lavender_blush = 0x00FFF0F5, 103 | lawn_green = 0x007CFC00, 104 | lemon_chiffon = 0x00FFFACD, 105 | light_blue = 0x00ADD8E6, 106 | light_coral = 0x00F08080, 107 | light_cyan = 0x00E0FFFF, 108 | light_goldenrod_yellow = 0x00FAFAD2, 109 | light_green = 0x0090EE90, 110 | light_gray = 0x00D3D3D3, 111 | light_grey = light_gray, 112 | light_pink = 0x00FFB6C1, 113 | light_salmon = 0x00FFA07A, 114 | light_sea_green = 0x0020B2AA, 115 | light_sky_blue = 0x0087CEFA, 116 | light_slate_gray = 0x00778899, 117 | light_slate_grey = light_slate_gray, 118 | light_steel_blue = 0x00B0C4DE, 119 | light_yellow = 0x00FFFFE0, 120 | lime = 0x0000FF00, 121 | lime_green = 0x0032CD32, 122 | linen = 0x00FAF0E6, 123 | magenta = 0x00FF00FF, 124 | maroon = 0x00800000, 125 | medium_aquamarine = 0x0066CDAA, 126 | medium_blue = 0x000000CD, 127 | medium_orchid = 0x00BA55D3, 128 | medium_purple = 0x009370DB, 129 | medium_sea_green = 0x003CB371, 130 | medium_slate_blue = 0x007B68EE, 131 | medium_spring_green = 0x0000FA9A, 132 | medium_turquoise = 0x0048D1CC, 133 | medium_violet_red = 0x00C71585, 134 | midnight_blue = 0x00191970, 135 | mint_cream = 0x00F5FFFA, 136 | misty_rose = 0x00FFE4E1, 137 | moccasin = 0x00FFE4B5, 138 | navajo_white = 0x00FFDEAD, 139 | navy = 0x00000080, 140 | old_lace = 0x00FDF5E6, 141 | olive = 0x00808000, 142 | olive_drab = 0x006B8E23, 143 | orange = 0x00FFA500, 144 | orange_red = 0x00FF4500, 145 | orchid = 0x00DA70D6, 146 | pale_goldenrod = 0x00EEE8AA, 147 | pale_green = 0x0098FB98, 148 | pale_turquoise = 0x00AFEEEE, 149 | pale_violet_red = 0x00DB7093, 150 | papay_whip = 0x00FFEFD5, 151 | peach_puff = 0x00FFDAB9, 152 | peru = 0x00CD853F, 153 | pink = 0x00FFC0CB, 154 | plum = 0x00DDA0DD, 155 | powder_blue = 0x00B0E0E6, 156 | purple = 0x00800080, 157 | red = 0x00FF0000, 158 | rosy_brown = 0x00BC8F8F, 159 | royal_blue = 0x004169E1, 160 | saddle_brown = 0x008B4513, 161 | salmon = 0x00FA8072, 162 | sandy_brown = 0x00F4A460, 163 | sea_green = 0x002E8B57, 164 | seashell = 0x00FFF5EE, 165 | sienna = 0x00A0522D, 166 | silver = 0x00C0C0C0, 167 | sky_blue = 0x0087CEEB, 168 | slate_blue = 0x006A5ACD, 169 | slate_gray = 0x00708090, 170 | slate_grey = slate_gray, 171 | snow = 0x00FFFAFA, 172 | spring_green = 0x0000FF7F, 173 | steel_blue = 0x004682B4, 174 | tan = 0x00D2B48C, 175 | teal = 0x00008080, 176 | thistle = 0x00D8BFD8, 177 | tomato = 0x00FF6347, 178 | turquoise = 0x0040E0D0, 179 | violet = 0x00EE82EE, 180 | wheat = 0x00F5DEB3, 181 | white = 0x00FFFFFF, 182 | white_smoke = 0x00F5F5F5, 183 | yellow = 0x00FFFF00, 184 | yellow_green = 0x009ACD32, 185 | }; 186 | } // namespace pros 187 | 188 | ///@} 189 | 190 | #endif //_PROS_COLORS_HPP_ 191 | -------------------------------------------------------------------------------- /include/pros/device.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file pros/device.h 3 | * 4 | * Contains functions for interacting with VEX devices. 5 | * 6 | * 7 | * 8 | * This file should not be modified by users, since it gets replaced whenever 9 | * a kernel upgrade occurs. 10 | * 11 | * \copyright (c) 2017-2021, Purdue University ACM SIGBots. 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 | * \defgroup c-device VEX Generic Device C API (For Advanced Users) 18 | */ 19 | 20 | #ifndef _PROS_DEVICE_H_ 21 | #define _PROS_DEVICE_H_ 22 | 23 | #include 24 | 25 | #ifdef __cplusplus 26 | namespace pros::c { 27 | extern "C" { 28 | #endif 29 | 30 | /** 31 | * \ingroup c-device 32 | * \note These functions can be used for dynamic device instantiation. 33 | */ 34 | 35 | /** 36 | * \addtogroup c-device 37 | * @{ 38 | */ 39 | 40 | /** 41 | * \enum v5_device_e 42 | * \brief 43 | * List of possible v5 devices 44 | * 45 | * This list contains all current V5 Devices, and mirrors V5_DeviceType from the 46 | * api. 47 | */ 48 | typedef enum v5_device_e { 49 | E_DEVICE_NONE = 0, ///< No device is plugged into the port 50 | E_DEVICE_MOTOR = 2, ///< A motor is plugged into the port 51 | E_DEVICE_ROTATION = 4, ///< A rotation sensor is plugged into the port 52 | E_DEVICE_IMU = 6, ///< An inertial sensor is plugged into the port 53 | E_DEVICE_DISTANCE = 7, ///< A distance sensor is plugged into the port 54 | E_DEVICE_RADIO = 8, ///< A radio is plugged into the port 55 | E_DEVICE_VISION = 11, ///< A vision sensor is plugged into the port 56 | E_DEVICE_ADI = 12, ///< This port is an ADI expander 57 | E_DEVICE_OPTICAL = 16, ///< An optical sensor is plugged into the port 58 | E_DEVICE_GPS = 20, ///< A GPS sensor is plugged into the port 59 | E_DEVICE_SERIAL = 129, ///< A serial device is plugged into the port 60 | E_DEVICE_GENERIC __attribute__((deprecated("use E_DEVICE_SERIAL instead"))) = E_DEVICE_SERIAL, 61 | E_DEVICE_UNDEFINED = 255 ///< The device type is not defined, or is not a valid device 62 | } v5_device_e_t; 63 | 64 | /** 65 | * Gets the type of device on given port. 66 | * 67 | * \return The device type as an enum. 68 | * 69 | * \b Example 70 | * \code 71 | * #define DEVICE_PORT 1 72 | * 73 | * void opcontrol() { 74 | * while (true) { 75 | * v5_device_e_t pt = get_plugged_type(DEVICE_PORT); 76 | * printf("device plugged type: {plugged type: %d}\n", pt); 77 | * delay(20); 78 | * } 79 | * } 80 | * \endcode 81 | */ 82 | v5_device_e_t get_plugged_type(uint8_t port); 83 | 84 | ///@} 85 | 86 | #ifdef __cplusplus 87 | } // namespace c 88 | } // namespace pros 89 | #endif 90 | 91 | #endif // _PROS_DEVICE_H_ 92 | -------------------------------------------------------------------------------- /include/pros/device.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file pros/device.hpp 3 | * 4 | * Base class for all smart devices. 5 | * 6 | * This file should not be modified by users, since it gets replaced whenever 7 | * a kernel upgrade occurs. 8 | * 9 | * \copyright (c) 2017-2021, 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 | * \defgroup cpp-device VEX Generic Device C++ API (For Advanced Users) 16 | */ 17 | 18 | #ifndef _PROS_DEVICE_HPP_ 19 | #define _PROS_DEVICE_HPP_ 20 | 21 | #include "pros/misc.hpp" 22 | #include "pros/rtos.hpp" 23 | 24 | namespace pros { 25 | inline namespace v5 { 26 | /** 27 | * \ingroup cpp-device 28 | * \note These functions can be used for dynamic device instantiation. 29 | */ 30 | 31 | /** 32 | * \addtogroup cpp-device 33 | * @{ 34 | */ 35 | 36 | /** 37 | * \enum DeviceType 38 | * \brief 39 | * Enum of possible v5 devices. 40 | * 41 | * Contains all current V5 Devices. 42 | */ 43 | enum class DeviceType { 44 | none = 0, ///< No device is plugged into the port 45 | motor = 2, ///< A motor is plugged into the port 46 | rotation = 4, ///< A rotation sensor is plugged into the port 47 | imu = 6, ///< An inertial sensor is plugged into the port 48 | distance = 7, ///< A distance sensor is plugged into the port 49 | radio = 8, ///< A radio is plugged into the port 50 | vision = 11, ///< A vision sensor is plugged into the port 51 | adi = 12, ///< This port is an ADI expander 52 | optical = 16, ///< An optical sensor is plugged into the port 53 | gps = 20, ///< A GPS sensor is plugged into the port 54 | serial = 129, ///< A serial device is plugged into the port 55 | undefined = 255 ///< The device type is not defined, or is not a valid device 56 | }; 57 | 58 | class Device { 59 | public: 60 | /** 61 | * Creates a Device object. 62 | * 63 | * \param port The V5 port number from 1-21 64 | * 65 | * \b Example 66 | * \code 67 | * #define DEVICE_PORT 1 68 | * 69 | * void opcontrol() { 70 | * Device device(DEVICE_PORT); 71 | * } 72 | * \endcode 73 | */ 74 | explicit Device(const std::uint8_t port); 75 | 76 | /** 77 | * Gets the port number of the Smart Device. 78 | * 79 | * \return The smart device's port number. 80 | * 81 | * \b Example 82 | * \code 83 | * void opcontrol() { 84 | * #define DEVICE_PORT 1 85 | * while (true) { 86 | * Device device(DEVICE_PORT); 87 | * printf("device plugged type: {port: %d}\n", device.get_port()); 88 | * delay(20); 89 | * } 90 | * } 91 | * \endcode 92 | */ 93 | std::uint8_t get_port(void) const; 94 | 95 | /** 96 | * Checks if the device is installed. 97 | * 98 | * \return true if the corresponding device is installed, false otherwise. 99 | * \b Example 100 | * 101 | * \code 102 | * #define DEVICE_PORT 1 103 | * 104 | * void opcontrol() { 105 | * Device device(DEVICE_PORT); 106 | * while (true) { 107 | * printf("device plugged type: {is_installed: %d}\n", device.is_installed()); 108 | * delay(20); 109 | * } 110 | * } 111 | * \endcode 112 | */ 113 | virtual bool is_installed(); 114 | 115 | /** 116 | * Gets the type of device. 117 | * 118 | * This function uses the following values of errno when an error state is 119 | * reached: 120 | * EACCES - Mutex of port cannot be taken (access denied). 121 | * 122 | * \return The device type as an enum. 123 | * 124 | * \b Example 125 | * \code 126 | * #define DEVICE_PORT 1 127 | * 128 | * void opcontrol() { 129 | Device device(DEVICE_PORT); 130 | * while (true) { 131 | * DeviceType dt = device.get_plugged_type(); 132 | * printf("device plugged type: {plugged type: %d}\n", dt); 133 | * delay(20); 134 | * } 135 | * } 136 | * \endcode 137 | */ 138 | pros::DeviceType get_plugged_type() const; 139 | 140 | static pros::DeviceType get_plugged_type(std::uint8_t port); 141 | 142 | static std::vector get_all_devices(pros::DeviceType device_type = pros::DeviceType::undefined); 143 | 144 | protected: 145 | /** 146 | * Creates a Device object. 147 | * 148 | * \param port The V5 port number from 1-21 149 | * 150 | * \param deviceType The type of the constructed device 151 | */ 152 | Device(const std::uint8_t port, const enum DeviceType deviceType) : 153 | _port(port), 154 | _deviceType(deviceType) {} 155 | 156 | protected: 157 | const std::uint8_t _port; 158 | const enum DeviceType _deviceType = pros::DeviceType::none; 159 | 160 | ///@} 161 | }; 162 | } // namespace v5 163 | } // namespace pros 164 | 165 | #endif 166 | -------------------------------------------------------------------------------- /include/pros/distance.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file pros/distance.h 3 | * \ingroup c-distance 4 | * 5 | * Contains prototypes for functions related to the VEX Distance sensor. 6 | * 7 | * This file should not be modified by users, since it gets replaced whenever 8 | * a kernel upgrade occurs. 9 | * 10 | * \copyright (c) 2017-2023, Purdue University ACM SIGBots. 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 | * \defgroup c-distance VEX Distance Sensor C API 17 | */ 18 | 19 | #ifndef _PROS_DISTANCE_H_ 20 | #define _PROS_DISTANCE_H_ 21 | 22 | #include 23 | #include 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | namespace pros { 28 | namespace c { 29 | #endif 30 | 31 | /** 32 | * \ingroup c-distance 33 | */ 34 | 35 | /** 36 | * \addtogroup c-distance 37 | * @{ 38 | */ 39 | 40 | /** 41 | * Get the currently measured distance from the sensor in mm 42 | * 43 | * This function uses the following values of errno when an error state is 44 | * reached: 45 | * ENXIO - The given value is not within the range of V5 ports (1-21). 46 | * ENODEV - The port cannot be configured as an Distance Sensor 47 | * 48 | * \param port The V5 Distance Sensor port number from 1-21 49 | * \return The distance value or PROS_ERR if the operation failed, setting 50 | * errno. 51 | * 52 | * \b Example 53 | * \code 54 | * #define DISTANCE_PORT 1 55 | * 56 | * void opcontrol() { 57 | * while (true) { 58 | * printf("Distance Value: %d mm\n", distance_get(DISTANCE_PORT)); 59 | * delay(20); 60 | * } 61 | * } 62 | * \endcode 63 | */ 64 | int32_t distance_get(uint8_t port); 65 | 66 | /** 67 | * Get the confidence in the distance reading 68 | * 69 | * This is a value that has a range of 0 to 63. 63 means high confidence, 70 | * lower values imply less confidence. Confidence is only available 71 | * when distance is > 200mm (the value 10 is returned in this scenario). 72 | * 73 | * This function uses the following values of errno when an error state is 74 | * reached: 75 | * ENXIO - The given value is not within the range of V5 ports (1-21). 76 | * ENODEV - The port cannot be configured as an Distance Sensor 77 | * 78 | * \param port The V5 Distance Sensor port number from 1-21 79 | * \return The confidence value or PROS_ERR if the operation failed, setting 80 | * errno. 81 | * 82 | * \b Example 83 | * \code 84 | * #define DISTANCE_PORT 1 85 | * 86 | * void opcontrol() { 87 | * while (true) { 88 | * printf("Distance Confidence Value: %d\n", distance_get_confidence(DISTANCE_PORT)); 89 | * delay(20); 90 | * } 91 | * } 92 | * \endcode 93 | */ 94 | int32_t distance_get_confidence(uint8_t port); 95 | 96 | /** 97 | * Get the current guess at relative object size 98 | * 99 | * This is a value that has a range of 0 to 400. 100 | * A 18" x 30" grey card will return a value of approximately 75 101 | * in typical room lighting. 102 | * 103 | * This function uses the following values of errno when an error state is 104 | * reached: 105 | * ENXIO - The given value is not within the range of V5 ports (1-21). 106 | * ENODEV - The port cannot be configured as an Distance Sensor 107 | * 108 | * \param port The V5 Distance Sensor port number from 1-21 109 | * \return The size value or PROS_ERR if the operation failed, setting 110 | * errno. 111 | * 112 | * \b Example 113 | * \code 114 | * #define DISTANCE_PORT 1 115 | * 116 | * void opcontrol() { 117 | * while (true) { 118 | * printf("Distance Object Size: %d\n", distance_get_object_size(DISTANCE_PORT)); 119 | * delay(20); 120 | * } 121 | * } 122 | * \endcode 123 | */ 124 | int32_t distance_get_object_size(uint8_t port); 125 | 126 | /** 127 | * Get the object velocity in m/s 128 | * 129 | * This function uses the following values of errno when an error state is 130 | * reached: 131 | * ENXIO - The given value is not within the range of V5 ports (1-21). 132 | * ENODEV - The port cannot be configured as an Distance Sensor 133 | * 134 | * \param port The V5 Distance Sensor port number from 1-21 135 | * \return The velocity value or PROS_ERR if the operation failed, setting 136 | * errno. 137 | * 138 | * \b Example 139 | * \code 140 | * #define DISTANCE_PORT 1 141 | * 142 | * void opcontrol() { 143 | * while (true) { 144 | * printf("Distance Object Velocity: %f\n", distance_get_object_velocity(DISTANCE_PORT)); 145 | * delay(20); 146 | * } 147 | * } 148 | * \endcode 149 | */ 150 | double distance_get_object_velocity(uint8_t port); 151 | 152 | ///@} 153 | 154 | #ifdef __cplusplus 155 | } 156 | } 157 | } 158 | #endif 159 | 160 | #endif 161 | -------------------------------------------------------------------------------- /include/pros/distance.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file pros/distance.hpp 3 | * \ingroup cpp-distance 4 | * 5 | * Contains prototypes for the V5 Distance Sensor-related functions. 6 | * 7 | * This file should not be modified by users, since it gets replaced whenever 8 | * a kernel upgrade occurs. 9 | * 10 | * \copyright (c) 2017-2023, Purdue University ACM SIGBots. 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 | * \defgroup cpp-distance VEX Distance Sensor C++ API 17 | */ 18 | 19 | #ifndef _PROS_DISTANCE_HPP_ 20 | #define _PROS_DISTANCE_HPP_ 21 | 22 | #include 23 | #include 24 | 25 | #include "pros/device.hpp" 26 | #include "pros/distance.h" 27 | 28 | namespace pros { 29 | inline namespace v5 { 30 | /** 31 | * \ingroup cpp-distance 32 | */ 33 | class Distance : public Device { 34 | /** 35 | * \addtogroup cpp-distance 36 | * @{ 37 | */ 38 | public: 39 | /** 40 | * Creates a Distance Sensor object for the given port. 41 | * 42 | * This function uses the following values of errno when an error state is 43 | * reached: 44 | * ENXIO - The given value is not within the range of V5 ports (1-21). 45 | * ENODEV - The port cannot be configured as a Distance Sensor 46 | * 47 | * \param port 48 | * The V5 port number from 1-21 49 | * 50 | * \b Example 51 | * \code 52 | * #define DISTANCE_PORT 1 53 | * 54 | * void opcontrol() { 55 | * Distance distance(DISTANCE_PORT); 56 | * } 57 | * \endcode 58 | */ 59 | Distance(const std::uint8_t port); 60 | 61 | Distance(const Device& device) 62 | : Distance(device.get_port()) {}; 63 | 64 | /** 65 | * Get the currently measured distance from the sensor in mm 66 | * 67 | * This function uses the following values of errno when an error state is 68 | * reached: 69 | * ENXIO - The given value is not within the range of V5 ports (1-21). 70 | * ENODEV - The port cannot be configured as an Distance Sensor 71 | * 72 | * \return The distance value or PROS_ERR if the operation failed, setting 73 | * errno. Will return 9999 if the sensor can not detect an object. 74 | * 75 | * \b Example 76 | * \code 77 | * #define DISTANCE_PORT 1 78 | * 79 | * void opcontrol() { 80 | Distance distance(DISTANCE_PORT); 81 | * while (true) { 82 | * printf("Distance confidence: %d\n", distance.get()); 83 | * delay(20); 84 | * } 85 | * } 86 | * \endcode 87 | */ 88 | virtual std::int32_t get(); 89 | 90 | static std::vector get_all_devices(); 91 | 92 | /** 93 | * Get the currently measured distance from the sensor in mm. 94 | * \note This function is identical to get(). 95 | * 96 | * This function uses the following values of errno when an error state is 97 | * reached: 98 | * ENXIO - The given value is not within the range of V5 ports (1-21). 99 | * ENODEV - The port cannot be configured as an Distance Sensor 100 | * 101 | * \return The distance value or PROS_ERR if the operation failed, setting 102 | * errno. Will return 9999 if the sensor can not detect an object. 103 | * 104 | * \b Example 105 | * \code 106 | * #define DISTANCE_PORT 1 107 | * 108 | * void opcontrol() { 109 | Distance distance(DISTANCE_PORT); 110 | * while (true) { 111 | * printf("Distance confidence: %d\n", distance.get_distance()); 112 | * delay(20); 113 | * } 114 | * } 115 | * \endcode 116 | */ 117 | virtual std::int32_t get_distance(); 118 | 119 | /** 120 | * Get the confidence in the distance reading 121 | * 122 | * This is a value that has a range of 0 to 63. 63 means high confidence, 123 | * lower values imply less confidence. Confidence is only available 124 | * when distance is > 200mm. 125 | * 126 | * This function uses the following values of errno when an error state is 127 | * reached: 128 | * ENXIO - The given value is not within the range of V5 ports (1-21). 129 | * ENODEV - The port cannot be configured as an Distance Sensor 130 | * 131 | * \return The confidence value or PROS_ERR if the operation failed, setting 132 | * errno. 133 | * 134 | * \b Example 135 | * \code 136 | * #define DISTANCE_PORT 1 137 | * 138 | * void opcontrol() { 139 | Distance distance(DISTANCE_PORT); 140 | * while (true) { 141 | * printf("Distance confidence: %d\n", distance.get_confidence()); 142 | * delay(20); 143 | * } 144 | * } 145 | * \endcode 146 | */ 147 | virtual std::int32_t get_confidence(); 148 | 149 | /** 150 | * Get the current guess at relative object size 151 | * 152 | * This is a value that has a range of 0 to 400. 153 | * A 18" x 30" grey card will return a value of approximately 75 154 | * in typical room lighting. 155 | * 156 | * This function uses the following values of errno when an error state is 157 | * reached: 158 | * ENXIO - The given value is not within the range of V5 ports (1-21). 159 | * ENODEV - The port cannot be configured as an Distance Sensor 160 | * 161 | * \return The size value or PROS_ERR if the operation failed, setting 162 | * errno. Will return -1 if the sensor is not able to determine object size. 163 | * 164 | * \b Example 165 | * \code 166 | * #define DISTANCE_PORT 1 167 | * 168 | * void opcontrol() { 169 | Distance distance(DISTANCE_PORT); 170 | * while (true) { 171 | * printf("Distance confidence: %d\n", distance.get_object_size()); 172 | * delay(20); 173 | * } 174 | * } 175 | * \endcode 176 | */ 177 | virtual std::int32_t get_object_size(); 178 | 179 | /** 180 | * Get the object velocity in m/s 181 | * 182 | * This function uses the following values of errno when an error state is 183 | * reached: 184 | * ENXIO - The given value is not within the range of V5 ports (1-21). 185 | * ENODEV - The port cannot be configured as an Distance Sensor 186 | * 187 | * \return The velocity value or PROS_ERR if the operation failed, setting 188 | * errno. 189 | * 190 | * \b Example 191 | * \code 192 | * 193 | * void opcontrol() { 194 | * Distance distance(DISTANCE_PORT); 195 | * while (true) { 196 | * printf("Distance Object velocity: %f\n", distance.get_object_velocity()); 197 | * delay(20); 198 | * } 199 | * } 200 | * \endcode 201 | */ 202 | virtual double get_object_velocity(); 203 | 204 | /** 205 | * This is the overload for the << operator for printing to streams 206 | * 207 | * Prints in format(this below is all in one line with no new line): 208 | * Distance [port: (port number), distance: (distance), confidence: (confidence), 209 | * object size: (object size), object velocity: (object velocity)] 210 | */ 211 | friend std::ostream& operator<<(std::ostream& os, pros::Distance& distance); 212 | 213 | private: 214 | ///@} 215 | }; 216 | 217 | namespace literals { 218 | const pros::Distance operator"" _dist(const unsigned long long int d); 219 | } // namespace literals 220 | } 221 | } // namespace pros 222 | 223 | #endif 224 | -------------------------------------------------------------------------------- /include/pros/error.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file pros/error.h 3 | * 4 | * Contains macro definitions for return types, mostly errors 5 | * 6 | * This file should not be modified by users, since it gets replaced whenever 7 | * a kernel upgrade occurs. 8 | * 9 | * \copyright Copyright (c) 2017-2023, 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 | #ifndef _PROS_ERROR_H_ 16 | #define _PROS_ERROR_H_ 17 | 18 | #include "limits.h" 19 | 20 | // Different Byte Size Errors 21 | 22 | /// @brief 23 | /// Return This on Byte Sized Return Error 24 | #define PROS_ERR_BYTE (INT8_MAX) 25 | 26 | /// @brief 27 | /// Return This on 2 Byte Sized Return Error 28 | #define PROS_ERR_2_BYTE (INT16_MAX) 29 | 30 | /// @brief 31 | /// Return This on 4 Byte Sized Return Error 32 | #define PROS_ERR (INT32_MAX) 33 | 34 | /// @brief 35 | /// Return This on 8 Byte Sized Return Error 36 | #define PROS_ERR_F (INFINITY) 37 | 38 | /// @brief 39 | /// Return This on Success (1) 40 | #define PROS_SUCCESS (1) 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /include/pros/link.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file pros/link.hpp 3 | * \ingroup cpp-link 4 | * 5 | * Contains prototypes for functions related to robot to robot communications. 6 | * 7 | * This file should not be modified by users, since it gets replaced whenever 8 | * a kernel upgrade occurs. 9 | * 10 | * Copyright (c) 2017-2021, Purdue University ACM SIGBots. 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 | * \defgroup cpp-link VEX Link C++ API 17 | */ 18 | #ifndef _PROS_LINK_HPP_ 19 | #define _PROS_LINK_HPP_ 20 | 21 | #include 22 | #include 23 | 24 | #include "pros/link.h" 25 | #include "pros/device.hpp" 26 | 27 | namespace pros { 28 | /** 29 | * \ingroup cpp-link 30 | */ 31 | class Link : public Device { 32 | /** 33 | * \addtogroup cpp-link 34 | * ///@{ 35 | */ 36 | private: 37 | 38 | public: 39 | /** 40 | * Initializes a link on a radio port, with an indicated type. There might be a 41 | * 1 to 2 second delay from when this function is called to when the link is initializes. 42 | * 43 | * \note This function uses the following values of errno when an error state is 44 | * reached: 45 | * ENXIO - The given value is not within the range of V5 ports (1-21). 46 | * ENODEV - The port cannot be configured as a radio. 47 | * ENXIO - The sensor is still calibrating, or no link is connected via the radio. 48 | * 49 | * \param port 50 | * The port of the radio for the intended link. 51 | * \param link_id 52 | * Unique link ID in the form of a string, needs to be different from other links in 53 | * the area. 54 | * \param type 55 | * Indicates whether the radio link on the brain is a transmitter or receiver, 56 | * with the transmitter having double the transmitting bandwidth as the receiving 57 | * end (1040 bytes/s vs 520 bytes/s). 58 | * \param ov 59 | * Indicates if the radio on the given port needs vexlink to override the controller radio. Defualts to True. 60 | * 61 | * \return PROS_ERR if initialization fails, 1 if the initialization succeeds. 62 | * 63 | * \b Example: 64 | * \code 65 | * pros::Link link(1, "my_link", pros::E_LINK_TX); 66 | * \endcode 67 | */ 68 | explicit Link(const std::uint8_t port, const std::string link_id, link_type_e_t type, bool ov = true); 69 | 70 | /** 71 | * Checks if a radio link on a port is active or not. 72 | * 73 | * \note This function uses the following values of errno when an error state is 74 | * reached: 75 | * ENXIO - The given value is not within the range of V5 ports (1-21). 76 | * ENODEV - The port cannot be configured as a radio. 77 | * ENXIO - The sensor is still calibrating, or no link is connected via the radio. 78 | * 79 | * \return If a radio is connected to a port and it's connected to a link. 80 | * 81 | * \b Example: 82 | * \code 83 | * pros::Link link(1, "my_link", pros::E_LINK_TX); 84 | * if (link.connected()) { 85 | * // do something 86 | * } 87 | * \endcode 88 | */ 89 | bool connected(); 90 | 91 | /** 92 | * Returns the bytes of data number of without protocol available to be read 93 | * 94 | * \note This function uses the following values of errno when an error state is 95 | * reached: 96 | * ENXIO - The given value is not within the range of V5 ports (1-21). 97 | * ENODEV - The port cannot be configured as a radio. 98 | * ENXIO - The sensor is still calibrating, or no link is connected via the radio. 99 | * 100 | * \return PROS_ERR if port is not a link/radio, else the bytes available to be 101 | * read by the user. 102 | * 103 | * \b Example: 104 | * \code 105 | * void opcontrol() { 106 | * pros::Link link(1, "my_link", pros::E_LINK_TX); 107 | * printf("Bytes available to read: %d", link.receivable_size()); 108 | * } 109 | * \endcode 110 | */ 111 | std::uint32_t raw_receivable_size(); 112 | 113 | /** 114 | * Returns the bytes of data available in transmission buffer. 115 | * 116 | * \note This function uses the following values of errno when an error state is 117 | * reached: 118 | * ENXIO - The given value is not within the range of V5 ports (1-21). 119 | * ENODEV - The port cannot be configured as a radio. 120 | * ENXIO - The sensor is still calibrating, or no link is connected via the radio. 121 | * 122 | * \return PROS_ERR if port is not a link/radio, 123 | * else the bytes available to be transmitted by the user. 124 | * 125 | * \b Example: 126 | * \code 127 | * void opcontrol() { 128 | * pros::Link link(1, "my_link", pros::E_LINK_TX); 129 | * printf("Bytes available to transmit: %d", link.transmittable_size()); 130 | * } 131 | */ 132 | std::uint32_t raw_transmittable_size(); 133 | 134 | /** 135 | * Send raw serial data through vexlink. 136 | * 137 | * \note This function uses the following values of errno when an error state is 138 | * reached: 139 | * ENXIO - The given value is not within the range of V5 ports (1-21). 140 | * ENODEV - The port cannot be configured as a radio. 141 | * ENXIO - The sensor is still calibrating, or no link is connected via the radio. 142 | * EBUSY - The transmitter buffer is still busy with a previous transmission, and there is no 143 | * room in the FIFO buffer (queue) to transmit the data. 144 | * EINVAL - The data given is NULL 145 | * 146 | * \param data 147 | * Buffer with data to send 148 | * \param data_size 149 | * Buffer with data to send 150 | * 151 | * \return PROS_ERR if port is not a link, and the successfully transmitted 152 | * data size if it succeeded. 153 | * 154 | * \b Example: 155 | * \code 156 | * void opcontrol() { 157 | * pros::Link link(1, "my_link", pros::E_LINK_TX); 158 | * std::uint8_t data[4] = {0x01, 0x02, 0x03, 0x04}; 159 | * link.transmit_raw(data, 4); 160 | * } 161 | * 162 | * \endcode 163 | */ 164 | std::uint32_t transmit_raw(void* data, std::uint16_t data_size); 165 | 166 | /** 167 | * Receive raw serial data through vexlink. 168 | * 169 | * \note This function uses the following values of errno when an error state is 170 | * reached: 171 | * ENXIO - The given value is not within the range of V5 ports (1-21). 172 | * ENODEV - The port cannot be configured as a radio. 173 | * ENXIO - The sensor is still calibrating, or no link is connected via the radio. 174 | * EINVAL - The destination given is NULL, or the size given is larger than the FIFO buffer 175 | * or destination buffer. 176 | * 177 | * \param dest 178 | * Destination buffer to read data to 179 | * \param data_size 180 | * Bytes of data to be read to the destination buffer 181 | * 182 | * \return PROS_ERR if port is not a link, and the successfully received 183 | * data size if it succeeded. 184 | * 185 | * \b Example: 186 | * \code 187 | * void opcontrol() { 188 | * pros::Link link(1, "my_link", pros::E_LINK_TX); 189 | * std::uint8_t data[4]; 190 | * link.receive_raw(data, 4); 191 | * } 192 | * \endcode 193 | */ 194 | std::uint32_t receive_raw(void* dest, std::uint16_t data_size); 195 | 196 | /** 197 | * Send packeted message through vexlink, with a checksum and start byte. 198 | * 199 | * \note This function uses the following values of errno when an error state is 200 | * reached: 201 | * ENXIO - The given value is not within the range of V5 ports (1-21). 202 | * ENODEV - The port cannot be configured as a radio. 203 | * ENXIO - The sensor is still calibrating, or no link is connected via the radio. 204 | * EBUSY - The transmitter buffer is still busy with a previous transmission, and there is no 205 | * room in the FIFO buffer (queue) to transmit the data. 206 | * EINVAL - The data given is NULL 207 | * 208 | * \param data 209 | * Buffer with data to send 210 | * \param data_size 211 | * Bytes of data to be read to the destination buffer 212 | * 213 | * \return PROS_ERR if port is not a link, and the successfully transmitted 214 | * data size if it succeeded. 215 | * 216 | * \b Example: 217 | * \code 218 | * void opcontrol() { 219 | * pros::Link link(1, "my_link", pros::E_LINK_TX); 220 | * std::uint8_t data[4] = {0x01, 0x02, 0x03, 0x04}; 221 | * link.transmit(data, 4); 222 | * } 223 | * \endcode 224 | */ 225 | std::uint32_t transmit(void* data, std::uint16_t data_size); 226 | 227 | /** 228 | * Receive packeted message through vexlink, with a checksum and start byte. 229 | * 230 | * \note This function uses the following values of errno when an error state is 231 | * reached: 232 | * ENXIO - The given value is not within the range of V5 ports (1-21). 233 | * ENODEV - The port cannot be configured as a radio. 234 | * ENXIO - The sensor is still calibrating, or no link is connected via the radio. 235 | * EINVAL - The destination given is NULL, or the size given is larger than the FIFO buffer 236 | * or destination buffer. 237 | * EBADMSG - Protocol error related to start byte, data size, or checksum. 238 | 239 | * \param dest 240 | * Destination buffer to read data to 241 | * \param data_size 242 | * Bytes of data to be read to the destination buffer 243 | * 244 | * \return PROS_ERR if port is not a link, and the successfully received 245 | * data size if it succeeded. 246 | * 247 | * \b Example: 248 | * \code 249 | * void opcontrol() { 250 | * pros::Link link(1, "my_link", pros::E_LINK_TX); 251 | * std::uint8_t data[4]; 252 | * link.receive(data, 4); 253 | * } 254 | * \endcode 255 | */ 256 | std::uint32_t receive(void* dest, std::uint16_t data_size); 257 | 258 | /** 259 | * Clear the receive buffer of the link, and discarding the data. 260 | * 261 | * \note This function uses the following values of errno when an error state is 262 | * reached: 263 | * ENXIO - The given value is not within the range of V5 ports (1-21). 264 | * ENODEV - The port cannot be configured as a radio. 265 | * ENXIO - The sensor is still calibrating, or no link is connected via the radio. 266 | * 267 | * \return PROS_ERR if port is not a link, 1 if the operation succeeded. 268 | * 269 | * \b Example: 270 | * \code 271 | * void opcontrol() { 272 | * pros::Link link(1, "my_link", pros::E_LINK_TX); 273 | * link.clear_receive_buf(); 274 | * } 275 | * \endcode 276 | */ 277 | std::uint32_t clear_receive_buf(); 278 | 279 | ///@} 280 | }; 281 | } // namespace pros 282 | 283 | #endif 284 | -------------------------------------------------------------------------------- /include/pros/llemu.h: -------------------------------------------------------------------------------- 1 | #ifndef _PROS_LLEMU_H_ 2 | #define _PROS_LLEMU_H_ 3 | 4 | // TODO:? Should there be weak symbols for the C api in here as well? 5 | 6 | #include "stdint.h" 7 | 8 | /******************************************************************************/ 9 | /** LLEMU Conditional Include **/ 10 | /** **/ 11 | /** When the libvgl versions of llemu.h is present, common.mk will **/ 12 | /** define a macro which lets this file know that liblvgl's llemu.h is **/ 13 | /** present. If it is, we conditionally include it so that it gets **/ 14 | /** included into api.h. **/ 15 | /******************************************************************************/ 16 | #ifdef _PROS_INCLUDE_LIBLVGL_LLEMU_H 17 | #include "liblvgl/llemu.h" 18 | #endif 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | namespace pros { 23 | namespace c { 24 | #endif//__cplusplus 25 | 26 | /** 27 | * Displays a formatted string on the emulated three-button LCD screen. 28 | * 29 | * This function uses the following values of errno when an error state is 30 | * reached: 31 | * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. 32 | * EINVAL - The line number specified is not in the range [0-7] 33 | * 34 | * \param line 35 | * The line on which to display the text [0-7] 36 | * \param fmt 37 | * Format string 38 | * \param ... 39 | * Optional list of arguments for the format string 40 | * 41 | * \return True if the operation was successful, or false otherwise, setting 42 | * errno values as specified above. 43 | */ 44 | bool __attribute__((weak)) lcd_print(int16_t line, const char* fmt, ...) { 45 | return false; 46 | } 47 | 48 | #ifdef __cplusplus 49 | } // namespace c 50 | } // namespace pros 51 | } // extern "C" 52 | #endif//__cplusplus 53 | 54 | #endif // _PROS_LLEMU_H_ 55 | -------------------------------------------------------------------------------- /include/pros/llemu.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file pros/llemu.hpp 3 | * \ingroup cpp-llemu 4 | * 5 | * Legacy LCD Emulator 6 | * 7 | * \details This file defines a high-level API for emulating the three-button, UART-based 8 | * VEX LCD, containing a set of functions that facilitate the use of a software- 9 | * emulated version of the classic VEX LCD module. 10 | * 11 | * This file should not be modified by users, since it gets replaced whenever 12 | * a kernel upgrade occurs. 13 | * 14 | * \copyright (c) 2017-2023, Purdue University ACM SIGBots. 15 | * 16 | * This Source Code Form is subject to the terms of the Mozilla Public 17 | * License, v. 2.0. If a copy of the MPL was not distributed with this 18 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 19 | */ 20 | 21 | #ifndef _PROS_LLEMU_HPP_ 22 | #define _PROS_LLEMU_HPP_ 23 | 24 | #include 25 | #include 26 | 27 | /******************************************************************************/ 28 | /** LLEMU Conditional Include **/ 29 | /** **/ 30 | /** When the libvgl versions of llemu.hpp is present, common.mk will **/ 31 | /** define a macro which lets this file know that liblvgl's llemu.hpp is **/ 32 | /** present. If it is, we conditionally include it so that it gets **/ 33 | /** included into api.h. **/ 34 | /******************************************************************************/ 35 | #ifdef _PROS_INCLUDE_LIBLVGL_LLEMU_HPP 36 | #include "liblvgl/llemu.hpp" 37 | #endif 38 | 39 | /******************************************************************************/ 40 | /** LLEMU Weak Stubs **/ 41 | /** **/ 42 | /** These functions allow main.cpp to be compiled without LVGL present **/ 43 | /******************************************************************************/ 44 | 45 | namespace pros { 46 | 47 | /** 48 | * \ingroup cpp-llemu 49 | */ 50 | namespace lcd { 51 | #pragma GCC diagnostic push 52 | #pragma GCC diagnostic ignored "-Wunused-function" 53 | namespace { 54 | template 55 | T convert_args(T arg) { 56 | return arg; 57 | } 58 | const char* convert_args(const std::string& arg) { 59 | return arg.c_str(); 60 | } 61 | } // namespace 62 | #pragma GCC diagnostic pop 63 | 64 | using lcd_btn_cb_fn_t = void (*)(void); 65 | 66 | /* 67 | * These weak symbols allow the example main.cpp in to compile even when 68 | * the liblvgl template is missing from the project. 69 | * 70 | * For documentation on these functions, please see the doxygen comments for 71 | * these functions in the libvgl llemu headers. 72 | */ 73 | 74 | extern __attribute__((weak)) bool set_text(std::int16_t line, std::string text); 75 | extern __attribute__((weak)) bool clear_line(std::int16_t line); 76 | extern __attribute__((weak)) bool initialize(void); 77 | extern __attribute__((weak)) std::uint8_t read_buttons(void); 78 | extern __attribute__((weak)) void register_btn1_cb(lcd_btn_cb_fn_t cb); 79 | extern __attribute__((weak)) bool is_initialized(void); 80 | 81 | /** 82 | * \addtogroup cpp-llemu 83 | * @{ 84 | */ 85 | 86 | /* 87 | * Note: This template resides in this file since the 88 | */ 89 | 90 | /** 91 | * Displays a formatted string on the emulated three-button LCD screen. 92 | * 93 | * This function uses the following values of errno when an error state is 94 | * reached: 95 | * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. 96 | * EINVAL - The line number specified is not in the range [0-7] 97 | * 98 | * \param line 99 | * The line on which to display the text [0-7] 100 | * \param fmt 101 | * Format string 102 | * \param ...args 103 | * Optional list of arguments for the format string 104 | * 105 | * \return True if the operation was successful, or false otherwise, setting 106 | * errno values as specified above. 107 | * 108 | * \b Example 109 | * \code 110 | * #include "pros/llemu.hpp" 111 | * 112 | * void initialize() { 113 | * pros::lcd::initialize(); 114 | * pros::lcd::print(0, "My formatted text: %d!", 2); 115 | * } 116 | * \endcode 117 | */ 118 | template 119 | bool print(std::int16_t line, const char* fmt, Params... args) { 120 | return pros::c::lcd_print(line, fmt, convert_args(args)...); 121 | } 122 | 123 | #ifndef LCD_BTN_LEFT 124 | #define LCD_BTN_LEFT 4 125 | #endif 126 | 127 | #ifndef LCD_BTN_CENTER 128 | #define LCD_BTN_CENTER 2 129 | #endif 130 | 131 | #ifndef LCD_BTN_RIGHT 132 | #define LCD_BTN_RIGHT 1 133 | #endif 134 | /// @} 135 | } // namespace lcd 136 | } // namespace pros 137 | 138 | #endif // _PROS_LLEMU_HPP_ 139 | -------------------------------------------------------------------------------- /include/pros/rotation.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file pros/rotation.h 3 | * \ingroup c-rotation 4 | * 5 | * Contains prototypes for functions related to the VEX Rotation Sensor. 6 | * 7 | * This file should not be modified by users, since it gets replaced whenever 8 | * a kernel upgrade occurs. 9 | * 10 | * \copyright (c) 2017-2023, Purdue University ACM SIGBots. 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 | * \defgroup c-rotation VEX Rotation Sensor C API 17 | */ 18 | 19 | #ifndef _PROS_ROTATION_H_ 20 | #define _PROS_ROTATION_H_ 21 | 22 | #include 23 | #include 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | namespace pros { 28 | namespace c { 29 | #endif 30 | 31 | /** 32 | * \ingroup c-rotation 33 | */ 34 | 35 | /** 36 | * \addtogroup c-rotation 37 | * @{ 38 | */ 39 | 40 | #define ROTATION_MINIMUM_DATA_RATE 5 41 | 42 | /** 43 | * Reset Rotation Sensor 44 | * 45 | * Reset the current absolute position to be the same as the 46 | * Rotation Sensor angle. 47 | * 48 | * This function uses the following values of errno when an error state is 49 | * reached: 50 | * ENXIO - The given value is not within the range of V5 ports (1-21). 51 | * ENODEV - The port cannot be configured as an Rotation Sensor 52 | * 53 | * \param port 54 | * The V5 Rotation Sensor port number from 1-21 55 | * \return 1 if the operation was successful or PROS_ERR if the operation 56 | * failed, setting errno. 57 | * 58 | * \b Example 59 | * \code 60 | * #define ROTATION_PORT 1 61 | * 62 | * void opcontrol() { 63 | * while (true) { 64 | * 65 | * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ 66 | * rotation_reset(ROTATION_PORT); 67 | * } 68 | * delay(20); 69 | * } 70 | * } 71 | * \endcode 72 | */ 73 | int32_t rotation_reset(uint8_t port); 74 | 75 | /** 76 | * Set the Rotation Sensor's refresh interval in milliseconds. 77 | * 78 | * The rate may be specified in increments of 5ms, and will be rounded down to 79 | * the nearest increment. The minimum allowable refresh rate is 5ms. The default 80 | * rate is 10ms. 81 | * 82 | * This function uses the following values of errno when an error state is 83 | * reached: 84 | * ENXIO - The given value is not within the range of V5 ports (1-21). 85 | * ENODEV - The port cannot be configured as an Rotation Sensor 86 | * 87 | * \param port 88 | * The V5 Rotation Sensor port number from 1-21 89 | * \param rate The data refresh interval in milliseconds 90 | * \return 1 if the operation was successful or PROS_ERR if the operation 91 | * failed, setting errno. 92 | * 93 | * \b Example 94 | * \code 95 | * #define ROTATION_PORT 1 96 | * 97 | * void initialize() { 98 | * pros::Rotation rotation_sensor(ROTATION_PORT); 99 | * rotation_set_data_rate(ROTATION_PORT, 5); 100 | * } 101 | * \endcode 102 | */ 103 | int32_t rotation_set_data_rate(uint8_t port, uint32_t rate); 104 | 105 | /** 106 | * Set the Rotation Sensor position reading to a desired rotation value 107 | * 108 | * This function uses the following values of errno when an error state is 109 | * reached: 110 | * ENXIO - The given value is not within the range of V5 ports (1-21). 111 | * ENODEV - The port cannot be configured as an Rotation Sensor 112 | * 113 | * \param port 114 | * The V5 Rotation Sensor port number from 1-21 115 | * \param position 116 | * The position in terms of ticks 117 | * \return 1 if the operation was successful or PROS_ERR if the operation 118 | * failed, setting errno. 119 | * 120 | * \b Example 121 | * \code 122 | * #define ROTATION_PORT 1 123 | * 124 | * void opcontrol() { 125 | * while (true) { 126 | * 127 | * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ 128 | * rotation_set_position(ROTATION_PORT, 600); 129 | * } 130 | * delay(20); 131 | * } 132 | * } 133 | * \endcode 134 | */ 135 | int32_t rotation_set_position(uint8_t port, uint32_t position); 136 | 137 | /** 138 | * Reset the Rotation Sensor position to 0 139 | * 140 | * This function uses the following values of errno when an error state is 141 | * reached: 142 | * ENXIO - The given value is not within the range of V5 ports (1-21). 143 | * ENODEV - The port cannot be configured as an Rotation Sensor 144 | * 145 | * \param port 146 | * The V5 Rotation Sensor port number from 1-21 147 | 148 | * \return 1 if the operation was successful or PROS_ERR if the operation 149 | * failed, setting errno. 150 | * 151 | * \b Example 152 | * \code 153 | * #define ROTATION_PORT 1 154 | * 155 | * void opcontrol() { 156 | * while (true) { 157 | * 158 | * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ 159 | * rotation_reset_position(ROTATION_PORT); 160 | * } 161 | * delay(20); 162 | * } 163 | * } 164 | * \endcode 165 | */ 166 | int32_t rotation_reset_position(uint8_t port); 167 | 168 | /** 169 | * Get the Rotation Sensor's current position in centidegrees 170 | * 171 | * This function uses the following values of errno when an error state is 172 | * reached: 173 | * ENXIO - The given value is not within the range of V5 ports (1-21). 174 | * ENODEV - The port cannot be configured as an Rotation Sensor 175 | * 176 | * \param port 177 | * The V5 Rotation Sensor port number from 1-21 178 | * \return The position value or PROS_ERR_F if the operation failed, setting 179 | * errno. 180 | * 181 | * \b Example 182 | * \code 183 | * #define ROTATION_PORT 1 184 | * 185 | * void opcontrol() { 186 | * while (true) { 187 | * printf("Position: %d centidegrees \n", rotation_get_position(ROTATION_PORT)); 188 | * delay(20); 189 | * } 190 | * } 191 | * \endcode 192 | */ 193 | int32_t rotation_get_position(uint8_t port); 194 | 195 | /** 196 | * Get the Rotation Sensor's current velocity in centidegrees per second 197 | * 198 | * This function uses the following values of errno when an error state is 199 | * reached: 200 | * ENXIO - The given value is not within the range of V5 ports (1-21). 201 | * ENODEV - The port cannot be configured as an Rotation Sensor 202 | * 203 | * \param port 204 | * The V5 Rotation Sensor port number from 1-21 205 | * \return The velocity value or PROS_ERR_F if the operation failed, setting 206 | * errno. 207 | * 208 | * \b Example 209 | * \code 210 | * #define ROTATION_PORT 1 211 | * 212 | * void opcontrol() { 213 | * while (true) { 214 | * printf("Velocity: %d centidegrees per second \n", rotation_get_velocity(ROTATION_PORT)); 215 | * delay(20); 216 | * } 217 | * } 218 | * \endcode 219 | */ 220 | int32_t rotation_get_velocity(uint8_t port); 221 | 222 | /** 223 | * Get the Rotation Sensor's current angle in centidegrees (0-36000) 224 | * 225 | * This function uses the following values of errno when an error state is 226 | * reached: 227 | * ENXIO - The given value is not within the range of V5 ports (1-21). 228 | * ENODEV - The port cannot be configured as an Rotation Sensor 229 | * 230 | * \param port 231 | * The V5 Rotation Sensor port number from 1-21 232 | * \return The angle value (0-36000) or PROS_ERR_F if the operation failed, setting 233 | * errno. 234 | * 235 | * \b Example 236 | * \code 237 | * #define ROTATION_PORT 1 238 | * 239 | * void opcontrol() { 240 | * while (true) { 241 | * printf("Angle: %d centidegrees \n", rotation_get_angle(ROTATION_PORT)); 242 | * delay(20); 243 | * } 244 | * } 245 | * \endcode 246 | */ 247 | int32_t rotation_get_angle(uint8_t port); 248 | 249 | /** 250 | * Set the Rotation Sensor's direction reversed flag 251 | * 252 | * This function uses the following values of errno when an error state is 253 | * reached: 254 | * ENXIO - The given value is not within the range of V5 ports (1-21). 255 | * ENODEV - The port cannot be configured as an Rotation Sensor 256 | * 257 | * \param port 258 | * The V5 Rotation Sensor port number from 1-21 259 | * \param value 260 | * Determines if the direction of the Rotation Sensor is reversed or not. 261 | * 262 | * \return 1 if operation succeeded or PROS_ERR if the operation failed, setting 263 | * errno. 264 | * 265 | * \b Example 266 | * \code 267 | * #define ROTATION_PORT 1 268 | * 269 | * void opcontrol() { 270 | * Rotation rotation_sensor(ROTATION_PORT); 271 | * while (true) { 272 | * 273 | * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ 274 | * rotation_set_reversed(ROTATION_PORT, true); // Reverses the Rotation Sensor on ROTATION_PORT 275 | * } 276 | * delay(20); 277 | * } 278 | * } 279 | * \endcode 280 | */ 281 | int32_t rotation_set_reversed(uint8_t port, bool value); 282 | 283 | /** 284 | * Reverse the Rotation Sensor's direction 285 | * 286 | * This function uses the following values of errno when an error state is 287 | * reached: 288 | * ENXIO - The given value is not within the range of V5 ports (1-21). 289 | * ENODEV - The port cannot be configured as an Rotation Sensor 290 | * 291 | * \param port 292 | * The V5 Rotation Sensor port number from 1-21 293 | * 294 | * \return 1 if the operation was successful or PROS_ERR if the operation 295 | * failed, setting errno. 296 | * 297 | * \b Example 298 | * \code 299 | * #define ROTATION_PORT 1 300 | * 301 | * void opcontrol() { 302 | * Rotation rotation_sensor(ROTATION_PORT); 303 | * while (true) { 304 | * 305 | * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ 306 | * rotation_reverse(ROTATION_PORT); 307 | * } 308 | * delay(20); 309 | * } 310 | * } 311 | * \endcode 312 | */ 313 | int32_t rotation_reverse(uint8_t port); 314 | 315 | /** 316 | * Initialize the Rotation Sensor with a reverse flag 317 | * 318 | * This function uses the following values of errno when an error state is 319 | * reached: 320 | * ENXIO - The given value is not within the range of V5 ports (1-21). 321 | * ENODEV - The port cannot be configured as an Rotation Sensor 322 | * 323 | * \param port 324 | * The V5 Rotation Sensor port number from 1-21 325 | * \param reverse_flag 326 | * Determines if the Rotation Sensor is reversed or not. 327 | * 328 | * \return 1 if the operation was successful or PROS_ERR if the operation 329 | * failed, setting errno. 330 | * 331 | * \b Example 332 | * \code 333 | * #define ROTATION_PORT 1 334 | * 335 | * void opcontrol() { 336 | * Rotation rotation_sensor(ROTATION_PORT); 337 | * bool reverse_flag = true; 338 | * while (true) { 339 | * 340 | * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ 341 | * rotation_init_reverse(ROTATION_PORT, reverse_flag); 342 | * } 343 | * delay(20); 344 | * } 345 | * } 346 | * \endcode 347 | */ 348 | int32_t rotation_init_reverse(uint8_t port, bool reverse_flag); 349 | 350 | /** 351 | * Get the Rotation Sensor's reversed flag 352 | * 353 | * This function uses the following values of errno when an error state is 354 | * reached: 355 | * ENXIO - The given value is not within the range of V5 ports (1-21). 356 | * ENODEV - The port cannot be configured as an Rotation Sensor 357 | * 358 | * \param port 359 | * The V5 Rotation Sensor port number from 1-21 360 | * 361 | * \return Boolean value of if the Rotation Sensor's direction is reversed or not 362 | * or PROS_ERR if the operation failed, setting errno. 363 | * 364 | * \b Example 365 | * \code 366 | * #define ROTATION_PORT 1 367 | * 368 | * void opcontrol() { 369 | * Rotation rotation_sensor(ROTATION_PORT); 370 | * while (true) { 371 | * 372 | * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ 373 | * rotation_get_reversed(ROTATION_PORT); 374 | * } 375 | * delay(20); 376 | * } 377 | * } 378 | * \endcode 379 | */ 380 | int32_t rotation_get_reversed(uint8_t port); 381 | 382 | ///@} 383 | 384 | #ifdef __cplusplus 385 | } //namespace C 386 | } //namespace pros 387 | } //extern "C" 388 | #endif 389 | 390 | #endif 391 | -------------------------------------------------------------------------------- /include/pros/rotation.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file pros/rotation.hpp 3 | * \ingroup cpp-rotation 4 | * 5 | * Contains prototypes for functions related to the VEX Rotation Sensor. 6 | * 7 | * This file should not be modified by users, since it gets replaced whenever 8 | * a kernel upgrade occurs. 9 | * 10 | * \copyright (c) 2017-2023, Purdue University ACM SIGBots. 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 | * \defgroup cpp-rotation VEX Rotation Sensor C++ API 17 | */ 18 | #ifndef _PROS_ROTATION_HPP_ 19 | #define _PROS_ROTATION_HPP_ 20 | 21 | #include 22 | #include 23 | 24 | #include "pros/rotation.h" 25 | #include "pros/device.hpp" 26 | 27 | namespace pros { 28 | inline namespace v5 { 29 | /** 30 | * \ingroup cpp-rotation 31 | */ 32 | class Rotation : public Device { 33 | /** 34 | * \addtogroup cpp-rotation 35 | * @{ 36 | */ 37 | 38 | public: 39 | /** 40 | * Constructs a new Rotation Sensor object 41 | * 42 | * ENXIO - The given value is not within the range of V5 ports |1-21|. 43 | * ENODEV - The port cannot be configured as a Rotation Sensor 44 | * 45 | * \param port 46 | * The V5 port number from 1 to 21, or from -21 to -1 for reversed Rotation Sensors. 47 | * 48 | * \b Example 49 | * \code 50 | * void opcontrol() { 51 | * pros::Rotation rotation_sensor(1); //Creates a Rotation Sensor on port 1 52 | * pros::Rotation reversed_rotation_sensor(-2); //Creates a reversed Rotation Sensor on port 2 53 | * } 54 | * \endcode 55 | */ 56 | Rotation(const std::int8_t port); 57 | 58 | Rotation(const Device& device) 59 | : Rotation(device.get_port()) {}; 60 | 61 | /** 62 | * Reset the Rotation Sensor 63 | * 64 | * Reset the current absolute position to be the same as the 65 | * Rotation Sensor angle. 66 | * 67 | * This function uses the following values of errno when an error state is 68 | * reached: 69 | * ENXIO - The given value is not within the range of V5 ports (1-21). 70 | * ENODEV - The port cannot be configured as an Rotation Sensor 71 | * 72 | * \return 1 if the operation was successful or PROS_ERR if the operation 73 | * failed, setting errno. 74 | * 75 | * \b Example 76 | * \code 77 | * void opcontrol() { 78 | * pros::Rotation rotation_sensor(1); 79 | * pros::Controller master (E_CONTROLLER_MASTER); 80 | * while (true) { 81 | * if(master.get_analog(E_CONTROLLER_DIGITAL_X) { 82 | * rotation_sensor.reset(); 83 | * } 84 | * pros::delay(20); 85 | * } 86 | * } 87 | * \endcode 88 | */ 89 | virtual std::int32_t reset(); 90 | 91 | /** 92 | * Set the Rotation Sensor's refresh interval in milliseconds. 93 | * 94 | * The rate may be specified in increments of 5ms, and will be rounded down to 95 | * the nearest increment. The minimum allowable refresh rate is 5ms. The default 96 | * rate is 10ms. 97 | * 98 | * As values are copied into the shared memory buffer only at 10ms intervals, 99 | * setting this value to less than 10ms does not mean that you can poll the 100 | * sensor's values any faster. However, it will guarantee that the data is as 101 | * recent as possible. 102 | * 103 | * This function uses the following values of errno when an error state is 104 | * reached: 105 | * ENXIO - The given value is not within the range of V5 ports (1-21). 106 | * ENODEV - The port cannot be configured as an Rotation Sensor 107 | * 108 | * \param rate The data refresh interval in milliseconds 109 | * \return 1 if the operation was successful or PROS_ERR if the operation 110 | * failed, setting errno. 111 | * 112 | * \b Example 113 | * \code 114 | * void initialize() { 115 | * pros::Rotation rotation_sensor(1); 116 | * rotation_sensor.set_data_rate(5); 117 | * } 118 | * \endcode 119 | */ 120 | virtual std::int32_t set_data_rate(std::uint32_t rate) const; 121 | 122 | /** 123 | * Set the Rotation Sensor position reading to a desired rotation value 124 | * 125 | * This function uses the following values of errno when an error state is 126 | * reached: 127 | * ENXIO - The given value is not within the range of V5 ports (1-21). 128 | * ENODEV - The port cannot be configured as an Rotation Sensor 129 | * 130 | * \param position 131 | * The position in terms of ticks 132 | * \return 1 if the operation was successful or PROS_ERR if the operation 133 | * failed, setting errno. 134 | * 135 | * \b Example 136 | * \code 137 | * void opcontrol() { 138 | * pros::Rotation rotation_sensor(1); 139 | * pros::Controller master (E_CONTROLLER_MASTER); 140 | * while (true) { 141 | * if(master.get_analog(E_CONTROLLER_DIGITAL_X) { 142 | * rotation_sensor.set_position(600); 143 | * } 144 | * pros::delay(20); 145 | * } 146 | * } 147 | * \endcode 148 | */ 149 | virtual std::int32_t set_position(std::uint32_t position) const; 150 | 151 | /** 152 | * Reset the Rotation Sensor position to 0 153 | * 154 | * This function uses the following values of errno when an error state is 155 | * reached: 156 | * ENXIO - The given value is not within the range of V5 ports (1-21). 157 | * ENODEV - The port cannot be configured as an Rotation Sensor 158 | * 159 | * \param position 160 | * The position in terms of ticks 161 | * \return 1 if the operation was successful or PROS_ERR if the operation 162 | * failed, setting errno. 163 | * 164 | * \b Example 165 | * \code 166 | * void opcontrol() { 167 | * pros::Rotation rotation_sensor(1); 168 | * pros::Controller master (E_CONTROLLER_MASTER); 169 | * while (true) { 170 | * if(master.get_analog(E_CONTROLLER_DIGITAL_X) { 171 | * rotation_sensor.reset_position(); 172 | * } 173 | * pros::delay(20); 174 | * } 175 | * } 176 | * \endcode 177 | */ 178 | virtual std::int32_t reset_position(void) const; 179 | 180 | /** 181 | * Get the Rotation Sensor's current position in centidegrees 182 | * 183 | * This function uses the following values of errno when an error state is 184 | * reached: 185 | * ENXIO - The given value is not within the range of V5 ports (1-21). 186 | * ENODEV - The port cannot be configured as an Rotation Sensor 187 | * 188 | * \return The position value or PROS_ERR if the operation failed, setting 189 | * errno. 190 | * 191 | * \b Example 192 | * \code 193 | * void opcontrol() { 194 | * pros::Rotation rotation_sensor(1); 195 | * while (true) { 196 | * printf("Position: %d Ticks \n", rotation_sensor.get_position()); 197 | * delay(20); 198 | * } 199 | * } 200 | * \endcode 201 | */ 202 | virtual std::int32_t get_position() const; 203 | 204 | /** 205 | * Get the Rotation Sensor's current velocity in centidegrees per second 206 | * 207 | * This function uses the following values of errno when an error state is 208 | * reached: 209 | * ENXIO - The given value is not within the range of V5 ports (1-21). 210 | * ENODEV - The port cannot be configured as an Rotation Sensor 211 | * 212 | * \param port 213 | * The V5 Rotation Sensor port number from 1-21 214 | * \return The velocity value or PROS_ERR if the operation failed, setting 215 | * errno. 216 | * 217 | * \b Example 218 | * \code 219 | * void opcontrol() { 220 | * pros::Rotation rotation_sensor(1); 221 | * while (true) { 222 | * printf("Velocity: %d centidegrees per second \n", rotation_sensor.get_velocity)); 223 | * delay(20); 224 | * } 225 | * } 226 | * \endcode 227 | */ 228 | virtual std::int32_t get_velocity() const; 229 | 230 | /** 231 | * Get the Rotation Sensor's current position in centidegrees 232 | * 233 | * This function uses the following values of errno when an error state is 234 | * reached: 235 | * ENXIO - The given value is not within the range of V5 ports (1-21). 236 | * ENODEV - The port cannot be configured as an Rotation Sensor 237 | * 238 | * \return The angle value or PROS_ERR if the operation failed, setting 239 | * errno. 240 | * 241 | * \b Example 242 | * \code 243 | * void opcontrol() { 244 | * pros::Rotation rotation_sensor(1); 245 | * while (true) { 246 | * printf("Angle: %d centidegrees \n", rotation_sensor.get_angle()); 247 | * delay(20); 248 | * } 249 | * } 250 | * \endcode 251 | */ 252 | virtual std::int32_t get_angle() const; 253 | 254 | /** 255 | * Set the Rotation Sensor's direction reversed flag 256 | * 257 | * This function uses the following values of errno when an error state is 258 | * reached: 259 | * ENXIO - The given value is not within the range of V5 ports (1-21). 260 | * ENODEV - The port cannot be configured as an Rotation Sensor 261 | * 262 | * \param value 263 | * Determines if the direction of the rotational sensor is 264 | * reversed or not. 265 | * 266 | * \return 1 if the operation was successful or PROS_ERR if the operation 267 | * failed, setting errno. 268 | * 269 | * \b Example 270 | * \code 271 | * void opcontrol() { 272 | * pros::Rotation rotation_sensor(1); 273 | * pros::Controller master (E_CONTROLLER_MASTER); 274 | * while (true) { 275 | * if(master.get_analog(E_CONTROLLER_DIGITAL_X) { 276 | * rotation_sensor.set_reversed(true); // Reverses the Rotation Sensor 277 | * } 278 | * pros::delay(20); 279 | * } 280 | * } 281 | * \endcode 282 | */ 283 | virtual std::int32_t set_reversed(bool value) const; 284 | 285 | /** 286 | * Reverse the Rotation Sensor's direction. 287 | * 288 | * This function uses the following values of errno when an error state is 289 | * reached: 290 | * ENXIO - The given value is not within the range of V5 ports (1-21). 291 | * ENODEV - The port cannot be configured as an Rotation Sensor 292 | * 293 | * \return 1 if the operation was successful or PROS_ERR if the operation 294 | * failed, setting errno. 295 | * 296 | * \b Example 297 | * \code 298 | * void opcontrol() { 299 | * pros::Rotation rotation_sensor(1); 300 | * pros::Controller master (E_CONTROLLER_MASTER); 301 | * while (true) { 302 | * if(master.get_analog(E_CONTROLLER_DIGITAL_X) { 303 | * rotation_sensor.reverse(); 304 | * } 305 | * pros::delay(20); 306 | * } 307 | * } 308 | * \endcode 309 | */ 310 | virtual std::int32_t reverse() const; 311 | 312 | /** 313 | * Get the Rotation Sensor's reversed flag 314 | * 315 | * This function uses the following values of errno when an error state is 316 | * reached: 317 | * ENXIO - The given value is not within the range of V5 ports (1-21). 318 | * ENODEV - The port cannot be configured as an Rotation Sensor 319 | * 320 | * \return Reversed value or PROS_ERR if the operation failed, setting 321 | * errno. 322 | * 323 | * \b Example 324 | * \code 325 | * void opcontrol() { 326 | * pros::Rotation rotation_sensor(1); 327 | * while (true) { 328 | * printf("Reversed: %d \n", rotation_sensor.get_reversed()); 329 | * delay(20); 330 | * } 331 | * } 332 | * \endcode 333 | */ 334 | virtual std::int32_t get_reversed() const; 335 | 336 | /** 337 | * This is the overload for the << operator for printing to streams 338 | * 339 | * Prints in format(this below is all in one line with no new line): 340 | * Rotation [port: rotation._port, position: (rotation position), velocity: (rotation velocity), 341 | * angle: (rotation angle), reversed: (reversed boolean)] 342 | * 343 | * \b Example 344 | * \code 345 | * #define ROTATION_PORT 1 346 | * 347 | * void opcontrol() { 348 | * pros::Rotation rotation_sensor(1); 349 | * while(true) { 350 | * std::cout << rotation_sensor << std::endl; 351 | * pros::delay(20); 352 | * } 353 | * } 354 | * \endcode 355 | */ 356 | friend std::ostream& operator<<(std::ostream& os, const pros::Rotation& rotation); 357 | 358 | ///@} 359 | }; 360 | 361 | namespace literals { 362 | const pros::Rotation operator"" _rot(const unsigned long long int r); 363 | } // namespace literals 364 | } 365 | } // namespace pros 366 | 367 | #endif 368 | -------------------------------------------------------------------------------- /include/pros/serial.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file pros/serial.h 3 | * \ingroup c-serial 4 | * 5 | * Contains prototypes for the V5 Generic Serial related functions. 6 | * 7 | * This file should not be modified by users, since it gets replaced whenever 8 | * a kernel upgrade occurs. 9 | * 10 | * \copyright (c) 2017-2023, Purdue University ACM SIGBots. 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 | * \defgroup c-serial Generic Serial C API 17 | */ 18 | 19 | #ifndef _PROS_SERIAL_H_ 20 | #define _PROS_SERIAL_H_ 21 | 22 | #include 23 | #include 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | namespace pros { 28 | namespace c { 29 | #endif 30 | 31 | /** 32 | * \ingroup c-serial 33 | */ 34 | 35 | /** 36 | * \addtogroup c-serial 37 | * @{ 38 | */ 39 | 40 | /// \name Serial communication functions 41 | /// These functions allow programmers to communicate using UART over RS485 42 | ///@{ 43 | 44 | /** 45 | * Enables generic serial on the given port. 46 | * 47 | * \note This function must be called before any of the generic serial 48 | * functions will work. 49 | * 50 | * This function uses the following values of errno when an error state is 51 | * reached: 52 | * EINVAL - The given value is not within the range of V5 ports (1-21). 53 | * EACCES - Another resource is currently trying to access the port. 54 | * 55 | * \param port 56 | * The V5 port number from 1-21 57 | * 58 | * \return 1 if the operation was successful or PROS_ERR if the operation 59 | * failed, setting errno. 60 | * 61 | * \b Example: 62 | * \code{.c} 63 | * void opcontrol() { 64 | * serial_enable(1); 65 | * serial_set_baudrate(1, 9600); 66 | * } 67 | * \endcode 68 | */ 69 | int32_t serial_enable(uint8_t port); 70 | 71 | /** 72 | * Sets the baudrate for the serial port to operate at. 73 | * 74 | * This function uses the following values of errno when an error state is 75 | * reached: 76 | * EINVAL - The given value is not within the range of V5 ports (1-21). 77 | * EACCES - Another resource is currently trying to access the port. 78 | * 79 | * \param port 80 | * The V5 port number from 1-21 81 | * \param baudrate 82 | * The baudrate to operate at 83 | * 84 | * \return 1 if the operation was successful or PROS_ERR if the operation 85 | * failed, setting errno. 86 | * 87 | * \b Example: 88 | * \code{.c} 89 | * void opcontrol() { 90 | * serial_enable(1); 91 | * serial_set_baudrate(1, 9600); 92 | * while (true) { 93 | * serial_write(1, "Hello World!", 12); 94 | * delay(100); 95 | * } 96 | * } 97 | * \endcode 98 | */ 99 | int32_t serial_set_baudrate(uint8_t port, int32_t baudrate); 100 | 101 | /** 102 | * Clears the internal input and output FIFO buffers. 103 | * 104 | * This can be useful to reset state and remove old, potentially unneeded data 105 | * from the input FIFO buffer or to cancel sending any data in the output FIFO 106 | * buffer. 107 | * 108 | * \note This function does not cause the data in the output buffer to be 109 | * written, it simply clears the internal buffers. Unlike stdout, generic 110 | * serial does not use buffered IO (the FIFO buffers are written as soon 111 | * as possible). 112 | * 113 | * This function uses the following values of errno when an error state is 114 | * reached: 115 | * EINVAL - The given value is not within the range of V5 ports (1-21). 116 | * EACCES - Another resource is currently trying to access the port. 117 | * 118 | * \param port 119 | * The V5 port number from 1-21 120 | * 121 | * \return 1 if the operation was successful or PROS_ERR if the operation 122 | * failed, setting errno. 123 | * 124 | * \b Example: 125 | * \code{.c} 126 | * void opcontrol() { 127 | * serial_enable(1); 128 | * serial_set_baudrate(1, 9600); 129 | * while (true) { 130 | * serial_flush(1); 131 | * serial_write(1, "Hello World!", 12); 132 | * delay(100); 133 | * } 134 | * } 135 | * \endcode 136 | */ 137 | int32_t serial_flush(uint8_t port); 138 | 139 | /** 140 | * Returns the number of bytes available to be read in the the port's FIFO 141 | * input buffer. 142 | * 143 | * \note This function does not actually read any bytes, is simply returns the 144 | * number of bytes available to be read. 145 | * 146 | * This function uses the following values of errno when an error state is 147 | * reached: 148 | * EINVAL - The given value is not within the range of V5 ports (1-21). 149 | * EACCES - Another resource is currently trying to access the port. 150 | * 151 | * \param port 152 | * The V5 port number from 1-21 153 | * 154 | * \return The number of bytes avaliable to be read or PROS_ERR if the operation 155 | * failed, setting errno. 156 | * 157 | * \b Example: 158 | * \code{.c} 159 | * void opcontrol() { 160 | * serial_enable(1); 161 | * serial_set_baudrate(1, 9600); 162 | * while (true) { 163 | * if (serial_get_read_avail(1) >= 12) { 164 | * char buffer[12]; 165 | * serial_read(1, buffer, 12); 166 | * printf("%s", buffer); 167 | * } 168 | * delay(100); 169 | * } 170 | * } 171 | * \endcode 172 | 173 | */ 174 | int32_t serial_get_read_avail(uint8_t port); 175 | 176 | /** 177 | * Returns the number of bytes free in the port's FIFO output buffer. 178 | * 179 | * \note This function does not actually write any bytes, is simply returns the 180 | * number of bytes free in the port's buffer. 181 | * 182 | * This function uses the following values of errno when an error state is 183 | * reached: 184 | * EINVAL - The given value is not within the range of V5 ports (1-21). 185 | * EACCES - Another resource is currently trying to access the port. 186 | * 187 | * \param port 188 | * The V5 port number from 1-21 189 | * 190 | * \return The number of bytes free or PROS_ERR if the operation failed, 191 | * setting errno. 192 | * 193 | * \b Example: 194 | * \code{.c} 195 | * void opcontrol() { 196 | * serial_enable(1); 197 | * serial_set_baudrate(1, 9600); 198 | * while (true) { 199 | * if (serial_get_write_free(1) >= 12) { 200 | * serial_write(1, "Hello World!", 12); 201 | * } 202 | * delay(100); 203 | * } 204 | * } 205 | * \endcode 206 | */ 207 | int32_t serial_get_write_free(uint8_t port); 208 | 209 | /** 210 | * Reads the next byte avaliable in the port's input buffer without removing it. 211 | * 212 | * This function uses the following values of errno when an error state is 213 | * reached: 214 | * EINVAL - The given value is not within the range of V5 ports (1-21). 215 | * EACCES - Another resource is currently trying to access the port. 216 | * 217 | * \param port 218 | * The V5 port number from 1-21 219 | * 220 | * \return The next byte avaliable to be read, -1 if none are available, or 221 | * PROS_ERR if the operation failed, setting errno. 222 | * 223 | * \b Example: 224 | * \code{.c} 225 | * void opcontrol() { 226 | * serial_enable(1); 227 | * serial_set_baudrate(1, 9600); 228 | * while (true) { 229 | * if (serial_peek_byte(1) == 'H') { 230 | * char buffer[12]; 231 | * serial_read(1, buffer, 12); 232 | * printf("%s", buffer); 233 | * } 234 | * delay(100); 235 | * } 236 | * } 237 | * \endcode 238 | */ 239 | int32_t serial_peek_byte(uint8_t port); 240 | 241 | /** 242 | * Reads the next byte avaliable in the port's input buffer. 243 | * 244 | * This function uses the following values of errno when an error state is 245 | * reached: 246 | * EINVAL - The given value is not within the range of V5 ports (1-21). 247 | * EACCES - Another resource is currently trying to access the port. 248 | * 249 | * \param port 250 | * The V5 port number from 1-21 251 | * 252 | * \return The next byte avaliable to be read, -1 if none are available, or 253 | * PROS_ERR if the operation failed, setting errno. 254 | * 255 | * \b Example: 256 | * \code{.c} 257 | * void opcontrol() { 258 | * serial_enable(1); 259 | * serial_set_baudrate(1, 9600); 260 | * while (true) { 261 | * if (serial_read_byte(1) == 'H') { 262 | * char buffer[12]; 263 | * serial_read(1, buffer, 12); 264 | * printf("%s", buffer); 265 | * } 266 | * delay(100); 267 | * } 268 | * } 269 | * \endcode 270 | */ 271 | int32_t serial_read_byte(uint8_t port); 272 | 273 | /** 274 | * Reads up to the next length bytes from the port's input buffer and places 275 | * them in the user supplied buffer. 276 | * 277 | * \note This function will only return bytes that are currently avaliable to be 278 | * read and will not block waiting for any to arrive. 279 | * 280 | * This function uses the following values of errno when an error state is 281 | * reached: 282 | * EINVAL - The given value is not within the range of V5 ports (1-21). 283 | * EACCES - Another resource is currently trying to access the port. 284 | * 285 | * \param port 286 | * The V5 port number from 1-21 287 | * \param buffer 288 | * The location to place the data read 289 | * \param length 290 | * The maximum number of bytes to read 291 | * 292 | * \return The number of bytes read or PROS_ERR if the operation failed, setting 293 | * errno. 294 | * 295 | * \b Example: 296 | * \code{.c} 297 | * void opcontrol() { 298 | * serial_enable(1); 299 | * serial_set_baudrate(1, 9600); 300 | * while (true) { 301 | * if (serial_get_read_avail(1) >= 12) { 302 | * char buffer[12]; 303 | * serial_read(1, buffer, 12); 304 | * printf("%s", buffer); 305 | * } 306 | * delay(100); 307 | * } 308 | * } 309 | * \endcode 310 | */ 311 | int32_t serial_read(uint8_t port, uint8_t* buffer, int32_t length); 312 | 313 | /** 314 | * Write the given byte to the port's output buffer. 315 | * 316 | * \note Data in the port's output buffer is written to the serial port as soon 317 | * as possible on a FIFO basis and can not be done manually by the user. 318 | * 319 | * This function uses the following values of errno when an error state is 320 | * reached: 321 | * EINVAL - The given value is not within the range of V5 ports (1-21). 322 | * EACCES - Another resource is currently trying to access the port. 323 | * EIO - Serious internal write error. 324 | * 325 | * \param port 326 | * The V5 port number from 1-21 327 | * \param buffer 328 | * The byte to write 329 | * 330 | * \return The number of bytes written or PROS_ERR if the operation failed, 331 | * setting errno. 332 | * 333 | * \b Example: 334 | * \code{.c} 335 | * void opcontrol() { 336 | * serial_enable(1); 337 | * serial_set_baudrate(1, 9600); 338 | * while (true) { 339 | * if (serial_get_write_free(1) >= 12) { 340 | * serial_write_byte(1, 'H'); 341 | * serial_write_byte(1, 'e'); 342 | * serial_write_byte(1, 'l'); 343 | * serial_write_byte(1, 'l'); 344 | * serial_write_byte(1, 'o'); 345 | * serial_write_byte(1, ' '); 346 | * serial_write_byte(1, 'W'); 347 | * serial_write_byte(1, 'o'); 348 | * serial_write_byte(1, 'r'); 349 | * serial_write_byte(1, 'l'); 350 | * serial_write_byte(1, 'd'); 351 | * serial_write_byte(1, '!'); 352 | * serial_write_byte(1, '\n'); 353 | * } 354 | * delay(100); 355 | * } 356 | * } 357 | * \endcode 358 | */ 359 | int32_t serial_write_byte(uint8_t port, uint8_t buffer); 360 | 361 | /** 362 | * Writes up to length bytes from the user supplied buffer to the port's output 363 | * buffer. 364 | * 365 | * \note Data in the port's output buffer is written to the serial port as soon 366 | * as possible on a FIFO basis and can not be done manually by the user. 367 | * 368 | * This function uses the following values of errno when an error state is 369 | * reached: 370 | * EINVAL - The given value is not within the range of V5 ports (1-21). 371 | * EACCES - Another resource is currently trying to access the port. 372 | * EIO - Serious internal write error. 373 | * 374 | * \param port 375 | * The V5 port number from 1-21 376 | * \param buffer 377 | * The data to write 378 | * \param length 379 | * The maximum number of bytes to write 380 | * 381 | * \return The number of bytes written or PROS_ERR if the operation failed, 382 | * setting errno. 383 | * 384 | * \b Example: 385 | * \code{.c} 386 | * void opcontrol() { 387 | * serial_enable(1); 388 | * serial_set_baudrate(1, 9600); 389 | * while (true) { 390 | * if (serial_get_write_free(1) >= 12) { 391 | * serial_write(1, "Hello World!\n", 12); 392 | * } 393 | * delay(100); 394 | * } 395 | * } 396 | * \endcode 397 | */ 398 | int32_t serial_write(uint8_t port, uint8_t* buffer, int32_t length); 399 | 400 | ///@} 401 | 402 | ///@} 403 | 404 | #ifdef __cplusplus 405 | } // namespace c 406 | } // namespace pros 407 | } 408 | #endif 409 | 410 | #endif // _PROS_SERIAL_H_ -------------------------------------------------------------------------------- /include/pros/serial.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file pros/serial.hpp 3 | * \ingroup cpp-serial 4 | * 5 | * Contains prototypes for the V5 Generic Serial related functions. 6 | * 7 | * This file should not be modified by users, since it gets replaced whenever 8 | * a kernel upgrade occurs. 9 | * 10 | * \copyright (c) 2017-2023, Purdue University ACM SIGBots. 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 | * \defgroup cpp-serial Generic Serial C++ API 17 | */ 18 | 19 | #ifndef _PROS_SERIAL_HPP_ 20 | #define _PROS_SERIAL_HPP_ 21 | 22 | #include 23 | #include "pros/serial.h" 24 | #include "pros/device.hpp" 25 | 26 | namespace pros { 27 | /** 28 | * \ingroup cpp-serial 29 | * @{ 30 | */ 31 | class Serial : public Device { 32 | /** 33 | * \addtogroup cpp-serial 34 | * @{ 35 | */ 36 | public: 37 | /** 38 | * Creates a Serial object for the given port and specifications. 39 | * 40 | * This function uses the following values of errno when an error state is 41 | * reached: 42 | * EINVAL - The given value is not within the range of V5 ports (1-21). 43 | * EACCES - Another resource is currently trying to access the port. 44 | * 45 | * \param port 46 | * The V5 port number from 1-21 47 | * \param baudrate 48 | * The baudrate to run the port at 49 | * 50 | * \b Example: 51 | * \code 52 | * pros::Serial serial(1, 9600); 53 | * \endcode 54 | */ 55 | explicit Serial(std::uint8_t port, std::int32_t baudrate); 56 | 57 | /** 58 | * Creates a Serial object for the given port without a set baudrate. 59 | * 60 | * This function uses the following values of errno when an error state is 61 | * reached: 62 | * EINVAL - The given value is not within the range of V5 ports (1-21). 63 | * EACCES - Another resource is currently trying to access the port. 64 | * 65 | * \param port 66 | * The V5 port number from 1-21 67 | * 68 | * \b Example: 69 | * \code 70 | * pros::Serial serial(1); 71 | * \endcode 72 | */ 73 | explicit Serial(std::uint8_t port); 74 | 75 | /******************************************************************************/ 76 | /** Serial communication functions **/ 77 | /** **/ 78 | /** These functions allow programmers to communicate using UART over RS485 **/ 79 | /******************************************************************************/ 80 | 81 | /** 82 | * Sets the baudrate for the serial port to operate at. 83 | * 84 | * This function uses the following values of errno when an error state is 85 | * reached: 86 | * EINVAL - The given value is not within the range of V5 ports (1-21). 87 | * EACCES - Another resource is currently trying to access the port. 88 | * 89 | * \param baudrate 90 | * The baudrate to operate at 91 | * 92 | * \return 1 if the operation was successful or PROS_ERR if the operation 93 | * failed, setting errno. 94 | * 95 | * \b Example: 96 | * \code 97 | * pros::Serial serial(1); 98 | * serial.set_baudrate(9600); 99 | * \endcode 100 | */ 101 | virtual std::int32_t set_baudrate(std::int32_t baudrate) const; 102 | 103 | /** 104 | * Clears the internal input and output FIFO buffers. 105 | * 106 | * This can be useful to reset state and remove old, potentially unneeded data 107 | * from the input FIFO buffer or to cancel sending any data in the output FIFO 108 | * buffer. 109 | * 110 | * \note This function does not cause the data in the output buffer to be 111 | * written, it simply clears the internal buffers. Unlike stdout, generic 112 | * serial does not use buffered IO (the FIFO buffers are written as soon 113 | * as possible). 114 | * 115 | * This function uses the following values of errno when an error state is 116 | * reached: 117 | * EINVAL - The given value is not within the range of V5 ports (1-21). 118 | * EACCES - Another resource is currently trying to access the port. 119 | * 120 | * \return 1 if the operation was successful or PROS_ERR if the operation 121 | * failed, setting errno. 122 | * 123 | * \b Example: 124 | * \code 125 | * pros::Serial serial(1); 126 | * serial.flush(); 127 | * \endcode 128 | */ 129 | virtual std::int32_t flush() const; 130 | 131 | /** 132 | * Returns the number of bytes available to be read in the the port's FIFO 133 | * input buffer. 134 | * 135 | * \note This function does not actually read any bytes, is simply returns the 136 | * number of bytes available to be read. 137 | * 138 | * This function uses the following values of errno when an error state is 139 | * reached: 140 | * EINVAL - The given value is not within the range of V5 ports (1-21). 141 | * EACCES - Another resource is currently trying to access the port. 142 | * 143 | * \return The number of bytes avaliable to be read or PROS_ERR if the operation 144 | * failed, setting errno. 145 | * 146 | * \b Example: 147 | * \code 148 | * void opcontrol() { 149 | * pros::Serial serial(1); 150 | * if(serial.get_read_avail() > 0) { 151 | * std::uint8_t byte = serial.read_byte(); 152 | * } 153 | * } 154 | * \endcode 155 | */ 156 | virtual std::int32_t get_read_avail() const; 157 | 158 | /** 159 | * Returns the number of bytes free in the port's FIFO output buffer. 160 | * 161 | * \note This function does not actually write any bytes, is simply returns the 162 | * number of bytes free in the port's buffer. 163 | * 164 | * This function uses the following values of errno when an error state is 165 | * reached: 166 | * EINVAL - The given value is not within the range of V5 ports (1-21). 167 | * EACCES - Another resource is currently trying to access the port. 168 | * 169 | * \return The number of bytes free or PROS_ERR if the operation failed, 170 | * setting errno. 171 | * 172 | * \b Example: 173 | * \code 174 | * void opcontrol() { 175 | * pros::Serial serial(1); 176 | * if(serial.get_write_free() > 0) { 177 | * serial.write_byte(0x01); 178 | * pros::delay(10); 179 | * } 180 | * } 181 | * \endcode 182 | */ 183 | virtual std::int32_t get_write_free() const; 184 | 185 | /** 186 | * Reads the next byte avaliable in the port's input buffer without removing it. 187 | * 188 | * This function uses the following values of errno when an error state is 189 | * reached: 190 | * EINVAL - The given value is not within the range of V5 ports (1-21). 191 | * EACCES - Another resource is currently trying to access the port. 192 | * 193 | * \return The next byte avaliable to be read, -1 if none are available, or 194 | * PROS_ERR if the operation failed, setting errno. 195 | * 196 | * \b Example: 197 | * \code 198 | * void opcontrol() { 199 | * pros::Serial serial(1); 200 | * if(serial.peek_byte() == 0x01) { 201 | * serial.read_byte(); 202 | * } 203 | * } 204 | * \endcode 205 | */ 206 | virtual std::int32_t peek_byte() const; 207 | 208 | /** 209 | * Reads the next byte avaliable in the port's input buffer. 210 | * 211 | * This function uses the following values of errno when an error state is 212 | * reached: 213 | * EINVAL - The given value is not within the range of V5 ports (1-21). 214 | * EACCES - Another resource is currently trying to access the port. 215 | * 216 | * \return The next byte avaliable to be read, -1 if none are available, or 217 | * PROS_ERR if the operation failed, setting errno. 218 | * 219 | * \b Example: 220 | * \code 221 | * void opcontrol() { 222 | * pros::Serial serial(1); 223 | * if(serial.read_byte() == 0x01) { 224 | * // Do something 225 | * } 226 | * } 227 | * \endcode 228 | */ 229 | virtual std::int32_t read_byte() const; 230 | 231 | /** 232 | * Reads up to the next length bytes from the port's input buffer and places 233 | * them in the user supplied buffer. 234 | * 235 | * \note This function will only return bytes that are currently avaliable to be 236 | * read and will not block waiting for any to arrive. 237 | * 238 | * This function uses the following values of errno when an error state is 239 | * reached: 240 | * EINVAL - The given value is not within the range of V5 ports (1-21). 241 | * EACCES - Another resource is currently trying to access the port. 242 | * 243 | * \param buffer 244 | * The location to place the data read 245 | * \param length 246 | * The maximum number of bytes to read 247 | * 248 | * \return The number of bytes read or PROS_ERR if the operation failed, setting 249 | * errno. 250 | * 251 | * \b Example: 252 | * \code 253 | * void opcontrol() { 254 | * pros::Serial serial(1); 255 | * std::uint8_t buffer[10]; 256 | * serial.read(buffer, 10); 257 | * } 258 | * \endcode 259 | */ 260 | virtual std::int32_t read(std::uint8_t* buffer, std::int32_t length) const; 261 | 262 | /** 263 | * Write the given byte to the port's output buffer. 264 | * 265 | * \note Data in the port's output buffer is written to the serial port as soon 266 | * as possible on a FIFO basis and can not be done manually by the user. 267 | * 268 | * This function uses the following values of errno when an error state is 269 | * reached: 270 | * EINVAL - The given value is not within the range of V5 ports (1-21). 271 | * EACCES - Another resource is currently trying to access the port. 272 | * EIO - Serious internal write error. 273 | * 274 | * \param buffer 275 | * The byte to write 276 | * 277 | * \return The number of bytes written or PROS_ERR if the operation failed, 278 | * setting errno. 279 | * 280 | * \b Example: 281 | * \code 282 | * void opcontrol() { 283 | * pros::Serial serial(1); 284 | * serial.write_byte(0x01); 285 | * } 286 | * \endcode 287 | */ 288 | virtual std::int32_t write_byte(std::uint8_t buffer) const; 289 | 290 | /** 291 | * Writes up to length bytes from the user supplied buffer to the port's output 292 | * buffer. 293 | * 294 | * \note Data in the port's output buffer is written to the serial port as soon 295 | * as possible on a FIFO basis and can not be done manually by the user. 296 | * 297 | * This function uses the following values of errno when an error state is 298 | * reached: 299 | * EINVAL - The given value is not within the range of V5 ports (1-21). 300 | * EACCES - Another resource is currently trying to access the port. 301 | * EIO - Serious internal write error. 302 | * 303 | * \param buffer 304 | * The data to write 305 | * \param length 306 | * The maximum number of bytes to write 307 | * 308 | * \return The number of bytes written or PROS_ERR if the operation failed, 309 | * setting errno. 310 | * 311 | * \b Example: 312 | * \code 313 | * void opcontrol() { 314 | * pros::Serial serial(1); 315 | * std::uint8_t buffer[10]; 316 | * serial.write(buffer, 10); 317 | * } 318 | * \endcode 319 | */ 320 | virtual std::int32_t write(std::uint8_t* buffer, std::int32_t length) const; 321 | 322 | private: 323 | ///@} 324 | }; 325 | 326 | namespace literals { 327 | const pros::Serial operator"" _ser(const unsigned long long int m); 328 | } // namespace literals 329 | } // namespace pros 330 | #endif // _PROS_SERIAL_HPP_ 331 | -------------------------------------------------------------------------------- /project.pros: -------------------------------------------------------------------------------- 1 | { 2 | "py/object": "pros.conductor.project.Project", 3 | "py/state": { 4 | "project_name": "Gamepad", 5 | "target": "v5", 6 | "templates": { 7 | "kernel": { 8 | "location": "/Users/nicholas.cheng/Library/Application Support/PROS/templates/kernel@4.0.7", 9 | "metadata": { 10 | "cold_addr": "58720256", 11 | "cold_output": "bin/cold.package.bin", 12 | "hot_addr": "125829120", 13 | "hot_output": "bin/hot.package.bin", 14 | "origin": "kernel-beta-mainline", 15 | "output": "bin/monolith.bin" 16 | }, 17 | "name": "kernel", 18 | "py/object": "pros.conductor.templates.local_template.LocalTemplate", 19 | "supported_kernels": null, 20 | "system_files": [ 21 | "include\\pros\\error.h", 22 | "include\\pros\\device.h", 23 | "firmware\\libpros.a", 24 | "include\\pros\\ext_adi.h", 25 | "firmware\\v5.ld", 26 | "include\\pros\\rotation.h", 27 | "include\\pros\\adi.h", 28 | "include\\pros\\motor_group.hpp", 29 | "include\\pros\\distance.h", 30 | "include\\pros\\gps.h", 31 | "include\\pros\\colors.h", 32 | "include\\pros\\abstract_motor.hpp", 33 | "firmware\\libm.a", 34 | "include\\pros\\optical.h", 35 | "include\\pros\\rotation.hpp", 36 | "include\\pros\\rtos.h", 37 | "include\\pros\\distance.hpp", 38 | "include\\pros\\vision.hpp", 39 | "include\\pros\\motors.hpp", 40 | "include\\pros\\vision.h", 41 | "firmware\\v5-hot.ld", 42 | "firmware\\libc.a", 43 | "include\\pros\\imu.h", 44 | "include\\pros\\llemu.h", 45 | "firmware\\v5-common.ld", 46 | "include\\pros\\link.h", 47 | "include\\pros\\adi.hpp", 48 | "include\\pros\\misc.hpp", 49 | "include\\pros\\llemu.hpp", 50 | "include\\pros\\motors.h", 51 | "include\\pros\\screen.h", 52 | "include\\pros\\serial.h", 53 | "include\\pros\\colors.hpp", 54 | "common.mk", 55 | "include\\pros\\misc.h", 56 | "include\\pros\\screen.hpp", 57 | "include\\pros\\apix.h", 58 | "include\\pros\\rtos.hpp", 59 | "include\\pros\\optical.hpp", 60 | "include\\pros\\device.hpp", 61 | "include\\pros\\imu.hpp", 62 | "include\\pros\\gps.hpp", 63 | "include\\api.h", 64 | "include\\pros\\link.hpp", 65 | "include\\pros\\serial.hpp" 66 | ], 67 | "target": "v5", 68 | "user_files": [ 69 | "include\\main.hpp", 70 | "include\\main.h", 71 | ".gitignore", 72 | "include\\main.hh", 73 | "src\\main.cpp", 74 | "src\\main.c", 75 | "src\\main.cc", 76 | "Makefile" 77 | ], 78 | "version": "4.0.7" 79 | } 80 | }, 81 | "upload_options": {}, 82 | "use_early_access": true 83 | } 84 | } -------------------------------------------------------------------------------- /src/gamepad/button.cpp: -------------------------------------------------------------------------------- 1 | #include "gamepad/button.hpp" 2 | #include "gamepad/todo.hpp" 3 | #include "pros/rtos.hpp" 4 | #include 5 | 6 | namespace gamepad { 7 | _impl::EventHandler* Button::get_handler(EventType event) const { 8 | switch (event) { 9 | case gamepad::EventType::ON_PRESS: return &m_on_press_event; 10 | case gamepad::EventType::ON_LONG_PRESS: return &m_on_long_press_event; 11 | case gamepad::EventType::ON_RELEASE: return &m_on_release_event; 12 | case gamepad::EventType::ON_SHORT_RELEASE: return &m_on_short_release_event; 13 | case gamepad::EventType::ON_LONG_RELEASE: return &m_on_long_release_event; 14 | case gamepad::EventType::ON_REPEAT_PRESS: return &m_on_repeat_press_event; 15 | default: return nullptr; 16 | } 17 | } 18 | 19 | void Button::setLongPressThreshold(uint32_t threshold) const { m_long_press_threshold = threshold; } 20 | 21 | void Button::setRepeatCooldown(uint32_t cooldown) const { m_repeat_cooldown = cooldown; } 22 | 23 | int32_t Button::onPress(std::string listenerName, std::function func) const { 24 | return m_on_press_event.addListener(std::move(listenerName) + "_user", std::move(func)); 25 | } 26 | 27 | int32_t Button::onLongPress(std::string listenerName, std::function func) const { 28 | return m_on_long_press_event.addListener(std::move(listenerName) + "_user", std::move(func)); 29 | } 30 | 31 | int32_t Button::onRelease(std::string listenerName, std::function func) const { 32 | return m_on_release_event.addListener(std::move(listenerName) + "_user", std::move(func)); 33 | } 34 | 35 | int32_t Button::onShortRelease(std::string listenerName, std::function func) const { 36 | return m_on_short_release_event.addListener(std::move(listenerName) + "_user", std::move(func)); 37 | } 38 | 39 | int32_t Button::onLongRelease(std::string listenerName, std::function func) const { 40 | return m_on_long_release_event.addListener(std::move(listenerName) + "_user", std::move(func)); 41 | } 42 | 43 | int32_t Button::onRepeatPress(std::string listenerName, std::function func) const { 44 | return m_on_repeat_press_event.addListener(std::move(listenerName) + "_user", std::move(func)); 45 | } 46 | 47 | int32_t Button::addListener(EventType event, std::string listenerName, std::function func) const { 48 | auto handler = this->get_handler(event); 49 | if (handler != nullptr) { 50 | return handler->addListener(listenerName + "_user", func); 51 | } else { 52 | TODO("add error logging") 53 | errno = EINVAL; 54 | return INT32_MAX; 55 | } 56 | } 57 | 58 | int32_t Button::removeListener(EventType event, std::string listenerName) const { 59 | return m_on_press_event.removeListener(listenerName + "_user") || 60 | m_on_long_press_event.removeListener(listenerName + "_user") || 61 | m_on_release_event.removeListener(listenerName + "_user") || 62 | m_on_short_release_event.removeListener(listenerName + "_user") || 63 | m_on_long_release_event.removeListener(listenerName + "_user") || 64 | m_on_repeat_press_event.removeListener(listenerName + "_user"); 65 | auto handler = this->get_handler(event); 66 | if (handler != nullptr) { 67 | return handler->removeListener(listenerName + "_user"); 68 | } else { 69 | TODO("add error logging") 70 | errno = EINVAL; 71 | return INT32_MAX; 72 | } 73 | } 74 | 75 | void Button::update(const bool is_held) { 76 | this->rising_edge = !this->is_pressed && is_held; 77 | this->falling_edge = this->is_pressed && !is_held; 78 | this->is_pressed = is_held; 79 | if (is_held) this->time_held += pros::millis() - m_last_update_time; 80 | else this->time_released += pros::millis() - m_last_update_time; 81 | 82 | if (this->rising_edge) { 83 | m_on_press_event.fire(); 84 | } else if (this->is_pressed && this->time_held >= m_long_press_threshold && 85 | m_last_long_press_time <= pros::millis() - this->time_held) { 86 | m_on_long_press_event.fire(); 87 | m_last_long_press_time = pros::millis(); 88 | m_last_repeat_time = pros::millis() - m_repeat_cooldown; 89 | this->repeat_iterations = 0; 90 | } else if (this->is_pressed && this->time_held >= m_long_press_threshold && 91 | pros::millis() - m_last_repeat_time >= m_repeat_cooldown) { 92 | this->repeat_iterations++; 93 | m_on_repeat_press_event.fire(); 94 | m_last_repeat_time = pros::millis(); 95 | } else if (this->falling_edge) { 96 | m_on_release_event.fire(); 97 | if (this->time_held < m_long_press_threshold) m_on_short_release_event.fire(); 98 | else m_on_long_release_event.fire(); 99 | } 100 | 101 | if (this->rising_edge) this->time_held = 0; 102 | if (this->falling_edge) this->time_released = 0; 103 | m_last_update_time = pros::millis(); 104 | } 105 | } // namespace gamepad 106 | -------------------------------------------------------------------------------- /src/gamepad/gamepad.cpp: -------------------------------------------------------------------------------- 1 | #include "gamepad/gamepad.hpp" 2 | #include "gamepad/todo.hpp" 3 | #include "pros/misc.h" 4 | #include "pros/rtos.hpp" 5 | #include "screens/abstractScreen.hpp" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace gamepad { 16 | Gamepad::Gamepad(pros::controller_id_e_t id) 17 | : m_controller(id) { 18 | this->addScreen(m_default_screen); 19 | } 20 | 21 | void Gamepad::updateButton(pros::controller_digital_e_t button_id) { 22 | Button Gamepad::* button = Gamepad::buttonToPtr(button_id); 23 | bool is_held = m_controller.get_digital(button_id); 24 | (this->*button).update(is_held); 25 | } 26 | 27 | void Gamepad::updateScreens() { 28 | // Lock Mutexes for Thread Safety 29 | std::lock_guard guard_scheduling(m_mutex); 30 | 31 | // Disable screen updates if the controller is disconnected 32 | if (!m_controller.is_connected()) { 33 | if (m_screen_cleared) { 34 | m_next_buffer = std::move(m_current_screen); 35 | m_current_screen = {}; 36 | m_screen_cleared = false; 37 | } 38 | return; 39 | } 40 | 41 | // Clear current screen and reset last update time on reconnect 42 | if (m_controller.is_connected() && !m_screen_cleared) { 43 | m_current_screen = {}; 44 | m_last_update_time = pros::millis(); 45 | } 46 | 47 | // Get new button presses 48 | std::set buttonUpdates; 49 | for (int i = pros::E_CONTROLLER_DIGITAL_L1; i <= pros::E_CONTROLLER_DIGITAL_A; ++i) { 50 | if ((this->*this->buttonToPtr(static_cast(i))).rising_edge) { 51 | buttonUpdates.emplace(static_cast(i)); 52 | } 53 | } 54 | 55 | // Update all screens, and send new button presses, also note deltatime 56 | for (std::shared_ptr screen : m_screens) { 57 | screen->update(pros::millis() - m_last_update_time); 58 | screen->handleEvents(buttonUpdates); 59 | } 60 | m_last_update_time = pros::millis(); 61 | 62 | // Check if enough time has passed for the Gamepad to poll for updates 63 | if (pros::millis() - m_last_print_time <= 50) return; 64 | 65 | for (std::shared_ptr screen : m_screens) { 66 | // get all lines that aren't being used by a higher priority screen 67 | std::set visible_lines; 68 | for (uint8_t j = 0; j < 4; j++) 69 | if (!m_next_buffer[j].has_value()) visible_lines.emplace(j); 70 | 71 | // get the buffer of the next lower priority screen and set it to be printed 72 | ScreenBuffer buffer = screen->getScreen(visible_lines); 73 | for (uint8_t j = 0; j < 4; j++) 74 | if (buffer[j].has_value() && !buffer[j]->empty() && !m_next_buffer[j].has_value()) 75 | m_next_buffer[j] = std::move(buffer[j]); 76 | } 77 | 78 | for (int i = 0; i < 4; i++) { 79 | // start from the line thats after the line thats been set so we dont get stuck setting the first line 80 | int line = (m_last_printed_line + i) % 4; 81 | 82 | // theres nothing on this line so we can skip it 83 | if (!m_next_buffer[line].has_value()) continue; 84 | 85 | if (!m_screen_cleared && line != 3) { 86 | m_controller.clear(); 87 | m_screen_cleared = true; 88 | m_current_screen = {}; 89 | m_last_print_time = pros::millis(); 90 | return; 91 | } 92 | 93 | // text on screen is the same as last frame's text so no use updating 94 | if (m_current_screen[line] == m_next_buffer[line] && line != 3) { 95 | m_next_buffer[line] = std::nullopt; 96 | continue; 97 | } 98 | 99 | // print to screen or rumble 100 | if (line == 3) m_controller.rumble(m_next_buffer[line].value_or("").c_str()); 101 | else m_controller.set_text(line, 0, m_next_buffer[line].value_or("") + std::string(40, ' ')); 102 | if (line != 3) m_current_screen[line] = std::move(m_next_buffer[line]); 103 | m_next_buffer[line] = std::nullopt; 104 | m_last_printed_line = line; 105 | m_last_print_time = pros::millis(); 106 | return; 107 | } 108 | } 109 | 110 | void Gamepad::update() { 111 | for (int i = pros::E_CONTROLLER_DIGITAL_L1; i <= pros::E_CONTROLLER_DIGITAL_A; ++i) { 112 | this->updateButton(static_cast(i)); 113 | } 114 | 115 | m_LeftX = m_controller.get_analog(pros::E_CONTROLLER_ANALOG_LEFT_X) / 127.0; 116 | m_LeftY = m_controller.get_analog(pros::E_CONTROLLER_ANALOG_LEFT_Y) / 127.0; 117 | m_RightX = m_controller.get_analog(pros::E_CONTROLLER_ANALOG_RIGHT_X) / 127.0; 118 | m_RightY = m_controller.get_analog(pros::E_CONTROLLER_ANALOG_RIGHT_Y) / 127.0; 119 | 120 | this->updateScreens(); 121 | } 122 | 123 | void Gamepad::addScreen(std::shared_ptr screen) { 124 | uint32_t last = UINT32_MAX; 125 | uint32_t pos = 0; 126 | for (pos = 0; pos < m_screens.size(); pos++) { 127 | if (m_screens[pos]->getPriority() < screen->getPriority() && last >= screen->getPriority()) break; 128 | last = m_screens[pos]->getPriority(); 129 | } 130 | m_screens.emplace(m_screens.begin() + pos, screen); 131 | } 132 | 133 | int32_t Gamepad::printLine(uint8_t line, std::string str) { return m_default_screen->printLine(line, str); } 134 | 135 | void Gamepad::clear() { m_default_screen->printLine(0, " \n \n "); } 136 | 137 | int32_t Gamepad::clear(uint8_t line) { return m_default_screen->printLine(line, " "); } 138 | 139 | void Gamepad::rumble(std::string rumble_pattern) { m_default_screen->rumble(rumble_pattern); } 140 | 141 | const Button& Gamepad::operator[](pros::controller_digital_e_t button) { return this->*Gamepad::buttonToPtr(button); } 142 | 143 | float Gamepad::operator[](pros::controller_analog_e_t axis) { 144 | switch (axis) { 145 | case pros::E_CONTROLLER_ANALOG_LEFT_X: return m_LeftX; 146 | case pros::E_CONTROLLER_ANALOG_LEFT_Y: return m_LeftY; 147 | case pros::E_CONTROLLER_ANALOG_RIGHT_X: return m_RightX; 148 | case pros::E_CONTROLLER_ANALOG_RIGHT_Y: return m_RightY; 149 | default: TODO("add error logging") return 0; 150 | } 151 | } 152 | 153 | const Button& Gamepad::buttonL1() { return m_L1; } 154 | 155 | const Button& Gamepad::buttonL2() { return m_L2; } 156 | 157 | const Button& Gamepad::buttonR1() { return m_R1; } 158 | 159 | const Button& Gamepad::buttonR2() { return m_R2; } 160 | 161 | const Button& Gamepad::buttonUp() { return m_Up; } 162 | 163 | const Button& Gamepad::buttonDown() { return m_Down; } 164 | 165 | const Button& Gamepad::buttonLeft() { return m_Left; } 166 | 167 | const Button& Gamepad::buttonRight() { return m_Right; } 168 | 169 | const Button& Gamepad::buttonX() { return m_X; } 170 | 171 | const Button& Gamepad::buttonB() { return m_B; } 172 | 173 | const Button& Gamepad::buttonY() { return m_Y; } 174 | 175 | const Button& Gamepad::buttonA() { return m_A; } 176 | 177 | float Gamepad::axisLeftX(bool use_curve) { 178 | if (use_curve && m_left_transformation) return m_left_transformation->get_value({m_LeftX, m_LeftY}).first; 179 | else return m_LeftX; 180 | } 181 | 182 | float Gamepad::axisLeftY(bool use_curve) { 183 | if (use_curve && m_left_transformation) return m_left_transformation->get_value({m_LeftX, m_LeftY}).second; 184 | else return m_LeftY; 185 | } 186 | 187 | float Gamepad::axisRightX(bool use_curve) { 188 | if (use_curve && m_right_transformation) return m_right_transformation->get_value({m_RightX, m_RightY}).first; 189 | else return m_RightX; 190 | } 191 | 192 | float Gamepad::axisRightY(bool use_curve) { 193 | if (use_curve && m_right_transformation) return m_right_transformation->get_value({m_RightX, m_RightY}).second; 194 | else return m_RightY; 195 | } 196 | 197 | void Gamepad::set_left_transform(Transformation left_transformation) { 198 | m_left_transformation = std::move(left_transformation); 199 | } 200 | 201 | void Gamepad::set_right_transform(Transformation right_transformation) { 202 | m_right_transformation = std::move(right_transformation); 203 | } 204 | 205 | std::string Gamepad::uniqueName() { 206 | static std::atomic i = 0; 207 | return std::to_string(i++) + "_internal"; 208 | } 209 | 210 | Button Gamepad::* Gamepad::buttonToPtr(pros::controller_digital_e_t button) { 211 | switch (button) { 212 | case pros::E_CONTROLLER_DIGITAL_L1: return &Gamepad::m_L1; 213 | case pros::E_CONTROLLER_DIGITAL_L2: return &Gamepad::m_L2; 214 | case pros::E_CONTROLLER_DIGITAL_R1: return &Gamepad::m_R1; 215 | case pros::E_CONTROLLER_DIGITAL_R2: return &Gamepad::m_R2; 216 | case pros::E_CONTROLLER_DIGITAL_UP: return &Gamepad::m_Up; 217 | case pros::E_CONTROLLER_DIGITAL_DOWN: return &Gamepad::m_Down; 218 | case pros::E_CONTROLLER_DIGITAL_LEFT: return &Gamepad::m_Left; 219 | case pros::E_CONTROLLER_DIGITAL_RIGHT: return &Gamepad::m_Right; 220 | case pros::E_CONTROLLER_DIGITAL_X: return &Gamepad::m_X; 221 | case pros::E_CONTROLLER_DIGITAL_B: return &Gamepad::m_B; 222 | case pros::E_CONTROLLER_DIGITAL_Y: return &Gamepad::m_Y; 223 | case pros::E_CONTROLLER_DIGITAL_A: return &Gamepad::m_A; 224 | default: TODO("add error logging") return &Gamepad::Fake; 225 | } 226 | } 227 | } // namespace gamepad 228 | -------------------------------------------------------------------------------- /src/gamepad/joystick_transformation.cpp: -------------------------------------------------------------------------------- 1 | #include "joystick_transformation.hpp" 2 | #include 3 | #include 4 | 5 | using std::abs; 6 | using std::copysign; 7 | using std::pow; 8 | 9 | namespace gamepad { 10 | float Deadband::apply_deadband(float value, float deadband) { 11 | float abs_val = abs(value); 12 | return copysign(abs_val < deadband ? 0 : (abs_val - deadband) / (1.0 - deadband), value); 13 | } 14 | 15 | std::pair Deadband::get_value(std::pair value) { 16 | float x = value.first; 17 | float y = value.second; 18 | float x_deadband = m_x_deadband + abs(y) * m_x_spread; 19 | float y_deadband = m_y_deadband + abs(x) * m_y_spread; 20 | x = apply_deadband(x, x_deadband); 21 | y = apply_deadband(y, y_deadband); 22 | return {x, y}; 23 | } 24 | 25 | std::pair ExpoCurve::get_value(std::pair value) { 26 | float x = value.first; 27 | float y = value.second; 28 | x = copysign(pow(abs(x), m_x_curve), x); 29 | y = copysign(pow(abs(y), m_y_curve), y); 30 | return {x, y}; 31 | } 32 | 33 | std::pair Fisheye::get_value(std::pair value) { 34 | float x = value.first; 35 | float y = value.second; 36 | float x_abs = abs(x); 37 | float y_abs = abs(y); 38 | float j = std::sqrt(m_radius * m_radius - 1.0 * 1.0); 39 | if (x_abs >= j && y_abs >= j) { 40 | float scale = std::hypot(std::min(x_abs / y_abs, y_abs / x_abs), 1.0) / m_radius; 41 | x_abs *= scale; 42 | y_abs *= scale; 43 | } 44 | x = std::copysign(std::min(1.0f, x_abs), x); 45 | y = std::copysign(std::min(1.0f, y_abs), y); 46 | return {x, y}; 47 | } 48 | 49 | std::pair Transformation::get_value(std::pair value) { 50 | return std::accumulate(m_all_transforms.begin(), m_all_transforms.end(), value, 51 | [](auto last_val, auto& next_transform) { return next_transform->get_value(last_val); }); 52 | } 53 | } // namespace gamepad -------------------------------------------------------------------------------- /src/gamepad/screens/alertScreen.cpp: -------------------------------------------------------------------------------- 1 | #include "gamepad/screens/alertScreen.hpp" 2 | #include "gamepad/todo.hpp" 3 | #include "pros/rtos.hpp" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace gamepad { 12 | 13 | ScreenBuffer AlertScreen::getScreen(std::set visible_lines) { 14 | std::lock_guard guard(m_mutex); 15 | if (m_screen_contents.has_value()) { 16 | m_screen_contents->screen.at(3) = std::nullopt; 17 | return m_screen_contents->screen; 18 | } 19 | if (m_screen_buffer.size() < 1) return ScreenBuffer(); 20 | 21 | for (uint8_t i = 0; i < 4; i++) { 22 | if (!m_screen_buffer[0].screen[i].has_value()) continue; 23 | if (m_screen_buffer[0].screen[i].has_value() && !visible_lines.contains(i)) return ScreenBuffer(); 24 | } 25 | m_screen_contents = std::move(m_screen_buffer[0]); 26 | m_screen_buffer.pop_front(); 27 | m_line_set_time = pros::millis(); 28 | return m_screen_contents->screen; 29 | } 30 | 31 | void AlertScreen::update(uint32_t delta_time) { 32 | std::lock_guard guard(m_mutex); 33 | if (pros::millis() - m_line_set_time >= m_screen_contents->duration) m_screen_contents = std::nullopt; 34 | } 35 | 36 | int32_t AlertScreen::addAlerts(uint8_t line, std::string str, uint32_t duration, std::string rumble) { 37 | int32_t ret_val = 0; 38 | if (line > 2) { 39 | TODO("add error logging") 40 | errno = EINVAL; 41 | return INT32_MAX; 42 | } 43 | 44 | if (std::ranges::count(str, '\n') > 2) { 45 | TODO("add warn logging") 46 | errno = EMSGSIZE; 47 | ret_val = INT32_MAX; 48 | } 49 | 50 | std::vector strs(3, ""); 51 | std::stringstream ss(str); 52 | 53 | // split string by newlines but only take the first 3 lines 54 | for (int i = line; i < 3; i++) { 55 | if (!std::getline(ss, strs[i], '\n')) break; 56 | } 57 | 58 | ScreenBuffer buffer; 59 | 60 | if (strs[0] != "") buffer[0] = std::move(strs[0]); 61 | if (strs[1] != "") buffer[1] = std::move(strs[1]); 62 | if (strs[2] != "") buffer[2] = std::move(strs[2]); 63 | if (rumble != "") buffer[3] = std::move(rumble); 64 | 65 | std::lock_guard guard(m_mutex); 66 | m_screen_buffer.push_back({buffer, duration}); 67 | return ret_val; 68 | } 69 | 70 | } // namespace gamepad 71 | -------------------------------------------------------------------------------- /src/gamepad/screens/defaultScreen.cpp: -------------------------------------------------------------------------------- 1 | #include "gamepad/screens/defaultScreen.hpp" 2 | #include "gamepad/screens/abstractScreen.hpp" 3 | #include "gamepad/todo.hpp" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace gamepad { 13 | 14 | ScreenBuffer DefaultScreen::getScreen(std::set visible_lines) { 15 | ScreenBuffer output; 16 | const std::lock_guard guard(m_mutex); 17 | 18 | for (auto i = visible_lines.begin(); i != visible_lines.end(); ++i) { 19 | output[*i] = std::move(m_current_buffer[*i]); 20 | m_current_buffer[*i] = std::nullopt; 21 | } 22 | return output; 23 | } 24 | 25 | int32_t DefaultScreen::printLine(uint8_t line, std::string str) { 26 | int32_t ret_val = 0; 27 | if (line > 2) { 28 | TODO("add error logging") 29 | errno = EINVAL; 30 | return INT32_MAX; 31 | } 32 | 33 | const std::lock_guard guard(m_mutex); 34 | 35 | if (str.find('\n') != std::string::npos) { 36 | if (std::ranges::count(str, '\n') > 2) { 37 | TODO("add warn logging for too many lines") 38 | errno = EMSGSIZE; 39 | ret_val = INT32_MAX; 40 | } 41 | 42 | std::vector strs(3); 43 | std::stringstream ss(str); 44 | 45 | for (int i = line; i < 3; i++) { 46 | if (!std::getline(ss, strs[i], '\n')) break; 47 | } 48 | 49 | for (uint8_t l = 0; l < 3; l++) { 50 | if (!strs[l].empty()) m_current_buffer[l] = (strs[l]); 51 | } 52 | return ret_val; 53 | } 54 | 55 | m_current_buffer[line] = std::move(str); 56 | return ret_val; 57 | } 58 | 59 | int32_t DefaultScreen::rumble(std::string rumble_pattern) { 60 | int32_t ret_val = 0; 61 | if (rumble_pattern.size() > 8) { 62 | TODO("add error logging") 63 | errno = EMSGSIZE; 64 | ret_val = INT32_MAX; 65 | rumble_pattern.resize(8); 66 | } 67 | 68 | if (rumble_pattern.find_first_not_of(".- ") != std::string::npos) { 69 | TODO("add error logging") 70 | errno = EINVAL; 71 | return INT32_MAX; 72 | } 73 | 74 | std::lock_guard guard(m_mutex); 75 | m_current_buffer[3] = std::move(rumble_pattern); 76 | return ret_val; 77 | } 78 | 79 | } // namespace gamepad -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "gamepad/api.hpp" 3 | #include "gamepad/gamepad.hpp" 4 | #include "gamepad/screens/alertScreen.hpp" 5 | #include "pros/rtos.hpp" 6 | #include 7 | #include 8 | #include 9 | 10 | // initialize the alerts screen so we can have alerts on the controller 11 | std::shared_ptr alerts = std::make_shared(); 12 | 13 | /** 14 | * Runs initialization code. This occurs as soon as the program is started. 15 | * 16 | * All other competition modes are blocked by initialize; it is recommended 17 | * to keep execution time for this mode under a few seconds. 18 | */ 19 | void initialize() { 20 | // VERY IMPORTANT, this actually adds the alerts screen to the gamepad 21 | // it wouldn't work without this line 22 | gamepad::master.addScreen(alerts); 23 | 24 | // When the A button is pressed, schedule an alert that spans all three 25 | // lines, lasts 3 seconds and rumbles in a long-short-long pattern 26 | gamepad::master.buttonA().onPress("alert", []() { 27 | alerts->addAlerts(0, "a very\nimportant alert\nat " + std::to_string(pros::millis()) + " ms", 3000, "-.-"); 28 | }); 29 | 30 | // Normally print a string on the first and third line without overriding 31 | // the second line when the B button is pressed 32 | gamepad::master.buttonB().onPress( 33 | "print02", []() { gamepad::master.printLine(0, "the time is\n\n" + std::to_string(pros::millis()) + " ms"); }); 34 | 35 | // rumbles 3 times for a short duration when the X button is pressed 36 | gamepad::master.buttonX().onPress("rumble", []() { gamepad::master.rumble("..."); }); 37 | 38 | // when the Y button is pressed and held the text should show up, and when 39 | // the button is released it should be cleared 40 | gamepad::master.buttonY().onPress("print1", []() { gamepad::master.printLine(1, "this should be cleared"); }); 41 | gamepad::master.buttonY().onRelease("clear1", []() { gamepad::master.clear(1); }); 42 | 43 | // set up controller curves: 44 | gamepad::master.set_left_transform( 45 | gamepad::TransformationBuilder(gamepad::Deadband(0.05, 0.05)).and_then(gamepad::ExpoCurve(2, 2))); 46 | } 47 | 48 | /** 49 | * Runs while the robot is in the disabled state of Field Management System or 50 | * the VEX Competition Switch, following either autonomous or opcontrol. When 51 | * the robot is enabled, this task will exit. 52 | */ 53 | void disabled() {} 54 | 55 | /** 56 | * Runs after initialize(), and before autonomous when connected to the Field 57 | * Management System or the VEX Competition Switch. This is intended for 58 | * competition-specific initialization routines, such as an autonomous selector 59 | * on the LCD. 60 | * 61 | * This task will exit when the robot is enabled and autonomous or opcontrol 62 | * starts. 63 | */ 64 | void competition_initialize() {} 65 | 66 | /** 67 | * Runs the user autonomous code. This function will be started in its own task 68 | * with the default priority and stack size whenever the robot is enabled via 69 | * the Field Management System or the VEX Competition Switch in the autonomous 70 | * mode. Alternatively, this function may be called in initialize or opcontrol 71 | * for non-competition testing purposes. 72 | * 73 | * If the robot is disabled or communications is lost, the autonomous task 74 | * will be stopped. Re-enabling the robot will restart the task, not re-start it 75 | * from where it left off. 76 | */ 77 | void autonomous() {} 78 | 79 | /** 80 | * Runs the operator control code. This function will be started in its own task 81 | * with the default priority and stack size whenever the robot is enabled via 82 | * the Field Management System or the VEX Competition Switch in the operator 83 | * control mode. 84 | * 85 | * If no competition control is connected, this function will run immediately 86 | * following initialize(). 87 | * 88 | * If the robot is disabled or communications is lost, the 89 | * operator control task will be stopped. Re-enabling the robot will restart the 90 | * task, not resume it from where it left off. 91 | */ 92 | void opcontrol() { 93 | pros::MotorGroup left_mg({1, -2, 3}); // Creates a motor group with forwards ports 1 & 3 and reversed port 2 94 | pros::MotorGroup right_mg({-4, 5, -6}); // Creates a motor group with forwards port 4 and reversed ports 4 & 6 95 | while (true) { 96 | // Remember to ALWAYS call update at the start of your while loop! 97 | gamepad::master.update(); 98 | // We'll use the arcade control scheme 99 | int dir = gamepad::master.axisLeftY() * 127; // Gets amount forward/backward from left joystick 100 | int turn = gamepad::master.axisRightX() * 127; // Gets the turn left/right from right joystick 101 | left_mg.move(dir - turn); // Sets left motor voltage 102 | right_mg.move(dir + turn); // Sets right motor voltage 103 | pros::delay(25); // Wait for 25 ms, then update the motor values again 104 | } 105 | } 106 | --------------------------------------------------------------------------------