diff --git a/.DS_Store b/.DS_Store
deleted file mode 100644
index 020bed74..00000000
Binary files a/.DS_Store and /dev/null differ
diff --git a/.clang-format b/.clang-format
index 857de7fe..1f1f52f5 100644
--- a/.clang-format
+++ b/.clang-format
@@ -6,6 +6,4 @@ UseCRLF: false
ColumnLimit: 100
AllowShortIfStatementsOnASingleLine: WithoutElse
AlignAfterOpenBracket: BlockIndent
-AlignArrayOfStructures: Left
AlwaysBreakTemplateDeclarations: "MultiLine"
-AlwaysBreakTemplateDeclarations: true
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..389a4851
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,17 @@
+---
+name: Bug report
+about: Report a bug in robodash
+title: 'Bug: '
+labels: bug
+assignees: unwieldycat
+
+---
+
+**Bug description**
+Description of what the bug is.
+
+**Expected behavior**
+Description of what you expected to happen.
+
+**Steps to reproduce**
+Steps to reproduce the behavior, including any necessary code.
diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md
new file mode 100644
index 00000000..4d62ac60
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/enhancement.md
@@ -0,0 +1,14 @@
+---
+name: Enhancement
+about: Suggest a new feature or idea
+title: 'Enhancement: '
+labels: enhancement
+assignees: unwieldycat
+
+---
+
+**Proposed enhancement**
+Describe the change or feature you want.
+
+**Motivation behind change**
+Describe why this enhancement would be helpful.
diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md
new file mode 100644
index 00000000..add02159
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/question.md
@@ -0,0 +1,10 @@
+---
+name: Question
+about: Ask a question about robodash
+title: 'Question: '
+labels: question
+assignees: unwieldycat
+
+---
+
+Ask your question here. Provide any relevant background information.
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 00000000..cf79042a
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,27 @@
+name: Build template
+
+on:
+ push:
+ branches:
+ - main
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Build template
+ id: build
+ uses: LemLib/pros-build@v4.0.1
+ with:
+ lib_folder_name: robodash
+ no_commit_hash: true
+
+ - name: Upload Artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{ steps.build.outputs.name }}
+ path: ${{ github.workspace }}/template/*
diff --git a/.github/workflows/depot.yml b/.github/workflows/depot.yml
new file mode 100644
index 00000000..2e0a7957
--- /dev/null
+++ b/.github/workflows/depot.yml
@@ -0,0 +1,26 @@
+name: Populate Depot json
+
+on:
+ # runs when this repository's releases are modified
+ release:
+ # allows for manual dispatching of the workflow
+ workflow_dispatch:
+
+jobs:
+ populate:
+ runs-on: ubuntu-latest
+ permissions:
+ # permits reading of releases and writing to the depot branch
+ contents: write
+ steps:
+ # where to find gh action and what version to use
+ - uses: LemLib/pros-depot@v0.1.0-beta.1
+ with:
+ # gives the github action the permissions specified above
+ token: ${{ github.token }}
+ # target repo for depots
+ repo: unwieldycat/robodash
+ # where to read releases from (can be omitted if repo is also the repo from which to read releases from, but it doesn't sem to be working at the moment)
+ source-repo: unwieldycat/robodash
+ # makes the json output human readable
+ readable-json: true
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
deleted file mode 100644
index d2338048..00000000
--- a/.github/workflows/docs.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-name: Build and Deploy Docs
-
-# Controls when the action will run. Triggers the workflow on push or pull request
-# events but only for the master branch
-on:
- push:
- branches:
- - main
- workflow_dispatch:
-
-jobs:
- build:
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout
- uses: actions/checkout@v2.0.0
- - name: Checkout Doxygen Awesome
- uses: Mushus/checkout-submodule@v1.0.1
- with:
- submodulePath: ./docs/doxygen-awesome-css
- - name: Generate Documentation
- uses: mattnotmitt/doxygen-action@edge
- with:
- doxyfile-path: "docs/Doxyfile"
- - name: Deploy
- uses: JamesIves/github-pages-deploy-action@v4.4.3
- with:
- branch: gh-pages # The branch the action should deploy to.
- folder: ./docs-output/html # The folder the action should deploy.
diff --git a/.gitignore b/.gitignore
index a670baf9..5a32da82 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,5 +16,6 @@ temp.errors
*.ini
.d/
-docs-output/
-.DS_STORE
\ No newline at end of file
+**/.DS_Store
+docs/build/
+docs/doxygen/
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 10beb965..00000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "docs/doxygen-awesome-css"]
- path = docs/doxygen-awesome-css
- url = https://github.com/jothepro/doxygen-awesome-css.git
diff --git a/.prettierrc b/.prettierrc
deleted file mode 100644
index cb427c47..00000000
--- a/.prettierrc
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "endOfLine": "lf",
- "printWidth": 80,
- "useTabs": true,
- "proseWrap": "always"
-}
\ No newline at end of file
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
new file mode 100644
index 00000000..8515b436
--- /dev/null
+++ b/.readthedocs.yaml
@@ -0,0 +1,13 @@
+version: 2
+
+build:
+ os: ubuntu-22.04
+ tools:
+ python: "3.12"
+
+python:
+ install:
+ - requirements: docs/requirements.txt
+
+sphinx:
+ configuration: docs/source/conf.py
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 00000000..acdd2183
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,74 @@
+# Changelog
+
+Changes to this project will be logged in this file. This project uses
+[Semantic Versioning](https://semver.org/spec/v2.0.0.html). Format is loosely
+based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
+
+## 2.3.1
+
+This release upgrades to liblvgl 8.3.9 and PROS 4.2.1
+
+### Fixes
+
+- Builds on PROS 4.2.1+ failing.
+
+## 2.3.0
+
+Robodash 2.3.0 improves the selector UI.
+
+### Added
+
+- An indication for what auton in the selector list is currently selected
+- `color_hue` parameter to autons, which places a color chip next to the auton's name in the list.
+- Page up / page down buttons to the selector if it's scrollable, making scrolling easier when there's many autons.
+- Up / down buttons to the selector, providing an alternate way to select autons in the list.
+- `rd::Selector::next_auton` and `rd::Selector::prev_auton` functions for user-defined methods to control the selector, enabling hardware buttons or dials.
+
+## 2.2.0
+
+Robodash 2.2.0 provides selector enhancements.
+
+### Added
+
+- Autonomous selector callbacks (`rd::Selector::on_select`)
+- Autonomous selector getter (`rd::Selector::get_auton`)
+
+### Fixed
+
+- `rd::Image` constructor for C array images required a `lv_img_dsc_t`, not a `const lv_img_dsc_t` (which LVGL outputs in its conversion). Added support for both.
+
+## 2.1.2
+
+Robodash 2.1.2 provides a fix for the image widget.
+
+> [!WARNING]
+>
+> This update has a breaking change. When constructing an `rd::Image` with a C
+> array, you must pass a pointer to your `lv_img_dsc_t` instead of a reference.
+> This is to prevent a dangling pointer.
+
+### Fixed
+
+- A bug where constructing an `rd::Image` with a C array would not display the
+ image.
+
+## 2.1.1
+
+Robodash 2.1.1 is a recompilation of 2.1.0 that upgrades to PROS version 4.1.0
+
+## 2.1.0
+
+Robodash 2.1.0 resolves issues with the autonomous selector.
+
+### Added
+
+- The ability to associate images with autonomous routines
+- Support for multiple active selectors
+- Automatic SD saving, no need to press a button
+
+Minor breaking changes with selector: `rd::Selector::routine_t` is now a
+`struct` instead of an `std::pair`. This shouldn't break any existing code.
+
+### Fixed
+
+- A data abort error when a routine name was too long
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..53f5c33c
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,37 @@
+# Contributing
+
+Thanks for wanting to contribute to robodash. Before contributing code to this
+repository, please first open an issue describing the problem you're having or
+the feature you want added. This document describes procedures you should follow
+when contributing code to this repository.
+
+## Pull Requests
+
+1. Describe the issue your pull request resolves and the changes it makes. Link
+ relevant issues.
+
+ - Keep changes focused. Multiple unrelated changes shouldn't be lumped into
+ one pull request.
+
+2. Ensure that your changes work before requesting to merge.
+
+ - Changes should compile without warnings and behave as intended
+ - Changes for non-major versions should not break API compatibility
+
+3. Ensure that your code is formatted with the provided clang-format
+ configuration and follows the style guide.
+
+## Style Guide
+
+Along with formatting with the provided configuration file, code should use the
+following conventions to preserve readability and consistency:
+
+- Use appropriate casing
+ - Class names should be in `PascalCase`
+ - Macros should be in `SCREAM_CASE`
+ - Everything else should be `snake_case`
+- Use clear (but not excessive) variable names. Don't use names like `temp`,
+ `var`, or single letters.
+- Add appropriate whitespace to visually seperate blocks of code
+- User-facing functions should be annotated with doxygen comments.
+- Code comments should only be used if necessary
diff --git a/LICENCE b/LICENCE
index ab87bd90..325112b1 100644
--- a/LICENCE
+++ b/LICENCE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2023 Thurston A Yates
+Copyright (c) 2025 Thurston A Yates
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Makefile b/Makefile
index 33c14f67..e4f0df1f 100644
--- a/Makefile
+++ b/Makefile
@@ -26,7 +26,7 @@ EXCLUDE_COLD_LIBRARIES:=
# Set this to 1 to add additional rules to compile your project as a PROS library template
IS_LIBRARY:=1
LIBNAME:=robodash
-VERSION:=2.0.0
+VERSION:=2.3.1
# EXCLUDE_SRC_FROM_LIB= $(SRCDIR)/unpublishedfile.c
# this line excludes opcontrol.c and similar files
diff --git a/README.md b/README.md
index 33904d51..2ce99994 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,51 @@
+> [!IMPORTANT]
+> ### Maintenance mode
+> This project will not recieve further feature updates as I, the author of robodash,
+> am no longer competing in the VEX V5RC competition and want to focus my energy elsewhere.
+>
+> Patches will be provided for an additional year, if there is a bug you need fixed do not
+> hesitate to create an issue.
+
# robodash
-Robodash is a GUI toolkit for the VEX V5 brain intended to provide tools that
-take full advantage of the V5 brain's LCD display, as well as provide a
-foundation to improve compatibility with templates that provide LVGL-powered
+
+
+
+
+Robodash is a GUI toolkit for the VEX V5 brain that provides GUI tools that
+take better advantage of the brain's LCD display and a
+system to improve compatibility with templates that provide LVGL-powered
GUIs.
Get started with robodash by reading
-[the docs](https://unwieldycat.github.io/robodash/).
+[the docs](https://robodash.readthedocs.io/en/latest/).
+
+### Screenshots
+
+
+Console Tool
+
+
+
+
+
+
+Image Tool
+
+
+
+
+
+
+Autonomous Selector Tool
+
+
+
+
+
+
+View Selector
+
+
+
+
diff --git a/build-docs.sh b/build-docs.sh
deleted file mode 100755
index 04de80a1..00000000
--- a/build-docs.sh
+++ /dev/null
@@ -1 +0,0 @@
-doxygen ./docs/Doxyfile
\ No newline at end of file
diff --git a/common.mk b/common.mk
index 33efe871..40da70c9 100644
--- a/common.mk
+++ b/common.mk
@@ -1,7 +1,7 @@
ARCHTUPLE=arm-none-eabi-
DEVICE=VEX EDR V5
-MFLAGS=-mcpu=cortex-a9 -mfpu=neon-fp16 -mfloat-abi=softfp -Os -g
+MFLAGS=-mcpu=cortex-a9 -mfpu=neon-fp16 -mfloat-abi=hard -Os -g -mthumb
CPPFLAGS=-D_POSIX_THREADS -D_UNIX98_THREAD_MUTEX_ATTRIBUTES -D_POSIX_TIMERS -D_POSIX_MONOTONIC_CLOCK
GCCFLAGS=-ffunction-sections -fdata-sections -fdiagnostics-color -funwind-tables
@@ -20,8 +20,8 @@ WARNFLAGS+=-Wno-psabi
SPACE := $() $()
COMMA := ,
-C_STANDARD?=gnu11
-CXX_STANDARD?=gnu++20
+C_STANDARD?=gnu2x
+CXX_STANDARD?=gnu++23
DEPDIR := .d
$(shell mkdir -p $(DEPDIR))
@@ -34,7 +34,7 @@ LIBRARIES+=$(wildcard $(FWDIR)/*.a)
EXCLUDE_COLD_LIBRARIES+=$(FWDIR)/libc.a $(FWDIR)/libm.a
COLD_LIBRARIES=$(filter-out $(EXCLUDE_COLD_LIBRARIES), $(LIBRARIES))
wlprefix=-Wl,$(subst $(SPACE),$(COMMA),$1)
-LNK_FLAGS=--gc-sections --start-group $(strip $(LIBRARIES)) -lgcc -lstdc++ --end-group -T$(FWDIR)/v5-common.ld
+LNK_FLAGS=--gc-sections --start-group $(strip $(LIBRARIES)) -lgcc -lstdc++ --end-group -T$(FWDIR)/v5-common.ld --no-warn-rwx-segments --sort-section=alignment --sort-common
ASMFLAGS=$(MFLAGS) $(WARNFLAGS)
CFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) $(GCCFLAGS) --std=$(C_STANDARD)
@@ -188,14 +188,14 @@ quick: $(DEFAULT_BIN)
all: clean $(DEFAULT_BIN)
-clean:
+clean::
@echo Cleaning project
-$Drm -rf $(BINDIR)
-$Drm -rf $(DEPDIR)
ifeq ($(IS_LIBRARY),1)
ifeq ($(LIBNAME),libbest)
-$(errror "You should rename your library! libbest is the default library name and should be changed")
+$(error "You should rename your library! libbest is the default library name and should be changed")
endif
LIBAR=$(BINDIR)/$(LIBNAME).a
@@ -206,6 +206,7 @@ clean-template:
-$Drm -rf $(TEMPLATE_DIR)
$(LIBAR): $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)) $(EXTRA_LIB_DEPS)
+ -$Dmkdir $(BINDIR)
-$Drm -f $@
$(call test_output_2,Creating $@ ,$(AR) rcs $@ $^, $(DONE_STRING))
@@ -213,7 +214,7 @@ $(LIBAR): $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)) $(EXTRA_LIB_DEPS)
library: $(LIBAR)
.PHONY: template
-template: clean-template $(LIBAR)
+template:: clean-template $(LIBAR)
$Dpros c create-template . $(LIBNAME) $(VERSION) $(foreach file,$(TEMPLATE_FILES) $(LIBAR),--system "$(file)") --target v5 $(CREATE_TEMPLATE_FLAGS)
endif
@@ -262,7 +263,7 @@ $(foreach asmext,$(ASMEXTS),$(eval $(call asm_rule,$(asmext))))
define c_rule
$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1
-$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 $(DEPDIR)/$(basename $1).d
+$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 $(DEPDIR)/$(basename %).d
$(VV)mkdir -p $$(dir $$@)
$(MAKEDEPFOLDER)
$$(call test_output_2,Compiled $$< ,$(CC) -c $(INCLUDE) -iquote"$(INCDIR)/$$(dir $$*)" $(CFLAGS) $(EXTRA_CFLAGS) $(DEPFLAGS) -o $$@ $$<,$(OK_STRING))
@@ -305,4 +306,4 @@ cxx-sysroot:
$(DEPDIR)/%.d: ;
.PRECIOUS: $(DEPDIR)/%.d
-include $(wildcard $(patsubst $(SRCDIR)/%,$(DEPDIR)/%.d,$(CSRC) $(CXXSRC)))
+include $(wildcard $(patsubst $(SRCDIR)/%,$(DEPDIR)/%.d,$(CSRC) $(CXXSRC)))
\ No newline at end of file
diff --git a/docs/.DS_Store b/docs/.DS_Store
deleted file mode 100644
index 6c9628bb..00000000
Binary files a/docs/.DS_Store and /dev/null differ
diff --git a/docs/Doxyfile b/docs/Doxyfile
index a4fa6b38..bf5382df 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -48,7 +48,7 @@ PROJECT_NAME = Robodash
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 2.0.0
+PROJECT_NUMBER = 2.3.1
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -68,7 +68,7 @@ PROJECT_LOGO =
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
-OUTPUT_DIRECTORY = docs-output/
+OUTPUT_DIRECTORY = doxygen/
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
# sub-directories (in 2 levels) under the output directory of each output format
@@ -184,7 +184,7 @@ FULL_PATH_NAMES = YES
# will be relative from the directory where doxygen is started.
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-STRIP_FROM_PATH = include/robodash/ docs/pages/
+STRIP_FROM_PATH = include/robodash/
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
# path mentioned in the documentation of a class, which tells the reader which
@@ -943,12 +943,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
-INPUT = include/robodash/ \
- docs/pages/installing.md \
- docs/pages/usage.md \
- docs/pages/ui.md \
- docs/pages/ \
- README.md
+INPUT = ../include/robodash/
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -1102,7 +1097,7 @@ EXAMPLE_RECURSIVE = NO
# that contain images that are to be included in the documentation (see the
# \image command).
-IMAGE_PATH = ./docs/assets/
+IMAGE_PATH = source/img/
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
@@ -1163,7 +1158,7 @@ FILTER_SOURCE_PATTERNS =
# (index.html). This can be useful if you have a project on for instance GitHub
# and want to reuse the introduction page also for the doxygen output.
-USE_MDFILE_AS_MAINPAGE = README.md
+USE_MDFILE_AS_MAINPAGE =
# The Fortran standard specifies that for fixed formatted Fortran code all
# characters from position 72 are to be considered as comment. A common
@@ -1287,7 +1282,7 @@ IGNORE_PREFIX =
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
# The default value is: YES.
-GENERATE_HTML = YES
+GENERATE_HTML = NO
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
@@ -1322,7 +1317,7 @@ HTML_FILE_EXTENSION = .html
# of the possible markers and block names see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_HEADER = ./docs/header.html
+HTML_HEADER =
# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
# generated HTML page. If the tag is left blank doxygen will generate a standard
@@ -1362,10 +1357,7 @@ HTML_STYLESHEET =
# documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_EXTRA_STYLESHEET = docs/doxygen-awesome-css/doxygen-awesome.css \
- docs/doxygen-awesome-css/doxygen-awesome-sidebar-only.css \
- docs/doxygen-awesome-css/doxygen-awesome-sidebar-only-darkmode-toggle.css \
- docs/custom.css
+HTML_EXTRA_STYLESHEET =
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note
@@ -1375,8 +1367,7 @@ HTML_EXTRA_STYLESHEET = docs/doxygen-awesome-css/doxygen-awesome.css \
# files will be copied as-is; there are no commands or markers available.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_EXTRA_FILES = docs/doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js \
- docs/doxygen-awesome-css/doxygen-awesome-paragraph-link.js
+HTML_EXTRA_FILES =
# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
# should be rendered with a dark or light theme.
@@ -2221,7 +2212,7 @@ MAN_LINKS = NO
# captures the structure of the code including all documentation.
# The default value is: NO.
-GENERATE_XML = NO
+GENERATE_XML = YES
# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 00000000..d0c3cbf1
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS ?=
+SPHINXBUILD ?= sphinx-build
+SOURCEDIR = source
+BUILDDIR = build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/docs/assets/alert.png b/docs/assets/alert.png
deleted file mode 100644
index 0203c095..00000000
Binary files a/docs/assets/alert.png and /dev/null differ
diff --git a/docs/assets/alert_button.png b/docs/assets/alert_button.png
deleted file mode 100644
index 2ac95e51..00000000
Binary files a/docs/assets/alert_button.png and /dev/null differ
diff --git a/docs/assets/selector.png b/docs/assets/selector.png
deleted file mode 100644
index 56c943e3..00000000
Binary files a/docs/assets/selector.png and /dev/null differ
diff --git a/docs/assets/view_button.png b/docs/assets/view_button.png
deleted file mode 100644
index bc4075e4..00000000
Binary files a/docs/assets/view_button.png and /dev/null differ
diff --git a/docs/assets/view_selector.png b/docs/assets/view_selector.png
deleted file mode 100644
index c32d2ad5..00000000
Binary files a/docs/assets/view_selector.png and /dev/null differ
diff --git a/docs/custom.css b/docs/custom.css
deleted file mode 100644
index 8c718a32..00000000
--- a/docs/custom.css
+++ /dev/null
@@ -1,11 +0,0 @@
-html {
- --primary-color: #ff1b7e;
- --primary-dark-color: #e60063;
- --primary-light-color: #ff4d9a;
-}
-
-html.dark-mode {
- --primary-color: #ff4d9a;
- --primary-dark-color: #ff80b7;
- --primary-light-color: #ff1a7d;
-}
diff --git a/docs/doxygen-awesome-css b/docs/doxygen-awesome-css
deleted file mode 160000
index df88fe4f..00000000
--- a/docs/doxygen-awesome-css
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit df88fe4fdd97714fadfd3ef17de0b4401f804052
diff --git a/docs/header.html b/docs/header.html
deleted file mode 100644
index 6a5c5844..00000000
--- a/docs/header.html
+++ /dev/null
@@ -1,163 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644
index 00000000..dc1312ab
--- /dev/null
+++ b/docs/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=source
+set BUILDDIR=build
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.https://www.sphinx-doc.org/
+ exit /b 1
+)
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
diff --git a/docs/pages/installing.md b/docs/pages/installing.md
deleted file mode 100644
index 598fd6ec..00000000
--- a/docs/pages/installing.md
+++ /dev/null
@@ -1,36 +0,0 @@
-@page installing Installation
-
-## Prerequisites
-
-- An installation of the PROS CLI or VSCode extension.
-
-- A PROS 4 project. Robodash does not support PROS 3 due to the bundled LVGL
- version.
-
-- [liblvgl 8](https://github.com/purduesigbots/liblvgl). LVGL 5.3 is not
- supported.
-
-## Installing the template
-
-@note If you only have the PROS VSCode extension installed, you must run the
-commands below in the Integrated Terminal.
-
-1. Download the latest template from the
- [releases tab](https://github.com/unwieldycat/robodash/releases) on GitHub
-
-2. Open the download location and fetch the template with
- `pros c fetch robodash@x.x.x.zip`. This registers the template with PROS
- Conductor, the PROS project management tools.
-
-3. Open the project you wish to use the library in and install the template with
- `pros c apply robodash@x.x.x`.
-
-4. `#include "robodash/api.hpp"` in your project's `main.h` file
-
-
diff --git a/docs/pages/usage.md b/docs/pages/usage.md
deleted file mode 100644
index f9e9055e..00000000
--- a/docs/pages/usage.md
+++ /dev/null
@@ -1,74 +0,0 @@
-@page usage Usage
-
-Robodash has two parts: the core, and the toolkit.
-
-- The core library is the system that enables interoperability between templates
- by providing a view-management system for LVGL. This API requires knowledge of
- LVGL. Compatible with C and C++.
-
-- The toolkit is the set of provided class-based UI tools intended for end users
- of the library. These require no knowledge of LVGL and require minimal
- configuration. Only compatible with C++.
-
-## Toolkit
-
-All of the tools provided by Robodash are class-based, and are designed to be as
-simple as possible to use. The following example utilizes the autonomous
-selector and the on-screen console.
-
-```cpp
-rd::Selector selector({
- {"Auton 0", &auton0},
- {"Auton 1", &simple_auton},
- {"Skills Run", &skills}
-});
-
-rd::Console console;
-
-void initialize() {
- console.println("Initializing robot...");
- // Robot stuff would happen...
-}
-
-void autonomous() {
- console.println("Running auton...");
- selector.run_auton();
-}
-```
-
-Documention for each class is linked on the topics page.
-
-## Core
-
-The core library is the view management system for LVGL, and is designed to be
-as familliar as possible to someone already familliar with LVGL. Each view,
-represented by a memory pointer to an `rd_view_t`, exposes an LVGL object the
-size of the view area, which can be thought of as a screen. It is very important
-that any LVGL objects that are created in your template or user program are a
-child of this exposed object, **NOT `lv_scr_act()`**, since robodash manages
-which view is active by hiding and unhiding the object cooresponding to each
-view.
-
-The name passed to each view will be the name that is displayed on screen in the
-view switcher and any alert dialogues spawned by the view.
-
-The following is an example of a simple view that displays a text label.
-
-```cpp
-void opcontrol() {
- rd_view_t *view = rd_view_create("custom view");
- lv_label_t *label = lv_label_create(rd_view_obj(view));
- lv_label_set_text(label, "example");
- lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
-}
-```
-
-You can learn more about the core library at the @ref core page.
-
-
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 00000000..d217b849
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,4 @@
+sphinx
+myst-parser
+breathe
+furo
\ No newline at end of file
diff --git a/docs/source/api/core.md b/docs/source/api/core.md
new file mode 100644
index 00000000..ce64a65a
--- /dev/null
+++ b/docs/source/api/core.md
@@ -0,0 +1,5 @@
+# Core
+
+```{doxygengroup} core
+:members:
+```
diff --git a/docs/source/api/index.md b/docs/source/api/index.md
new file mode 100644
index 00000000..e0c6a1de
--- /dev/null
+++ b/docs/source/api/index.md
@@ -0,0 +1,6 @@
+# API Reference
+
+```{toctree}
+core.md
+views/index.md
+```
diff --git a/docs/source/api/views/console.md b/docs/source/api/views/console.md
new file mode 100644
index 00000000..b3f0020e
--- /dev/null
+++ b/docs/source/api/views/console.md
@@ -0,0 +1,5 @@
+# Console
+
+```{doxygengroup} console
+:members:
+```
diff --git a/docs/source/api/views/image.md b/docs/source/api/views/image.md
new file mode 100644
index 00000000..8686ab81
--- /dev/null
+++ b/docs/source/api/views/image.md
@@ -0,0 +1,5 @@
+# Image
+
+```{doxygengroup} image
+:members:
+```
diff --git a/docs/source/api/views/index.md b/docs/source/api/views/index.md
new file mode 100644
index 00000000..d689c5ee
--- /dev/null
+++ b/docs/source/api/views/index.md
@@ -0,0 +1,11 @@
+# Views
+
+Included robodash views.
+
+```{toctree}
+:caption: Views
+
+selector.md
+image.md
+console.md
+```
diff --git a/docs/source/api/views/selector.md b/docs/source/api/views/selector.md
new file mode 100644
index 00000000..6ddb7733
--- /dev/null
+++ b/docs/source/api/views/selector.md
@@ -0,0 +1,5 @@
+# Selector
+
+```{doxygengroup} selector
+:members:
+```
diff --git a/docs/source/conf.py b/docs/source/conf.py
new file mode 100644
index 00000000..428abf45
--- /dev/null
+++ b/docs/source/conf.py
@@ -0,0 +1,69 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# For the full list of built-in configuration values, see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Project information -----------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
+
+project = "Robodash"
+copyright = "2025, Thurston A Yates"
+author = "Thurston A Yates"
+
+# -- General configuration ---------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
+
+extensions = ["myst_parser", "breathe"]
+
+templates_path = ["_templates"]
+exclude_patterns = []
+
+
+# -- Options for HTML output -------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
+
+html_theme = "furo"
+html_static_path = ["_static"]
+
+html_theme_options = {
+ "light_css_variables": {
+ "color-brand-primary": "#FF67E3",
+ "color-brand-content": "#FF67E3",
+ },
+ "dark_css_variables": {
+ "color-brand-primary": "#FF67E3",
+ "color-brand-content": "#FF67E3",
+ },
+}
+
+# -- Extension configuration -------------------------------------------------
+
+myst_enable_extensions = [
+ "amsmath",
+ "attrs_inline",
+ "colon_fence",
+ "deflist",
+ "dollarmath",
+ "fieldlist",
+ "html_admonition",
+ "html_image",
+ "replacements",
+ "smartquotes",
+ "strikethrough",
+ "substitution",
+ "tasklist",
+]
+
+breathe_projects = {"Robodash": "../doxygen/xml/"}
+
+breathe_default_project = "Robodash"
+
+
+# -- Run Doxygen -------------------------------------------------------------
+
+import subprocess, os
+
+read_the_docs_build = os.environ.get("READTHEDOCS", None) == "True"
+
+if read_the_docs_build:
+ subprocess.call("cd ..; doxygen", shell=True)
diff --git a/docs/source/guides/faq.md b/docs/source/guides/faq.md
new file mode 100644
index 00000000..b615f00b
--- /dev/null
+++ b/docs/source/guides/faq.md
@@ -0,0 +1,39 @@
+# Frequently Asked Questions
+
+## Why is Robodash frozen? The rest of the brain is still functional and the program is running.
+
+You likely have an indefinite loop that doesn't yield to PROS' task scheduler
+with `pros::delay`, this hogs CPU time and never lets LVGL's tasks run. You
+should add a delay in any long-living loop, like your drive code.
+
+## Is Robodash V5RC Legal?
+
+As per the
+[RECF Student-Centered Policy](https://kb.roboticseducation.org/hc/en-us/articles/5449868745367-Student-Centered-Policy)
+under "Programming / Coding":
+
+> Teams that utilize example code or custom libraries from outside sources
+> should use caution. The program used should represent the students’ efforts
+> and abilities. Blindly using code without understanding the code functionality
+> is not consistent with the educational goals of this program. Students should
+> be able to understand and explain the code, and students should be able to
+> demonstrate that they can program on a level equivalent to the code used in
+> their mechanism.
+
+In short yes, as long as you can explain what Robodash does and roughly how it
+works. Wether this is necessary is sort-of a grey area, since Robodash gives you
+no competitive advantage and PROS itself does many things that you're not
+expected to explain (like its RTOS), but it's still good to know.
+
+Reading this documentation, reading the source code, and asking questions on the
+Discord server will help you get an idea of how Robodash works and is
+implemented if you believe it is necessary.
+
+## Is Robodash compatible with ___ template?
+
+As long as the other template doesn't use the screen itself (without using
+Robodash), it is compatible with Robodash.
+
+## Is Robodash compatible with LLEMU?
+
+No.
diff --git a/docs/source/guides/installing.md b/docs/source/guides/installing.md
new file mode 100644
index 00000000..a80d2dcb
--- /dev/null
+++ b/docs/source/guides/installing.md
@@ -0,0 +1,49 @@
+# Installing
+
+```{note}
+If you only have the PROS VSCode extension installed, you must run
+commands in the PROS "Integrated Terminal", not your system terminal.
+```
+
+## Prerequisites
+
+Before you install robodash you must have the following:
+
+- An installation of the PROS CLI or VSCode extension
+
+- A PROS 4 project
+
+- [liblvgl 8](https://github.com/purduesigbots/liblvgl) added to your project
+
+## Add the depot
+
+Before adding robodash to your project, you'll need to register the depot with
+the PROS CLI. A depot is a remote file that informs the PROS CLI of templates
+that exist and where they can be installed from. You can run the command below
+to add the depot.
+
+```
+pros c add-depot robodash https://raw.githubusercontent.com/unwieldycat/robodash/depot/stable.json
+```
+
+### Or don't
+
+Alternatively, you can download and register an individual version of robodash
+by downloading it from the releases tab on the GitHub page and registering it
+with `pros c fetch robodash@x.x.x.zip`. This is not recommended since you will
+have to manually repeat this step as robodash updates.
+
+## Apply to project
+
+Now let's add robodash to a project. Open the project you wish to use the
+robodash in and run the command below to apply it to your project.
+
+```
+pros c apply robodash
+```
+
+You can now add the following to your project's `main.h` file to use robodash.
+
+```cpp
+#include "robodash/api.h"
+```
diff --git a/docs/pages/ui.md b/docs/source/guides/ui.md
similarity index 72%
rename from docs/pages/ui.md
rename to docs/source/guides/ui.md
index 83850982..9c286622 100644
--- a/docs/pages/ui.md
+++ b/docs/source/guides/ui.md
@@ -1,38 +1,30 @@
-@page ui User Interface
+# User Interface
The user interface of robodash is designed to be minimally intrusive on the
content on screen. In the top right of the screen, no matter which view is
active, a button is present to open a pane to change the current view.
-@image html view_button.png
+
Upon opening the view switcher, a list of views are displayed on the right.
Tapping on any one of these will set them as the active view, and close the
switcher UI. If you do not wish to switch the active view, you can click the X
button or tap away.
-@image html view_selector.png
+
-# Alerts
+## Alerts
Some views may encounter an error and request attention by sending an alert.
Alerts are placed front and center on screen.
-@image html alert.png
+
Tapping the alert will dismiss the alert and focus the view that sent it.
Tapping away from the alert will hide the alert, where you can later view it by
clicking the bell icon to reopen the alert menu.
-@image html alert_button.png
+
If multiple alerts appear, you can view the remaining ones in this menu as well.
-The alert button will dissapear once all alerts are dismissed.
-
-
+The alert button will disappear once all alerts are dismissed.
diff --git a/docs/source/guides/usage.md b/docs/source/guides/usage.md
new file mode 100644
index 00000000..6a3a73f2
--- /dev/null
+++ b/docs/source/guides/usage.md
@@ -0,0 +1,20 @@
+# Using Robodash
+
+Robodash provides multiple functionalities for different use cases:
+
+- If you would like to learn more about Robodash's suite of built-in widgets,
+ such as the autonomous selector, see the [widgets guide](./usage/widgets.md).
+
+- If you want to integrate your own LVGL GUIs with Robodash, see the
+ [views guide](./usage/views.md).
+
+- If you're a template developer looking to depend on Robodash, check out the
+ [template guide](./usage/template.md) as well
+
+```{toctree}
+:hidden:
+
+./usage/views.md
+./usage/widgets.md
+./usage/template.md
+```
diff --git a/docs/source/guides/usage/template.md b/docs/source/guides/usage/template.md
new file mode 100644
index 00000000..bc8d4184
--- /dev/null
+++ b/docs/source/guides/usage/template.md
@@ -0,0 +1,20 @@
+# Template Integration
+
+When depending on Robodash, it is recommended that you follow these instructions
+for better user ease of use.
+
+- **Do not bundle Robodash with your template** - It is not recommended that you
+ add Robodash's source files to your template and distribute it with your own
+ template. This prevents users from upgrading unless your own template
+ upgrades, and places the burden on you to upgrade your template when Robodash
+ upgrades. For new users, it is recommended instead to have a "starter project"
+ that is pre-configured with Robodash and your own template.
+
+- **Inform users that your template uses Robodash** - You should inform users
+ that your template depends on Robodash so they know to install it.
+ Additionally, provide some form of guidance for installing Robodash (a link to
+ these docs or your own instructions). You should also indicate which version
+ of Robodash your template uses, so users know what versions they can use.
+
+- **Do not modify Robodash** - No modifications should be made to Robodash's
+ header or source files, and no additions should be made to its namespace.
diff --git a/docs/source/guides/usage/views.md b/docs/source/guides/usage/views.md
new file mode 100644
index 00000000..5c1675ac
--- /dev/null
+++ b/docs/source/guides/usage/views.md
@@ -0,0 +1,30 @@
+# Views
+
+Robodash provides the views API for other LVGL-powered GUIs to plug into its
+view-management system.
+
+Below is an example on creating a view called "my view".
+
+```cpp
+rd_view_t *view = rd_view_create("my view");
+```
+
+Creating a view will return a pointer to an `rd_view_t`, which holds the name of
+the view and the LVGL object for the view. The name passed to the view
+constructor will be the name that is displayed on screen in the view switcher
+and any alert dialogues spawned by the view. The view's LVGL object should
+parent any LVGL UI that is a part of that view, since this is how Robodash
+changes which view is currently active on the screen. **Any instance of
+`lv_scr_act()` in your LVGL GUI code should be replaced with
+`lv_view_obj(your_view)`.**
+
+The following is an example of a simple view that displays a text label.
+
+```cpp
+rd_view_t *view = rd_view_create("custom view");
+lv_label_t *label = lv_label_create(rd_view_obj(view));
+lv_label_set_text(label, "example");
+lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
+```
+
+[Views API Reference](../../api/core.md) page.
diff --git a/docs/source/guides/usage/widgets.md b/docs/source/guides/usage/widgets.md
new file mode 100644
index 00000000..9b5a9899
--- /dev/null
+++ b/docs/source/guides/usage/widgets.md
@@ -0,0 +1,83 @@
+# Widgets
+
+Robodash provides a suite of simple, commonly used GUI widgets.
+
+## Selector
+
+The [Selector Widget](../../api/views/selector.md) is a function selector
+designed for managing autonomous runs.
+
+To use the selector we can construct it in the global scope of our `main.cpp`
+file.
+
+```cpp
+rd::Selector selector({
+ {"Best auton", best_auton},
+ {"Simple auton", simple_auton},
+ {"Good auton", good_auton},
+});
+```
+
+The selector's constructor takes a vector of pairs that hold a string and a
+function. The string is the name that appears on the display as the function's
+name, and the function is what is called when it is selected.
+
+Our example assumes we have three functions, `best_auton`, `simple_auton`, and
+`good_auton`. These functions should take no arguments and return `void`.
+
+While the selector appears on the screen, we still need to make our selected
+routine run when our bot is in autonomous mode.
+
+In your `main.cpp` file, call `selector.run_auton()` in your `autonomous`
+function.
+
+```cpp
+void autonomous() {
+ selector.run_auton();
+}
+```
+
+Now, when our robot is in autonomous mode, our user-selected routine will run.
+In addition, if an SD card is in the brain, the selected routine will be
+preserved next time the program is run.
+
+## Console
+
+The [Console Widget](../../api/views/console.md) provides a text display for
+quickly and easily displaying information for debugging. To create a console, we
+can construct it in our `main.cpp` file's global scope.
+
+```cpp
+rd::Console console;
+```
+
+We can now log information to the console with `console.print`,
+`console.println`, and `console.printf`, and we can clear the console with
+`console.clear`.
+
+```cpp
+console.println("Hello");
+console.printf("The robot's heading is %f\n", some_imu.get_heading());
+```
+
+## Image
+
+The [Image Widget](../../api/views/image.md) provides a way to display LVGL
+images to the LCD.
+
+Images displayed must be converted with the
+[LVGL image converter](https://lvgl.io/tools/imageconverter) for LVGL 8. You can
+convert the image to a C array and place it in your project's `src` directory,
+or convert it to a a binary file and load it onto a microSD card.
+
+To create an image, we can construct it with a path to an LVGL-converted
+`image.bin` file on a loaded SD card, or a pointer to an LVGL image variable.
+You also must pass a name to the image.
+
+```cpp
+// microSD approach
+rd::Image image1("S:/usd/logo.bin", "Team Logo");
+
+// C array approach
+rd::Image image2(&team_logo, "Team Logo")
+```
diff --git a/docs/source/img/alert.png b/docs/source/img/alert.png
new file mode 100644
index 00000000..f35dbc0f
Binary files /dev/null and b/docs/source/img/alert.png differ
diff --git a/docs/source/img/alert_button.png b/docs/source/img/alert_button.png
new file mode 100644
index 00000000..a4d70d09
Binary files /dev/null and b/docs/source/img/alert_button.png differ
diff --git a/docs/assets/console.png b/docs/source/img/console.png
similarity index 100%
rename from docs/assets/console.png
rename to docs/source/img/console.png
diff --git a/docs/assets/image.png b/docs/source/img/image.png
similarity index 100%
rename from docs/assets/image.png
rename to docs/source/img/image.png
diff --git a/docs/source/img/selector.png b/docs/source/img/selector.png
new file mode 100644
index 00000000..5fc6b055
Binary files /dev/null and b/docs/source/img/selector.png differ
diff --git a/docs/source/img/view_button.png b/docs/source/img/view_button.png
new file mode 100644
index 00000000..1d2846bb
Binary files /dev/null and b/docs/source/img/view_button.png differ
diff --git a/docs/source/img/view_selector.png b/docs/source/img/view_selector.png
new file mode 100644
index 00000000..7f7d1d0c
Binary files /dev/null and b/docs/source/img/view_selector.png differ
diff --git a/docs/source/index.md b/docs/source/index.md
new file mode 100644
index 00000000..0b2c2681
--- /dev/null
+++ b/docs/source/index.md
@@ -0,0 +1,51 @@
+# Welcome to the Robodash docs!
+
+Robodash is a GUI toolkit for PROS 4 that provides a suite of easy to use GUI
+utilities and an API for interoperable LVGL-based user interfaces.
+
+To get started, visit the [Installing](guides/installing.md) page.
+
+## Why?
+
+Robodash was created to solve a problem with the V5 LCD -- it is incredibly
+underutilized. There are two parts to this issue: ease of use and sharing.
+
+For one, most people opt to use the legacy LCD emulator since it is the easiest
+and fastest way to utilize the V5 screen. While an alright solution, the V5 LCD
+isnt completely taken advantage of in this scenario and additional code is
+required to display other information like a graph or images.
+
+Secondly, the V5 screen cannot be easily shared by multiple pieces of code. If a
+template wants to provide a GUI widget, this may interfere with a user's
+autonomous selector or another template's GUI with no way to switch between
+them.
+
+Robodash aims to solve these two issues by providing a set of easy to use GUI
+utilities for users, and an API for template developers to create LVGL GUIS that
+work in harmony with each other.
+
+```{toctree}
+:hidden:
+:caption: Links
+GitHub
+Discord
+```
+
+```{toctree}
+:hidden:
+:caption: Getting Started
+:maxdepth: 2
+
+guides/installing.md
+guides/usage.md
+guides/ui.md
+guides/faq.md
+```
+
+```{toctree}
+:hidden:
+:caption: Reference
+
+api/index.md
+LVGL 8.3 Docs
+```
diff --git a/firmware/libc.a b/firmware/libc.a
index 51439b99..a2e1cdb7 100644
Binary files a/firmware/libc.a and b/firmware/libc.a differ
diff --git a/firmware/liblvgl.a b/firmware/liblvgl.a
index 6b3a68e9..e35a1225 100644
Binary files a/firmware/liblvgl.a and b/firmware/liblvgl.a differ
diff --git a/firmware/libm.a b/firmware/libm.a
index 3d4066d5..63c9951f 100644
Binary files a/firmware/libm.a and b/firmware/libm.a differ
diff --git a/firmware/libpros.a b/firmware/libpros.a
index ae9d5871..b316dae6 100644
Binary files a/firmware/libpros.a and b/firmware/libpros.a differ
diff --git a/firmware/v5-common.ld b/firmware/v5-common.ld
index c341c605..7f262fc3 100644
--- a/firmware/v5-common.ld
+++ b/firmware/v5-common.ld
@@ -1,263 +1,226 @@
-/* Define the sections, and where they are mapped in memory */
-SECTIONS
-{
-/* This will get stripped out before uploading, but we need to place code
- here so we can at least link to it (install_hot_table) */
-.hot_init : {
- KEEP (*(.hot_magic))
- KEEP (*(.hot_init))
-} > HOT_MEMORY
-
-.text : {
- KEEP (*(.vectors))
- /* boot data should be exactly 32 bytes long */
- *(.boot_data)
- . = 0x20;
- *(.boot)
- . = ALIGN(64);
- *(.freertos_vectors)
- *(.text)
- *(.text.*)
- *(.gnu.linkonce.t.*)
- *(.plt)
- *(.gnu_warning)
- *(.gcc_except_table)
- *(.glue_7)
- *(.glue_7t)
- *(.vfp11_veneer)
- *(.ARM.extab)
- *(.gnu.linkonce.armextab.*)
-} > RAM
-
-.init : {
- KEEP (*(.init))
-} > RAM
-
-.fini : {
- KEEP (*(.fini))
-} > RAM
-
-.rodata : {
- __rodata_start = .;
- *(.rodata)
- *(.rodata.*)
- *(.gnu.linkonce.r.*)
- __rodata_end = .;
-} > RAM
-
-.rodata1 : {
- __rodata1_start = .;
- *(.rodata1)
- *(.rodata1.*)
- __rodata1_end = .;
-} > RAM
-
-.sdata2 : {
- __sdata2_start = .;
- *(.sdata2)
- *(.sdata2.*)
- *(.gnu.linkonce.s2.*)
- __sdata2_end = .;
-} > RAM
-
-.sbss2 : {
- __sbss2_start = .;
- *(.sbss2)
- *(.sbss2.*)
- *(.gnu.linkonce.sb2.*)
- __sbss2_end = .;
-} > RAM
-
-.data : {
- __data_start = .;
- *(.data)
- *(.data.*)
- *(.gnu.linkonce.d.*)
- *(.jcr)
- *(.got)
- *(.got.plt)
- __data_end = .;
-} > RAM
-
-.data1 : {
- __data1_start = .;
- *(.data1)
- *(.data1.*)
- __data1_end = .;
-} > RAM
-
-.got : {
- *(.got)
-} > RAM
-
-.ctors : {
- __CTOR_LIST__ = .;
- ___CTORS_LIST___ = .;
- KEEP (*crtbegin.o(.ctors))
- KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors))
- KEEP (*(SORT(.ctors.*)))
- KEEP (*(.ctors))
- __CTOR_END__ = .;
- ___CTORS_END___ = .;
-} > RAM
-
-.dtors : {
- __DTOR_LIST__ = .;
- ___DTORS_LIST___ = .;
- KEEP (*crtbegin.o(.dtors))
- KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors))
- KEEP (*(SORT(.dtors.*)))
- KEEP (*(.dtors))
- __DTOR_END__ = .;
- ___DTORS_END___ = .;
-} > RAM
-
-.fixup : {
- __fixup_start = .;
- *(.fixup)
- __fixup_end = .;
-} > RAM
-
-.eh_frame : {
- *(.eh_frame)
-} > RAM
-
-.eh_framehdr : {
- __eh_framehdr_start = .;
- *(.eh_framehdr)
- __eh_framehdr_end = .;
-} > RAM
-
-.gcc_except_table : {
- *(.gcc_except_table)
-} > RAM
-
-.mmu_tbl (ALIGN(16384)) : {
- __mmu_tbl_start = .;
- *(.mmu_tbl)
- __mmu_tbl_end = .;
-} > RAM
-
-.ARM.exidx : {
- __exidx_start = .;
- *(.ARM.exidx*)
- *(.gnu.linkonce.armexidix.*.*)
- __exidx_end = .;
-} > RAM
-
-.preinit_array : {
- __preinit_array_start = .;
- KEEP (*(SORT(.preinit_array.*)))
- KEEP (*(.preinit_array))
- __preinit_array_end = .;
-} > RAM
-
-.init_array : {
- __init_array_start = .;
- KEEP (*(SORT(.init_array.*)))
- KEEP (*(.init_array))
- __init_array_end = .;
-} > RAM
-
-.fini_array : {
- __fini_array_start = .;
- KEEP (*(SORT(.fini_array.*)))
- KEEP (*(.fini_array))
- __fini_array_end = .;
-} > RAM
-
-.ARM.attributes : {
- __ARM.attributes_start = .;
- *(.ARM.attributes)
- __ARM.attributes_end = .;
-} > RAM
-
-.sdata : {
- __sdata_start = .;
- *(.sdata)
- *(.sdata.*)
- *(.gnu.linkonce.s.*)
- __sdata_end = .;
-} > RAM
-
-.sbss (NOLOAD) : {
- __sbss_start = .;
- *(.sbss)
- *(.sbss.*)
- *(.gnu.linkonce.sb.*)
- __sbss_end = .;
-} > RAM
-
-.tdata : {
- __tdata_start = .;
- *(.tdata)
- *(.tdata.*)
- *(.gnu.linkonce.td.*)
- __tdata_end = .;
-} > RAM
-
-.tbss : {
- __tbss_start = .;
- *(.tbss)
- *(.tbss.*)
- *(.gnu.linkonce.tb.*)
- __tbss_end = .;
-} > RAM
-
-.bss (NOLOAD) : {
- __bss_start = .;
- *(.bss)
- *(.bss.*)
- *(.gnu.linkonce.b.*)
- *(COMMON)
- __bss_end = .;
-} > RAM
-
-_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 );
-
-_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 );
-
-/* Generate Stack and Heap definitions */
-
-.heap (NOLOAD) : {
- . = ALIGN(16);
- _heap = .;
- HeapBase = .;
- _heap_start = .;
- . += _HEAP_SIZE;
- _heap_end = .;
- HeapLimit = .;
-} > HEAP
-
-.stack (NOLOAD) : {
- . = ALIGN(16);
- _stack_end = .;
- . += _STACK_SIZE;
- . = ALIGN(16);
- _stack = .;
- __stack = _stack;
- . = ALIGN(16);
- _irq_stack_end = .;
- . += _IRQ_STACK_SIZE;
- . = ALIGN(16);
- __irq_stack = .;
- _supervisor_stack_end = .;
- . += _SUPERVISOR_STACK_SIZE;
- . = ALIGN(16);
- __supervisor_stack = .;
- _abort_stack_end = .;
- . += _ABORT_STACK_SIZE;
- . = ALIGN(16);
- __abort_stack = .;
- _fiq_stack_end = .;
- . += _FIQ_STACK_SIZE;
- . = ALIGN(16);
- __fiq_stack = .;
- _undef_stack_end = .;
- . += _UNDEF_STACK_SIZE;
- . = ALIGN(16);
- __undef_stack = .;
-} > COLD_MEMORY
-
-_end = .;
-}
+/* Define the sections, and where they are mapped in memory */
+SECTIONS
+{
+/* This will get stripped out before uploading, but we need to place code
+ here so we can at least link to it (install_hot_table) */
+.hot_init : {
+ KEEP (*(.hot_magic))
+ KEEP (*(.hot_init))
+} > HOT_MEMORY
+
+.text : {
+ KEEP (*(.vectors))
+ /* boot data should be exactly 32 bytes long */
+ *(.boot_data)
+ . = 0x20;
+ *(.boot)
+ . = ALIGN(64);
+ *(.freertos_vectors)
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t.*)
+ *(.plt)
+ *(.gnu_warning)
+ *(.gcc_except_table)
+ *(.glue_7)
+ *(.glue_7t)
+ *(.vfp11_veneer)
+ *(.ARM.extab)
+ *(.gnu.linkonce.armextab.*)
+} > RAM
+
+.init : {
+ KEEP (*(.init))
+} > RAM
+
+.fini : {
+ KEEP (*(.fini))
+} > RAM
+
+.rodata : {
+ __rodata_start = .;
+ *(.rodata)
+ *(.rodata.*)
+ *(.gnu.linkonce.r.*)
+ __rodata_end = .;
+} > RAM
+
+.rodata1 : {
+ __rodata1_start = .;
+ *(.rodata1)
+ *(.rodata1.*)
+ __rodata1_end = .;
+} > RAM
+
+.sdata2 : {
+ __sdata2_start = .;
+ *(.sdata2)
+ *(.sdata2.*)
+ *(.gnu.linkonce.s2.*)
+ __sdata2_end = .;
+} > RAM
+
+.sbss2 : {
+ __sbss2_start = .;
+ *(.sbss2)
+ *(.sbss2.*)
+ *(.gnu.linkonce.sb2.*)
+ __sbss2_end = .;
+} > RAM
+
+.data : {
+ __data_start = .;
+ *(.data)
+ *(.data.*)
+ *(.gnu.linkonce.d.*)
+ *(.jcr)
+ *(.got)
+ *(.got.plt)
+ __data_end = .;
+} > RAM
+
+.data1 : {
+ __data1_start = .;
+ *(.data1)
+ *(.data1.*)
+ __data1_end = .;
+} > RAM
+
+.got : {
+ *(.got)
+} > RAM
+
+.ctors : {
+ __CTOR_LIST__ = .;
+ ___CTORS_LIST___ = .;
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ __CTOR_END__ = .;
+ ___CTORS_END___ = .;
+} > RAM
+
+.dtors : {
+ __DTOR_LIST__ = .;
+ ___DTORS_LIST___ = .;
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ __DTOR_END__ = .;
+ ___DTORS_END___ = .;
+} > RAM
+
+.fixup : {
+ __fixup_start = .;
+ *(.fixup)
+ __fixup_end = .;
+} > RAM
+
+.eh_frame : {
+ *(.eh_frame)
+} > RAM
+
+.eh_framehdr : {
+ __eh_framehdr_start = .;
+ *(.eh_framehdr)
+ __eh_framehdr_end = .;
+} > RAM
+
+.gcc_except_table : {
+ *(.gcc_except_table)
+} > RAM
+
+.ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ *(.gnu.linkonce.armexidix.*.*)
+ __exidx_end = .;
+} > RAM
+
+.preinit_array : {
+ __preinit_array_start = .;
+ KEEP (*(SORT(.preinit_array.*)))
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+} > RAM
+
+.init_array : {
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+} > RAM
+
+.fini_array : {
+ __fini_array_start = .;
+ KEEP (*(SORT(.fini_array.*)))
+ KEEP (*(.fini_array))
+ __fini_array_end = .;
+} > RAM
+
+/DISCARD/ : {
+ *(.ARM.attributes*)
+}
+
+.sdata : {
+ __sdata_start = .;
+ *(.sdata)
+ *(.sdata.*)
+ *(.gnu.linkonce.s.*)
+ __sdata_end = .;
+} > RAM
+
+.sbss (NOLOAD) : {
+ __sbss_start = .;
+ *(.sbss)
+ *(.sbss.*)
+ *(.gnu.linkonce.sb.*)
+ __sbss_end = .;
+} > RAM
+
+.tdata : {
+ __tdata_start = .;
+ *(.tdata)
+ *(.tdata.*)
+ *(.gnu.linkonce.td.*)
+ __tdata_end = .;
+} > RAM
+
+.tbss : {
+ __tbss_start = .;
+ *(.tbss)
+ *(.tbss.*)
+ *(.gnu.linkonce.tb.*)
+ __tbss_end = .;
+} > RAM
+
+.bss (NOLOAD) : {
+ __bss_start = .;
+ *(.bss)
+ *(.bss.*)
+ *(.gnu.linkonce.b.*)
+ *(COMMON)
+ __bss_end = .;
+} > RAM
+
+_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 );
+
+_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 );
+
+/* Generate Stack and Heap definitions */
+
+.heap (NOLOAD) : {
+ . = ALIGN(16);
+ _heap = .;
+ HeapBase = .;
+ _heap_start = .;
+ . += _HEAP_SIZE;
+ _heap_end = .;
+ HeapLimit = .;
+} > HEAP
+/* There are no sections for the stack. This is intentional, since VEXOs sets up a stack before
+ starting the program, and FreeRTOS task stacks are dynamically allocated. */
+_end = .;
+}
diff --git a/firmware/v5-hot.ld b/firmware/v5-hot.ld
index 96180802..017cb356 100644
--- a/firmware/v5-hot.ld
+++ b/firmware/v5-hot.ld
@@ -1,33 +1,33 @@
-/* This stack is used during initialization, but FreeRTOS tasks have their own
- stack allocated in BSS or Heap (kernel tasks in FreeRTOS .bss heap; user tasks
- in standard heap) */
-_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000;
-
-_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
-_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048;
-_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024;
-_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
-_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;
-
-_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x02E00000; /* ~48 MB */
-
-/* Define Memories in the system */
-start_of_cold_mem = 0x03800000;
-_COLD_MEM_SIZE = 0x04800000;
-end_of_cold_mem = start_of_cold_mem + _COLD_MEM_SIZE;
-
-start_of_hot_mem = 0x07800000;
-_HOT_MEM_SIZE = 0x00800000;
-end_of_hot_mem = start_of_hot_mem + _HOT_MEM_SIZE;
-
-MEMORY
-{
- /* user code 72M */
- COLD_MEMORY : ORIGIN = start_of_cold_mem, LENGTH = _COLD_MEM_SIZE /* Just under 19 MB */
- HEAP : ORIGIN = 0x04A00000, LENGTH = _HEAP_SIZE
- HOT_MEMORY : ORIGIN = start_of_hot_mem, LENGTH = _HOT_MEM_SIZE /* Just over 8 MB */
-}
-
-REGION_ALIAS("RAM", HOT_MEMORY);
-
-ENTRY(install_hot_table)
+/* This stack is used during initialization, but FreeRTOS tasks have their own
+ stack allocated in BSS or Heap (kernel tasks in FreeRTOS .bss heap; user tasks
+ in standard heap) */
+_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000;
+
+_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
+_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048;
+_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024;
+_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
+_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;
+
+_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x02E00000; /* ~48 MB */
+
+/* Define Memories in the system */
+start_of_cold_mem = 0x03800000;
+_COLD_MEM_SIZE = 0x04800000;
+end_of_cold_mem = start_of_cold_mem + _COLD_MEM_SIZE;
+
+start_of_hot_mem = 0x07800000;
+_HOT_MEM_SIZE = 0x00800000;
+end_of_hot_mem = start_of_hot_mem + _HOT_MEM_SIZE;
+
+MEMORY
+{
+ /* user code 72M */
+ COLD_MEMORY : ORIGIN = start_of_cold_mem, LENGTH = _COLD_MEM_SIZE /* Just under 19 MB */
+ HEAP : ORIGIN = 0x04A00000, LENGTH = _HEAP_SIZE
+ HOT_MEMORY : ORIGIN = start_of_hot_mem, LENGTH = _HOT_MEM_SIZE /* Just over 8 MB */
+}
+
+REGION_ALIAS("RAM", HOT_MEMORY);
+
+ENTRY(install_hot_table)
diff --git a/firmware/v5.ld b/firmware/v5.ld
index a8ef570d..7cbd06f3 100644
--- a/firmware/v5.ld
+++ b/firmware/v5.ld
@@ -1,33 +1,33 @@
-/* This stack is used during initialization, but FreeRTOS tasks have their own
- stack allocated in BSS or Heap (kernel tasks in FreeRTOS .bss heap; user tasks
- in standard heap) */
-_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000;
-
-_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
-_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048;
-_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024;
-_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
-_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;
-
-_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x02E00000; /* ~48 MB */
-
-/* Define Memories in the system */
-start_of_cold_mem = 0x03800000;
-_COLD_MEM_SIZE = 0x04800000;
-end_of_cold_mem = start_of_cold_mem + _COLD_MEM_SIZE;
-
-start_of_hot_mem = 0x07800000;
-_HOT_MEM_SIZE = 0x00800000;
-end_of_hot_mem = start_of_hot_mem + _HOT_MEM_SIZE;
-
-MEMORY
-{
- /* user code 72M */
- COLD_MEMORY : ORIGIN = start_of_cold_mem, LENGTH = _COLD_MEM_SIZE /* Just under 19 MB */
- HEAP : ORIGIN = 0x04A00000, LENGTH = _HEAP_SIZE
- HOT_MEMORY : ORIGIN = start_of_hot_mem, LENGTH = _HOT_MEM_SIZE /* Just over 8 MB */
-}
-
-REGION_ALIAS("RAM", COLD_MEMORY);
-
-ENTRY(vexStartup)
+/* This stack is used during initialization, but FreeRTOS tasks have their own
+ stack allocated in BSS or Heap (kernel tasks in FreeRTOS .bss heap; user tasks
+ in standard heap) */
+_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000;
+
+_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
+_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048;
+_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024;
+_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
+_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;
+
+_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x02E00000; /* ~48 MB */
+
+/* Define Memories in the system */
+start_of_cold_mem = 0x03800000;
+_COLD_MEM_SIZE = 0x04800000;
+end_of_cold_mem = start_of_cold_mem + _COLD_MEM_SIZE;
+
+start_of_hot_mem = 0x07800000;
+_HOT_MEM_SIZE = 0x00800000;
+end_of_hot_mem = start_of_hot_mem + _HOT_MEM_SIZE;
+
+MEMORY
+{
+ /* user code 72M */
+ COLD_MEMORY : ORIGIN = start_of_cold_mem, LENGTH = _COLD_MEM_SIZE /* Just under 19 MB */
+ HEAP : ORIGIN = 0x04A00000, LENGTH = _HEAP_SIZE
+ HOT_MEMORY : ORIGIN = start_of_hot_mem, LENGTH = _HOT_MEM_SIZE /* Just over 8 MB */
+}
+
+REGION_ALIAS("RAM", COLD_MEMORY);
+
+ENTRY(vexStartup)
diff --git a/include/.DS_Store b/include/.DS_Store
deleted file mode 100644
index 479bbb26..00000000
Binary files a/include/.DS_Store and /dev/null differ
diff --git a/include/api.h b/include/api.h
index 58e58dde..5ba908b3 100644
--- a/include/api.h
+++ b/include/api.h
@@ -8,7 +8,7 @@
* This file should not be modified by users, since it gets replaced whenever
* a kernel upgrade occurs.
*
- * \copyright Copyright (c) 2017-2023, Purdue University ACM SIGBots.
+ * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots.
* All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
@@ -39,12 +39,8 @@
#include
#endif /* __cplusplus */
-#define PROS_VERSION_MAJOR 4
-#define PROS_VERSION_MINOR 0
-#define PROS_VERSION_PATCH 6
-#define PROS_VERSION_STRING "4.0.6"
-
#include "pros/adi.h"
+#include "pros/ai_vision.h"
#include "pros/colors.h"
#include "pros/device.h"
#include "pros/distance.h"
@@ -64,6 +60,7 @@
#ifdef __cplusplus
#include "pros/adi.hpp"
+#include "pros/ai_vision.hpp"
#include "pros/colors.hpp"
#include "pros/device.hpp"
#include "pros/distance.hpp"
diff --git a/include/liblvgl/core/lv_obj_style.h b/include/liblvgl/core/lv_obj_style.h
index 18e530a6..127f060d 100644
--- a/include/liblvgl/core/lv_obj_style.h
+++ b/include/liblvgl/core/lv_obj_style.h
@@ -91,7 +91,15 @@ void lv_obj_remove_style(struct _lv_obj_t * obj, lv_style_t * style, lv_style_se
*/
static inline void lv_obj_remove_style_all(struct _lv_obj_t * obj)
{
+
+#ifdef __cplusplus
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion"
+#endif
lv_obj_remove_style(obj, NULL, LV_PART_ANY | LV_STATE_ANY);
+#ifdef __cplusplus
+#pragma GCC diagnostic pop
+#endif
}
/**
diff --git a/include/liblvgl/lv_conf.h b/include/liblvgl/lv_conf.h
index bd93a55a..8a4888f9 100644
--- a/include/liblvgl/lv_conf.h
+++ b/include/liblvgl/lv_conf.h
@@ -83,7 +83,7 @@ typedef int16_t lv_coord_t;
#define LV_MEM_CUSTOM 0
#if LV_MEM_CUSTOM == 0
/* Size of the memory used by `lv_mem_alloc` in bytes (>= 2kB)*/
-# define LV_MEM_SIZE (32U * 1024U)
+# define LV_MEM_SIZE (10U * 1024U * 1024U)
/* Compiler prefix for a big array declaration */
# define LV_MEM_ATTR
@@ -217,6 +217,15 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h" */
typedef void * lv_fs_drv_user_data_t;
#endif
+#define LV_USE_FS_STDIO 1
+#define LV_FS_STDIO_LETTER 'S'
+#define LV_FS_STDIO_PATH "/usd/"
+#define LV_FS_STDIO_CACHE_SIZE 0
+
+#define LV_USE_PNG 1
+#define LV_USE_GIF 1
+#define LV_USE_SJPG 1
+
/*1: Add a `user_data` to drivers and objects*/
#define LV_USE_USER_DATA 1
@@ -243,7 +252,7 @@ typedef void * lv_fs_drv_user_data_t;
* With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images.
* However the opened images might consume additional RAM.
* Set it to 0 to disable caching */
-#define LV_IMG_CACHE_DEF_SIZE 1
+#define LV_IMG_CACHE_DEF_SIZE (8U * 1024U)
/*Declare the type of the user data of image decoder (can be e.g. `void *`, `int`, `struct`)*/
typedef void * lv_img_decoder_user_data_t;
@@ -314,7 +323,7 @@ typedef void * lv_indev_drv_user_data_t; /*Type of user data in the i
*===============*/
/*1: Enable the log module*/
-#define LV_USE_LOG 0
+#define LV_USE_LOG 1
#if LV_USE_LOG
/* How important log should be added:
* LV_LOG_LEVEL_TRACE A lot of logs to give detailed information
@@ -327,7 +336,7 @@ typedef void * lv_indev_drv_user_data_t; /*Type of user data in the i
/* 1: Print the log with 'printf';
* 0: user need to register a callback with `lv_log_register_print_cb`*/
-# define LV_LOG_PRINTF 0
+# define LV_LOG_PRINTF 1
#endif /*LV_USE_LOG*/
/*=================
@@ -759,8 +768,6 @@ typedef void * lv_obj_user_data_t;
# define LV_TILEVIEW_DEF_ANIM_TIME 300
#endif
-#define CONFIG_LV_USE_GIF 1
-
/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/
#define LV_USE_WIN 1
diff --git a/include/liblvgl/lv_version.h b/include/liblvgl/lv_version.h
index 1e62e1e2..266d60b9 100644
--- a/include/liblvgl/lv_version.h
+++ b/include/liblvgl/lv_version.h
@@ -14,9 +14,9 @@ extern "C" {
* INCLUDES
*********************/
/*Current version of LittlevGL*/
-#define LVGL_VERSION_MAJOR 5
+#define LVGL_VERSION_MAJOR 8
#define LVGL_VERSION_MINOR 3
-#define LVGL_VERSION_PATCH 0
+#define LVGL_VERSION_PATCH 8
#define LVGL_VERSION_INFO ""
diff --git a/include/pros/abstract_motor.hpp b/include/pros/abstract_motor.hpp
index 1468f35f..fd8e8034 100644
--- a/include/pros/abstract_motor.hpp
+++ b/include/pros/abstract_motor.hpp
@@ -9,7 +9,7 @@
* This file should not be modified by users, since it gets replaced whenever
* a kernel upgrade occurs.
*
- * \copyright Copyright (c) 2017-2023, Purdue University ACM SIGBots.
+ * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots.
* All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
@@ -31,7 +31,7 @@ namespace pros {
inline namespace v5 {
/**
- * \enum motor_brake
+ * \enum MotorBrake
* Indicates the current 'brake mode' of a motor.
*/
enum class MotorBrake {
@@ -42,7 +42,7 @@ enum class MotorBrake {
};
/**
- * \enum Motor_Encoder_Units
+ * \enum MotorEncoderUnits
* Indicates the units used by the motor encoders.
*/
enum class MotorEncoderUnits {
@@ -53,7 +53,7 @@ enum class MotorEncoderUnits {
invalid = INT32_MAX ///< Invalid motor encoder units
};
-// Alias for Motor_Encoder_Units
+// Alias for MotorEncoderUnits
using MotorUnits = MotorEncoderUnits;
enum class MotorGears {
@@ -69,8 +69,18 @@ enum class MotorGears {
invalid = INT32_MAX ///< Error return code
};
+/**
+ * \enum MotorType
+ * Indicates the type of a motor
+ */
+enum class MotorType {
+ v5 = 0, ///< 11w motor
+ exp = 1, ///< 5.5w motor
+ invalid = INT32_MAX ///< Error return code
+};
+
-// Provide Aliases for Motor_Gears
+// Provide Aliases for MotorGears
using MotorGearset = MotorGears;
using MotorCart = MotorGears;
using MotorCartridge = MotorGears;
@@ -89,25 +99,6 @@ class AbstractMotor {
/// These functions allow programmers to make motors move
///@{
- /**
- * Sets the voltage for the motor from -127 to 127.
- *
- * This is designed to map easily to the input from the controller's analog
- * stick for simple opcontrol use. The actual behavior of the motor is
- * analogous to use of pros::Motor::move().
- *
- * This function uses the following values of errno when an error state is
- * reached:
- * ENODEV - The port cannot be configured as a motor
- *
- * \param voltage
- * The new motor voltage from -127 to 127
- *
- * \return 1 if the operation was successful or PROS_ERR if the operation
- * failed, setting errno.
- */
- virtual std::int32_t operator=(std::int32_t voltage) const = 0;
-
/**
* Sets the voltage for the motor from -127 to 127.
*
@@ -778,7 +769,7 @@ class AbstractMotor {
* The index of the motor to get the target position of.
* By default index is 0, and will return an error for an out of bounds index
*
- * \return One of Motor_Brake, according to what was set for the
+ * \return One of MotorBrake, according to what was set for the
* motor, or E_MOTOR_BRAKE_INVALID if the operation failed, setting errno.
*/
virtual MotorBrake get_brake_mode(const std::uint8_t index = 0) const = 0;
@@ -794,7 +785,7 @@ class AbstractMotor {
* The index of the motor to get the target position of.
* By default index is 0, and will return an error for an out of bounds index
*
- * \return A vector containing Motor_Brake(s), according to what was set for the
+ * \return A vector containing MotorBrake(s), according to what was set for the
* motor(s), or E_MOTOR_BRAKE_INVALID if the operation failed, setting errno.
*/
virtual std::vector get_brake_mode_all(void) const = 0;
@@ -846,7 +837,7 @@ class AbstractMotor {
* The index of the motor to get the target position of.
* By default index is 0, and will return an error for an out of bounds index
*
- * \return One of Motor_Units according to what is set for the
+ * \return One of MotorUnits according to what is set for the
* motor or E_MOTOR_ENCODER_INVALID if the operation failed.
*/
virtual MotorUnits get_encoder_units(const std::uint8_t index = 0) const = 0;
@@ -862,7 +853,7 @@ class AbstractMotor {
* The index of the motor to get the target position of.
* By default index is 0, and will return an error for an out of bounds index
*
- * \return A vector of Motor_Units according to what is set for the
+ * \return A vector of MotorUnits according to what is set for the
* motor(s) or E_MOTOR_ENCODER_INVALID if the operation failed.
*/
virtual std::vector get_encoder_units_all(void) const = 0;
@@ -878,8 +869,8 @@ class AbstractMotor {
* The index of the motor to get the target position of.
* By default index is 0, and will return an error for an out of bounds index
*
- * \return One of Motor_Gears according to what is set for the motor,
- * or pros::Motor_Gears::invalid if the operation failed.
+ * \return One of MotorGears according to what is set for the motor,
+ * or pros::MotorGears::invalid if the operation failed.
*/
virtual MotorGears get_gearing(const std::uint8_t index = 0) const = 0;
@@ -894,8 +885,8 @@ class AbstractMotor {
* The index of the motor to get the target position of.
* By default index is 0, and will return an error for an out of bounds index
*
- * \return A vector of Motor_Gears according to what is set for the motor(s),
- * or pros::Motor_Gears::invalid if the operation failed.
+ * \return A vector of MotorGears according to what is set for the motor(s),
+ * or pros::MotorGears::invalid if the operation failed.
*/
virtual std::vector get_gearing_all(void) const = 0;
@@ -977,7 +968,35 @@ class AbstractMotor {
virtual std::vector is_reversed_all(void) const = 0;
/**
- * Sets one of Motor_Brake to the motor. Works with the C enum
+ * Gets the type of the motor
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENODEV - The port cannot be configured as a motor
+ *
+ * \param index Optional parameter.
+ * The index of the motor to get the target position of.
+ * By default index is 0, and will return an error for an out of bounds index
+ *
+ * \return One of MotorType according to the type of the motor,
+ * or pros::MotorType::invalid if the operation failed
+ */
+ virtual MotorType get_type(const std::uint8_t index = 0) const = 0;
+
+ /**
+ * Gets a vector of the type(s) of the motor(s).
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENODEV - The port cannot be configured as a motor
+ *
+ * \return A vector of MotorType according to the type(s) of the motor(s),
+ * or pros::MotorType::invalid if the operation failed.
+ */
+ virtual std::vector get_type_all(void) const = 0;
+
+ /**
+ * Sets one of MotorBrake to the motor. Works with the C enum
* and the C++ enum class.
*
* This function uses the following values of errno when an error state is
@@ -985,7 +1004,7 @@ class AbstractMotor {
* ENODEV - The port cannot be configured as a motor
*
* \param mode
- * The Motor_Brake to set for the motor
+ * The MotorBrake to set for the motor
*
* \param index Optional parameter.
* The index of the motor to get the target position of.
@@ -1018,7 +1037,7 @@ class AbstractMotor {
virtual std::int32_t set_current_limit(const std::int32_t limit, const std::uint8_t index = 0) const = 0;
virtual std::int32_t set_current_limit_all(const std::int32_t limit) const = 0;
/**
- * Sets one of Motor_Units for the motor encoder. Works with the C
+ * Sets one of MotorUnits for the motor encoder. Works with the C
* enum and the C++ enum class.
*
* This function uses the following values of errno when an error state is
diff --git a/include/pros/adi.h b/include/pros/adi.h
index f1bbe373..0b45e57d 100644
--- a/include/pros/adi.h
+++ b/include/pros/adi.h
@@ -7,7 +7,7 @@
* This file should not be modified by users, since it gets replaced whenever
* a kernel upgrade occurs.
*
- * \copyright (c) 2017-2023, Purdue University ACM SIGBots.
+ * \copyright (c) 2017-2024, Purdue University ACM SIGBots.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
diff --git a/include/pros/adi.hpp b/include/pros/adi.hpp
index a12bd4ac..f01615d7 100644
--- a/include/pros/adi.hpp
+++ b/include/pros/adi.hpp
@@ -7,12 +7,12 @@
* This file should not be modified by users, since it gets replaced whenever
* a kernel upgrade occurs.
*
- * \copyright (c) 2017-2023, Purdue University ACM SIGBots.
+ * \copyright (c) 2017-2024, Purdue University ACM SIGBots.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
+ *
* \defgroup cpp-adi ADI (TriPort) C++ API
* \note The external ADI API can be found [here.](@ref ext-adi)
* \note Additional example code for this module can be found in its [Tutorial.](@ref adi)
@@ -22,25 +22,24 @@
#define _PROS_ADI_HPP_
#include
-#include
+#include
#include
#include
-#include
+#include
#include "pros/adi.h"
-#define LEGACY_TYPEDEF(old_name, new_name) \
- using old_name [[deprecated("use " #new_name " instead")]] = new_name
+#define LEGACY_TYPEDEF(old_name, new_name) using old_name [[deprecated("use " #new_name " instead")]] = new_name
namespace pros {
namespace adi {
-
+
/** type definition for the pair of smart port and adi port for the basic adi devices */
using ext_adi_port_pair_t = std::pair;
/** type definition for the triplet of smart port and two adi ports for the two wire adi devices*/
using ext_adi_port_tuple_t = std::tuple;
-
+
/**
* \ingroup cpp-adi
*/
@@ -63,12 +62,12 @@ class Port {
* The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
* \param type
* The configuration type for the port
- *
+ *
* \b Example
* \code
* #define POTENTIOMETER_PORT 1
* #define POTENTIOMETER_TYPE pros::E_ADI_POT_EDR
- *
+ *
* void opcontrol() {
* pros::ADIPotentiometer potentiometer (POTENTIOMETER_PORT, POTENTIOMETER_TYPE);
* while (true) {
@@ -94,14 +93,14 @@ class Port {
* (from 1-8, 'a'-'h', 'A'-'H') to configure
* \param type
* The configuration type for the port
- *
+ *
* \b Example
* \code
* #define ANALOG_SENSOR_PORT 'a'
* #define EXT_ADI_SMART_PORT 1
- *
+ *
* void initialize() {
- * pros::adi::Port sensor ({{ EXT_ADI_SMART_PORT , ANALOG_SENSOR_PORT }}, E_ADI_ANALOG_IN);
+ * pros::adi::Port sensor ({EXT_ADI_SMART_PORT, ANALOG_SENSOR_PORT}, E_ADI_ANALOG_IN);
* // Displays the value of E_ADI_ANALOG_IN
* std::cout << "Port Type: " << sensor.get_config();
* }
@@ -113,7 +112,7 @@ class Port {
* Gets the configuration for the given ADI port.
*
* \return The ADI configuration for the given port
- *
+ *
* \b Example
* \code
* #define ANALOG_SENSOR_PORT 1
@@ -130,11 +129,11 @@ class Port {
* Gets the value for the given ADI port.
*
* \return The value stored for the given port
- *
+ *
* \b Example
* \code
* #define ANALOG_SENSOR_PORT 1
- *
+ *
* void opcontrol() {
* pros::adi::Port sensor (ANALOG_SENSOR_PORT, E_ADI_ANALOG_IN);
* std::cout << "Port Value: " << sensor.get_value();
@@ -151,11 +150,11 @@ class Port {
*
* \return 1 if the operation was successful or PROS_ERR if the operation
* failed, setting errno.
- *
+ *
* \b Example
* \code
* #define ANALOG_SENSOR_PORT 1
- *
+ *
* void initialize() {
* pros::adi::Port sensor (ANALOG_SENSOR_PORT, E_ADI_DIGITAL_IN);
* // Do things as a digital sensor
@@ -177,11 +176,11 @@ class Port {
*
* \return 1 if the operation was successful or PROS_ERR if the operation
* failed, setting errno.
- *
+ *
* \b Example
* \code
* #define DIGITAL_SENSOR_PORT 1
- *
+ *
* void initialize() {
* pros::adi::Port sensor (DIGITAL_SENSOR_PORT, E_ADI_DIGITAL_OUT);
* sensor.set_value(DIGITAL_SENSOR_PORT, HIGH);
@@ -190,6 +189,33 @@ class Port {
*/
std::int32_t set_value(std::int32_t value) const;
+ /**
+ * Gets the port of the sensor.
+ *
+ * \return returns a tuple of integer ports.
+ *
+ * \note The parts of the tuple are {smart port, adi port, second adi port (when applicable)}.
+ *
+ *
+ * \b Example
+ * \code
+ * #define DIGITAL_SENSOR_PORT 1 // 'A'
+ *
+ * void initialize() {
+ * pros::adi::AnalogIn sensor (DIGITAL_SENSOR_PORT);
+ *
+ * // Getting values from the tuple using std::get
+ * int sensorSmartPort = std::get<0>(sensor.get_port()); // First value
+ * int sensorAdiPort = std::get<1>(sensor.get_port()); // Second value
+ *
+ * // Prints the first and second value from the port tuple (The Adi Port. The first value is the Smart Port)
+ * printf("Sensor Smart Port: %d\n", sensorSmartPort);
+ * printf("Sensor Adi Port: %d\n", sensorAdiPort);
+ * }
+ * \endcode
+ */
+ virtual ext_adi_port_tuple_t get_port() const;
+
protected:
std::uint8_t _smart_port;
std::uint8_t _adi_port;
@@ -215,11 +241,11 @@ class AnalogIn : protected Port {
*
* \return 1 if the operation was successful or PROS_ERR if the operation
* failed, setting errno.
- *
+ *
* \b Example
* \code
* #define ANALOG_SENSOR_PORT 1
- *
+ *
* void opcontrol() {
* pros::ADIAnalogIn sensor (ANALOG_SENSOR_PORT);
* while (true) {
@@ -243,14 +269,14 @@ class AnalogIn : protected Port {
*
* \return 1 if the operation was successful or PROS_ERR if the operation
* failed, setting errno.
- *
+ *
* \b Example
* \code
* #define EXT_ADI_SENSOR_PORT 1
* #define ADI_PORT 'a'
- *
+ *
* void opcontrol() {
- * pros::ADIAnalogIn sensor ({{EXT_ADI_SMART_PORT, ADI_PORT}});
+ * pros::ADIAnalogIn sensor ({EXT_ADI_SMART_PORT, ADI_PORT});
* while (true) {
* // Use the sensor
* }
@@ -274,20 +300,20 @@ class AnalogIn : protected Port {
*
* Do not use this function when the sensor value might be unstable (gyro
* rotation, accelerometer movement).
- *
+ *
* \note The ADI currently returns data at 10ms intervals, in contrast to the
- * calibrate function’s 1ms sample rate.
+ * calibrate function’s 1ms sample rate.
*
* This function uses the following values of errno when an error state is
* reached:
* ENODEV - The port is not configured as an analog input
*
* \return The average sensor value computed by this function
- *
+ *
* \b Example
* \code
* #define ANALOG_SENSOR_PORT 1
- *
+ *
* void initialize() {
* pros::adi::AnalogIn sensor (ANALOG_SENSOR_PORT);
* sensor.calibrate(ANALOG_SENSOR_PORT);
@@ -312,11 +338,11 @@ class AnalogIn : protected Port {
*
* \return The difference of the sensor value from its calibrated default from
* -4095 to 4095
- *
+ *
* \b Example
* \code
* #define ANALOG_SENSOR_PORT 1
- *
+ *
* void initialize() {
* pros::adi::AnalogIn sensor (ANALOG_SENSOR_PORT);
* sensor.calibrate(ANALOG_SENSOR_PORT);
@@ -346,11 +372,11 @@ class AnalogIn : protected Port {
*
* \return The difference of the sensor value from its calibrated default from
* -16384 to 16384
- *
+ *
* \b Example
* \code
* #define ANALOG_SENSOR_PORT 1
- *
+ *
* void initialize() {
* pros::adi::AnalogIn sensor (ANALOG_SENSOR_PORT);
* sensor.calibrate(ANALOG_SENSOR_PORT);
@@ -363,22 +389,23 @@ class AnalogIn : protected Port {
/**
* Reads an analog input channel and returns the 12-bit value.
- *
- * The value returned is undefined if the analog pin has been switched to a different mode. The meaning of the returned value varies depending on the sensor attached.
- *
+ *
+ * The value returned is undefined if the analog pin has been switched to a different mode. The meaning of the
+ * returned value varies depending on the sensor attached.
+ *
* Inherited from ADIPort::get_value.
- *
+ *
* This function uses the following values of errno when an error state is reached:
* EADDRINUSE - The port is not configured as an analog input (e.g. the port has been reconfigured)
- *
+ *
* \return The analog sensor value, where a value of 0 reflects an input
* voltage of nearly 0 V and a value of 4095 reflects an input voltage of
* nearly 5 V
- *
+ *
* \b Example
* \code
* #define ANALOG_SENSOR_PORT 1
- *
+ *
* void initialize() {
* pros::adi::AnalogIn sensor (ANALOG_SENSOR_PORT);
* std::cout << "Sensor Reading:" << sensor.get_value();
@@ -388,14 +415,16 @@ class AnalogIn : protected Port {
using Port::get_value;
/**
- * This is the overload for the << operator for printing to streams
- *
- * Prints in format(this below is all in one line with no new line):
+ * This is the overload for the << operator for printing to streams
+ *
+ * Prints in format(this below is all in one line with no new line):
* AnalogIn [smart_port: analog_in._smart_port, adi_port: analog_in._adi_port,
- * value calibrated: (12 bit calibrated value),
+ * value calibrated: (12 bit calibrated value),
* value calibrated HR: (16 bit calibrated value), value: (12 bit value)]
*/
friend std::ostream& operator<<(std::ostream& os, pros::adi::AnalogIn& analog_in);
+
+ using Port::get_port;
};
///@}
@@ -421,11 +450,11 @@ class AnalogOut : private Port {
*
* \param adi_port
* The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
- *
+ *
* \b Example
* \code
* #define ANALOG_SENSOR_PORT 1
- *
+ *
* void opcontrol() {
* pros::AnalogOut sensor (ANALOG_SENSOR_PORT);
* // Use the sensor
@@ -445,14 +474,14 @@ class AnalogOut : private Port {
* \param port_pair
* The pair of the smart port number (from 1-22) and the
* ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
- *
+ *
* \b Example
* \code
* #define EXT_ADI_SMART_PORT 1
* #define ADI_PORT 'a'
- *
+ *
* void opcontrol() {
- * pros::AnalogOut sensor ({{EXT_ADI_SMART_PORT, ADI_PORT}});
+ * pros::AnalogOut sensor ({EXT_ADI_SMART_PORT, ADI_PORT});
* // Use the sensor
* }
* \endcode
@@ -463,7 +492,7 @@ class AnalogOut : private Port {
* Sets the output for the Analog Output from 0 (0V) to 4095 (5V).
*
* Inherited from ADIPort::set_value.
- *
+ *
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the ADI.
*
@@ -472,11 +501,11 @@ class AnalogOut : private Port {
*
* \return 1 if the operation was successful or PROS_ERR if the operation
* failed, setting errno.
- *
+ *
* \b Example
* \code
* #define ANALOG_SENSOR_PORT 1
- *
+ *
* void opcontrol() {
* pros::AnalogOut sensor (ANALOG_SENSOR_PORT);
* sensor.set_value(4095); // Set the port to 5V
@@ -485,10 +514,12 @@ class AnalogOut : private Port {
*/
using Port::set_value;
+ using Port::get_port;
+
/**
* This is the overload for the << operator for printing to streams
- *
- * Prints in format(this below is all in one line with no new line):
+ *
+ * Prints in format(this below is all in one line with no new line):
* AnalogOut [smart_port: analog_out._smart_port, adi_port: analog_out._adi_port,
* value: (value)]
*/
@@ -514,11 +545,11 @@ class DigitalOut : private Port {
* The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
* \param init_state
* The initial state for the port
- *
+ *
* \b Example
* \code
* #define DIGITAL_SENSOR_PORT 1
- *
+ *
* void opcontrol() {
* bool state = LOW;
* pros::adi::DigitalOut sensor (DIGITAL_SENSOR_PORT, state);
@@ -545,15 +576,15 @@ class DigitalOut : private Port {
* ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
* \param init_state
* The initial state for the port
- *
+ *
* \b Example
* \code
* #define EXT_ADI_SMART_PORT 1
* #define ADI_PORT 'a'
- *
+ *
* void opcontrol() {
* bool state = LOW;
- * pros::adi::DigitalOut sensor ( {{ EXT_ADI_SMART_PORT , ADI_PORT }});
+ * pros::adi::DigitalOut sensor ({EXT_ADI_SMART_PORT , ADI_PORT});
* while (true) {
* state != state;
* sensor.set_value(state);
@@ -568,7 +599,7 @@ class DigitalOut : private Port {
* Sets the digital value (1 or 0) of a pin.
*
* Inherited from ADIPort::set_value.
- *
+ *
* This function uses the following values of errno when an error state is
* reached:
* EADDRINUSE - The port is not configured as a digital output (e.g. the port has been reconfigured)
@@ -577,11 +608,11 @@ class DigitalOut : private Port {
* The value to set the ADI port to
*
* \return if the operation was successful or PROS_ERR if the operation failed, setting errno.
- *
+ *
* \b Example
* \code
* #define DIGITAL_SENSOR_PORT 1
- *
+ *
* void opcontrol() {
* bool state = LOW;
* pros::adi::DigitalOut sensor (DIGITAL_SENSOR_PORT);
@@ -595,13 +626,15 @@ class DigitalOut : private Port {
*/
using Port::set_value;
+ using Port::get_port;
+
/**
* This is the overload for the << operator for printing to streams
*
* Prints in format(this below is all in one line with no new line):
* DigitalOut [smart_port: digital_out._smart_port, adi_port: digital_out._adi_port,
* value: (value)]
- */
+ */
friend std::ostream& operator<<(std::ostream& os, pros::adi::DigitalOut& digital_out);
};
///@}
@@ -610,7 +643,7 @@ class DigitalIn : private Port {
/**
* \addtogroup cpp-adi
* @{
- */
+ */
public:
/**
* Configures an ADI port to act as a Digital Input.
@@ -622,11 +655,11 @@ class DigitalIn : private Port {
*
* \param adi_port
* The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
- *
+ *
* \b Example
* \code
* #define DIGITAL_SENSOR_PORT 1
- *
+ *
* void opcontrol() {
* pros::adi::DigitalIn sensor (ANALOG_SENSOR_PORT);
* // Use the sensor
@@ -646,14 +679,14 @@ class DigitalIn : private Port {
* \param port_pair
* The pair of the smart port number (from 1-22) and the
* ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
- *
+ *
* \b Example
* \code
* #define EXT_ADI_SMART_PORT 1
* #define ADI_PORT 'a'
- *
+ *
* void opcontrol() {
- * pros::adi::DigitalIn sensor ({{EXT_ADI_SMART_PORT, ADI_PORT}});
+ * pros::adi::DigitalIn sensor ({EXT_ADI_SMART_PORT, ADI_PORT});
* // Use the sensor
* }
* \endcode
@@ -677,11 +710,11 @@ class DigitalIn : private Port {
*
* \return 1 if the button is pressed and had not been pressed the last time
* this function was called, 0 otherwise.
- *
+ *
* \b Example
* \code
* #define DIGITAL_SENSOR_PORT 1
- *
+ *
* void opcontrol() {
* pros::adi::DigitalIn sensor (DIGITAL_SENSOR_PORT);
* while (true) {
@@ -697,21 +730,21 @@ class DigitalIn : private Port {
/**
* Gets the digital value (1 or 0) of a pin.
- *
+ *
* Inherited from ADIPort::get_value.
- *
+ *
* This function uses the following values of errno when an error state is reached:
- *
+ *
* EADDRINUSE - The port is not configured as a digital input (e.g. the port has been reconfigured)
- *
+ *
* Analogous to adi_digital_read.
*
* \return The value stored for the given port
- *
+ *
* \b Example
* \code
* #define DIGITAL_SENSOR_PORT 1
- *
+ *
* void opcontrol() {
* pros::adi::DigitalIn sensor (DIGITAL_SENSOR_PORT);
* while (true) {
@@ -731,18 +764,20 @@ class DigitalIn : private Port {
* value: (value)]
*/
friend std::ostream& operator<<(std::ostream& os, pros::adi::DigitalIn& digital_in);
+
+ using Port::get_port;
};
///@}
-//Derived Class(es) from DigitalIn
+// Derived Class(es) from DigitalIn
using Button = DigitalIn;
class Motor : private Port {
/**
* \addtogroup cpp-adi
* @{
- */
+ */
public:
/**
* Configures an ADI port to act as a Motor.
@@ -754,11 +789,11 @@ class Motor : private Port {
*
* \param adi_port
* The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
- *
+ *
* \b Example
* \code
* #define MOTOR_PORT 1
- *
+ *
* void opcontrol() {
* pros::adi::Motor motor (MOTOR_PORT);
* motor.set_value(127); // Go full speed forward
@@ -781,14 +816,14 @@ class Motor : private Port {
* \param port_pair
* The pair of the smart port number (from 1-22) and the
* ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
- *
+ *
* \b Example
* \code
* #define EXT_ADI_SMART_PORT 1
* #define ADI_MOTOR_PORT 'a'
- *
+ *
* void opcontrol() {
- * pros::adi::Motor motor ( {{ EXT_ADI_SMART_PORT , ADI_MOTOR_PORT}} );
+ * pros::adi::Motor motor ({EXT_ADI_SMART_PORT, ADI_MOTOR_PORT});
* motor.set_value(127); // Go full speed forward
* std::cout << "Commanded Motor Power: " << motor.get_value(); // Will display 127
* delay(1000);
@@ -807,11 +842,11 @@ class Motor : private Port {
*
* \return 1 if the operation was successful or PROS_ERR if the operation
* failed, setting errno.
- *
+ *
* \b Example
* \code
* #define MOTOR_PORT 1
- *
+ *
* void opcontrol() {
* pros::adi::Motor motor (MOTOR_PORT);
* motor.set_value(127); // Go full speed forward
@@ -836,11 +871,11 @@ class Motor : private Port {
*
* \return 1 if the operation was successful or PROS_ERR if the operation
* failed, setting errno.
- *
+ *
* \b Example
* \code
* #define MOTOR_PORT 1
- *
+ *
* void opcontrol() {
* pros::adi::Motor motor (MOTOR_PORT);
* motor.set_value(127); // Go full speed forward
@@ -859,13 +894,13 @@ class Motor : private Port {
* reached:
* ENODEV - The port is not configured as a motor
*
- * \return The last set speed of the motor on the given
- *
+ * \return The last set speed of the motor on the given
+ *
* \b Example
* \code
* #define MOTOR_PORT 1
- *
- * void opcontrol() {
+ *
+ * void opcontrol() {
* pros::adi::Motor motor (MOTOR_PORT);
* motor.set_value(127); // Go full speed forward
* std::cout << "Commanded Motor Power: " << motor.get_value(); // Will display 127
@@ -875,6 +910,8 @@ class Motor : private Port {
* \endcode
*/
using Port::get_value;
+
+ using Port::get_port;
};
///@}
@@ -883,7 +920,7 @@ class Encoder : private Port {
/**
* \addtogroup cpp-adi
* @{
- */
+ */
public:
/**
* Configures a set of ADI ports to act as an Encoder.
@@ -899,12 +936,12 @@ class Encoder : private Port {
* The "bottom" wire from the encoder sensor
* \param reverse
* If "true", the sensor will count in the opposite direction
- *
+ *
* \b Example
* \code
* #define PORT_TOP 1
* #define PORT_BOTTOM 2
- *
+ *
* void opcontrol() {
* pros::adi::Encoder sensor (PORT_TOP, PORT_BOTTOM, false);
* // Use the sensor
@@ -927,13 +964,13 @@ class Encoder : private Port {
* the encoder sensor
* \param reverse
* If "true", the sensor will count in theopposite direction
- *
+ *
* \b Example
* \code
* #define PORT_TOP 'A'
* #define PORT_BOTTOM 'B'
* #define SMART_PORT 1
- *
+ *
* void opcontrol() {
* pros::adi::Encoder sensor ({ SMART_PORT, PORT_TOP, PORT_BOTTOM }, false);
* // Use the sensor
@@ -954,12 +991,12 @@ class Encoder : private Port {
*
* \return 1 if the operation was successful or PROS_ERR if the operation
* failed, setting errno.
- *
+ *
* \b Example
* \code
* #define PORT_TOP 1
* #define PORT_BOTTOM 2
- *
+ *
* void opcontrol() {
* pros::adi::Encoder sensor (PORT_TOP, PORT_BOTTOM, false);
* delay(1000); // Move the encoder around in this time
@@ -979,12 +1016,12 @@ class Encoder : private Port {
* ENODEV - The port is not configured as a motor
*
* \return The signed and cumulative number of counts since the last start or
- *
+ *
* \b Example
* \code
* #define PORT_TOP 1
* #define PORT_BOTTOM 2
- *
+ *
* void opcontrol() {
* pros::adi::Encoder sensor (PORT_TOP, PORT_BOTTOM, false);
* while (true) {
@@ -1002,8 +1039,12 @@ class Encoder : private Port {
* Prints in format(this below is all in one line with no new line):
* Encoder [smart_port: encoder._smart_port, adi_port: encoder._adi_port,
* value: (value)]
- */
+ */
friend std::ostream& operator<<(std::ostream& os, pros::adi::Encoder& encoder);
+ ext_adi_port_tuple_t get_port() const override;
+
+ private:
+ ext_adi_port_pair_t _port_pair;
};
///@}
@@ -1012,7 +1053,7 @@ class Ultrasonic : private Port {
/**
* \addtogroup cpp-adi
* @{
- */
+ */
public:
/**
* Configures a set of ADI ports to act as an Ultrasonic sensor.
@@ -1028,12 +1069,12 @@ class Ultrasonic : private Port {
* \param port_echo
* The port connected to the yellow INPUT cable. This should be in the
* next highest port following port_ping.
- *
+ *
* \b Example
* \code
* #define PORT_PING 1
* #define PORT_ECHO 2
- *
+ *
* void opcontrol() {
* pros::adi::Ultrasonic sensor (PORT_PING, PORT_ECHO);
* while (true) {
@@ -1059,13 +1100,13 @@ class Ultrasonic : private Port {
* OUTPUT cable (1, 3, 5, 7 or 'A', 'C', 'E', 'G'), and the port
* connected to the yellow INPUT cable (the next) highest port
* following port_ping).
- *
+ *
* \b Example
* \code
* #define PORT_PING 'A'
* #define PORT_ECHO 'B'
* #define SMART_PORT 1
- *
+ *
* void opcontrol() {
* pros::adi::Ultrasonic sensor ( {{ SMART_PORT, PORT_PING, PORT_ECHO }} );
* while (true) {
@@ -1091,12 +1132,12 @@ class Ultrasonic : private Port {
*
* \return The distance to the nearest object in m^-4 (10000 indicates 1
* meter), measured from the sensor's mounting points.
- *
+ *
* \b Example
* \code
* #define PORT_PING 1
* #define PORT_ECHO 2
- *
+ *
* void opcontrol() {
* pros::adi::Ultrasonic sensor (PORT_PING, PORT_ECHO);
* while (true) {
@@ -1108,6 +1149,8 @@ class Ultrasonic : private Port {
* \endcode
*/
std::int32_t get_value() const;
+
+ using Port::get_port;
};
///@}
@@ -1116,7 +1159,7 @@ class Gyro : private Port {
/**
* \addtogroup cpp-adi
* @{
- */
+ */
public:
/**
* Initializes a gyroscope on the given port. If the given port has not
@@ -1138,12 +1181,12 @@ class Gyro : private Port {
* The ADI port to initialize as a gyro (from 1-8, 'a'-'h', 'A'-'H')
* \param multiplier
* A scalar value that will be multiplied by the gyro heading value
- * supplied by the
- *
+ * supplied by the
+ *
* \b Example
* \code
* #define GYRO_PORT 1
- *
+ *
* void opcontrol() {
* pros::adi::Gyro gyro (GYRO_PORT);
* while (true) {
@@ -1177,15 +1220,15 @@ class Gyro : private Port {
* ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
* \param multiplier
* A scalar value that will be multiplied by the gyro heading value
- * supplied by the
- *
+ * supplied by the
+ *
* \b Example
* \code
* #define ADI_GYRO_PORT 'a'
* #define SMART_PORT 1
- *
+ *
* void opcontrol() {
- * pros::adi::Gyro gyro ({{ SMART_PORT , ADI_GYRO_PORT }});
+ * pros::adi::Gyro gyro ({SMART_PORT ,ADI_GYRO_PORT});
* while (true) {
* // Get the gyro heading
* std::cout << "Distance: " << gyro.get_value();
@@ -1195,7 +1238,7 @@ class Gyro : private Port {
* \endcode
*/
explicit Gyro(ext_adi_port_pair_t port_pair, double multiplier = 1);
-
+
/**
* Gets the current gyro angle in tenths of a degree. Unless a multiplier is
* applied to the gyro, the return value will be a whole number representing
@@ -1209,11 +1252,11 @@ class Gyro : private Port {
* ENODEV - The port is not configured as a gyro
*
* \return The gyro angle in degrees.
- *
+ *
* \b Example
* \code
* #define GYRO_PORT 1
- *
+ *
* void opcontrol() {
* pros::adi::Gyro gyro (GYRO_PORT);
* while (true) {
@@ -1235,30 +1278,32 @@ class Gyro : private Port {
*
* \return 1 if the operation was successful or PROS_ERR if the operation
* failed, setting errno.
- *
+ *
* \b Example
* \code
* #define GYRO_PORT 1
- *
+ *
* void opcontrol() {
* pros::adi::Gyro gyro (GYRO_PORT);
* std::uint32_t now = pros::millis();
* while (true) {
* // Get the gyro heading
* std::cout << "Distance: " << gyro.get_value();
- *
+ *
* if (pros::millis() - now > 2000) {
* // Reset the gyro every 2 seconds
* gyro.reset();
* now = pros::millis();
* }
- *
+ *
* pros::delay(10);
* }
* }
* \endcode
*/
std::int32_t reset() const;
+
+ using Port::get_port;
};
///@}
@@ -1267,7 +1312,7 @@ class Potentiometer : public AnalogIn {
/**
* \addtogroup cpp-adi
* @{
- */
+ */
public:
/**
* Configures an ADI port to act as a Potentiometer.
@@ -1280,22 +1325,22 @@ class Potentiometer : public AnalogIn {
* \param adi_port
* The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
* \param potentiometer_type
- * An adi_potentiometer_type_e_t enum value specifying the potentiometer version type
- *
- * \b Example
- * \code
- * #define POTENTIOMETER_PORT 1
- * #define POTENTIOMETER_TYPE pros::E_ADI_POT_EDR
- *
- * void opcontrol() {
- * pros::adi::Potentiometer potentiometer (POTENTIOMETER_PORT, POTENTIOMETER_TYPE);
- * while (true) {
- * // Get the potentiometer angle
- * std::cout << "Angle: " << potentiometer.get_angle();
- * pros::delay(10);
- * }
- * }
- * \endcode
+ * An adi_potentiometer_type_e_t enum value specifying the potentiometer version type
+ *
+ * \b Example
+ * \code
+ * #define POTENTIOMETER_PORT 1
+ * #define POTENTIOMETER_TYPE pros::E_ADI_POT_EDR
+ *
+ * void opcontrol() {
+ * pros::adi::Potentiometer potentiometer (POTENTIOMETER_PORT, POTENTIOMETER_TYPE);
+ * while (true) {
+ * // Get the potentiometer angle
+ * std::cout << "Angle: " << potentiometer.get_angle();
+ * pros::delay(10);
+ * }
+ * }
+ * \endcode
*/
explicit Potentiometer(std::uint8_t adi_port, adi_potentiometer_type_e_t potentiometer_type = E_ADI_POT_EDR);
@@ -1311,15 +1356,15 @@ class Potentiometer : public AnalogIn {
* The pair of the smart port number (from 1-22) and the
* ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
* \param potentiometer_type
- * An adi_potentiometer_type_e_t enum value specifying the potentiometer version type
- *
+ * An adi_potentiometer_type_e_t enum value specifying the potentiometer version type
+ *
* \b Example
* \code
* #define ADI_POTENTIOMETER_PORT 'a'
* #define SMART_PORT 1
- *
+ *
* void opcontrol() {
- * pros::adi::Potentiometer potentiometer ({{ SMART_PORT , ADI_POTENTIOMETER_PORT }});
+ * pros::adi::Potentiometer potentiometer ({SMART_PORT, ADI_POTENTIOMETER_PORT});
* while (true) {
* // Get the potentiometer angle
* std::cout << "Angle: " << potentiometer.get_angle();
@@ -1340,14 +1385,14 @@ class Potentiometer : public AnalogIn {
* reached:
* ENXIO - The given value is not within the range of ADI Ports
* EADDRINUSE - The port is not configured as a potentiometer
- *
+ *
* \return The potentiometer angle in degrees.
- *
+ *
* \b Example
* \code
* #define ADI_POTENTIOMETER_PORT 'a'
* #define SMART_PORT 1
- *
+ *
* void opcontrol() {
* pros::adi::Potentiometer potentiometer ({{ SMART_PORT , ADI_POTENTIOMETER_PORT }});
* while (true) {
@@ -1414,11 +1459,13 @@ class Potentiometer : public AnalogIn {
/**
* This is the overload for the << operator for printing to streams
- * Potentiometer [value: (value), value calibrated: (calibrated value),
+ * Potentiometer [value: (value), value calibrated: (calibrated value),
* angle: (angle)]
* Prints in format(this below is all in one line with no new line):
- */
+ */
friend std::ostream& operator<<(std::ostream& os, pros::adi::Potentiometer& potentiometer);
+
+ using Port::get_port;
};
///@}
@@ -1427,11 +1474,11 @@ class Led : protected Port {
/**
* \addtogroup cpp-adi
* @{
- */
+ */
public:
/**
* @brief Configures an ADI port to act as a LED.
- *
+ *
* This function uses the following values of errno when an error state is
* reached:
* ENXIO - Either the ADI port value or the smart port value is not within its
@@ -1441,12 +1488,12 @@ class Led : protected Port {
* The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
* \param length
* The number of LEDs in the chain
- *
- * \b Example:
+ *
+ * \b Example:
* \code
* #define LED_PORT 'a'
* #define LED_LENGTH 3
- *
+ *
* void opcontrol() {
* pros::Led led (LED_PORT, LED_LENGTH);
* while (true) {
@@ -1455,14 +1502,14 @@ class Led : protected Port {
* pros::delay(20);
* }
* }
- * \endcode
- *
+ * \endcode
+ *
*/
explicit Led(std::uint8_t adi_port, std::uint32_t length);
/**
* @brief Configures an ADI port on a adi_expander to act as a LED.
- *
+ *
* This function uses the following values of errno when an error state is
* reached:
* ENXIO - Either the ADI port value or the smart port value is not within its
@@ -1473,15 +1520,15 @@ class Led : protected Port {
* ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
* \param length
* The number of LEDs in the chain
- *
- * \b Example:
+ *
+ * \b Example:
* \code
* #define LED_PORT 'a'
* #define SMART_PORT 1
* #define LED_LENGTH 3
- *
+ *
* void opcontrol() {
- * pros::Led led ({{ SMART_PORT , LED_PORT }}, LED_LENGTH);
+ * pros::Led led ({SMART_PORT, LED_PORT}, LED_LENGTH);
* while (true) {
* // Set entire LED strip to red
* led.set_all(0xFF0000);
@@ -1493,17 +1540,17 @@ class Led : protected Port {
explicit Led(ext_adi_port_pair_t port_pair, std::uint32_t length);
/**
- * @brief Operator overload to access the buffer in the ADILed class, it is
+ * @brief Operator overload to access the buffer in the ADILed class, it is
* recommended that you call .update(); after doing any operations with this.
- *
+ *
* @param i 0 indexed pixel of the lED
* @return uint32_t& the address of the buffer at i to modify
- *
- * \b Example:
+ *
+ * \b Example:
* \code
* #define LED_PORT 'a'
* #define LED_LENGTH 3
- *
+ *
* void opcontrol() {
* pros::Led led (LED_PORT, LED_LENGTH);
* while (true) {
@@ -1512,7 +1559,7 @@ class Led : protected Port {
* led.set_pixel(0x00FF00, 1);
* led.set_pixel(0x0000FF, 2);
* pros::delay(20);
- *
+ *
* // Use the [] operator to set the first pixel to black
* led.operator[](0) = 0x000000;
* led.update();
@@ -1520,196 +1567,198 @@ class Led : protected Port {
* }
* }
*/
- std::uint32_t& operator[] (size_t i);
-
- /**
- * @brief Clear the entire led strip of color
- *
- * This function uses the following values of errno when an error state is
- * reached:
- * ENXIO - The given value is not within the range of ADI Ports
- * EINVAL - A parameter is out of bounds/incorrect
- * EADDRINUSE - The port is not configured for ADI output
- *
- * @return PROS_SUCCESS if successful, PROS_ERR if not
- *
- * \b Example:
- * \code
- * #define LED_PORT 'a'
- * #define LED_LENGTH 3
- *
- * void opcontrol() {
- * pros::Led led (LED_PORT, LED_LENGTH);
- * while (true) {
- * // Set the first 3 pixels to red, green, and blue
- * led.set_pixel(0xFF0000, 0);
- * led.set_pixel(0x00FF00, 1);
- * led.set_pixel(0x0000FF, 2);
- * pros::delay(20);
- *
- * // Clear the led strip of color
- * led.clear();
- * pros::delay(20);
- * }
- * }
- * \endcode
- */
+ std::uint32_t& operator[](size_t i);
+
+ /**
+ * @brief Clear the entire led strip of color
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of ADI Ports
+ * EINVAL - A parameter is out of bounds/incorrect
+ * EADDRINUSE - The port is not configured for ADI output
+ *
+ * @return PROS_SUCCESS if successful, PROS_ERR if not
+ *
+ * \b Example:
+ * \code
+ * #define LED_PORT 'a'
+ * #define LED_LENGTH 3
+ *
+ * void opcontrol() {
+ * pros::Led led (LED_PORT, LED_LENGTH);
+ * while (true) {
+ * // Set the first 3 pixels to red, green, and blue
+ * led.set_pixel(0xFF0000, 0);
+ * led.set_pixel(0x00FF00, 1);
+ * led.set_pixel(0x0000FF, 2);
+ * pros::delay(20);
+ *
+ * // Clear the led strip of color
+ * led.clear();
+ * pros::delay(20);
+ * }
+ * }
+ * \endcode
+ */
std::int32_t clear_all();
std::int32_t clear();
-
- /**
- * @brief Force the LED strip to update with the current buffered values, this
- * should be called after any changes to the buffer using the [] operator.
- *
- * This function uses the following values of errno when an error state is
- * reached:
- * EINVAL - A parameter is out of bounds/incorrect
- * EADDRINUSE - The port is not configured for ADI output
- *
- * @return PROS_SUCCESS if successful, PROS_ERR if not
- *
- * \b Example:
- * \code
- * #define LED_PORT 'a'
- * #define LED_LENGTH 3
- *
- * void opcontrol() {
- * pros::Led led (LED_PORT, LED_LENGTH);
- * while (true) {
- * // Set the first 3 pixels to red, green, and blue
- * led.set_pixel(0xFF0000, 0);
- * led.set_pixel(0x00FF00, 1);
- * led.set_pixel(0x0000FF, 2);
- * pros::delay(20);
- *
- * // Use the [] operator to set the first pixel to black
- * led.operator[](0) = 0x000000;
- * // Update the led strip with the new values
- * led.update();
- * pros::delay(20);
- * }
- * }
- * \endcode
- */
+
+ /**
+ * @brief Force the LED strip to update with the current buffered values, this
+ * should be called after any changes to the buffer using the [] operator.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * EINVAL - A parameter is out of bounds/incorrect
+ * EADDRINUSE - The port is not configured for ADI output
+ *
+ * @return PROS_SUCCESS if successful, PROS_ERR if not
+ *
+ * \b Example:
+ * \code
+ * #define LED_PORT 'a'
+ * #define LED_LENGTH 3
+ *
+ * void opcontrol() {
+ * pros::Led led (LED_PORT, LED_LENGTH);
+ * while (true) {
+ * // Set the first 3 pixels to red, green, and blue
+ * led.set_pixel(0xFF0000, 0);
+ * led.set_pixel(0x00FF00, 1);
+ * led.set_pixel(0x0000FF, 2);
+ * pros::delay(20);
+ *
+ * // Use the [] operator to set the first pixel to black
+ * led.operator[](0) = 0x000000;
+ * // Update the led strip with the new values
+ * led.update();
+ * pros::delay(20);
+ * }
+ * }
+ * \endcode
+ */
std::int32_t update() const;
/**
- * @brief Set the entire led strip to one color
- *
- * This function uses the following values of errno when an error state is
- * reached:
- * EINVAL - A parameter is out of bounds/incorrect
- * EADDRINUSE - The port is not configured for ADI output
- *
- * @param color color to set all the led strip value to
- * @return PROS_SUCCESS if successful, PROS_ERR if not
- *
- * \b Example:
- * \code
- * #define LED_PORT 'a'
- * #define LED_LENGTH 3
- *
- * void opcontrol() {
- * pros::Led led (LED_PORT, LED_LENGTH);
- * while (true) {
- * // Set the entire led strip to blue
- * led.set_all(0x0000FF);
- * pros::delay(20);
- * }
- * }
- * \endcode
- */
+ * @brief Set the entire led strip to one color
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * EINVAL - A parameter is out of bounds/incorrect
+ * EADDRINUSE - The port is not configured for ADI output
+ *
+ * @param color color to set all the led strip value to
+ * @return PROS_SUCCESS if successful, PROS_ERR if not
+ *
+ * \b Example:
+ * \code
+ * #define LED_PORT 'a'
+ * #define LED_LENGTH 3
+ *
+ * void opcontrol() {
+ * pros::Led led (LED_PORT, LED_LENGTH);
+ * while (true) {
+ * // Set the entire led strip to blue
+ * led.set_all(0x0000FF);
+ * pros::delay(20);
+ * }
+ * }
+ * \endcode
+ */
std::int32_t set_all(uint32_t color);
/**
- * @brief Set one pixel on the led strip
- *
- * This function uses the following values of errno when an error state is
- * reached:
- * EINVAL - A parameter is out of bounds/incorrect
- * EADDRINUSE - The port is not configured for ADI output
- *
- * @param color color to clear all the led strip to
- * @param pixel_position position of the pixel to clear
- * @return PROS_SUCCESS if successful, PROS_ERR if not
- *
- * \b Example:
- * \code
- * #define LED_PORT 'a'
- * #define LED_LENGTH 3
- *
- * void opcontrol() {
- * pros::Led led (LED_PORT, LED_LENGTH);
- * while (true) {
- * // Set the first pixel to blue
- * led.set_pixel(0x0000FF, 0);
- * pros::delay(20);
- * }
- * }
- * \endcode
- */
+ * @brief Set one pixel on the led strip
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * EINVAL - A parameter is out of bounds/incorrect
+ * EADDRINUSE - The port is not configured for ADI output
+ *
+ * @param color color to clear all the led strip to
+ * @param pixel_position position of the pixel to clear
+ * @return PROS_SUCCESS if successful, PROS_ERR if not
+ *
+ * \b Example:
+ * \code
+ * #define LED_PORT 'a'
+ * #define LED_LENGTH 3
+ *
+ * void opcontrol() {
+ * pros::Led led (LED_PORT, LED_LENGTH);
+ * while (true) {
+ * // Set the first pixel to blue
+ * led.set_pixel(0x0000FF, 0);
+ * pros::delay(20);
+ * }
+ * }
+ * \endcode
+ */
std::int32_t set_pixel(uint32_t color, uint32_t pixel_position);
/**
- * @brief Clear one pixel on the led strip
- *
- * This function uses the following values of errno when an error state is
- * reached:
- * EINVAL - A parameter is out of bounds/incorrect
- * EADDRINUSE - The port is not configured for ADI output
- *
- * @param pixel_position position of the pixel to clear
- * @return PROS_SUCCESS if successful, PROS_ERR if not
- *
- * \b Example:
- * \code
- * #define LED_PORT 'a'
- * #define LED_LENGTH 3
- *
- * void opcontrol() {
- * pros::Led led (LED_PORT, LED_LENGTH);
- * while (true) {
- * // Set the first pixel to blue
- * led.set_pixel(0x0000FF, 0);
- * pros::delay(20);
- *
- * // Clear the first pixel
- * led.clear_pixel(0);
- * pros::delay(20);
- * }
- * }
- * \endcode
- */
+ * @brief Clear one pixel on the led strip
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * EINVAL - A parameter is out of bounds/incorrect
+ * EADDRINUSE - The port is not configured for ADI output
+ *
+ * @param pixel_position position of the pixel to clear
+ * @return PROS_SUCCESS if successful, PROS_ERR if not
+ *
+ * \b Example:
+ * \code
+ * #define LED_PORT 'a'
+ * #define LED_LENGTH 3
+ *
+ * void opcontrol() {
+ * pros::Led led (LED_PORT, LED_LENGTH);
+ * while (true) {
+ * // Set the first pixel to blue
+ * led.set_pixel(0x0000FF, 0);
+ * pros::delay(20);
+ *
+ * // Clear the first pixel
+ * led.clear_pixel(0);
+ * pros::delay(20);
+ * }
+ * }
+ * \endcode
+ */
std::int32_t clear_pixel(uint32_t pixel_position);
/**
- * @brief Get the length of the led strip
- *
- * This function uses the following values of errno when an error state is
- * reached:
- * EINVAL - A parameter is out of bounds/incorrect
- * EADDRINUSE - The port is not configured for ADI output
- *
- * @return The length (in pixels) of the LED strip
- *
- * \b Example:
- * \code
- * #define LED_PORT 'a'
- * #define LED_LENGTH 3
- *
- * void opcontrol() {
- * pros::Led led (LED_PORT, LED_LENGTH);
- * while (true) {
- * // Get the length of the led strip
- * int length = led.length();
- * pros::lcd::print(1, "Length: %d", length);
- * pros::delay(20);
- * }
- * }
- * \endcode
- */
+ * @brief Get the length of the led strip
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * EINVAL - A parameter is out of bounds/incorrect
+ * EADDRINUSE - The port is not configured for ADI output
+ *
+ * @return The length (in pixels) of the LED strip
+ *
+ * \b Example:
+ * \code
+ * #define LED_PORT 'a'
+ * #define LED_LENGTH 3
+ *
+ * void opcontrol() {
+ * pros::Led led (LED_PORT, LED_LENGTH);
+ * while (true) {
+ * // Get the length of the led strip
+ * int length = led.length();
+ * pros::lcd::print(1, "Length: %d", length);
+ * pros::delay(20);
+ * }
+ * }
+ * \endcode
+ */
std::int32_t length();
+ using Port::get_port;
+
protected:
std::vector _buffer;
};
@@ -1722,35 +1771,34 @@ class Pneumatics : public DigitalOut {
/**
* \addtogroup cpp-adi
* @{
- */
+ */
public:
-
/**
* Creates a Pneumatics object for the given port.
- *
+ *
* This function uses the following values of errno when an error state is
* reached:
* ENXIO - The given value is not within the range of ADI Ports
- *
+ *
* \param adi_port
* The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
* \param start_extended
* If true, the pneumatic will start extended when the program starts.
* By default, the piston starts retracted when the program starts.
* \param extended_is_low
- * A flag to set whether the the pneumatic is extended when the ADI
+ * A flag to set whether the the pneumatic is extended when the ADI
* it receives a high or a low value. When true, the extended state
- * corresponds to a output low on the ADI port. This allows the user
+ * corresponds to a output low on the ADI port. This allows the user
* to reverse the behavior of the pneumatics if needed.
- *
+ *
* /b Example:
* \code
* void opcontrol() {
* pros::adi::Pneumatics left_piston('a', false); // Starts retracted, extends when the ADI port is high
- * pros::adi::Pneumatics right_piston('b', false, true); // Starts retracted, extends when the ADI port is low
- *
+ * pros::adi::Pneumatics right_piston('b', false, true); // Starts retracted, extends when the ADI port is low
+ *
* pros::Controller master(pros::E_CONTROLLER_MASTER);
- *
+ *
* while (true) {
* if(master.get_digital(pros::E_CONTROLLER_DIGITAL_L1)) {
* left_piston.extend();
@@ -1758,31 +1806,28 @@ class Pneumatics : public DigitalOut {
* if(master.get_digital(pros::E_CONTROLLER_DIGITAL_L2)) {
* left_piston.retract();
* }
- *
+ *
* if(master.get_digital(pros::E_CONTROLLER_DIGITAL_R1)) {
* left_piston.extend();
* }
* if(master.get_digital(pros::E_CONTROLLER_DIGITAL_2)) {
* left_piston.retract();
* }
- *
+ *
* pros::delay(10);
* }
- *
+ *
* \endcode
*/
- explicit Pneumatics(std::uint8_t adi_port,
- bool start_extended,
- bool extended_is_low = false
- );
+ explicit Pneumatics(std::uint8_t adi_port, bool start_extended, bool extended_is_low = false);
/**
* Creates a Pneumatics object for the given port pair.
- *
+ *
* This function uses the following values of errno when an error state is
* reached:
* ENXIO - The given value is not within the range of ADI Ports
- *
+ *
* \param port_pair
* The pair of the smart port number (from 1-22) and the
* ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure
@@ -1790,19 +1835,20 @@ class Pneumatics : public DigitalOut {
* If true, the pneumatic will start extended when the program starts.
* By default, the piston starts retracted when the program starts.
* \param extended_is_low
- * A flag to set whether the the pneumatic is extended when the ADI
+ * A flag to set whether the the pneumatic is extended when the ADI
* it receives a high or a low value. When true, the extended state
- * corresponds to a output low on the ADI port. This allows the user
+ * corresponds to a output low on the ADI port. This allows the user
* to reverse the behavior of the pneumatics if needed.
- *
+ *
* /b Example:
* \code
* void opcontrol() {
* pros::adi::Pneumatics left_piston({1, 'a'}, false); // Starts retracted, extends when the ADI port is high
- * pros::adi::Pneumatics right_piston({1, 'b'}, false, true); // Starts retracted, extends when the ADI port is low
- *
+ * pros::adi::Pneumatics right_piston({1, 'b'}, false, true); // Starts retracted, extends when the ADI port is
+ *low
+ *
* pros::Controller master(pros::E_CONTROLLER_MASTER);
- *
+ *
* while (true) {
* if(master.get_digital(pros::E_CONTROLLER_DIGITAL_L1)) {
* left_piston.extend();
@@ -1810,37 +1856,34 @@ class Pneumatics : public DigitalOut {
* if(master.get_digital(pros::E_CONTROLLER_DIGITAL_L2)) {
* left_piston.retract();
* }
- *
+ *
* if(master.get_digital(pros::E_CONTROLLER_DIGITAL_R1)) {
* left_piston.extend();
* }
* if(master.get_digital(pros::E_CONTROLLER_DIGITAL_R2)) {
* left_piston.retract();
* }
- *
+ *
* pros::delay(10);
* }
* }
* \endcode
*/
- explicit Pneumatics(ext_adi_port_pair_t port_pair,
- bool start_extended,
- bool extended_is_low = false
- );
+ explicit Pneumatics(ext_adi_port_pair_t port_pair, bool start_extended, bool extended_is_low = false);
/**
* Extends the piston, if not already extended.
- *
+ *
* \return 1 if the piston newly extended, 0 if the piston was already
- * extended, or PROS_ERR is the operation failed, setting errno.
- *
+ * extended, or PROS_ERR is the operation failed, setting errno.
+ *
* \b Example:
* \code
* void opcontrol() {
* pros::adi::Pneumatics piston({1, 'a'}, false); // Starts retracted, extends when the ADI port is high
- *
+ *
* pros::Controller master(pros::E_CONTROLLER_MASTER);
- *
+ *
* while (true) {
* if(master.get_digital(pros::E_CONTROLLER_DIGITAL_X)) {
* left_piston.extend();
@@ -1851,7 +1894,7 @@ class Pneumatics : public DigitalOut {
* if(mastetr.get_digital(pros::E_CONTROLLER_DIGITAL_A)) {
* left_piston.toggle();
* }
- *
+ *
* pros::delay(10);
* }
* }
@@ -1863,15 +1906,15 @@ class Pneumatics : public DigitalOut {
* Retracts the piston, if not already retracted.
*
* \return 1 if the piston newly retracted, 0 if the piston was already
- * retracted, or PROS_ERR is the operation failed, setting errno.
+ * retracted, or PROS_ERR is the operation failed, setting errno.
*
* \b Example:
* \code
* void opcontrol() {
* pros::adi::Pneumatics piston({1, 'a'}, false); // Starts retracted, extends when the ADI port is high
- *
+ *
* pros::Controller master(pros::E_CONTROLLER_MASTER);
- *
+ *
* while (true) {
* if(master.get_digital(pros::E_CONTROLLER_DIGITAL_X)) {
* left_piston.extend();
@@ -1882,7 +1925,7 @@ class Pneumatics : public DigitalOut {
* if(mastetr.get_digital(pros::E_CONTROLLER_DIGITAL_A)) {
* left_piston.toggle();
* }
- *
+ *
* pros::delay(10);
* }
* }
@@ -1896,17 +1939,17 @@ class Pneumatics : public DigitalOut {
*
* \return 1 if the operation was successful or PROS_ERR if the operation
* failed, setting errno.
- *
- * \return 1 if the piston successfully toggled, or PROS_ERR if the
+ *
+ * \return 1 if the piston successfully toggled, or PROS_ERR if the
* operation failed, setting errno.
*
*\b Example:
* \code
* void opcontrol() {
* pros::adi::Pneumatics piston({1, 'a'}, false); // Starts retracted, extends when the ADI port is high
- *
+ *
* pros::Controller master(pros::E_CONTROLLER_MASTER);
- *
+ *
* while (true) {
* if(master.get_digital(pros::E_CONTROLLER_DIGITAL_X)) {
* left_piston.extend();
@@ -1917,7 +1960,7 @@ class Pneumatics : public DigitalOut {
* if(mastetr.get_digital(pros::E_CONTROLLER_DIGITAL_A)) {
* left_piston.toggle();
* }
- *
+ *
* pros::delay(10);
* }
* }
@@ -1926,10 +1969,10 @@ class Pneumatics : public DigitalOut {
std::int32_t toggle();
/**
- * Returns whether the piston is extended or not.
- *
+ * Returns whether the piston is extended or not.
+ *
* \return true if the piston is extended, false if it is retracted.
- *
+ *
* \b Example
* \code
* #define ADI_PNEUMATICS_PORT 'a'
@@ -1944,20 +1987,18 @@ class Pneumatics : public DigitalOut {
* else {
* printf("The pneumatic is not extended\n");
* }
- *
+ *
* pros::delay(10);
* }
* }
* \endcode
*/
- bool is_extended() const;
-
-private:
- bool state; // Holds the physical state of the ADI port
- bool extended_is_low; // A flag that sets whether extended corresponds to
- // a low signal
+ bool is_extended() const;
-
+ private:
+ bool state; // Holds the physical state of the ADI port
+ bool extended_is_low; // A flag that sets whether extended corresponds to
+ // a low signal
};
///@}
@@ -1966,7 +2007,7 @@ class Pneumatics : public DigitalOut {
/*
Pros4 upgrade backwards compatibility for ADI api.
-Prints a deprecated warning when user uses old pros::ADIDevice style API.
+Prints a deprecated warning when user uses old pros::ADIDevice style API.
Remove when and if fully removing old API.
*/
LEGACY_TYPEDEF(ADIPort, pros::adi::Port);
@@ -1981,15 +2022,15 @@ LEGACY_TYPEDEF(ADIUltrasonic, pros::adi::Ultrasonic);
LEGACY_TYPEDEF(LED, pros::adi::Led);
// Backwards Compatibility for Derived Classes
-LEGACY_TYPEDEF(ADIPotentiometer,pros::adi::Potentiometer);
-LEGACY_TYPEDEF(ADILineSensor,pros::adi::LineSensor);
-LEGACY_TYPEDEF(ADILightSensor,pros::adi::LightSensor);
-LEGACY_TYPEDEF(ADIAccelerometer,pros::adi::Accelerometer);
-LEGACY_TYPEDEF(ADIButton,pros::adi::Button);
-LEGACY_TYPEDEF(ADIPneumatics,pros::adi::Pneumatics);
+LEGACY_TYPEDEF(ADIPotentiometer, pros::adi::Potentiometer);
+LEGACY_TYPEDEF(ADILineSensor, pros::adi::LineSensor);
+LEGACY_TYPEDEF(ADILightSensor, pros::adi::LightSensor);
+LEGACY_TYPEDEF(ADIAccelerometer, pros::adi::Accelerometer);
+LEGACY_TYPEDEF(ADIButton, pros::adi::Button);
+LEGACY_TYPEDEF(ADIPneumatics, pros::adi::Pneumatics);
LEGACY_TYPEDEF(ADILED, pros::adi::Led);
LEGACY_TYPEDEF(ADILed, pros::adi::Led);
} // namespace pros
-#endif // _PROS_ADI_HPP_
+#endif // _PROS_ADI_HPP_
\ No newline at end of file
diff --git a/include/pros/ai_vision.h b/include/pros/ai_vision.h
new file mode 100644
index 00000000..5deea418
--- /dev/null
+++ b/include/pros/ai_vision.h
@@ -0,0 +1,502 @@
+/**
+ * \file pros/aivision.h
+ * \ingroup c-aivision
+ *
+ * Contains prototypes for the VEX AI Vision Sensor-related functions.
+ *
+ * This file should not be modified by users, since it gets replaced whenever
+ * a kernel upgrade occurs.
+ *
+ * \copyright (c) 2017-2024, Purdue University ACM SIGBots.
+ * All rights reserved.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * \defgroup c-aivision AI Vision Sensor C API
+ * \note Additional example code for this module can be found in its [Tutorial.](@ref aivision)
+ */
+
+#ifndef _PROS_AIVISION_H_
+#define _PROS_AIVISION_H_
+
+/**
+ * \addtogroup c-aivision
+ * @{
+ */
+
+/// \name Macros
+/// Parameters given by VEX
+///@{
+
+#define AIVISION_MAX_OBJECT_COUNT 24
+#define AIVISION_MAX_CLASSNAME_COUNT 20
+#define AIVISION_MODE_TAG_SET_BIT (1 << 29)
+
+///@}
+
+///@}
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+namespace pros {
+#endif
+
+/**
+ * \addtogroup c-aivision
+ * @{
+ */
+
+/**
+ * \enum aivision_detected_type_e_t
+ * This enumeration defines what kind of object is stored inside the union in aivision_object_s
+ */
+typedef enum aivision_detected_type {
+ E_AIVISION_DETECTED_COLOR = (1 << 0),
+ E_AIVISION_DETECTED_CODE = (1 << 1),
+ E_AIVISION_DETECTED_OBJECT = (1 << 2),
+ E_AIVISION_DETECTED_TAG = (1 << 3)
+} aivision_detected_type_e_t;
+
+/**
+ * \enum aivision_mode_type_e_t
+ * This enumeration defines what kinds of objects the ai vision sensor will scan for:
+ * tags (april tags), colors (user defined colors), and objects (game elements), and all (all objects)
+ */
+
+typedef enum aivision_mode_type {
+ E_AIVISION_MODE_TAGS = (1 << 0),
+ E_AIVISION_MODE_COLORS = (1 << 1),
+ E_AIVISION_MODE_OBJECTS = (1 << 2),
+ E_AIVISION_MODE_COLOR_MERGE = (1 << 4),
+ E_AIVISION_MODE_ALL = (1 << 0) | (1 << 1) | (1 << 2),
+} aivision_mode_type_e_t;
+
+/**
+ * \struct aivision_color_s_t
+ * This structure contains the parameters used by the AI Vision Sensor to define a color. hue_range and saturation_range
+ * are ranges for hue and saturation that are acceptable.
+ * For example, if a large hue range is specified for a blue color, colors that are more magenta or teal may be detected
+ * as "blue".
+ */
+typedef struct aivision_color_s {
+ uint8_t id; /**< id of color descriptor, can range from 1-7 */
+ uint8_t red; /**< red value of color */
+ uint8_t green; /**< green value of color */
+ uint8_t blue; /**< blue value of color */
+ float hue_range; /**< range by which detected color's hue can vary from the base color, can range from 1-40 */
+ float saturation_range; /**< range by which detected color's saturation can vary from base color, can range from 0.1-1 */
+} aivision_color_s_t;
+
+/**
+ * \struct aivision_code_s_t
+ * This structure contains the parameters used by the AI Vision sensor to define a code.
+ * Codes are a combination of color descriptors, and tells the AI Vision sensor to merge objects
+ * close to each other that belong to the given color descriptors into a single object that matches
+ * the code descriptor.
+ * Codes must use at least 2, and no greater than 5, color descriptors.
+ */
+typedef struct aivision_code_s {
+ uint8_t id; /**< id of code descriptor, can range from 1-5 */
+ uint8_t length; /**< number of color descriptors used by this code. */
+ int16_t c1; /**< id of first color descriptor */
+ int16_t c2; /**< id of second color descriptor */
+ int16_t c3; /**< id of third color descriptor */
+ int16_t c4; /**< id of fourth color descriptor */
+ int16_t c5; /**< id of fifth color descriptor */
+} aivision_code_s_t;
+
+/**
+ * \enum aivision_tag_family_e_t
+ * This enumeration corresponds to a family of AprilTags.
+ * \see https://april.eecs.umich.edu/software/apriltag
+ */
+typedef enum aivision_tag_family_e {
+ TAG_CIRCLE_21H7 = 0,
+ TAG_16H5 = 1,
+ TAG_25H9 = 2,
+ TAG_61H11 = 3
+} aivision_tag_family_e_t;
+
+/**
+ * \struct aivision_object_color_s_t
+ * This structure contains a detected color.
+ */
+typedef struct __attribute__((packed)) aivision_object_color_s {
+ uint16_t xoffset; // left edge (from camera's view)
+ uint16_t yoffset; // top edge
+ uint16_t width;
+ uint16_t height;
+ uint16_t angle; // angle, in tenths of a degree
+} aivision_object_color_s_t;
+
+/**
+ * \struct aivision_object_tag_s_t
+ * This structure contains a detected tag.
+ */
+typedef struct __attribute__((packed)) aivision_object_tag_s {
+ int16_t x0;
+ int16_t y0;
+ int16_t x1;
+ int16_t y1;
+ int16_t x2;
+ int16_t y2;
+ int16_t x3;
+ int16_t y3;
+} aivision_object_tag_s_t;
+
+typedef struct __attribute__((packed)) aivision_object_element_s {
+ uint16_t xoffset; // left
+ uint16_t yoffset; // top
+ uint16_t width;
+ uint16_t height;
+ uint16_t score; // confidence that this struct is
+} aivision_object_element_s_t;
+/**
+ * \struct aivision_object_s_t
+ * This structure contains one of aivision_detected_type_e_t, stored in type
+ *
+ * If the object is a color, id stores the color's id
+ * If the object is an April Tag, id stores the tag's id
+ * If the object is an AI model element, id stores the element id as per
+ * https://api.vex.com/v5/home/cpp/AiVision/AiObjdesc.html
+ */
+typedef struct __attribute__((packed)) aivision_object_s {
+ uint8_t id; // object id
+ uint8_t type; // object type
+ union {
+ aivision_object_color_s_t color;
+ aivision_object_tag_s_t tag;
+ aivision_object_element_s_t element;
+ } object;
+} aivision_object_s_t;
+/// @}
+
+#ifdef __cplusplus
+namespace c {
+#endif
+
+/**
+ * \addtogroup c-aivision
+ * @{
+ */
+/// \name Functions
+
+/**
+ * Resets the AI Vision sensor to the initial state.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \param port The V5 port number from 1-21
+ *
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno.
+ *
+ * \b Example
+ * \code
+ * #define AIVISION_PORT 1
+ * void initialize() {
+ * aivision_reset(AIVISION_PORT);
+ * }
+ * \endcode
+ */
+int32_t aivision_reset(uint8_t port);
+
+/**
+ * Returns a bitfield of the types of objects the AI vision sensor is currently searching for,
+ * as per aivision_mode_type_e_t.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \param port The V5 port number from 1-21
+ * \return the bitfield if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno.
+ *
+ * \b Example
+ * \code
+ * #define AIVISION_PORT 1
+ * void initialize() {
+ * aivision_get_enabled_detection_types(AIVISION_PORT);
+ * }
+ * \endcode
+ */
+int32_t aivision_get_enabled_detection_types(uint8_t port);
+
+/**
+ * Modifies the types of objects the AI vision sensor is currently searching for, as per aivision_mode_type_e_t.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \b Example
+ * aivision_set_enabled_detection_types(1, 0b010, 0b101) would disable the detection of tags and objects,
+ * and leave the setting of colors alone.
+ *
+ * \param port The V5 port number from 1-21
+ * \param bits the bits to set
+ * \param bitmask the bitmask to apply
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno.
+ */
+int32_t aivision_set_enabled_detection_types(uint8_t port, uint8_t bits, uint8_t bitmask);
+
+/**
+ * Enable detecting these types of objects, a bitmask as per aivision_mode_type_e_t.
+ * Enabling any given type of object will not disable the detection of other objects.
+ * This must be done explicitly.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \b Example
+ * \code
+ * #define AIVISION_PORT 1
+ * void initialize() {
+ * // start or continue looking for AI model objects
+ * aivision_enable_detection_types(AIVISION_PORT, aivision_mode_type_e_t::E_AIVISION_MODE_OBJECTS);
+ * }
+ * \endcode
+ *
+ * \param port The V5 port number from 1-21
+ * \param types_mask The types to enable
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno.
+ */
+int32_t aivision_enable_detection_types(uint8_t port, uint8_t types_mask);
+
+/**
+ * Disable detecting these types of objects, a bitmask as per aivision_mode_type_e_t.
+ * Disabling any given type of object will not affect the detection of other objects.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \b Example
+ * \code
+ * #define AIVISION_PORT 1
+ * void initialize() {
+ * // stop looking for AI model objects (competition elements, for example)
+ * aivision_disable_detection_types(AIVISION_PORT, aivision_mode_type_e_t::E_AIVISION_MODE_OBJECTS);
+ * }
+ * \endcode
+ *
+ * \param port The V5 port number from 1-21
+ * \param types_mask The types to enable
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno.
+ */
+int32_t aivision_disable_detection_types(uint8_t port, uint8_t types_mask);
+
+/**
+ * Sets the april tag family to detect. Use this function will override the enabled apriltag
+ * detection family.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \param port The V5 port number from 1-21
+ * \param family the tag family to configure the AI Vision sensor to detect
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno.
+ */
+int32_t aivision_set_tag_family_override(uint8_t port, aivision_tag_family_e_t family);
+
+/**
+ * Sets the april tag family to detect. Use this function will allow multiple apriltags
+ * to be detected.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \param port The V5 port number from 1-21
+ * \param family the tag family to configure the AI Vision sensor to detect
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno.
+ */
+int32_t aivision_set_tag_family(uint8_t port, aivision_tag_family_e_t family);
+
+/**
+ * Set a color configuration that the AI vision sensor will detect.
+ * The color detection type must be separately enabled.
+ * If a color with the same ID already is stored in the sensor, it will be overwritten.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \param port The V5 port number from 1-21
+ * \param color the color to configure the AI Vision sensor to detect
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno
+ */
+int32_t aivision_set_color(uint8_t port, const aivision_color_s_t* color);
+
+/**
+ * Get a color configuration that the AI vision sensor has stored.
+ * If you attempt to get a color configuration that has not been previously used, the
+ * behavior is not defined.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \param port The V5 port number from 1-21
+ * \param id the id of color from 1-7
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno
+ */
+aivision_color_s_t aivision_get_color(uint8_t port, uint32_t id);
+
+/**
+ * Get a class name that the AI vision sensor has stored.
+ * The AI Vision sensor may not correctly report classnames for the first several hundred milliseconds
+ * of being plugged in.
+ * By passing in -1 for the id, the function will return the number of class names the AI vision sensor reports.
+ * For other values of id, the function return value is undefined
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \param port The V5 port number from 1-21
+ * \param id the id of the class name from 0-(AIVISION_MAX_CLASSNAME_COUNT - 1)
+ * \param class_name a string of length >=20 to store the classname.
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno
+ */
+int32_t aivision_get_class_name(uint8_t port, int32_t id, uint8_t* class_name);
+
+/**
+ * Enable or disable the bounding box overlay the AI Vision sensor outputs on the USB port.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \param port The V5 port number from 1-21
+ * \param enabled if the overlay is enabled or disabled
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno
+ */
+int32_t aivision_set_usb_bounding_box_overlay(uint8_t port, bool enabled);
+
+/**
+ * Runs auto white balance to adjust to different lighting conditions.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \param port The V5 port number from 1-21
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno
+ */
+int32_t aivision_start_awb(uint8_t port);
+
+/**
+ * Get a code that the AI vision sensor has stored.
+ *
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \param port The V5 port number from 1-21
+ * \param id The id from 1-5
+ * \return the code, or a struct with an invalid ID if the operation failed, setting errno
+ */
+aivision_code_s_t aivision_get_code(uint8_t port, uint32_t id);
+
+/**
+ * Set a code that the AI vision sensor will detect for.
+ * The id of the code is stored in the aivision_code_s_t struct. If there is already a code
+ * stored in the AI vision sensor with the id, this function will overwrite.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \param port The V5 port number from 1-21
+ * \param code The code to set
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno
+ */
+int32_t aivision_set_code(uint8_t port, const aivision_code_s_t* wcode);
+
+/**
+ * Get the current number of objects detected by the AI vision sensor.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \param port The V5 port number from 1-21
+ * \return the number of objects if the operation was successful or PROS_ERR if the operation failed, setting errno
+ */
+int32_t aivision_get_object_count(uint8_t port);
+
+/**
+ * Get the detected object at a given object index; there are aivision_get_object_count objects and the index starts
+ * from 0.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * @param port The V5 port number from 1-21
+ * @param object_index the object index
+ * @return the detected object if the operation was successful or an invalid object type if the operation failed,
+ * setting errno
+ */
+aivision_object_s_t aivision_get_object(uint8_t port, uint32_t object_index);
+
+/**
+ * Get the current reported temperature of the AI Vision sensor in degrees Celsius.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \param port The V5 port number from 1-21
+ * \return the temperature if the operation was successful or PROS_ERR_F if the operation failed, setting errno
+ */
+double aivision_get_temperature(uint8_t port);
+
+///@}
+
+#ifdef __cplusplus
+} // namespace c
+} // namespace pros
+}
+#endif
+
+#endif // _PROS_VISION_H_
\ No newline at end of file
diff --git a/include/pros/ai_vision.hpp b/include/pros/ai_vision.hpp
new file mode 100644
index 00000000..30863d55
--- /dev/null
+++ b/include/pros/ai_vision.hpp
@@ -0,0 +1,600 @@
+/**
+ * \file pros/aivision.hpp
+ * \ingroup cpp-aivision
+ *
+ * Contains prototypes for the VEX AI Vision Sensor-related functions in C++.
+ *
+ * This file should not be modified by users, since it gets replaced whenever
+ * a kernel upgrade occurs.
+ *
+ * \copyright (c) 2017-2024, Purdue University ACM SIGBots.
+ * All rights reserved.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * \defgroup cpp-aivision AI Vision Sensor C++ API
+ * \note Additional example code for this module can be found in its [Tutorial.](@ref aivision)
+ */
+
+#ifndef _PROS_AIVISION_HPP_
+#define _PROS_AIVISION_HPP_
+
+#include
+#include
+#include
+
+#include "pros/ai_vision.h"
+#include "pros/device.hpp"
+
+namespace pros {
+inline namespace v5 {
+
+/**
+ * \enum AivisionDetectType
+ * \ingroup cpp-aivision
+ * Enum class for describing detection type of objects detected by the AI Vision Sensor.
+ */
+enum class AivisionDetectType : uint8_t {
+ color = (1 << 0), /**< object was detected based on color descriptor */
+ code = (1 << 1), /**< object was detected based on code descriptor */
+ object = (1 << 2), /**< object was detected using AI model */
+ tag = (1 << 3) /**< object was detected as an AprilTag */
+};
+
+/**
+ * \enum AivisionModeType
+ * \ingroup cpp-aivision
+ * Enum class for enabling/disabling detection types of AI Vision Sensor.
+ */
+enum class AivisionModeType : uint8_t {
+ tags = (1 << 0), /**< AprilTag detection */
+ colors = (1 << 1), /**< color and code detection */
+ objects = (1 << 2), /**< AI model object detection */
+ color_merge = (1 << 4), /**< merge adjacent color detections */
+ all = (1 << 0) | (1 << 1) | (1 << 2),
+};
+
+/**
+ * \enum AivisionTagFamily
+ * \ingroup cpp-aivision
+ * Enum class for describing family of apriltags to detect.
+ */
+enum class AivisionTagFamily { tag_21H7 = 0, tag_16H5 = 1, tag_25H9 = 2, tag_61H11 = 3 };
+
+/**
+ * \ingroup cpp-aivision
+ */
+class AIVision : public Device {
+ /**
+ * \addtogroup cpp-aivision
+ * @{
+ */
+ public:
+
+ using Color = aivision_color_s_t;
+ using Code = aivision_code_s_t;
+ using Object = aivision_object_s_t;
+
+ /**
+ * Create a AI Vision Sensor object on the given port.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as an AI vision sensor
+ *
+ * \param port
+ * The V5 port number from 1-21
+ *
+ * \b Example
+ * \code
+ * void opcontrol() {
+ * pros::AIVision ai_sensor(2); // Creates a vision sensor on port two
+ * }
+ * \endcode
+ */
+ explicit AIVision(const std::uint8_t port);
+
+ AIVision(const Device& device) : AIVision(device.get_port()){};
+
+ /**
+ * Gets all vision sensors.
+ *
+ * \return A vector of AIVision sensor objects.
+ *
+ * \b Example
+ * \code
+ * void opcontrol() {
+ * std::vector aivision_all = pros::AIVision::get_all_devices(); // All AI vision sensors that are
+ * connected
+ * }
+ * \endcode
+ */
+ static std::vector get_all_devices();
+
+ /**
+ * Check if the dected type is the same as the given type.
+ *
+ * \return true if the type is the same, false otherwise
+ *
+ * \b Example
+ * \code
+ * void opcontrol() {
+ * pros::AIVision aivision(1);
+ * pros::AIVision::Object object = aivision.get_object(0);
+ * if (AIVision::is_type(AivisionDetectType::color, object)) {
+ * printf("is color\n");
+ * } else if (AIVision::is_type(AivisionDetectType::object, object)) {
+ * printf("is object\n");
+ * } else if (AIVision::is_type(AivisionDetectType::code, object)) {
+ * printf("is code\n");
+ * } else if (AIVision::is_type(AivisionDetectType::tag, object)) {
+ * printf("is tag\n");
+ * } else {
+ * printf("unknown\n");
+ * }
+ * }
+ * \endcode
+ */
+ static bool is_type(const Object& object, AivisionDetectType type);
+
+ /**
+ * Resets the AI Vision sensor to the initial state.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+
+ *
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno.
+ *
+ * \b Example
+ * \code
+ * #define AIVISION_PORT 1
+ * void initialize() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * aivision.reset();
+ * }
+ * \endcode
+ */
+ int32_t reset();
+
+ /**
+ * Returns a bitfield of the types of objects the AI vision sensor is currently searching for,
+ * as per AivisionModeType.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+
+ * \return the bitfield if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno.
+ *
+ * \b Example
+ * \code
+ * #define AIVISION_PORT 1
+ * void initialize() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * int32_t enabled_types = aivision.get_enabled_detection_types();
+ * printf("is tag: %d\n", enabled_types | AivisionModeType::tags);
+ * }
+ * \endcode
+ */
+ int32_t get_enabled_detection_types();
+
+ /**
+ * Enable detecting these types of objects, a bitmask as per aivision_mode_type_e_t.
+ * Enabling any given type of object will not disable the detection of other objects.
+ * This must be done explicitly.
+ *
+ * For this function you must use bitwise or to combine the types you want to enable.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \b Example
+ * \code
+ * #define AIVISION_PORT 1
+ * void initialize() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * // start or continue looking for AI model objects
+ * // enable aivision to look for tags and objects
+ * aivision.enable_detection_types(AivisionModeType::tags | AivisionModeType::objects);
+ * }
+ * \endcode
+ *
+ * \param types_mask The types to enable
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno.
+ */
+ int32_t enable_detection_types(AivisionModeType types_mask);
+
+ /**
+ * Enable detecting these types of objects, a bitmask as per aivision_mode_type_e_t.
+ * Enabling any given type of object will not disable the detection of other objects.
+ * This must be done explicitly.
+ *
+ * For this function you can use comma separated values to combine the types you want to enable.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \b Example
+ * \code
+ * #define AIVISION_PORT 1
+ * void initialize() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * // start or continue looking for AI model objects
+ * // enable aivision to look for tags and objects
+ * aivision.enable_detection_types(AivisionModeType::tags, AivisionModeType::objects);
+ * }
+ * \endcode
+ *
+ * \param types_mask The types to enable
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno.
+ */
+ template
+ requires((std::conjunction_v...>))
+ int32_t enable_detection_types(Flags... flags) {
+ auto types_mask = (static_cast(flags) | ...);
+ return c::aivision_enable_detection_types(this->_port, static_cast(types_mask));
+ }
+
+ /**
+ * Disable detecting these types of objects, a bitmask as per aivision_mode_type_e_t.
+ * Disabling any given type of object will not affect the detection of other objects.
+ *
+ * For this function you must use bitwise or to combine the types you want to disable.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \b Example
+ * \code
+ * #define AIVISION_PORT 1
+ * void initialize() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * // stop looking for AI model objects (competition elements, for example)
+ * // disable aivision to look for tags and objects
+ * aivision.disable_detection_types(AivisionModeType::tags | AivisionModeType::objects);
+ * }
+ * \endcode
+ *
+ * \param types_mask The types to enable
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno.
+ */
+ int32_t disable_detection_types(AivisionModeType types_mask);
+
+ /**
+ * Disable detecting these types of objects, a bitmask as per aivision_mode_type_e_t.
+ * Disabling any given type of object will not affect the detection of other objects.
+ *
+ * For this function you can use comma separated values to combine the types you want to disable.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \b Example
+ * \code
+ * #define AIVISION_PORT 1
+ * void initialize() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * // stop looking for AI model objects (competition elements, for example)
+ * // disable aivision to look for tags and objects
+ * aivision.disable_detection_types(AivisionModeType::tags | AivisionModeType::objects);
+ * }
+ * \endcode
+ *
+ * \param types_mask The types to enable
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno.
+ */
+ template
+ requires((std::conjunction_v...>))
+ int32_t disable_detection_types(Flags... flags) {
+ auto types_mask = (static_cast(flags) | ...);
+ return c::aivision_disable_detection_types(this->_port, static_cast(types_mask));
+ }
+
+ /**
+ * Sets the april tag family to detect.
+ * If override is true, the AI vision sensor will only look for the given family.
+ * Otherwise, it will add the given tag to the list of enabled tags.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \code
+ * #define AIVISION_PORT 1
+ * void initialize() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * // set the only tag family to look for to 21H7
+ * aivision.set_tag_family(AivisionTagFamily::tag_21H7);
+ * // add 16H5 to the list of enabled tag families
+ * aivision.set_tag_family(AivisionTagFamily::tag_16H5);
+ * // set the only tag family to look for to 25H9
+ * aivision.set_tag_family(AivisionTagFamily::tag_25H9, true);
+ * }
+ * \endcode
+ *
+ * \param family the tag family to configure the AI Vision sensor to detect
+ * \param override if true, the given family will be set as the only enabled tag family.
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno.
+ */
+ int32_t set_tag_family(AivisionTagFamily family, bool override = false);
+
+ /**
+ * Set a color configuration that the AI vision sensor will detect.
+ * The color detection type must be separately enabled.
+ * If a color with the same ID already is stored in the sensor, it will be overwritten.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \code
+ * #define AIVISION_PORT 1
+ * void opcontrol() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * AIVision::Color color = {1, 207, 19, 25, 10.00, 0.20};
+ * aivision.set_color(color);
+ * }
+ * \endcode
+ *
+ * \param color the color to configure the AI Vision sensor to detect
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno
+ */
+ int32_t set_color(const Color& color);
+
+ /**
+ * Get a color configuration that the AI vision sensor has stored.
+ * If you attempt to get a color configuration that has not been previously used, the
+ * behavior is not defined.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ *
+ * #define AIVISION_PORT 1
+ * void opcontrol() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * AIVision::Code color = aivision.get_color(0);
+ * printf("id: %d, red: %d, green: %d, blue: %d, hue_range: %f, saturation_range: %f\n",
+ * color.id, color.red, color.green, color.blue, color.hue_range, color.saturation_range);
+ * }
+ *
+ * \param id the id of color from 1-7
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno
+ */
+ AIVision::Color get_color(uint32_t id);
+
+ /**
+ * Set a code that the AI vision sensor will detect for.
+ * The id of the code is stored in the aivision_code_s_t struct. If there is already a code
+ * stored in the AI vision sensor with the id, this function will overwrite.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \code
+ *
+ * #define AIVISION_PORT 1
+ * void opcontrol() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * AIVision::Code code = {1, 207, 19, 25, 10.00, 0.20};
+ * aivision.set_code(code);
+ * }
+ *
+ * \endcode
+ *
+ * \param code The code to set
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno
+ */
+ uint32_t set_code(const Code& code);
+
+ /**
+ * Get a code that the AI vision sensor has stored.
+ *
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \code
+ *
+ * #define AIVISION_PORT 1
+ * void opcontrol() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * AIVision::Code code = aivision.get_code(0);
+ * printf("id: %d, length: %d, c1: %d, c2: %d, c3: %d, c4: %d, c5: %d\n",
+ * code.id, code.length, code.c1, code.c2, code.c3, code.c4, code.c5);
+ * )
+ * }
+ *
+ * \endcode
+ *
+ * \param id The id from 1-5
+ * \return the code, or a struct with an invalid ID if the operation failed, setting errno
+ */
+ AIVision::Code get_code(uint32_t id);
+
+ /**
+ * Runs auto white balance to adjust to different lighting conditions.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno
+ */
+ int32_t start_awb();
+
+ /**
+ * Get a class name that the AI vision sensor has stored.
+ * The AI Vision sensor may not correctly report classnames for the first several hundred milliseconds
+ * of being plugged in.
+ * By passing in -1 for the id, the function will return the number of class names the AI vision sensor reports.
+ * For other values of id, the function return value is undefined
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ * \code
+ * #define AIVISION_PORT 1
+ * void opcontrol() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * char* class_name = new char[21];
+ * aivision.get_class_name(0, class_name);
+ * printf("%s\n", class_name);
+ * delete[] class_name;
+ * }
+ *
+ * \endcode
+ *
+ * \param id the id of the class name from 0-(AIVISION_MAX_CLASSNAME_COUNT - 1)
+ * \param class_name a string of length >=20 to store the classname.
+ * \return PROS_SUCCESS if the operation was successful or PROS_ERR if the operation
+ * failed, setting errno
+ */
+ int32_t get_class_name(int32_t id, char* class_name);
+
+ /**
+ * Get a class name that the AI vision sensor has stored.
+ * The AI Vision sensor may not correctly report classnames for the first several hundred milliseconds
+ * of being plugged in.
+ * By passing in -1 for the id, the function will return the number of class names the AI vision sensor reports.
+ * For other values of id, the function return value is undefined
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ * \code
+ * #define AIVISION_PORT 1
+ * void opcontrol() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * auto name = aivision.get_class_name(1);
+ *
+ * if(name.has_value()) {
+ * printf("Class name: %s\n", name.value().c_str());
+ * } else {
+ * printf("Error: %ld\n", errno);
+ * }
+ * }
+ *
+ * \endcode
+ *
+ * \param id the id of the class name from 0-(AIVISION_MAX_CLASSNAME_COUNT - 1)
+ * \return the class name string in std::optional if the operation was successful
+ * or an empty optional if the operation failed, setting errno
+ */
+ std::optional get_class_name(int32_t id);
+
+ /**
+ * Get the current number of objects detected by the AI vision sensor.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \code
+ * #define AIVISION_PORT 1
+ * void opcontrol() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * int32_t object_count = aivision.get_object_count();
+ * printf("%d\n", object_count);
+ * }
+ * \endcode
+ *
+ * \return the number of objects if the operation was successful or PROS_ERR if the operation failed, setting errno
+ */
+ int32_t get_object_count();
+
+ /**
+ * Get the detected object at a given object index; there are aivision_get_object_count objects and the index starts
+ * from 0.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \code
+ * #define AIVISION_PORT 1
+ * void opcontrol() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * int32_t object_count = aivision.get_object_count();
+ * for (int i = 0; i < object_count; i++) {
+ * pros::AIVision::Object object = aivision.get_object(i);
+ * printf("Object %d: %d\n", i, object.type);
+ * }
+ * }
+ *
+ * \endcode
+ *
+ * @param object_index the object index
+ * @return the detected object if the operation was successful or an invalid object type if the operation failed,
+ * setting errno
+ */
+ Object get_object(uint32_t object_index);
+
+ /**
+ * Get all detected objects in a vector.
+ *
+ * This function uses the following values of errno when an error state is
+ * reached:
+ * ENXIO - The given value is not within the range of V5 ports (1-21).
+ * ENODEV - The port cannot be configured as a vision sensor
+ *
+ * \code
+ * #define AIVISION_PORT 1
+ * void opcontrol() {
+ * pros::AIVision aivision(AIVISION_PORT);
+ * auto objects = aivision.get_all_objects();
+ * for (const auto& object : objects) {
+ * printf("Object %d: %d\n", object.id, object.type);
+ * }
+ * }
+ * \endcode
+ *
+ * @return a vector of all detected objects
+ */
+ std::vector