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 +![Latest Release](https://img.shields.io/github/v/release/unwieldycat/robodash) +![License](https://img.shields.io/github/license/unwieldycat/robodash) +![Stars](https://img.shields.io/github/stars/unwieldycat/robodash) + +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 + +![The robodash image display](./docs/source/img/console.png) + +
+ +
+Image Tool + +![The robodash image display](./docs/source/img/image.png) + +
+ +
+Autonomous Selector Tool + +![The robodash selector](./docs/source/img/selector.png) + +
+ +
+View Selector + +![The robodash view switcher](./docs/source/img/view_selector.png) + +
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 @@ - - - - - - - - - - $projectname: $title - - - $title - - - - - - - - - - $treeview $search $mathjax $darkmode - - $extrastylesheet - - - - - - - - - - - - - -
- - - - -
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- $projectname $projectnumber -
- -
$projectbrief
- -
-
$projectbrief
-
$searchbox
$searchbox
-
- - \ 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 - -
- -| Previous | Next | -|:---------|--------------------:| -| | [Usage](@ref usage) | - -
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. - -
- -| Previous | Next | -|:------------------------------|--------------------------:| -| [Installing](@ref installing) | [User Interface](@ref ui) | - -
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 +![View button](../img/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 +![View selector](../img/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 +![Alert](../img/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 +![Alert button](../img/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. - -
- -| Previous | Next | -| :------------------ | ---: | -| [Usage](@ref usage) | | - -
+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 get_all_objects(); + /// @} +}; +} // namespace v5 +} // namespace pros +#endif // _PROS_VISION_HPP_ diff --git a/include/pros/apix.h b/include/pros/apix.h index 165c0541..dc6c5b00 100644 --- a/include/pros/apix.h +++ b/include/pros/apix.h @@ -11,7 +11,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. * All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public @@ -101,86 +101,6 @@ bool task_abort_delay(task_t task); void task_notify_when_deleting(task_t target_task, task_t task_to_notify, uint32_t value, notify_action_e_t notify_action); -/** - * Creates a recursive mutex which can be locked recursively by the owner. - * - * \return A newly created recursive mutex. - * - * \b Example: - * \code - * mutex_t mutex = mutex_recursive_create(); - * - * void task_fn(void* param) { - * while(1) { - * mutex_recursive_take(mutex, 1000); - * // critical section - * mutex_recursive_give(mutex); - * task_delay(1000); - * } - * } - * task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, - * TASK_STACK_DEPTH_DEFAULT, "task_fn"); - * - * \endcode - */ -mutex_t mutex_recursive_create(void); - -/** - * Takes a recursive mutex. - * - * \param mutex - * A mutex handle created by mutex_recursive_create - * \param wait_time - * Amount of time to wait before timing out - * - * \return 1 if the mutex was obtained, 0 otherwise - * - * \b Example: - * \code - * mutex_t mutex = mutex_recursive_create(); - * - * void task_fn(void* param) { - * while(1) { - * mutex_recursive_take(mutex, 1000); - * // critical section - * mutex_recursive_give(mutex); - * task_delay(1000); - * } - * } - * task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, - * TASK_STACK_DEPTH_DEFAULT, "task_fn"); - * - * \endcode - */ -bool mutex_recursive_take(mutex_t mutex, uint32_t timeout); - -/** - * Gives a recursive mutex. - * - * \param mutex - * A mutex handle created by mutex_recursive_create - * - * \return 1 if the mutex was obtained, 0 otherwise - * - * \b Example: - * \code - * mutex_t mutex = mutex_recursive_create(); - * - * void task_fn(void* param) { - * while(1) { - * mutex_recursive_take(mutex, 1000); - * // critical section - * mutex_recursive_give(mutex); - * task_delay(1000); - * } - * } - * task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, - * TASK_STACK_DEPTH_DEFAULT, "task_fn"); - * - * \endcode - */ -bool mutex_recursive_give(mutex_t mutex); - /** * Returns a handle to the current owner of a mutex. * @@ -741,6 +661,48 @@ v5_device_e_t registry_get_plugged_type(uint8_t port); ///@} +/// \name Startup options +///@{ + +/** + * Enable/disable the PROS banner printed to the serial stream. + * + * \warning This function must be called BEFORE the PROS daemon starts. + * The easiest way to acheive this is to NOT call this function directly, + * and instead use the BANNER_ENABLE macro. + * + * \param enable + * Whether the banner should be enabled or disabled. + */ +void enable_banner(bool enabled); + +/** + * This priority value, when used with __attribute__((constructor( ))), is + * guaranteed to run before PROS initializes. + */ +#define PRE_PROS_INIT_PRIORITY 101 + +/** + * Enable/disable the PROS banner printed to the serial stream. + * + * \warning This macro must be used in global scope, outside of any function. + * + * \param enable + * Whether the banner should be enabled or disabled. + */ +#ifdef __cplusplus +#define ENABLE_BANNER(enabled) static_assert(!__builtin_strcmp(__FUNCTION__, "top level"), \ + "Cannot use ENABLE_BANNER inside a function!"); \ + __attribute__((constructor(PRE_PROS_INIT_PRIORITY))) static void _enable_banner_impl() \ + { pros::c::enable_banner(enabled); } +#else +#define ENABLE_BANNER(enabled) static_assert(!__builtin_strcmp(__FUNCTION__, "top level"), \ + "Cannot use ENABLE_BANNER inside a function!"); \ + __attribute__((constructor(PRE_PROS_INIT_PRIORITY))) static void _enable_banner_impl() \ + { enable_banner(enabled); } +#endif +///@} + /// \name Filesystem ///@{ diff --git a/include/pros/colors.h b/include/pros/colors.h index b70a8f99..431d9d85 100644 --- a/include/pros/colors.h +++ b/include/pros/colors.h @@ -6,7 +6,7 @@ * This file should not be modified by users, since it gets replaced whenever * a kernel upgrade occurs. * - * Copyright (c) 2017-2020 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/colors.hpp b/include/pros/colors.hpp index 970c2cfa..c19ec6e6 100644 --- a/include/pros/colors.hpp +++ b/include/pros/colors.hpp @@ -6,7 +6,7 @@ * This file should not be modified by users, since it gets replaced whenever * a kernel upgrade occurs. * - * Copyright (c) 2017-2022 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/device.h b/include/pros/device.h index 889e0085..c6fb5bfb 100644 --- a/include/pros/device.h +++ b/include/pros/device.h @@ -8,7 +8,7 @@ * This file should not be modified by users, since it gets replaced whenever * a kernel upgrade occurs. * - * \copyright (c) 2017-2021, 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 @@ -56,6 +56,7 @@ typedef enum v5_device_e { E_DEVICE_ADI = 12, ///< This port is an ADI expander E_DEVICE_OPTICAL = 16, ///< An optical sensor is plugged into the port E_DEVICE_GPS = 20, ///< A GPS sensor is plugged into the port + E_DEVICE_AIVISION = 29, ///< An AI Vision sensor is plugged into the port E_DEVICE_SERIAL = 129, ///< A serial device is plugged into the port E_DEVICE_GENERIC __attribute__((deprecated("use E_DEVICE_SERIAL instead"))) = E_DEVICE_SERIAL, E_DEVICE_UNDEFINED = 255 ///< The device type is not defined, or is not a valid device diff --git a/include/pros/device.hpp b/include/pros/device.hpp index 7fcee80c..560e03fd 100644 --- a/include/pros/device.hpp +++ b/include/pros/device.hpp @@ -6,7 +6,7 @@ * This file should not be modified by users, since it gets replaced whenever * a kernel upgrade occurs. * - * \copyright (c) 2017-2021, 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 @@ -51,6 +51,7 @@ enum class DeviceType { adi = 12, ///< This port is an ADI expander optical = 16, ///< An optical sensor is plugged into the port gps = 20, ///< A GPS sensor is plugged into the port + aivision = 29, ///< An AI vision sensor is plugged into the port serial = 129, ///< A serial device is plugged into the port undefined = 255 ///< The device type is not defined, or is not a valid device }; @@ -90,7 +91,7 @@ class Device { * } * \endcode */ - std::uint8_t get_port(void); + std::uint8_t get_port(void) const; /** * Checks if the device is installed. @@ -138,6 +139,49 @@ class Device { pros::DeviceType get_plugged_type() const; + /** + * Gets the type of device on a given port. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Mutex of port cannot be taken (access denied). + * + * \param port The V5 port number from 1-21 + * + * \return The device type as an enum. + * + * \b Example + * \code + * #define DEVICE_PORT 1 + * + * void opcontrol() { + * while (true) { + * DeviceType dt = pros::Device::get_plugged_type(DEVICE_PORT); + * printf("device plugged type: {plugged type: %d}\n", dt); + * delay(20); + * } + * } + * \endcode + */ + static pros::DeviceType get_plugged_type(std::uint8_t port); + + /** + * Gets all devices of a given device type. + * + * \param device_type The pros::DeviceType enum that matches the type of device desired. + * + * \return A vector of Device objects for the given device type. + * + * \b Example + * \code + * void opcontrol() { + * std::vector motor_devices = pros::Device::get_all_devices(pros::DeviceType::motor); // All Device objects are motors + * } + * \endcode + */ + + static std::vector get_all_devices(pros::DeviceType device_type = pros::DeviceType::undefined); + protected: /** * Creates a Device object. diff --git a/include/pros/distance.h b/include/pros/distance.h index 63bcd417..e64f0d90 100644 --- a/include/pros/distance.h +++ b/include/pros/distance.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/distance.hpp b/include/pros/distance.hpp index 288dff10..17df3d1e 100644 --- a/include/pros/distance.hpp +++ b/include/pros/distance.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-distance VEX Distance Sensor C++ API */ @@ -34,7 +34,7 @@ class Distance : public Device { /** * \addtogroup cpp-distance * @{ - */ + */ public: /** * Creates a Distance Sensor object for the given port. @@ -56,8 +56,9 @@ class Distance : public Device { * } * \endcode */ - explicit Distance(const std::uint8_t port); + Distance(const std::uint8_t port); + Distance(const Device& device) : Distance(device.get_port()){}; /** * Get the currently measured distance from the sensor in mm * @@ -67,16 +68,16 @@ class Distance : public Device { * ENODEV - The port cannot be configured as an Distance Sensor * * \return The distance value or PROS_ERR if the operation failed, setting - * errno. + * errno. Will return 9999 if the sensor can not detect an object. * * \b Example * \code * #define DISTANCE_PORT 1 - * + * * void opcontrol() { - Distance distance(DISTANCE_PORT); + Distance distance(DISTANCE_PORT); * while (true) { - * printf("Distance confidence: %d\n", distance.get()); + * printf("Distance: %d\n", distance.get()); * delay(20); * } * } @@ -84,6 +85,48 @@ class Distance : public Device { */ virtual std::int32_t get(); + /** + * Get the currently measured distance from the sensor in mm. + * \note This function is identical to get(). + * + * 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 Distance Sensor + * + * \return The distance value or PROS_ERR if the operation failed, setting + * errno. Will return 9999 if the sensor can not detect an object. + * + * \b Example + * \code + * #define DISTANCE_PORT 1 + * + * void opcontrol() { + Distance distance(DISTANCE_PORT); + * while (true) { + * printf("Distance: %d\n", distance.get_distance()); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t get_distance(); + + /** + * Gets all distance sensors. + * + * \return A vector of Distance sensor objects. + * + * \b Example + * \code + * void opcontrol() { + * std::vector distance_all = pros::Distance::get_all_devices(); // All distance sensors that are + * connected + * } + * \endcode + */ + static std::vector get_all_devices(); + /** * Get the confidence in the distance reading * @@ -102,9 +145,9 @@ class Distance : public Device { * \b Example * \code * #define DISTANCE_PORT 1 - * + * * void opcontrol() { - Distance distance(DISTANCE_PORT); + Distance distance(DISTANCE_PORT); * while (true) { * printf("Distance confidence: %d\n", distance.get_confidence()); * delay(20); @@ -127,16 +170,16 @@ class Distance : public Device { * ENODEV - The port cannot be configured as an Distance Sensor * * \return The size value or PROS_ERR if the operation failed, setting - * errno. + * errno. Will return -1 if the sensor is not able to determine object size. * * \b Example * \code * #define DISTANCE_PORT 1 - * + * * void opcontrol() { - Distance distance(DISTANCE_PORT); + Distance distance(DISTANCE_PORT); * while (true) { - * printf("Distance confidence: %d\n", distance.get_object_size()); + * printf("Distance object size: %d\n", distance.get_object_size()); * delay(20); * } * } @@ -154,14 +197,14 @@ class Distance : public Device { * * \return The velocity value or PROS_ERR if the operation failed, setting * errno. - * + * * \b Example * \code - * + * * void opcontrol() { * Distance distance(DISTANCE_PORT); * while (true) { - * printf("Distance Object velocity: %f\n", distance.get_object_velocity()); + * printf("Distance object velocity: %f\n", distance.get_object_velocity()); * delay(20); * } * } @@ -169,23 +212,36 @@ class Distance : public Device { */ virtual double get_object_velocity(); - /** - * 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): - * Distance [port: (port number), distance: (distance), confidence: (confidence), - * object size: (object size), object velocity: (object velocity)] - */ + /** + * 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): + * Distance [port: (port number), distance: (distance), confidence: (confidence), + * object size: (object size), object velocity: (object velocity)] + */ friend std::ostream& operator<<(std::ostream& os, pros::Distance& distance); - + private: ///@} }; namespace literals { +/** + * Constructs a Distance sensor object from a literal ending in _dist via calling the constructor + * + * \return a pros::Distance for the corresponding port + * + * \b Example + * \code + * using namespace pros::literals; + * void opcontrol() { + * pros::Distance dist = 2_dist; //Makes an dist object on port 2 + * } + * \endcode + */ const pros::Distance operator"" _dist(const unsigned long long int d); } // namespace literals -} +} // namespace v5 } // namespace pros #endif diff --git a/include/pros/error.h b/include/pros/error.h index 17dd6d3d..e1d03b6b 100644 --- a/include/pros/error.h +++ b/include/pros/error.h @@ -6,7 +6,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. * * 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/ext_adi.h b/include/pros/ext_adi.h index 421b1938..18fde003 100644 --- a/include/pros/ext_adi.h +++ b/include/pros/ext_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/gps.h b/include/pros/gps.h index 9304e0f9..5cc5eef3 100644 --- a/include/pros/gps.h +++ b/include/pros/gps.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 @@ -26,7 +26,7 @@ #ifdef __cplusplus extern "C" { namespace pros { -#endif +#endif /** * \ingroup c-gps @@ -55,23 +55,36 @@ typedef struct __attribute__((__packed__)) gps_status_s { double x; /// Y Position (meters) double y; - /// Percieved Pitch based on GPS + IMU + /// Perceived Pitch based on GPS + IMU double pitch; - /// Percieved Roll based on GPS + IMU + /// Perceived Roll based on GPS + IMU double roll; - /// Percieved Yaw based on GPS + IMU + /// Perceived Yaw based on GPS + IMU double yaw; } gps_status_s_t; +/** + * \struct gps_orientation_s_t + */ +typedef struct __attribute__((__packed__)) gps_orientation_s { + /// Perceived Pitch based on GPS + IMU + double pitch; + /// Perceived Roll based on GPS + IMU + double roll; + /// Perceived Yaw based on GPS + IMU + double yaw; +} gps_orientation_s_t; + + /** * \struct gps_raw_s */ struct gps_raw_s { - /// Percieved Pitch based on GPS + IMU + /// Perceived Pitch based on GPS + IMU double x; - /// Percieved Roll based on GPS + IMU + /// Perceived Roll based on GPS + IMU double y; - /// Percieved Yaw based on GPS + IMU + /// Perceived Yaw based on GPS + IMU double z; }; @@ -166,7 +179,7 @@ int32_t gps_initialize_full(uint8_t port, double xInitial, double yInitial, doub int32_t gps_set_offset(uint8_t port, double xOffset, double yOffset); /** - * Gets the position and roll, yaw, and pitch of the GPS. + * Get the GPS's cartesian location relative to the center of turning/origin in meters. * * This function uses the following values of errno when an error state is * reached: @@ -176,30 +189,93 @@ int32_t gps_set_offset(uint8_t port, double xOffset, double yOffset); * * \param port * The V5 GPS port number from 1-21 + * \return A struct (gps_position_s_t) containing the X and Y values if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * gps_position_s_t pos; + * + * while (true) { + * pos = gps_get_offset(GPS_PORT); + * screen_print(TEXT_MEDIUM, 1, "X Offset: %4d, Y Offset: %4d", pos.x, pos.y); + * delay(20); + * } + * } + * \endcode + */ +gps_position_s_t gps_get_offset(uint8_t port); + +/** + * Sets the robot's location relative to the center of the field in meters. * - * \return A struct (gps_status_s_t) containing values mentioned above. - * If the operation failed, all the structure's members are filled with - * PROS_ERR_F and errno is set. + * 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 GPS + * EAGAIN - The sensor is still calibrating * + * \param port + * The V5 GPS port number from 1-21 + * \param xInitial + * Initial 4-Quadrant X Position, with (0,0) being at the center of the field (meters) + * \param yInitial + * Initial 4-Quadrant Y Position, with (0,0) being at the center of the field (meters) + * \param headingInitial + * Heading with 0 being north on the field, in degrees [0,360) going clockwise + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * * \b Example * \code * #define GPS_PORT 1 + * #define X_INITIAL -1.15 + * #define Y_INITIAL 1.45 + * #define HEADING_INITIAL 90 + * + * void initialize() { + * gps_set_position(GPS_PORT, X_INITIAL, Y_INITIAL, HEADING_INITIAL); + * } + * \endcode + */ +int32_t gps_set_position(uint8_t port, double xInitial, double yInitial, double headingInitial); + +/** + * Set the GPS sensor's data rate in milliseconds, only applies to IMU on GPS. * - * void opcontrol() { - * gps_status_s_t status; + * 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 GPS + * EAGAIN - The sensor is still calibrating * + * \param port + * The V5 GPS port number from 1-21 + * \param rate + * Data rate in milliseconds (Minimum: 5 ms) + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * #define GPS_DATA_RATE 5 + * + * void initialize() { + * gps_set_data_rate(GPS_PORT, GPS_DATA_RATE); * while (true) { - * status = gps_get_status(GPS_PORT); - * printf("X: %f, Y: %f, Pitch: %f, Roll: %f, Yaw: %f\n", status.x, status.y, status.pitch, status.roll, status.yaw); - * delay(20); + * // Do something * } * } * \endcode */ -gps_status_s_t gps_get_status(uint8_t port); +int32_t gps_set_data_rate(uint8_t port, uint32_t rate); /** - * Gets the x and y position on the field of the GPS in meters. + * Get the possible RMS (Root Mean Squared) error in meters for GPS position. * * This function uses the following values of errno when an error state is * reached: @@ -210,29 +286,57 @@ gps_status_s_t gps_get_status(uint8_t port); * \param port * The V5 GPS port number from 1-21 * - * \return A struct (gps_position_s_t) containing values mentioned above. + * \return Possible RMS (Root Mean Squared) error in meters for GPS position. + * If the operation failed, returns PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * double error; + * error = gps_get_error(GPS_PORT); + * screen_print(TEXT_MEDIUM, 1, "Error: %4d", error); + * } + * \endcode + */ +double gps_get_error(uint8_t port); + +/** + * Gets the position and roll, yaw, and pitch of the GPS. + * + * 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 GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * + * \return A struct (gps_status_s_t) containing values mentioned above. * If the operation failed, all the structure's members are filled with * PROS_ERR_F and errno is set. - * + * * \b Example * \code * #define GPS_PORT 1 * * void opcontrol() { - * gps_position_s_t position; + * gps_status_s_t status; * * while (true) { - * position = gps_get_position(GPS_PORT); - * printf("X: %f, Y: %f\n", position.x, position.y); + * status = gps_get_position_and_orientation(GPS_PORT); + * printf("X: %f, Y: %f, Pitch: %f, Roll: %f, Yaw: %f\n", status.x, status.y, status.pitch, status.roll, status.yaw); * delay(20); * } * } * \endcode */ -gps_position_s_t gps_get_position(uint8_t port); +gps_status_s_t gps_get_position_and_orientation(uint8_t port); /** - * Get the GPS's raw gyroscope values + * Gets the x and y position on the field of the GPS in meters. * * This function uses the following values of errno when an error state is * reached: @@ -242,60 +346,63 @@ gps_position_s_t gps_get_position(uint8_t port); * * \param port * The V5 GPS port number from 1-21 - * \return The raw gyroscope values. If the operation failed, all the - * structure's members are filled with PROS_ERR_F and errno is set. * + * \return A struct (gps_position_s_t) containing values mentioned above. + * If the operation failed, all the structure's members are filled with + * PROS_ERR_F and errno is set. + * * \b Example * \code * #define GPS_PORT 1 * * void opcontrol() { - * gps_gyro_s_t gyro; + * gps_position_s_t position; * * while (true) { - * gyro = gps_get_gyro(GPS_PORT); - * printf("Gyro: %f %f %f\n", gyro.x, gyro.y, gyro.z); + * position = gps_get_position(GPS_PORT); + * printf("X: %f, Y: %f\n", position.x, position.y); * delay(20); * } * } * \endcode */ -gps_gyro_s_t gps_get_gyro_rate(uint8_t port); +gps_position_s_t gps_get_position(uint8_t port); /** - * Get the GPS's raw accelerometer values + * Gets the X position in meters of the robot relative to the starting position. * * 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 GPS + * ENODEV - The port cannot be configured as a GPS * EAGAIN - The sensor is still calibrating * * \param port - * The V5 GPS's port number from 1-21 - * \return The raw accelerometer values. If the operation failed, all the - * structure's members are filled with PROS_ERR_F and errno is set. + * The V5 GPS port number from 1-21 + * + * \return The X position in meters. If the operation failed, + * returns PROS_ERR_F and errno is set. * * \b Example * \code * #define GPS_PORT 1 * * void opcontrol() { - * gps_accel_s_t accel; + * double pos_x; * * while (true) { - * accel = gps_get_accel(GPS_PORT); - * printf("X: %f, Y: %f, Z: %f\n", accel.x, accel.y, accel.z); + * pos_x = gps_get_position_x(GPS_PORT); + * printf("X: %f\n", pos_x); * delay(20); * } * } * \endcode */ -gps_accel_s_t gps_get_accel(uint8_t port); +double gps_get_position_x(uint8_t port); /** - * Get the GPS's cartesian location relative to the center of turning/origin in meters. - * + * Gets the Y position in meters of the robot relative to the starting position. + * * 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). @@ -304,28 +411,29 @@ gps_accel_s_t gps_get_accel(uint8_t port); * * \param port * The V5 GPS port number from 1-21 - * \return A struct (gps_position_s_t) containing the X and Y values if the operation - * failed, setting errno. + * + * \return The Y position in meters. If the operation failed, + * returns PROS_ERR_F and errno is set. * * \b Example * \code * #define GPS_PORT 1 - * + * * void opcontrol() { - * gps_position_s_t pos; - * + * double pos_y; + * * while (true) { - * pos = gps_get_offset(GPS_PORT, x, y); - * screen_print(TEXT_MEDIUM, 1, "X Offset: %4d, Y Offset: %4d", pos.x, pos.y); + * pos_y = gps_get_position_y(GPS_PORT); + * printf("Y: %f\n", pos_y); * delay(20); * } * } * \endcode */ -gps_position_s_t gps_get_offset(uint8_t port); +double gps_get_position_y(uint8_t port); /** - * Sets the robot's location relative to the center of the field in meters. + * Gets the pitch, roll, and yaw of the GPS relative to the starting orientation. * * This function uses the following values of errno when an error state is * reached: @@ -335,31 +443,30 @@ gps_position_s_t gps_get_offset(uint8_t port); * * \param port * The V5 GPS port number from 1-21 - * \param xInitial - * Initial 4-Quadrant X Position, with (0,0) being at the center of the field (meters) - * \param yInitial - * Initial 4-Quadrant Y Position, with (0,0) being at the center of the field (meters) - * \param headingInitial - * Heading with 0 being north on the field, in degrees [0,360) going clockwise - * \return 1 if the operation was successful or PROS_ERR if the operation - * failed, setting errno. + * + * \return A struct (gps_orientation_s_t) containing values mentioned above. + * If the operation failed, all the structure's members are filled with + * PROS_ERR_F and errno is set. * * \b Example * \code * #define GPS_PORT 1 - * #define X_INITIAL -1.15 - * #define Y_INITIAL 1.45 - * #define HEADING_INITIAL 90 - * - * void initialize() { - * gps_set_position(GPS_PORT, X_INITIAL, Y_INITIAL, HEADING_INITIAL); + * + * void opcontrol() { + * gps_orientation_s_t orientation; + * + * while (true) { + * orientation = gps_get_orientation(GPS_PORT); + * printf("pitch: %f, roll: %f, yaw: %f\n", orientation.pitch, orientation.roll, orientation.yaw); + * delay(20); + * } * } * \endcode - */ -int32_t gps_set_position(uint8_t port, double xInitial, double yInitial, double headingInitial); +*/ +gps_orientation_s_t gps_get_orientation(uint8_t port); /** - * Set the GPS sensor's data rate in milliseconds, only applies to IMU on GPS. + * Gets the pitch of the robot in degrees relative to the starting oreintation. * * This function uses the following values of errno when an error state is * reached: @@ -369,28 +476,29 @@ int32_t gps_set_position(uint8_t port, double xInitial, double yInitial, double * * \param port * The V5 GPS port number from 1-21 - * \param rate - * Data rate in milliseconds (Minimum: 5 ms) - * \return 1 if the operation was successful or PROS_ERR if the operation - * failed, setting errno. + * + * \return The pitch in [0,360) degree values. If the operation failed, + * returns PROS_ERR_F and errno is set. * * \b Example * \code * #define GPS_PORT 1 - * #define GPS_DATA_RATE 5 - * - * void initialize() { - * gps_set_data_rate(GPS_PORT, GPS_DATA_RATE); + * + * void opcontrol() { + * double pitch; + * * while (true) { - * // Do something + * pitch = gps_get_pitch(GPS_PORT); + * printf("pitch: %f\n", pitch); + * delay(20); * } * } * \endcode */ -int32_t gps_set_data_rate(uint8_t port, uint32_t rate); +double gps_get_pitch(uint8_t port); /** - * Get the possible RMS (Root Mean Squared) error in meters for GPS position. + * Gets the roll of the robot in degrees relative to the starting oreintation. * * This function uses the following values of errno when an error state is * reached: @@ -400,25 +508,29 @@ int32_t gps_set_data_rate(uint8_t port, uint32_t rate); * * \param port * The V5 GPS port number from 1-21 - * - * \return Possible RMS (Root Mean Squared) error in meters for GPS position. - * If the operation failed, returns PROS_ERR_F and errno is set. + * + * \return The roll in [0,360) degree values. If the operation failed, + * returns PROS_ERR_F and errno is set. * * \b Example * \code * #define GPS_PORT 1 - * + * * void opcontrol() { - * double error; - * error = gps_get_error(GPS_PORT); - * screen_print(TEXT_MEDIUM, 1, "Error: %4d", error); + * double roll; + * + * while (true) { + * roll = gps_get_roll(GPS_PORT); + * printf("roll: %f\n", roll); + * delay(20); + * } * } * \endcode */ -double gps_get_error(uint8_t port); +double gps_get_roll(uint8_t port); /** - * Gets the position and roll, yaw, and pitch of the GPS. + * Gets the yaw of the robot in degrees relative to the starting oreintation. * * This function uses the following values of errno when an error state is * reached: @@ -428,29 +540,26 @@ double gps_get_error(uint8_t port); * * \param port * The V5 GPS port number from 1-21 - * - * \return A struct (gps_status_s_t) containing values mentioned above. - * If the operation failed, all the structure's members are filled with - * PROS_ERR_F and errno is set. + * + * \return The yaw in [0,360) degree values. If the operation failed, + * returns PROS_ERR_F and errno is set. * * \b Example * \code * #define GPS_PORT 1 - * + * * void opcontrol() { - * struct gps_status_s_t status; - * + * double yaw; + * * while (true) { - * status = gps_get_status(GPS_PORT); - * screen_print(TEXT_MEDIUM, 1, "x: %3f, y: %3f, pitch: %3f", status.x, status.y); - * screen_print(TEXT_MEDIUM, 2, "yaw: %3f, roll: %3f", status.pitch, status.yaw); - * screen_print(TEXT_MEDIUM, 3, "roll: %3f", status.roll); + * yaw = gps_get_yaw(GPS_PORT); + * printf("yaw: %f\n", yaw); * delay(20); * } * } * \endcode */ -gps_status_s_t gps_get_status(uint8_t port); +double gps_get_yaw(uint8_t port); /** * Get the heading in [0,360) degree values. @@ -470,12 +579,13 @@ gps_status_s_t gps_get_status(uint8_t port); * \b Example * \code * #define GPS_PORT 1 - * + * * void opcontrol() { * double heading; - * + * * while (true) { * heading = gps_get_heading(GPS_PORT); + * printf("heading: %f\n", heading); * delay(20); * } * } @@ -501,12 +611,13 @@ double gps_get_heading(uint8_t port); * \b Example * \code * #define GPS_PORT 1 - * + * * void opcontrol() { - * double heading; - * + * double heading_raw; + * * while (true) { - * heading = gps_get_heading_raw(GPS_PORT); + * heading_raw = gps_get_heading_raw(GPS_PORT); + * printf("heading_raw: %f\n", heading_raw); * delay(20); * } * } @@ -515,7 +626,7 @@ double gps_get_heading(uint8_t port); double gps_get_heading_raw(uint8_t port); /** - * Gets the GPS sensor's elapsed rotation value + * Get the GPS's raw gyroscope values * * This function uses the following values of errno when an error state is * reached: @@ -525,107 +636,119 @@ double gps_get_heading_raw(uint8_t port); * * \param port * The V5 GPS port number from 1-21 - * \return The elased heading in degrees. If the operation fails, returns - * PROS_ERR_F and errno is set. - * + * \return A struct (gps_gyro_s_t) containing values mentioned above. + * If the operation failed, all the + * structure's members are filled with PROS_ERR_F and errno is set. + * * \b Example * \code * #define GPS_PORT 1 - * + * * void opcontrol() { - * double elapsed_rotation; - * - * elapsed_rotation = gps_get_rotation(GPS_PORT); - * printf("Elapsed rotation: %3f", elapsed_rotation); + * gps_gyro_s_t gyro; + * + * while (true) { + * gyro = gps_get_gyro(GPS_PORT); + * printf("Gyro: %f %f %f\n", gyro.x, gyro.y, gyro.z); + * delay(20); + * } * } * \endcode */ -double gps_get_rotation(uint8_t port); +gps_gyro_s_t gps_get_gyro_rate(uint8_t port); /** - * Set the GPS sensor's rotation value to target value - * + * Get the GPS's raw gyroscope value in x-axis + * * 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 GPS * EAGAIN - The sensor is still calibrating - * + * * \param port * The V5 GPS port number from 1-21 - * \param target - * Target rotation value to set rotation value to - * \return 1 if the operation was successful or PROS_ERR if the operation - * failed, setting errno. + * \return The raw gyroscope value in x-axis. If the operation fails, returns + * PROS_ERR_F and errno is set. * * \b Example * \code * #define GPS_PORT 1 - * + * * void opcontrol() { - * gps_set_rotation(GPS_PORT, 60); - * printf("Elapsed rotation: %3f", gps_get_rotation(GPS_PORT)); + * double gyro_x; + * + * while (true) { + * gyro_x = gps_get_gyro_x(GPS_PORT); + * printf("gyro_x: %f\n", gyro_x); + * delay(20); + * } * } * \endcode - */ -int32_t gps_set_rotation(uint8_t port, double target); +*/ +double gps_get_gyro_rate_x(uint8_t port); /** - * Tare the GPS sensor's rotation value - * + * Get the GPS's raw gyroscope value in y-axis + * * 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 GPS * EAGAIN - The sensor is still calibrating - * + * * \param port * The V5 GPS port number from 1-21 - * \return 1 if the operation was successful or PROS_ERR if the operation - * failed, setting errno. + * \return The raw gyroscope value in y-axis. If the operation fails, returns + * PROS_ERR_F and errno is set. * * \b Example * \code * #define GPS_PORT 1 - * - * void initialize() { - * gps_tare_rotation(GPS_PORT); - * printf("Elapsed rotation: %3f", gps_get_rotation(GPS_PORT)); // should be 0 + * + * void opcontrol() { + * double gyro_y; + * + * while (true) { + * gyro_y = gps_get_gyro_y(GPS_PORT); + * printf("gyro_y: %f\n", gyro_y); + * delay(20); + * } * } * \endcode - */ -int32_t gps_tare_rotation(uint8_t port); +*/ +double gps_get_gyro_rate_y(uint8_t port); /** - * Get the GPS's raw gyroscope values - * + * Get the GPS's raw gyroscope value in z-axis + * * 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 GPS * EAGAIN - The sensor is still calibrating - * + * * \param port * The V5 GPS port number from 1-21 - * \return The raw gyroscope values. If the operation failed, all the - * structure's members are filled with PROS_ERR_F and errno is set. + * \return The raw gyroscope value in z-axis. If the operation fails, returns + * PROS_ERR_F and errno is set. * * \b Example * \code * #define GPS_PORT 1 - * + * * void opcontrol() { - * struct gps_gyro_s_t gyro; - * + * double gyro_z; + * * while (true) { - * gyro = gps_get_gyro_rate(GPS_PORT); - * screen_print(TEXT_MEDIUM, 1, "gyroscope- x: %3f, y: %3f, z: %3f", gyro.x, gyro.y, gyro.z); + * gyro_z = gps_get_gyro_z(GPS_PORT); + * printf("gyro_z: %f\n", gyro_z); * delay(20); * } * } * \endcode - */ -gps_gyro_s_t gps_get_gyro_rate(uint8_t port); +*/ +double gps_get_gyro_rate_z(uint8_t port); /** * Get the GPS's raw accelerometer values @@ -638,26 +761,119 @@ gps_gyro_s_t gps_get_gyro_rate(uint8_t port); * * \param port * The V5 GPS's port number from 1-21 - * \return The raw accelerometer values. If the operation failed, all the + * \return A struct (gps_accel_s_t) containing values mentioned above. + * If the operation failed, all the * structure's members are filled with PROS_ERR_F and errno is set. * * \b Example * \code * #define GPS_PORT 1 - * + * * void opcontrol() { - * struct gps_accel_s_t accel; - * + * gps_accel_s_t accel; + * * while (true) { * accel = gps_get_accel(GPS_PORT); - * screen_print(TEXT_MEDIUM, 1, "accleration- x: %3f, y: %3f, z: %3f", accel.x, accel.y, accel.z); + * printf("X: %f, Y: %f, Z: %f\n", accel.x, accel.y, accel.z); + * delay(20); * } * } * \endcode */ gps_accel_s_t gps_get_accel(uint8_t port); -///@} +/** + * Get the GPS's raw accelerometer value in x-axis + * + * 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 GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS's port number from 1-21 + * \return The raw accelerometer value in x-axis. If the operation fails, returns + * PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * double accel_x; + * + * while (true) { + * accel_x = gps_get_accel_x(GPS_PORT); + * printf("accel_x: %f\n", accel_x); + * delay(20); + * } + * } + * \endcode +*/ +double gps_get_accel_x(uint8_t port); + +/** + * Get the GPS's raw accelerometer value in y-axis + * + * 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 GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS's port number from 1-21 + * \return The raw accelerometer value in y-axis. If the operation fails, returns + * PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * double accel_y; + * + * while (true) { + * accel_y = gps_get_accel_y(GPS_PORT); + * printf("accel_y: %f\n", accel_y); + * delay(20); + * } + * } + * \endcode +*/ +double gps_get_accel_y(uint8_t port); + +/** + * Get the GPS's raw accelerometer value in z-axis + * + * 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 GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS's port number from 1-21 + * \return The raw accelerometer value in z-axis. If the operation fails, returns + * PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * double accel_z; + * + * while (true) { + * accel_z = gps_get_accel_z(GPS_PORT); + * printf("accel_z: %f\n", accel_z); + * delay(20); + * } + * } + * \endcode +*/ +double gps_get_accel_z(uint8_t port); #ifdef __cplusplus } diff --git a/include/pros/gps.hpp b/include/pros/gps.hpp index d081d619..b9fc7b5a 100644 --- a/include/pros/gps.hpp +++ b/include/pros/gps.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-gps VEX GPS Sensor C API * \note For a pros-specific usage guide on the GPS, please check out our article [here.](@ref gps) */ @@ -25,8 +25,8 @@ #include #include -#include "pros/gps.h" #include "pros/device.hpp" +#include "pros/gps.h" namespace pros { inline namespace v5 { @@ -41,7 +41,6 @@ class Gps : public Device { */ public: - /** * Creates a GPS object for the given port. * @@ -59,7 +58,9 @@ class Gps : public Device { * \endcode * */ - explicit Gps(const std::uint8_t port) : Device(port, DeviceType::gps){}; + Gps(const std::uint8_t port) : Device(port, DeviceType::gps){}; + + Gps(const Device& device) : Gps(device.get_port()){}; /** * Creates a GPS object for the given port. @@ -85,7 +86,8 @@ class Gps : public Device { * \endcode * */ - explicit Gps(const std::uint8_t port, double xInitial, double yInitial, double headingInitial) : Device(port, DeviceType::gps){ + explicit Gps(const std::uint8_t port, double xInitial, double yInitial, double headingInitial) + : Device(port, DeviceType::gps) { pros::c::gps_set_position(port, xInitial, yInitial, headingInitial); }; @@ -105,19 +107,19 @@ class Gps : public Device { * \param yOffset * Cartesian 4-Quadrant Y offset from center of turning (meters) * - * \b Example: + * \b Example: * \code * pros::Gps gps(1, 1.30, 1.20); * \endcode * */ - explicit Gps(const std::uint8_t port, double xOffset, double yOffset) : Device(port, DeviceType::gps){ + explicit Gps(const std::uint8_t port, double xOffset, double yOffset) : Device(port, DeviceType::gps) { pros::c::gps_set_offset(port, xOffset, yOffset); }; /** * Creates a GPS 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 V5 ports (1-21). @@ -143,8 +145,9 @@ class Gps : public Device { * \endcode * */ - explicit Gps(const std::uint8_t port, double xInitial, double yInitial, double headingInitial, double xOffset, double yOffset) - : Device(port, DeviceType::gps){ + explicit Gps(const std::uint8_t port, double xInitial, double yInitial, double headingInitial, double xOffset, + double yOffset) + : Device(port, DeviceType::gps) { pros::c::gps_initialize_full(port, xInitial, yInitial, headingInitial, xOffset, yOffset); }; @@ -221,34 +224,49 @@ class Gps : public Device { virtual std::int32_t set_offset(double xOffset, double yOffset) const; /** - * Get the GPS's cartesian location relative to the center of turning/origin in meters. - * - * 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 GPS - * EAGAIN - The sensor is still calibrating - * - * \param port - * The V5 GPS port number from 1-21 - * \return A struct (gps_position_s_t) containing the X and Y values if the operation - * failed, setting errno. - * - * \b Example - * \code - * #define GPS_PORT 1 - * - * void opcontrol() { - * gps_position_s_t pos; - * Gps gps(GPS_PORT); - * while (true) { - * pos = gps.get_offset(); - * screen_print(TEXT_MEDIUM, 1, "X Offset: %4d, Y Offset: %4d", pos.x, pos.y); - * delay(20); - * } - * } - * \endcode - */ + + * Gets all GPS sensors. + * + * \return A vector of Gps sensor objects. + * + * \b Example + * \code + * void opcontrol() { + * std::vector gps_all = pros::Gps::get_all_devices(); // All GPS sensors that are connected + * } + * \endcode + */ + static std::vector get_all_devices(); + + /** + * Get the GPS's cartesian location relative to the center of turning/origin in meters. + * + * 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 GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * \return A struct (gps_position_s_t) containing the X and Y values if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * gps_position_s_t pos; + * Gps gps(GPS_PORT); + * while (true) { + * pos = gps.get_offset(); + * screen_print(TEXT_MEDIUM, 1, "X Offset: %4d, Y Offset: %4d", pos.x, pos.y); + * delay(20); + * } + * } + * \endcode + */ virtual pros::gps_position_s_t get_offset() const; /** @@ -268,7 +286,7 @@ class Gps : public Device { * Heading with 0 being north on the field, in degrees [0,360) going clockwise * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * #define GPS_PORT 1 @@ -277,7 +295,7 @@ class Gps : public Device { * Gps gps(GPS_PORT); * gps.set_position(1.3, 1.4, 180); * while (true) { - * printf("X: %f, Y: %f, Heading: %f\n", gps.get_position().x, + * printf("X: %f, Y: %f, Heading: %f\n", gps.get_position().x, * gps.get_position().y, gps.get_position().heading); * delay(20); * } @@ -356,7 +374,7 @@ class Gps : public Device { * \return A struct (gps_status_s_t) containing values mentioned above. * If the operation failed, all the structure's members are filled with * PROS_ERR_F and errno is set. - * + * * \b Example * \code * #define GPS_PORT 1 @@ -365,15 +383,15 @@ class Gps : public Device { * Gps gps(GPS_PORT); * gps_status_s_t status; * while (true) { - * status = gps.get_status(); - * printf("X: %f, Y: %f, Heading: %f, Roll: %f, Pitch: %f, Yaw: %f\n", - * status.x, status.y, status.heading, status.roll, status.pitch, status.yaw); + * status = gps.get_position_and_orientation(); + * printf("X: %f, Y: %f, Roll: %f, Pitch: %f, Yaw: %f\n", + * status.x, status.y, status.roll, status.pitch, status.yaw); * delay(20); * } * } * \endcode */ - virtual pros::gps_status_s_t get_status() const; + virtual pros::gps_status_s_t get_position_and_orientation() const; /** * Gets the x and y position on the field of the GPS in meters. @@ -397,8 +415,7 @@ class Gps : public Device { * gps_position_s_t position; * while (true) { * position = gps.get_position(); - * printf("X: %f, Y: %f, Heading: %f\n", position.x, position.y, - * position.heading); + * printf("X: %f, Y: %f\n", position.x, position.y); * delay(20); * } * } @@ -406,6 +423,177 @@ class Gps : public Device { */ virtual pros::gps_position_s_t get_position() const; + /** + * Gets the X position in meters of the robot relative to the starting position. + * + * 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 GPS + * EAGAIN - The sensor is still calibrating + * + * \return The X position in meters. If the operation failed, + * returns PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * while(true) { + * double pos_x = gps.get_position_x(); + * printf("X: %f\n", pos_x); + * pros::delay(20); + * } + * } + * \endcode + */ + virtual double get_position_x() const; + + /** + * Gets the Y position in meters of the robot relative to the starting position. + * + * 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 GPS + * EAGAIN - The sensor is still calibrating + * + * \return The Y position in meters. If the operation failed, + * returns PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * while(true) { + * double pos_y = gps.get_position_y(); + * printf("Y: %f\n", pos_y); + * pros::delay(20); + * } + * } + * \endcode + */ + virtual double get_position_y() const; + + /** + * Gets the pitch, roll, and yaw of the GPS relative to the starting orientation. + * + * 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 GPS + * EAGAIN - The sensor is still calibrating + * + * \return A struct (gps_orientation_s_t) containing values mentioned above. + * If the operation failed, all the structure's members are filled with + * PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * gps_orientation_s_t orientation; + * while (true) { + * orientation = gps.get_orientation(); + * printf("pitch: %f, roll: %f, yaw: %f\n", orientation.pitch, + * orientation.roll, orientation.yaw); + * delay(20); + * } + * } + * \endcode + */ + virtual pros::gps_orientation_s_t get_orientation() const; + + /** + * Gets the pitch of the robot in degrees relative to the starting oreintation. + * + * 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 GPS + * EAGAIN - The sensor is still calibrating + * + * \return The pitch in [0,360) degree values. If the operation failed, + * returns PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * while(true) { + * double pitch = gps.get_pitch(); + * printf("pitch: %f\n", pitch); + * pros::delay(20); + * } + * } + * \endcode + */ + virtual double get_pitch() const; + + /** + * Gets the roll of the robot in degrees relative to the starting oreintation. + * + * 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 GPS + * EAGAIN - The sensor is still calibrating + * + * \return The roll in [0,360) degree values. If the operation failed, + * returns PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * while(true) { + * double roll = gps.get_roll(); + * printf("roll: %f\n", roll); + * pros::delay(20); + * } + * } + * \endcode + */ + virtual double get_roll() const; + + /** + * Gets the yaw of the robot in degrees relative to the starting oreintation. + * + * 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 GPS + * EAGAIN - The sensor is still calibrating + * + * \return The yaw in [0,360) degree values. If the operation failed, + * returns PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * while(true) { + * double yaw = gps.get_yaw(); + * printf("yaw: %f\n", yaw); + * pros::delay(20); + * } + * } + * \endcode + */ + virtual double get_yaw() const; + /** * Get the heading in [0,360) degree values. * @@ -464,7 +652,7 @@ class Gps : public Device { virtual double get_heading_raw() const; /** - * Gets the GPS sensor's elapsed rotation value + * Get the GPS's raw gyroscope value in z-axis * * This function uses the following values of errno when an error state is * reached: @@ -472,27 +660,27 @@ class Gps : public Device { * ENODEV - The port cannot be configured as a GPS * EAGAIN - The sensor is still calibrating * - * \return The elased heading in degrees. If the operation fails, returns + * \return The raw gyroscope value in z-axis. If the operation fails, returns * PROS_ERR_F and errno is set. * - * \b Example + \b Example * \code * #define GPS_PORT 1 * * void opcontrol() { * Gps gps(GPS_PORT); * while(true) { - double rotation = gps.get_rotation(); - * printf("Rotation: %f\n", rotation); + * double gyro_z = gps.get_gyro_z(); + * printf("gyro_z: %f\n", gyro_z); * pros::delay(20); * } * } * \endcode */ - virtual double get_rotation() const; + virtual pros::gps_gyro_s_t get_gyro_rate() const; /** - * Set the GPS sensor's rotation value to target value + * Get the GPS's raw gyroscope value in x-axis * * This function uses the following values of errno when an error state is * reached: @@ -500,10 +688,8 @@ class Gps : public Device { * ENODEV - The port cannot be configured as a GPS * EAGAIN - The sensor is still calibrating * - * \param target - * Target rotation value to set rotation value to - * \return 1 if the operation was successful or PROS_ERR if the operation - * failed, setting errno. + * \return The raw gyroscope value in x-axis. If the operation fails, returns + * PROS_ERR_F and errno is set. * * \b Example * \code @@ -511,18 +697,18 @@ class Gps : public Device { * * void opcontrol() { * Gps gps(GPS_PORT); - * double rotation = gps.set_rotation(90); * while(true) { - * printf("Rotation: %f\n", rotation); + * double gyro_x = gps.get_gyro_x(); + * printf("gyro_x: %f\n", gyro_x); * pros::delay(20); * } * } * \endcode */ - virtual std::int32_t set_rotation(double target) const; + virtual double get_gyro_rate_x() const; /** - * Tare the GPS sensor's rotation value + * Get the GPS's raw gyroscope value in y-axis * * This function uses the following values of errno when an error state is * reached: @@ -530,28 +716,27 @@ class Gps : public Device { * ENODEV - The port cannot be configured as a GPS * EAGAIN - The sensor is still calibrating * - * \return 1 if the operation was successful or PROS_ERR if the operation - * failed, setting errno. - * - * \b Example: + * \return The raw gyroscope value in y-axis. If the operation fails, returns + * PROS_ERR_F and errno is set. + * + * \b Example * \code * #define GPS_PORT 1 * * void opcontrol() { * Gps gps(GPS_PORT); - * gps.tare_rotation(); * while(true) { - * Should be around 0 on first call since it was tared. - * printf("Rotation: %f\n", rotation); + * double gyro_y = gps.get_gyro_y(); + * printf("gyro_y: %f\n", gyro_y); * pros::delay(20); * } * } * \endcode */ - virtual std::int32_t tare_rotation() const; + virtual double get_gyro_rate_y() const; /** - * Get the GPS's raw gyroscope values + * Get the GPS's raw gyroscope value in z-axis * * This function uses the following values of errno when an error state is * reached: @@ -559,24 +744,24 @@ class Gps : public Device { * ENODEV - The port cannot be configured as a GPS * EAGAIN - The sensor is still calibrating * - * \return The raw gyroscope values. If the operation failed, all the - * structure's members are filled with PROS_ERR_F and errno is set. + * \return The raw gyroscope value in z-axis. If the operation fails, returns + * PROS_ERR_F and errno is set. * - * \b Example + \b Example * \code * #define GPS_PORT 1 * * void opcontrol() { * Gps gps(GPS_PORT); * while(true) { - * pros::gps_gyro_s_t gyro = gps.get_gyro_rate(); - * printf("Gyro: %f, %f, %f\n", gyro.x, gyro.y, gyro.z); + * double gyro_z = gps.get_gyro_z(); + * printf("gyro_z: %f\n", gyro_z); * pros::delay(20); * } * } * \endcode - */ - virtual pros::gps_gyro_s_t get_gyro_rate() const; + */ + virtual double get_gyro_rate_z() const; /** * Get the GPS's raw accelerometer values @@ -587,18 +772,22 @@ class Gps : public Device { * ENODEV - The port cannot be configured as an GPS * EAGAIN - The sensor is still calibrating * - * \param port - * The V5 GPS's port number from 1-21 * \return The raw accelerometer values. If the operation failed, all the * structure's members are filled with PROS_ERR_F and errno is set. */ virtual pros::gps_accel_s_t get_accel() const; /** - * This is the overload for the << operator for printing to streams - * - * Prints in format: - * Gps [port: gps._port, x: (x position), y: (y position), heading: (gps heading), rotation: (gps rotation)] + * Get the GPS's raw accelerometer value in x-axis + * + * 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 GPS + * EAGAIN - The sensor is still calibrating + * + * \return The raw accelerometer value in x-axis. If the operation fails, returns + * PROS_ERR_F and errno is set. * * \b Example * \code @@ -607,43 +796,142 @@ class Gps : public Device { * void opcontrol() { * Gps gps(GPS_PORT); * while(true) { - * std::cout << gps << std::endl; + * double accel_x = gps.get_accel_x(); + * printf("accel_x: %f\n", accel_x); * pros::delay(20); * } * } * \endcode */ - friend std::ostream& operator<<(std::ostream& os, const pros::Gps& gps); + virtual double get_accel_x() const; -///@} -}; // Gps Class + /** + * Get the GPS's raw accelerometer value in y-axis + * + * 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 GPS + * EAGAIN - The sensor is still calibrating + * + * \return The raw accelerometer value in y-axis. If the operation fails, returns + * PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * while(true) { + * double accel_y = gps.get_accel_y(); + * printf("accel_y: %f\n", accel_y); + * pros::delay(20); + * } + * } + * \endcode + */ + virtual double get_accel_y() const; -namespace literals { /** - * Constructs a Gps object with the given port number - * + * Get the GPS's raw accelerometer value in z-axis + * + * 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 GPS + * EAGAIN - The sensor is still calibrating + * + * \return The raw accelerometer value in z-axis. If the operation fails, returns + * PROS_ERR_F and errno is set. + * * \b Example * \code - * using namespace literals; - * + * #define GPS_PORT 1 + * * void opcontrol() { - * pros::Gps gps = 1_gps; - * while (true) { - * pos = gps.get_position(); - * screen_print(TEXT_MEDIUM, 1, "X Position: %4d, Y Position: %4d", pos.x, pos.y); - * delay(20); - * } + * Gps gps(GPS_PORT); + * while(true) { + * double accel_z = gps.get_accel_z(); + * printf("accel_z: %f\n", accel_z); + * pros::delay(20); + * } + * } + * \endcode + */ + virtual double get_accel_z() const; + + /** + * This is the overload for the << operator for printing to streams + * + * Prints in format: + * Gps [port: gps._port, x: (x position), y: (y position), heading: (gps heading), rotation: (gps rotation)] + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * while(true) { + * std::cout << gps << std::endl; + * pros::delay(20); + * } * } * \endcode */ - const pros::Gps operator""_gps(const unsigned long long int g); + friend std::ostream& operator<<(std::ostream& os, const pros::Gps& gps); + + /** + * Gets a gps sensor that is plugged in to the brain + * + * \note The first time this function is called it returns the gps sensor at the lowest port + * If this function is called multiple times, it will cycle through all the ports. + * For example, if you have 1 gps sensor on the robot + * this function will always return a gps sensor object for that port. + * If you have 2 gps sensors, all the odd numered calls to this function will return objects + * for the lower port number, + * all the even number calls will return gps objects for the higher port number + * + * + * This functions uses the following values of errno when an error state is + * reached: + * ENODEV - No gps sensor is plugged into the brain + * + * \return A gps object corresponding to a port that a gps sensor is connected to the brain + * If no gps sensor is plugged in, it returns a gps sensor on port PROS_ERR_BYTE + * + */ + static Gps get_gps(); + ///@} +}; // Gps Class + +namespace literals { +/** + * Constructs a Gps object with the given port number + * + * \b Example + * \code + * using namespace literals; + * + * void opcontrol() { + * pros::Gps gps = 1_gps; + * while (true) { + * pos = gps.get_position(); + * screen_print(TEXT_MEDIUM, 1, "X Position: %4d, Y Position: %4d", pos.x, pos.y); + * delay(20); + * } + * } + * \endcode + */ +const pros::Gps operator""_gps(const unsigned long long int g); } // namespace literals /// @brief /// Alias for Gps is GPS for user convenience. using GPS = Gps; -} // namespace v5 -} // namespace pros +} // namespace v5 +} // namespace pros #endif diff --git a/include/pros/imu.h b/include/pros/imu.h index bf724ab0..00ed1647 100644 --- a/include/pros/imu.h +++ b/include/pros/imu.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 @@ -41,13 +41,25 @@ namespace pros { * @brief Indicates IMU status. */ typedef enum imu_status_e { + E_IMU_STATUS_READY = 0, // IMU is connected but not currently calibrating /** The IMU is calibrating */ - E_IMU_STATUS_CALIBRATING = 0x01, + E_IMU_STATUS_CALIBRATING = 1, /** Used to indicate that an error state was reached in the imu_get_status function,\ not that the IMU is necessarily in an error state */ E_IMU_STATUS_ERROR = 0xFF, } imu_status_e_t; +typedef enum imu_orientation_e { + E_IMU_Z_UP = 0, // IMU has the Z axis UP (VEX Logo facing DOWN) + E_IMU_Z_DOWN = 1, // IMU has the Z axis DOWN (VEX Logo facing UP) + E_IMU_X_UP = 2, // IMU has the X axis UP + E_IMU_X_DOWN = 3, // IMU has the X axis DOWN + E_IMU_Y_UP = 4, // IMU has the Y axis UP + E_IMU_Y_DOWN = 5, // IMU has the Y axis DOWN + E_IMU_ORIENTATION_ERROR = 0xFF // NOTE: used for returning an error from the get_physical_orientation function, not + // that the IMU is necessarily in an error state +} imu_orientation_e_t; + /** * \struct quaternion_s_t */ @@ -934,6 +946,21 @@ int32_t imu_set_roll(uint8_t port, double target); */ int32_t imu_set_yaw(uint8_t port, double target); +/** + * Returns the physical orientation of the IMU + * + * 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 Inertial Sensor + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \returns The orientation of the Inertial Sensor or PROS_ERR if an error occured. + * + */ +imu_orientation_e_t imu_get_physical_orientation(uint8_t port); + /** @} */ /** @} */ diff --git a/include/pros/imu.hpp b/include/pros/imu.hpp index cb141ecc..4163d857 100644 --- a/include/pros/imu.hpp +++ b/include/pros/imu.hpp @@ -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 @@ -19,10 +19,10 @@ #define _PROS_IMU_HPP_ #include +#include -#include "pros/imu.h" #include "pros/device.hpp" -#include +#include "pros/imu.h" namespace pros { /** @@ -40,8 +40,9 @@ namespace pros { */ enum class ImuStatus { + ready = 0, /** The IMU is calibrating */ - calibrating = 0x01, + calibrating = 19, /** Used to indicate that an error state was reached in the imu_get_status function,\ not that the IMU is necessarily in an error state */ error = 0xFF, @@ -54,9 +55,8 @@ inline namespace v5 { class Imu : public Device { /** * \addtogroup cpp-imu - * ///@{ + * @{ */ - public: /** @@ -68,22 +68,47 @@ class Imu : public Device { * * \param port * The V5 Inertial Sensor port number from 1-21 - * + * * \b Example * \code * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Do something with the sensor data * } * } * \endcode */ - explicit Imu(const std::uint8_t port) : Device(port, DeviceType::imu) {}; + + + Imu(const std::uint8_t port) : Device(port, DeviceType::imu){}; + + Imu(const Device& device) : Imu(device.get_port()){}; + /** + * Gets a IMU sensor that is plugged in to the brain + * + * \note The first time this function is called it returns the IMU sensor at the lowest port + * If this function is called multiple times, it will cycle through all the ports. + * For example, if you have 1 IMU sensor on the robot + * this function will always return a IMU sensor object for that port. + * If you have 2 IMU sensors, all the odd numered calls to this function will return objects + * for the lower port number, + * all the even number calls will return IMU objects for the higher port number + * + * + * This functions uses the following values of errno when an error state is + * reached: + * ENODEV - No IMU sensor is plugged into the brain + * + * \return A IMU object corresponding to a port that a IMU sensor is connected to the brain + * If no IMU sensor is plugged in, it returns a IMU sensor on port PROS_ERR_BYTE + * + */ + static Imu get_imu(); /** * Calibrate IMU * @@ -103,15 +128,15 @@ class Imu : public Device { * Whether this function blocks during calibration. * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * imu.calibrate(); + * * // Block until calibration is complete * imu.reset(true); * } @@ -139,31 +164,48 @@ class Imu : public Device { * \param rate The data refresh interval in milliseconds * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Set the refresh rate to 5ms * std::int32_t status = imu.set_data_rate(5); * delay(20); - * + * * // Check if the operation was successful * if (status == PROS_ERR) { * // Do something with the error * } - * + * * // Do something with the sensor data * } * } * \endcode */ virtual std::int32_t set_data_rate(std::uint32_t rate) const; + + + /** + * Gets all IMU sensors. + * + * \return A vector of Imu sensor objects. + * + * \b Example + * \code + * void opcontrol() { + * std::vector imu_all = pros::Imu::get_all_devices(); // All IMU sensors that are connected + * } + * \endcode + */ + + static std::vector get_all_devices(); + /** * Get the total number of degrees the Inertial Sensor has spun about the z-axis * @@ -181,15 +223,15 @@ class Imu : public Device { * The V5 Inertial Sensor port number from 1-21 * \return The degree value or PROS_ERR_F if the operation failed, setting * errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Get the total number of degrees the sensor has spun * printf("Total rotation: %f\n", imu.get_rotation()); @@ -217,15 +259,15 @@ class Imu : public Device { * The V5 Inertial Sensor port number from 1-21 * \return The degree value or PROS_ERR_F if the operation failed, setting * errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Get the sensor's heading * printf("Heading: %f\n", imu.get_heading()); @@ -249,15 +291,15 @@ class Imu : public Device { * \return The quaternion representing the sensor's orientation. If the * operation failed, all the quaternion's members are filled with PROS_ERR_F and * errno is set. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Get the sensor's quaternion * pros::quaternion_s_t quat = imu.get_quaternion(); @@ -282,15 +324,15 @@ class Imu : public Device { * \return The Euler angles representing the sensor's orientation. If the * operation failed, all the structure's members are filled with PROS_ERR_F and * errno is set. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Get the sensor's Euler angles * pros::euler_s_t euler = imu.get_euler(); @@ -314,15 +356,15 @@ class Imu : public Device { * The V5 Inertial Sensor port number from 1-21 * \return The pitch angle, or PROS_ERR_F if the operation failed, setting * errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Get the sensor's pitch * printf("Pitch: %f\n", imu.get_pitch()); @@ -344,15 +386,15 @@ class Imu : public Device { * \param port * The V5 Inertial Sensor port number from 1-21 * \return The roll angle, or PROS_ERR_F if the operation failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Get the sensor's roll * printf("Roll: %f\n", imu.get_roll()); @@ -374,15 +416,15 @@ class Imu : public Device { * \param port * The V5 Inertial Sensor port number from 1-21 * \return The yaw angle, or PROS_ERR_F if the operation failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Get the sensor's yaw * printf("Yaw: %f\n", imu.get_yaw()); @@ -405,15 +447,15 @@ class Imu : public Device { * The V5 Inertial Sensor port number from 1-21 * \return The raw gyroscope values. If the operation failed, all the * structure's members are filled with PROS_ERR_F and errno is set. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Get the sensor's raw gyroscope values * pros::imu_gyro_s_t gyro = imu.get_gyro_rate(); @@ -437,22 +479,22 @@ class Imu : public Device { * The V5 Inertial Sensor port number from 1-21 * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Set the sensor's rotation value to 10 * imu.set_rotation(10); * delay(20); - * + * * // Do something with sensor - * + * * // Reset the sensor's rotation value to 0 * imu.tare_rotation(); * delay(20); @@ -474,22 +516,22 @@ class Imu : public Device { * The V5 Inertial Sensor port number from 1-21 * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Set the sensor's heading value to 10 * imu.set_heading(10); * delay(20); - * + * * // Do something with sensor - * + * * // Reset the sensor's heading value to 0 * imu.tare_heading(); * delay(20); @@ -511,22 +553,22 @@ class Imu : public Device { * The V5 Inertial Sensor port number from 1-21 * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Set the sensor's pitch value to 10 * imu.set_pitch(10); * delay(20); - * + * * // Do something with sensor - * + * * // Reset the sensor's pitch value to 0 * imu.tare_pitch(); * delay(20); @@ -548,22 +590,22 @@ class Imu : public Device { * The V5 Inertial Sensor port number from 1-21 * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Set the sensor's yaw value to 10 * imu.set_yaw(10); * delay(20); - * + * * // Do something with sensor - * + * * // Reset the sensor's yaw value to 0 * imu.tare_yaw(); * delay(20); @@ -585,22 +627,22 @@ class Imu : public Device { * The V5 Inertial Sensor port number from 1-21 * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Set the sensor's roll value to 10 * imu.set_roll(10); * delay(20); - * + * * // Do something with sensor - * + * * // Reset the sensor's roll value to 0 * imu.tare_roll(); * delay(20); @@ -622,15 +664,15 @@ class Imu : public Device { * The V5 Inertial Sensor port number from 1-21 * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Reset all values of the sensor to 0 * imu.tare(); @@ -653,22 +695,22 @@ class Imu : public Device { * The V5 Inertial Sensor port number from 1-21 * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Reset all euler values of the sensor to 0 * imu.tare_euler(); * delay(20); * } * } - * \endcode + * \endcode */ virtual std::int32_t tare_euler() const; /** @@ -687,20 +729,20 @@ class Imu : public Device { * Target value for the heading value to be set to * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Set the sensor's heading value to 10 * imu.set_heading(10); * delay(20); - * + * * // Do something with sensor * } * } @@ -722,20 +764,20 @@ class Imu : public Device { * Target value for the rotation value to be set to * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Set the sensor's rotation value to 10 * imu.set_rotation(10); * delay(20); - * + * * // Do something with sensor * } * } @@ -758,20 +800,20 @@ class Imu : public Device { * Target value for yaw value to be set to * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Set the sensor's yaw value to 10 * imu.set_yaw(10); * delay(20); - * + * * // Do something with sensor * } * } @@ -793,20 +835,20 @@ class Imu : public Device { * Target value for the pitch value to be set to * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Set the sensor's pitch value to 10 * imu.set_pitch(10); * delay(20); - * + * * // Do something with sensor * } * } @@ -829,20 +871,20 @@ class Imu : public Device { * Target euler values for the euler values to be set to * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Set the sensor's roll value to 100 * imu.set_roll(100); * delay(20); - * + * * // Do something with sensor * } * } @@ -865,20 +907,20 @@ class Imu : public Device { * Target euler values for the euler values to be set to * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Set the sensor's euler values to 50 * imu.set_euler(50); * delay(20); - * + * * // Do something with sensor * } * } @@ -898,25 +940,25 @@ class Imu : public Device { * The V5 Inertial Sensor port number from 1-21 * \return The raw accelerometer values. If the operation failed, all the * structure's members are filled with PROS_ERR_F and errno is set. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Get the sensor's raw accelerometer values * pros::imu_accel_s_t accel = imu.get_accel(); * printf("x: %f, y: %f, z: %f\n", accel.x, accel.y, accel.z); * delay(20); - * + * * // Do something with sensor * } * } - * \endcode + * \endcode */ virtual pros::imu_accel_s_t get_accel() const; /** @@ -932,21 +974,21 @@ class Imu : public Device { * The V5 Inertial Sensor port number from 1-21 * \return The Inertial Sensor's status code, or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Get the sensor's status * pros::ImuStatus status = imu.get_status(); * cout << "Status: " << status << endl; * delay(20); - * + * * // Do something with sensor * } * } @@ -958,38 +1000,52 @@ class Imu : public Device { * * \return true if the V5 Inertial Sensor is calibrating or false * false if it is not. - * + * * \b Example * \code - * + * * #define IMU_PORT 1 - * + * * void opcontrol() { * pros::Imu imu(IMU_PORT); - * + * * while (true) { * // Calibrate the sensor - * imu.calibrate(); + * imu.reset(); * delay(20); - * + * * // Check if the sensor is calibrating * if (imu.is_calibrating()) { * printf("Calibrating...\n"); * } - * + * * // Do something with sensor * } * } * \endcode */ virtual bool is_calibrating() const; + /** + * Returns the physical orientation of the IMU + * + * 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 Inertial Sensor + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \returns The physical orientation of the Inertial Sensor or PROS_ERR if an error occured. + * + */ + virtual imu_orientation_e_t get_physical_orientation() const; /** - * 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): - * Imu [port: imu._port, rotation: (rotation), heading: (heading), - * pitch: (pitch angle), roll: (roll angle), yaw: (yaw angle), + * 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): + * Imu [port: imu._port, rotation: (rotation), heading: (heading), + * pitch: (pitch angle), roll: (roll angle), yaw: (yaw angle), * gyro rate: {x,y,z}, get accel: {x,y,z}, calibrating: (calibrating boolean)] */ friend std::ostream& operator<<(std::ostream& os, const pros::Imu& imu); @@ -998,6 +1054,19 @@ class Imu : public Device { }; namespace literals { +/** + * Constructs a Imu from a literal ending in _imu via calling the constructor + * + * \return a pros::Imu for the corresponding port + * + * \b Example + * \code + * using namespace pros::literals; + * void opcontrol() { + * pros::Imu imu = 2_imu; //Makes an IMU object on port 2 + * } + * \endcode + */ const pros::Imu operator"" _imu(const unsigned long long int i); } // namespace literals diff --git a/include/pros/link.h b/include/pros/link.h index bd02a17e..e4a1472c 100644 --- a/include/pros/link.h +++ b/include/pros/link.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 @@ -41,9 +41,9 @@ namespace pros { * \brief Enum for the type of link (TX or RX) */ typedef enum link_type_e { - E_LINK_RECEIVER = 0, ///< Indicates that the radio is a receiver. + E_LINK_RECIEVER = 0, ///< Indicates that the radio is a reciever. E_LINK_TRANSMITTER, ///< Indicates that the link is a transmitter. - E_LINK_RX = E_LINK_RECEIVER, ///< Alias for E_LINK_RECEIVER + E_LINK_RX = E_LINK_RECIEVER, ///< Alias for E_LINK_RECIEVER E_LINK_TX = E_LINK_TRANSMITTER ///< Alias for E_LINK_TRANSMITTER } link_type_e_t; diff --git a/include/pros/link.hpp b/include/pros/link.hpp index 45d98df8..995d433b 100644 --- a/include/pros/link.hpp +++ b/include/pros/link.hpp @@ -7,7 +7,7 @@ * This file should not be modified by users, since it gets replaced whenever * a kernel upgrade occurs. * - * Copyright (c) 2017-2021, 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 @@ -56,7 +56,7 @@ class Link : public Device { * with the transmitter having double the transmitting bandwidth as the receiving * end (1040 bytes/s vs 520 bytes/s). * \param ov - * Indicates if the radio on the given port needs vexlink to override the controller radio + * Indicates if the radio on the given port needs vexlink to override the controller radio. Defualts to True. * * \return PROS_ERR if initialization fails, 1 if the initialization succeeds. * @@ -65,7 +65,7 @@ class Link : public Device { * pros::Link link(1, "my_link", pros::E_LINK_TX); * \endcode */ - explicit Link(const std::uint8_t port, const std::string link_id, link_type_e_t type, bool ov = false); + explicit Link(const std::uint8_t port, const std::string link_id, link_type_e_t type, bool ov = true); /** * Checks if a radio link on a port is active or not. diff --git a/include/pros/llemu.h b/include/pros/llemu.h index 868cd736..1f3ee4a3 100644 --- a/include/pros/llemu.h +++ b/include/pros/llemu.h @@ -3,6 +3,7 @@ // TODO:? Should there be weak symbols for the C api in here as well? +#include "stdbool.h" #include "stdint.h" /******************************************************************************/ @@ -41,7 +42,7 @@ namespace c { * \return True if the operation was successful, or false otherwise, setting * errno values as specified above. */ -bool __attribute__((weak)) lcd_print(int16_t line, const char* fmt, ...) { +bool __attribute__((weak)) lcd_print(__attribute__((unused)) int16_t line, __attribute__((unused)) const char* fmt, ...) { return false; } diff --git a/include/pros/llemu.hpp b/include/pros/llemu.hpp index 4f75d6c7..6e860176 100644 --- a/include/pros/llemu.hpp +++ b/include/pros/llemu.hpp @@ -11,7 +11,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 @@ -47,7 +47,11 @@ namespace pros { /** * \ingroup cpp-llemu */ +#if defined(_PROS_KERNEL_SUPPRESS_LLEMU_WARNING) || defined(_PROS_INCLUDE_LIBLVGL_LLEMU_HPP) namespace lcd { +#else +namespace [[deprecated("Without liblvgl, LLEMU functions will not display anything. To install liblvgl run \"pros c install liblvgl\" in the PROS terminal.")]] lcd { +#endif #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" namespace { @@ -70,14 +74,19 @@ namespace lcd { * For documentation on these functions, please see the doxygen comments for * these functions in the libvgl llemu headers. */ - + extern __attribute__((weak)) bool is_initialized(void); + extern __attribute__((weak)) bool initialize(void); + extern __attribute__((weak)) bool shutdown(void); extern __attribute__((weak)) bool set_text(std::int16_t line, std::string text); + extern __attribute__((weak)) bool clear(void); extern __attribute__((weak)) bool clear_line(std::int16_t line); - extern __attribute__((weak)) bool initialize(void); - extern __attribute__((weak)) std::uint8_t read_buttons(void); + // TODO: Text_Align is defined in liblvgl so this ain't going to compile for now. + // extern __attribute__((weak)) void set_text_align(Text_Align text_align); + extern __attribute__((weak)) void register_btn0_cb(lcd_btn_cb_fn_t cb); extern __attribute__((weak)) void register_btn1_cb(lcd_btn_cb_fn_t cb); - extern __attribute__((weak)) bool is_initialized(void); - + extern __attribute__((weak)) void register_btn2_cb(lcd_btn_cb_fn_t cb); + extern __attribute__((weak)) std::uint8_t read_buttons(void); + /** * \addtogroup cpp-llemu * @{ diff --git a/include/pros/misc.h b/include/pros/misc.h index d0ad6764..8123fbfd 100644 --- a/include/pros/misc.h +++ b/include/pros/misc.h @@ -8,13 +8,13 @@ * 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. * All rights reservered. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * + * * \defgroup c-misc Miscellaneous C API * \note Additional example code for this module can be found in its [Tutorial.](@ref controller) */ @@ -38,9 +38,16 @@ /// \name V5 Competition //@{ -#define COMPETITION_DISABLED (1 << 0) +/*#define COMPETITION_DISABLED (1 << 0) #define COMPETITION_AUTONOMOUS (1 << 1) #define COMPETITION_CONNECTED (1 << 2) +#define COMPETITION_SYSTEM (1 << 3)*/ +typedef enum { + COMPETITION_DISABLED = 1 << 0, + COMPETITION_CONNECTED = 1 << 2, + COMPETITION_AUTONOMOUS = 1 << 1, + COMPETITION_SYSTEM = 1 << 3, +} competition_status; #ifdef __cplusplus extern "C" { @@ -54,7 +61,7 @@ namespace c { * * \return The competition control status as a mask of bits with * COMPETITION_{ENABLED,AUTONOMOUS,CONNECTED}. - * + * * \b Example * \code * void initialize() { @@ -67,17 +74,11 @@ namespace c { */ uint8_t competition_get_status(void); -#ifdef __cplusplus -} -} -} -#endif - /** * \fn competition_is_disabled() - * + * * \return True if the V5 Brain is disabled, false otherwise. - * + * * \b Example * \code * void my_task_fn(void* ignore) { @@ -85,17 +86,17 @@ uint8_t competition_get_status(void); * // Run competition tasks (like Lift Control or similar) * } * } - * + * * void initialize() { * task_t my_task = task_create(my_task_fn, NULL, TASK_PRIO_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "My Task"); * } * \endcode */ -#define competition_is_disabled() ((competition_get_status() & COMPETITION_DISABLED) != 0) +uint8_t competition_is_disabled(void); /** * \return True if the V5 Brain is connected to competition control, false otherwise. - * + * * \b Example * \code * void initialize() { @@ -106,11 +107,11 @@ uint8_t competition_get_status(void); * } * \endcode */ -#define competition_is_connected() ((competition_get_status() & COMPETITION_CONNECTED) != 0) +uint8_t competition_is_connected(void); /** * \return True if the V5 Brain is in autonomous mode, false otherwise. - * + * * \b Example * \code * void my_task_fn(void* ignore) { @@ -122,14 +123,46 @@ uint8_t competition_get_status(void); * // Run whatever code is desired to just execute in autonomous * } * } - * + * * void initialize() { * task_t my_task = task_create(my_task_fn, NULL, TASK_PRIO_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "My Task"); * } * \endcode */ -#define competition_is_autonomous() ((competition_get_status() & COMPETITION_AUTONOMOUS) != 0) +uint8_t competition_is_autonomous(void); + +/** + * \return True if the V5 Brain is connected to VEXnet Field Controller, false otherwise. + * + * \b Example + * \code + * void initialize() { + * if (competition_is_field()) { + * // connected to VEXnet Field Controller + * } + * } + * \endcode + */ +uint8_t competition_is_field(void); +/** + * \return True if the V5 Brain is connected to VEXnet Competition Switch, false otherwise. + * + * \b Example + * \code + * void initialize() { + * if (competition_is_switch()) { + * // connected to VEXnet Competition Switch + * } + * } + */ +uint8_t competition_is_switch(void); + +#ifdef __cplusplus +} +} +} +#endif ///@} /// \name V5 Controller @@ -143,22 +176,23 @@ namespace pros { * \enum */ typedef enum { - ///The master controller. + /// The master controller. E_CONTROLLER_MASTER = 0, - ///The partner controller. - E_CONTROLLER_PARTNER } controller_id_e_t; + /// The partner controller. + E_CONTROLLER_PARTNER +} controller_id_e_t; /** * \enum */ typedef enum { - ///The horizontal axis of the controller’s left analog stick. + /// The horizontal axis of the controller’s left analog stick. E_CONTROLLER_ANALOG_LEFT_X = 0, - ///The vertical axis of the controller’s left analog stick. + /// The vertical axis of the controller’s left analog stick. E_CONTROLLER_ANALOG_LEFT_Y, - ///The horizontal axis of the controller’s right analog stick. + /// The horizontal axis of the controller’s right analog stick. E_CONTROLLER_ANALOG_RIGHT_X, - ///The vertical axis of the controller’s right analog stick. + /// The vertical axis of the controller’s right analog stick. E_CONTROLLER_ANALOG_RIGHT_Y } controller_analog_e_t; @@ -166,30 +200,32 @@ typedef enum { * \enum */ typedef enum { - ///The first trigger on the left side of the controller. + /// The first trigger on the left side of the controller. E_CONTROLLER_DIGITAL_L1 = 6, - ///The second trigger on the left side of the controller. + /// The second trigger on the left side of the controller. E_CONTROLLER_DIGITAL_L2, - ///The first trigger on the right side of the controller. + /// The first trigger on the right side of the controller. E_CONTROLLER_DIGITAL_R1, - ///The second trigger on the right side of the controller. + /// The second trigger on the right side of the controller. E_CONTROLLER_DIGITAL_R2, - ///The up arrow on the left arrow pad of the controller. + /// The up arrow on the left arrow pad of the controller. E_CONTROLLER_DIGITAL_UP, - ///The down arrow on the left arrow pad of the controller. + /// The down arrow on the left arrow pad of the controller. E_CONTROLLER_DIGITAL_DOWN, - ///The left arrow on the left arrow pad of the controller. + /// The left arrow on the left arrow pad of the controller. E_CONTROLLER_DIGITAL_LEFT, - ///The right arrow on the left arrow pad of the controller. + /// The right arrow on the left arrow pad of the controller. E_CONTROLLER_DIGITAL_RIGHT, - ///The ‘X’ button on the right button pad of the controller. + /// The ‘X’ button on the right button pad of the controller. E_CONTROLLER_DIGITAL_X, - ///The ‘B’ button on the right button pad of the controller. + /// The ‘B’ button on the right button pad of the controller. E_CONTROLLER_DIGITAL_B, - ///The ‘Y’ button on the right button pad of the controller. + /// The ‘Y’ button on the right button pad of the controller. E_CONTROLLER_DIGITAL_Y, - ///The ‘A’ button on the right button pad of the controller. - E_CONTROLLER_DIGITAL_A + /// The ‘A’ button on the right button pad of the controller. + E_CONTROLLER_DIGITAL_A, + /// The power button on the front of the controller. + E_CONTROLLER_DIGITAL_POWER } controller_digital_e_t; #ifdef PROS_USE_SIMPLE_NAMES @@ -212,6 +248,7 @@ typedef enum { #define DIGITAL_B pros::E_CONTROLLER_DIGITAL_B #define DIGITAL_Y pros::E_CONTROLLER_DIGITAL_Y #define DIGITAL_A pros::E_CONTROLLER_DIGITAL_A +#define DIGITAL_POWER pros::E_CONTROLLER_DIGITAL_POWER #else #define CONTROLLER_MASTER E_CONTROLLER_MASTER #define CONTROLLER_PARTNER E_CONTROLLER_PARTNER @@ -235,26 +272,27 @@ typedef enum { #endif /** - * \def Given an id and a port, this macro sets the port variable based on the id and allows the mutex to take that port. - * + * \def Given an id and a port, this macro sets the port variable based on the id and allows the mutex to take that + * port. + * * \returns error (in the function/scope it's in) if the controller failed to connect or an invalid id is given. -*/ + */ #define CONTROLLER_PORT_MUTEX_TAKE(id, port) \ - switch (id) { \ - case E_CONTROLLER_MASTER: \ - port = V5_PORT_CONTROLLER_1; \ - break; \ - case E_CONTROLLER_PARTNER: \ - port = V5_PORT_CONTROLLER_2; \ - break; \ - default: \ - errno = EINVAL; \ - return PROS_ERR; \ - } \ - if (!internal_port_mutex_take(port)) { \ - errno = EACCES; \ - return PROS_ERR; \ - } \ + switch (id) { \ + case E_CONTROLLER_MASTER: \ + port = V5_PORT_CONTROLLER_1; \ + break; \ + case E_CONTROLLER_PARTNER: \ + port = V5_PORT_CONTROLLER_2; \ + break; \ + default: \ + errno = EINVAL; \ + return PROS_ERR; \ + } \ + if (!internal_port_mutex_take(port)) { \ + errno = EACCES; \ + return PROS_ERR; \ + } #ifdef __cplusplus namespace c { @@ -274,7 +312,7 @@ namespace c { * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER * * \return 1 if the controller is connected, 0 otherwise - * + * * \b Example * \code * void initialize() { @@ -306,7 +344,7 @@ int32_t controller_is_connected(controller_id_e_t id); * * \return The current reading of the analog channel: [-127, 127]. * If the controller was not connected, then 0 is returned - * + * * \b Example * \code * void opcontrol() { @@ -333,7 +371,7 @@ int32_t controller_get_analog(controller_id_e_t id, controller_analog_e_t channe * Must be one of E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER * * \return The controller's battery capacity - * + * * \b Example * \code * void initialize() { @@ -357,7 +395,7 @@ int32_t controller_get_battery_capacity(controller_id_e_t id); * Must be one of E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER * * \return The controller's battery level - * + * * \b Example * \code * void initialize() { @@ -385,7 +423,7 @@ int32_t controller_get_battery_level(controller_id_e_t id); * * \return 1 if the button on the controller is pressed. * If the controller was not connected, then 0 is returned - * + * * \b Example * \code * void opcontrol() { @@ -430,7 +468,7 @@ int32_t controller_get_digital(controller_id_e_t id, controller_digital_e_t butt * * \return 1 if the button on the controller is pressed and had not been pressed * the last time this function was called, 0 otherwise. - * + * * \b Example * \code * void opcontrol() { @@ -438,7 +476,7 @@ int32_t controller_get_digital(controller_id_e_t id, controller_digital_e_t butt * if (controller_get_digital_new_press(E_CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_A)) { * // Toggle pneumatics or other similar actions * } - * + * * delay(2); * } * } @@ -446,6 +484,45 @@ int32_t controller_get_digital(controller_id_e_t id, controller_digital_e_t butt */ int32_t controller_get_digital_new_press(controller_id_e_t id, controller_digital_e_t button); +/** + * Returns a falling-edge case for a controller button press. + * + * This function is not thread-safe. + * Multiple tasks polling a single button may return different results under + * the same circumstances, so only one task should call this function for any + * given button. E.g., Task A calls this function for buttons 1 and 2. + * Task B may call this function for button 3, but should not for buttons + * 1 or 2. A typical use-case for this function is to call inside opcontrol + * to detect new button releases, and not in any other tasks. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the controller + * port. + * + * \param button + * The button to read. Must be one of + * DIGITAL_{RIGHT,DOWN,LEFT,UP,A,B,Y,X,R1,R2,L1,L2} + * + * \return 1 if the button on the controller is not pressed and had been + * pressed the last time this function was called, 0 otherwise. + * + * \b Example + * \code + * void opcontrol() { + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * while (true) { + * if (master.get_digital_new_release(pros::E_CONTROLLER_DIGITAL_A)) { + * // Toggle pneumatics or other similar actions + * } + * + * delay(2); + * } + * } + * \endcode + */ +int32_t controller_get_digital_new_release(controller_id_e_t id, controller_digital_e_t button); + /** * Sets text to the controller LCD screen. * @@ -473,7 +550,7 @@ int32_t controller_get_digital_new_press(controller_id_e_t id, controller_digita * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * void opcontrol() { @@ -516,7 +593,7 @@ int32_t controller_print(controller_id_e_t id, uint8_t line, uint8_t col, const * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * void opcontrol() { @@ -554,7 +631,7 @@ int32_t controller_set_text(controller_id_e_t id, uint8_t line, uint8_t col, con * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * void opcontrol() { @@ -585,7 +662,7 @@ int32_t controller_clear_line(controller_id_e_t id, uint8_t line); * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * void opcontrol() { @@ -619,7 +696,7 @@ int32_t controller_clear(controller_id_e_t id); * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * void opcontrol() { @@ -645,7 +722,7 @@ int32_t controller_rumble(controller_id_e_t id, const char* rumble_pattern); * EACCES - Another resource is currently trying to access the battery port. * * \return The current voltage of the battery - * + * * \b Example * \code * void initialize() { @@ -663,7 +740,7 @@ int32_t battery_get_voltage(void); * EACCES - Another resource is currently trying to access the battery port. * * \return The current current of the battery - * + * * \b Example * \code * void initialize() { @@ -681,7 +758,7 @@ int32_t battery_get_current(void); * EACCES - Another resource is currently trying to access the battery port. * * \return The current temperature of the battery - * + * * \b Example * \code * void initialize() { @@ -699,7 +776,7 @@ double battery_get_temperature(void); * EACCES - Another resource is currently trying to access the battery port. * * \return The current capacity of the battery - * + * * \b Example * \code * void initialize() { @@ -713,7 +790,7 @@ double battery_get_capacity(void); * Checks if the SD card is installed. * * \return 1 if the SD card is installed, 0 otherwise - * + * * \b Example * \code * void opcontrol() { @@ -723,6 +800,49 @@ double battery_get_capacity(void); */ int32_t usd_is_installed(void); +/** + * Lists the files in a directory specified by the path + * Puts the list of file names (NOT DIRECTORIES) into the buffer seperated by newlines + * + * This function uses the following values of errno when an error state is + * reached: + * + * EIO - Hard error occured in the low level disk I/O layer + * EINVAL - file or directory is invalid, or length is invalid + * EBUSY - THe physical drinve cannot work + * ENOENT - cannot find the path or file + * EINVAL - the path name format is invalid + * EACCES - Access denied or directory full + * EEXIST - Access denied + * EROFS - SD card is write protected + * ENXIO - drive number is invalid or not a FAT32 drive + * ENOBUFS - drive has no work area + * ENFILE - too many open files + * + * + * + * \note use a path of "\" to list the files in the main directory NOT "/usd/" + * DO NOT PREPEND YOUR PATHS WITH "/usd/" + * + * \return 1 on success or PROS_ERR on failure setting errno + * + * \b Example + * \code + * void opcontrol() { + * char* test = (char*) malloc(128); + * pros::c::usd_list_files("/", test, 128); + * pros::delay(200); + * printf("%s\n", test); //Prints the file names in the root directory seperated by newlines + * pros::delay(100); + * pros::c::usd_list_files("/test", test, 128); + * pros::delay(200); + * printf("%s\n", test); //Prints the names of files in the folder named test seperated by newlines + * pros::delay(100); + * } + * \endcode + */ +int32_t usd_list_files(const char* path, char* buffer, int32_t len); + /******************************************************************************/ /** Date and Time **/ /******************************************************************************/ @@ -731,16 +851,16 @@ extern const char* baked_date; extern const char* baked_time; typedef struct { - uint16_t year; // Year - 1980 + uint16_t year; // Year - 1980 uint8_t day; - uint8_t month; // 1 = January + uint8_t month; // 1 = January } date_s_t; typedef struct { uint8_t hour; uint8_t min; uint8_t sec; - uint8_t sec_hund; // hundredths of a second + uint8_t sec_hund; // hundredths of a second } time_s_t; ///@} @@ -749,7 +869,7 @@ typedef struct { #ifdef __cplusplus } -} // namespace pros +} // namespace pros } #endif diff --git a/include/pros/misc.hpp b/include/pros/misc.hpp index 8ade055a..b0a115e4 100644 --- a/include/pros/misc.hpp +++ b/include/pros/misc.hpp @@ -8,13 +8,13 @@ * 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. * All rights reservered. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * + * * \defgroup cpp-misc Miscellaneous C++ API * \note Additional example code for this module can be found in its [Tutorial.](@ref controller) */ @@ -22,11 +22,11 @@ #ifndef _PROS_MISC_HPP_ #define _PROS_MISC_HPP_ -#include "pros/misc.h" - #include #include +#include "pros/misc.h" + namespace pros { inline namespace v5 { /** @@ -56,13 +56,13 @@ class Controller { * port. * * \return 1 if the controller is connected, 0 otherwise - * + * * \b Example * \code * void status_display_controller(){ * pros::Controller master(pros::E_CONTROLLER_MASTER); * if(!master.is_connected()) { - * pros::lcd::print(0, "Main controller is not connected!"); + * pros::lcd::print(0, "Main controller is not connected!"); * } * } * \endcode @@ -84,7 +84,7 @@ class Controller { * * \return The current reading of the analog channel: [-127, 127]. * If the controller was not connected, then 0 is returned - * + * * \b Example * \code * void opcontrol() { @@ -107,7 +107,7 @@ class Controller { * port. * * \return The controller's battery capacity - * + * * \b Example * \code * void initialize() { @@ -127,7 +127,7 @@ class Controller { * port. * * \return The controller's battery level - * + * * \b Example * \code * void initialize() { @@ -153,7 +153,7 @@ class Controller { * * \return 1 if the button on the controller is pressed. * If the controller was not connected, then 0 is returned - * + * * \b Example * \code * void opcontrol() { @@ -194,7 +194,7 @@ class Controller { * * \return 1 if the button on the controller is pressed and had not been * pressed the last time this function was called, 0 otherwise. - * + * * \b Example * \code * void opcontrol() { @@ -203,7 +203,7 @@ class Controller { * if (master.get_digital_new_press(pros::E_CONTROLLER_DIGITAL_A)) { * // Toggle pneumatics or other similar actions * } - * + * * delay(2); * } * } @@ -211,6 +211,45 @@ class Controller { */ std::int32_t get_digital_new_press(controller_digital_e_t button); + /** + * Returns a falling-edge case for a controller button press. + * + * This function is not thread-safe. + * Multiple tasks polling a single button may return different results under + * the same circumstances, so only one task should call this function for any + * given button. E.g., Task A calls this function for buttons 1 and 2. + * Task B may call this function for button 3, but should not for buttons + * 1 or 2. A typical use-case for this function is to call inside opcontrol + * to detect new button releases, and not in any other tasks. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the controller + * port. + * + * \param button + * The button to read. Must be one of + * DIGITAL_{RIGHT,DOWN,LEFT,UP,A,B,Y,X,R1,R2,L1,L2} + * + * \return 1 if the button on the controller is not pressed and had been + * pressed the last time this function was called, 0 otherwise. + * + * \b Example + * \code + * void opcontrol() { + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * while (true) { + * if (master.get_digital_new_release(pros::E_CONTROLLER_DIGITAL_A)) { + * // Toggle pneumatics or other similar actions + * } + * + * delay(2); + * } + * } + * \endcode + */ + std::int32_t get_digital_new_release(controller_digital_e_t button); + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" template @@ -244,7 +283,7 @@ class Controller { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * void opcontrol() { @@ -286,22 +325,22 @@ class Controller { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example - * \code - * void opcontrol() { - * int count = 0; + * \code + * void opcontrol() { + * int count = 0; * pros::Controller master(pros::E_CONTROLLER_MASTER); - * while (true) { - * if (!(count % 25)) { - * // Only print every 50ms, the controller text update rate is slow - * master.set_text(0, 0, "Example text"); - * } - * count++; - * delay(2); - * } - * } - * \endcode + * while (true) { + * if (!(count % 25)) { + * // Only print every 50ms, the controller text update rate is slow + * master.set_text(0, 0, "Example text"); + * } + * count++; + * delay(2); + * } + * } + * \endcode */ std::int32_t set_text(std::uint8_t line, std::uint8_t col, const char* str); std::int32_t set_text(std::uint8_t line, std::uint8_t col, const std::string& str); @@ -322,16 +361,16 @@ class Controller { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example - * \code - * void opcontrol() { - * pros::Controller master(pros::E_CONTROLLER_MASTER); - * master.set_text(0, 0, "Example"); - * delay(100); - * master.clear_line(0); - * } - * \endcode + * \code + * void opcontrol() { + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * master.set_text(0, 0, "Example"); + * delay(100); + * master.clear_line(0); + * } + * \endcode */ std::int32_t clear_line(std::uint8_t line); @@ -353,7 +392,7 @@ class Controller { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * void opcontrol() { @@ -386,7 +425,7 @@ class Controller { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * void opcontrol() { @@ -403,7 +442,7 @@ class Controller { controller_id_e_t _id; ///@} }; -} // namespace v5 +} // namespace v5 namespace battery { /** @@ -418,7 +457,7 @@ namespace battery { * EACCES - Another resource is currently trying to access the battery port. * * \return The current voltage of the battery - * + * * \b Example * \code * void initialize() { @@ -436,7 +475,7 @@ double get_capacity(void); * EACCES - Another resource is currently trying to access the battery port. * * \return The current current of the battery - * + * * \b Example * \code * void initialize() { @@ -454,7 +493,7 @@ int32_t get_current(void); * EACCES - Another resource is currently trying to access the battery port. * * \return The current temperature of the battery - * + * * \b Example * \code * void initialize() { @@ -472,7 +511,7 @@ double get_temperature(void); * EACCES - Another resource is currently trying to access the battery port. * * \return The current capacity of the battery - * + * * \b Example * \code * void initialize() { @@ -490,7 +529,7 @@ namespace competition { * * \return The competition control status as a mask of bits with * COMPETITION_{ENABLED,AUTONOMOUS,CONNECTED}. - * + * * \b Example * \code * void status_display_task(){ @@ -509,6 +548,8 @@ std::uint8_t get_status(void); std::uint8_t is_autonomous(void); std::uint8_t is_connected(void); std::uint8_t is_disabled(void); +std::uint8_t is_field_control(void); +std::uint8_t is_competition_switch(void); } // namespace competition namespace usd { @@ -516,7 +557,7 @@ namespace usd { * Checks if the SD card is installed. * * \return 1 if the SD card is installed, 0 otherwise - * + * * \b Example * \code * void opcontrol() { @@ -525,6 +566,49 @@ namespace usd { * \endcode */ std::int32_t is_installed(void); +/** + * Lists the files in a directory specified by the path + * Puts the list of file names (NOT DIRECTORIES) into the buffer seperated by newlines + * + * This function uses the following values of errno when an error state is + * reached: + * + * EIO - Hard error occured in the low level disk I/O layer + * EINVAL - file or directory is invalid, or length is invalid + * EBUSY - THe physical drinve cannot work + * ENOENT - cannot find the path or file + * EINVAL - the path name format is invalid + * EACCES - Access denied or directory full + * EEXIST - Access denied + * EROFS - SD card is write protected + * ENXIO - drive number is invalid or not a FAT32 drive + * ENOBUFS - drive has no work area + * ENFILE - too many open files + * + * + * + * \note use a path of "\" to list the files in the main directory NOT "/usd/" + * DO NOT PREPEND YOUR PATHS WITH "/usd/" + * + * \return 1 on success or PROS_ERR on failure setting errno + * + * \b Example + * \code + * void opcontrol() { + * char* test = (char*) malloc(128); + * pros::usd::list_files("/", test, 128); + * pros::delay(200); + * printf("%s\n", test); //Prints the file names in the root directory seperated by newlines + * pros::delay(100); + * pros::list_files("/test", test, 128); + * pros::delay(200); + * printf("%s\n", test); //Prints the names of files in the folder named test seperated by newlines + * pros::delay(100); + * } + * \endcode + */ + +std::int32_t list_files(const char* path, char* buffer, std::int32_t len); } // namespace usd } // namespace pros diff --git a/include/pros/motor_group.hpp b/include/pros/motor_group.hpp index f99576e0..c9a4a1a0 100644 --- a/include/pros/motor_group.hpp +++ b/include/pros/motor_group.hpp @@ -10,13 +10,14 @@ * 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-motor-group Motor Groups C++ API + * \defgroup cpp-motor-group Motors C++ API + * \note Additional example code for this module can be found in its [Tutorial](@ref motors). */ #ifndef _PROS_MOTOR_GROUP_HPP_ @@ -40,143 +41,112 @@ class MotorGroup : public virtual AbstractMotor { * @{ */ public: - /** * Constructs a new MotorGroup object. - * + * * 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 motor - * + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * * \param port - * A initializer list of V5 port numbers from 1 to 21, or from -21 to -1 for reversed motors. + * A initializer list of V5 port numbers from 1 to 21, or from -21 to -1 for reversed motors. * A reversed motor will reverse the input or output movement functions and movement related * telemetry in order to produce consistant behavior with non-reversed motors - * - * \param gearset = pros::v5::MotorGears::green + * + * \param gearset = pros::v5::MotorGears::invalid * Optional parameter for the gearset for the motor. - * set to pros::v5::MotorGears::green if not specifed. - * - * \param encoder_units = pros::v5::MotorUnits::degrees + * Does not explicitly set the motor gearset if it is invalid or not specified + * + * \param encoder_units = pros::v5::MotorUnits::invalid * Optional parameter for the encoder units of the motor - * set to pros::v5::MotorUnits::degrees if not specified by the user - * + * Does not explicitly set the motor units if it is invalid or not specified + * * \b Example - * \code - * void opcontrol() { - * MotorGroup first_mg({1, -2}); //Creates a motor on port 1 and a reversed motor on port 2 with - * with both motors using the green gearset and degrees as the encoder units + * \code + * void opcontrol() { + * MotorGroup first_mg({1, -2}); //Creates a motor on port 1 and a reversed motor on port 2 * MotorGroup rotations_mg({4, 5}, pros::v5::MotorGears::blue, pros::v5::MotorUnits::rotations); - * //Creates a motor group on ports 4 and 5 with blue motors using rotaions as the encoder units - * } + * //Creates a motor group on ports 4 and 5 with blue motors using rotaions as the encoder units + * } * \endcode */ - explicit MotorGroup(const std::initializer_list, const pros::v5::MotorGears gearset = pros::v5::MotorGears::green, - const pros::v5::MotorUnits encoder_units = pros::v5::MotorUnits::degrees); + MotorGroup(const std::initializer_list, + const pros::v5::MotorGears gearset = pros::v5::MotorGears::invalid, + const pros::v5::MotorUnits encoder_units = pros::v5::MotorUnits::invalid); /** * Constructs a new MotorGroup object. - * + * * This function uses the following values of errno when an error state is - * reached: - * + * reached: + * * ENXIO - The given value is not within the range of V5 ports |1-21|. - * + * * ENODEV - The port cannot be configured as a motor - * + * * EDOM - The motor group is empty - * + * * \param port - * A initializer list of V5 port numbers from 1 to 21, or from -21 to -1 for reversed motors. + * A initializer list of V5 port numbers from 1 to 21, or from -21 to -1 for reversed motors. * A reversed motor will reverse the input or output movement functions and movement related * telemetry in order to produce consistant behavior with non-reversed motors - * - * \param gearset = pros::v5::MotorGears::green + * + * \param gearset = pros::v5::MotorGears::invalid + * \param gearset = pros::v5::MotorGears::green * Optional parameter for the gearset for the motor. - * set to pros::v5::MotorGears::green if not specifed. - * - * \param encoder_units = pros::v5::MotorUnits::degrees + * Does not explicitly set the motor gearset if it is invalid or not specified + * + * \param encoder_units = pros::v5::MotorUnits::invalid * Optional parameter for the encoder units of the motor - * set to pros::v5::MotorUnits::degrees if not specified by the user - * + * Does not explicitly set the motor units if it is invalid or not specified + * * \b Example - * \code - * void opcontrol() { - * MotorGroup first_mg({1, -2}); //Creates a motor on port 1 and a reversed motor on port 2 with + * \code + * void opcontrol() { + * MotorGroup first_mg({1, -2}); //Creates a motor on port 1 and a reversed motor on port 2 with * with both motors using the green gearset and degrees as the encoder units * MotorGroup rotations_mg({4, 5}, pros::v5::MotorGears::blue, pros::v5::MotorUnits::rotations); - * //Creates a motor group on ports 4 and 5 with blue motors using rotaions as the encoder units - * } + * //Creates a motor group on ports 4 and 5 with blue motors using rotaions as the encoder units + * } * \endcode */ - explicit MotorGroup(const std::vector& ports, const pros::v5::MotorGears gearset = pros::v5::MotorGears::green, - const pros::v5::MotorUnits encoder_units = pros::v5::MotorUnits::degrees); + MotorGroup(const std::vector& ports, const pros::v5::MotorGears gearset = pros::v5::MotorGears::invalid, + const pros::v5::MotorUnits encoder_units = pros::v5::MotorUnits::invalid); - /** + /** * Constructs a new MotorGroup object from an abstract motor. - * + * * This function uses the following values of errno when an error state is - * reached: - * + * reached: + * * ENXIO - The given value is not within the range of V5 ports |1-21|. - * + * * ENODEV - The port cannot be configured as a motor - * + * * EDOM - The motor group is empty - * + * * \param abstract_motor - * THe abstract motor to turn into a motor group + * The abstract motor to turn into a motor group * Uses abstract_motor.get_port_all() to get the vector of ports - * - * + * + * * \b Example - * \code - * void opcontrol() { - * MotorGroup first_mg({1, -2}); //Creates a motor on port 1 and a reversed motor on port 2 with + * \code + * void opcontrol() { + * MotorGroup first_mg({1, -2}); //Creates a motor on port 1 and a reversed motor on port 2 with * with both motors using the green gearset and degrees as the encoder units * AbstractMotor abs_mtr_group = first_mg; * MotorGroup new_mg = (MotorGroup) abs_mtr_group; - * } + * } * \endcode */ - - MotorGroup(AbstractMotor& abstract_motor); + + MotorGroup(AbstractMotor& motor_group); + /// \name Motor movement functions /// These functions allow programmers to make motors move ///@{ - /** - * Sets the voltage for the motor group from -128 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 - * EDOM - the motor group is empty - * - * \param voltage - * The new voltage from -127 to 127 - * - * \return 1 if the operation was successful or PROS_ERR if the operation - * failed, setting errno. - * - * \b Example - * \code - * void opcontrol() { - * pros::MotorGroup MotorGroup ({1,3}, E_MOTOR_GEARSET_18); - * pros::Controller master (E_CONTROLLER_MASTER); - * while (true) { - * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); - * pros::delay(2); - * } - * } - * \endcode - */ - std::int32_t operator=(std::int32_t voltage) const; - /** * Sets the voltage for the motor group from -127 to 127. * @@ -354,10 +324,9 @@ class MotorGroup : public virtual AbstractMotor { */ std::int32_t move_voltage(const std::int32_t voltage) const; - /** * Stops the motor group using the currently configured brake mode. - * + * * This function sets motor velocity to zero, which will cause it to act * according to the set brake mode. If brake mode is set to MOTOR_BRAKE_HOLD, * this function may behave differently than calling move_absolute(0) @@ -366,22 +335,22 @@ class MotorGroup : public virtual AbstractMotor { * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor - * + * * EDOM - The motor group is empty - * - * \return 1 if the operation was successful or PROS_ERR if the operation - * failed, setting errno. - * - * \b Example - * \code - * void autonomous() { - * Motor motor(1); - * mg.move_voltage(12000); - * pros::delay(1000); // Move at max voltage for 1 second - * motor.brake(); - * } - * \endcode - */ + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * Motor motor(1); + * mg.move_voltage(12000); + * pros::delay(1000); // Move at max voltage for 1 second + * motor.brake(); + * } + * \endcode + */ std::int32_t brake(void) const; /** @@ -400,7 +369,7 @@ class MotorGroup : public virtual AbstractMotor { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * void autonomous() { @@ -412,7 +381,7 @@ class MotorGroup : public virtual AbstractMotor { * \endcode */ std::int32_t modify_profiled_velocity(const std::int32_t velocity) const; - + /** * Gets the target position set for a motor in the motor group, with a parameter * for the motor index. @@ -422,7 +391,7 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group @@ -441,7 +410,7 @@ class MotorGroup : public virtual AbstractMotor { * } * \endcode */ - double get_target_position(const std::uint8_t index = 0) const; + double get_target_position(const std::uint8_t index) const; /** * Gets a vector of the the target positions set for the motor group @@ -468,16 +437,16 @@ class MotorGroup : public virtual AbstractMotor { /** * Gets the velocity commanded to the motor by the user at the index specified. - * + * * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor * EOVERFLOW - The index is greater than or equal to MotorGroup::size() * EDOM - The motor group was empty - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero indexed index of the motor in the motor group - * + * * \return The commanded motor velocity from +-100, +-200, or +-600, or * PROS_ERR if the operation failed, setting errno. * @@ -489,7 +458,7 @@ class MotorGroup : public virtual AbstractMotor { * while (true) { * mg.move_velocity(master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y)); * // get the target velocity from motor at index 1. (port 3) - * std::cout << "Motor Velocity: " << mg.get_target_velocity(1); + * std::cout << "Motor Velocity: " << mg.get_target_velocity(1); * pros::delay(2); * } * } @@ -499,12 +468,12 @@ class MotorGroup : public virtual AbstractMotor { /** * Gets a vector of the velocity commanded to the motor by the user - * + * * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor * EDOM - THe motor group is empty - * + * * \return A vector of the commanded motor velocity from +-100, +-200, or +-600, or * PROS_ERR if the operation failed, setting errno. * @@ -515,7 +484,7 @@ class MotorGroup : public virtual AbstractMotor { * pros::Controller master (E_CONTROLLER_MASTER); * while (true) { * mg.move_velocity(master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y)); - * std::cout << "Motor Velocity: " << mg.get_target_velocity_all(); + * std::cout << "Motor Velocity: " << mg.get_target_velocity_all(); * pros::delay(2); * } * } @@ -535,13 +504,13 @@ class MotorGroup : public virtual AbstractMotor { * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor - * + * * EDOM - THe motor group is empty * * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * - * \param index Optional parameter. - * The zero indexed index of the motor in the motor group + * + * \param index Optional parameter. + * The zero indexed index of the motor in the motor group * * \return The motor's actual velocity in RPM or PROS_ERR_F if the operation * failed, setting errno. @@ -560,14 +529,14 @@ class MotorGroup : public virtual AbstractMotor { * \endcode */ double get_actual_velocity(const std::uint8_t index = 0) const; - + /** * Gets a vector of the the actual velocity of each motor the motor group. * * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor - * + * * EDOM - THe motor group is empty * * \return A vector of the each motor's actual velocity in RPM or PROS_ERR_F if the operation @@ -594,13 +563,13 @@ class MotorGroup : public virtual AbstractMotor { * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor - * + * * EDOM - The motor group is empty * * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * - * \param index Optional parameter. - * The zero indexed index of the motor in the motor group + * + * \param index Optional parameter. + * The zero indexed index of the motor in the motor group * * \return The motor's current in mA or PROS_ERR if the operation failed, * setting errno. @@ -626,7 +595,7 @@ class MotorGroup : public virtual AbstractMotor { * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor - * + * * EDOM - The motor group is empty * * @@ -654,14 +623,14 @@ class MotorGroup : public virtual AbstractMotor { * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor - * + * * EDOM - The motor group is empty - * + * * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * + * * \return 1 for moving in the positive direction, -1 for moving in the * negative direction, and PROS_ERR if the operation failed, setting errno. * @@ -688,7 +657,7 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * * EDOM - The motor group is empty - * + * * \return 1 for moving in the positive direction, -1 for moving in the * negative direction, and PROS_ERR if the operation failed, setting errno. * @@ -717,12 +686,12 @@ class MotorGroup : public virtual AbstractMotor { * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor - * + * * EDOM - The motor group is empty - * + * * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * - * + * + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group * @@ -754,7 +723,7 @@ class MotorGroup : public virtual AbstractMotor { * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor - * + * * EDOM - THe motor group is empty * * \return A vector containing each motor's efficiency in percent or PROS_ERR_F if the operation @@ -783,9 +752,9 @@ class MotorGroup : public virtual AbstractMotor { * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor - * + * * EDOM - The motor group is empty - * + * * EOVERFLOW - The index is greater than or equal to MotorGroup::size() * * \param index Optional parameter, 0 by default. @@ -815,9 +784,9 @@ class MotorGroup : public virtual AbstractMotor { * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor - * + * * EDOM - The motor group is empty - * + * * * \return A vector containing the bitfields containing each motor's faults. * @@ -865,7 +834,7 @@ class MotorGroup : public virtual AbstractMotor { * \endcode */ std::uint32_t get_flags(const std::uint8_t index = 0) const; - + /** * Gets a vector of the flags set by each motor in the motor groups's operation. * @@ -901,7 +870,7 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group * @@ -949,14 +918,14 @@ class MotorGroup : public virtual AbstractMotor { std::vector get_position_all(void) const; /** - * Gets the power drawn by a motor in the motor group in Watts. + * Gets the power drawn by a motor in the motor group in Watts. * * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group * @@ -1010,13 +979,13 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * - * + * + * * \param timestamp * A pointer to a time in milliseconds for which the encoder count * will be returned. If NULL, the timestamp at which the encoder * count was read will not be supplied - * + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group * @@ -1080,7 +1049,7 @@ class MotorGroup : public virtual AbstractMotor { * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * + * * \return The motor's temperature in degrees Celsius or PROS_ERR_F if the * operation failed, setting errno. * @@ -1099,7 +1068,7 @@ class MotorGroup : public virtual AbstractMotor { */ double get_temperature(const std::uint8_t index = 0) const; /** - * Gets the temperature of each motor in the motor group in degrees Celsius. + * Gets the temperature of each motor in the motor group in degrees Celsius. * * This function uses the following values of errno when an error state is * reached: @@ -1134,7 +1103,7 @@ class MotorGroup : public virtual AbstractMotor { * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * + * * \return The motor's torque in Nm or PROS_ERR_F if the operation failed, * setting errno. * @@ -1185,10 +1154,10 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * + * * \return The motor's voltage in mV or PROS_ERR_F if the operation failed, * setting errno. * @@ -1240,10 +1209,10 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * + * * \return 1 if the motor's current limit is being exceeded and 0 if the * current limit is not exceeded, or PROS_ERR if the operation failed, setting * errno. @@ -1270,9 +1239,8 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * - * \return A vector containing the following for each motor: 1 if the motor's current limit is being exceeded and 0 if the - * current limit is not exceeded, or PROS_ERR if the operation failed, setting - * errno. + * \return A vector containing the following for each motor: 1 if the motor's current limit is being exceeded and 0 if + * the current limit is not exceeded, or PROS_ERR if the operation failed, setting errno. * * \b Example * \code @@ -1297,7 +1265,7 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group * @@ -1358,11 +1326,11 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group * - * \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. * * \b Example @@ -1383,7 +1351,7 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * - * \return A vector with one of Motor_Brake for each motor in the motor group, according to what was set for the + * \return A vector with one of MotorBrake for each motor in the motor group, according to what was set for the * motor, or E_MOTOR_BRAKE_INVALID if the operation failed, setting errno. * * \b Example @@ -1407,7 +1375,7 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group * @@ -1426,7 +1394,7 @@ class MotorGroup : public virtual AbstractMotor { * \endcode */ std::int32_t get_current_limit(const std::uint8_t index = 0) const; - + /** * Gets a vector of the current limit for each motor in the motor group in mA. * @@ -1461,11 +1429,11 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * - * \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. * * \b Example @@ -1477,7 +1445,7 @@ class MotorGroup : public virtual AbstractMotor { * \endcode */ MotorUnits get_encoder_units(const std::uint8_t index = 0) const; - + /** * Gets a vector of the encoder units that were set for each motor in the motor group. * @@ -1486,7 +1454,7 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * - * \return A vector with the following for each motor, One of Motor_Units according to what is set for the + * \return A vector with the following for each motor, One of MotorUnits according to what is set for the * motor or E_MOTOR_ENCODER_INVALID if the operation failed. * * \b Example @@ -1507,12 +1475,12 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * *\param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * - * \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. * * \b Example * \code @@ -1531,9 +1499,9 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * - * - * \return A vector with one of Motor_Gears according to what is set for the motor, - * or pros::Motor_Gears::invalid if the operation failed for each motor. + * + * \return A vector with one of MotorGears according to what is set for the motor, + * or pros::MotorGears::invalid if the operation failed for each motor. * * \b Example * \code @@ -1548,7 +1516,7 @@ class MotorGroup : public virtual AbstractMotor { /** * Gets a vector with all the port numbers in the motor group. * A port will be negative if the motor in the motor group is reversed - * + * * @return a vector with all the port numbers for the motor group */ std::vector get_port_all(void) const; @@ -1564,7 +1532,7 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * *\param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group * @@ -1582,7 +1550,7 @@ class MotorGroup : public virtual AbstractMotor { std::int32_t get_voltage_limit(const std::uint8_t index = 0) const; /** - * Gets a vector of the voltage limit of each motor in the motor group + * Gets a vector of the voltage limit of each motor in the motor group * * Default value is 0V, which means that there is no software limitation * imposed on the voltage. @@ -1610,10 +1578,10 @@ class MotorGroup : public virtual AbstractMotor { * * This function uses the following values of errno when an error state is * reached: - * + * * EDOM - The motor group is empty * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * *\param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group * @@ -1637,8 +1605,8 @@ class MotorGroup : public virtual AbstractMotor { * reached: * EDOM - The motor group is empty * - * \return A vector conatining the following for each motor: 1 if the motor has been reversed and 0 if the motor was not - * reversed, or PROS_ERR if the operation failed, setting errno. + * \return A vector conatining the following for each motor: 1 if the motor has been reversed and 0 if the motor was + * not reversed, or PROS_ERR if the operation failed, setting errno. * * \b Example * \code @@ -1652,7 +1620,52 @@ class MotorGroup : public virtual AbstractMotor { std::vector is_reversed_all(void) const; /** - * Sets one of Motor_Brake to a motor in the motor group. Works with the C enum + * Gets the type of a motor in the motor group. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + *\param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return One of MotorType according to the type of the motor, + * or pros::MotorType::invalid if the operation failed. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg ({1,3}, E_MOTOR_GEARSET_06, false, E_MOTOR_ENCODER_COUNTS); + * std::cout << "Motor Type: " << mg.get_type(); + * } + * \endcode + */ + MotorType get_type(const std::uint8_t index = 0) const; + /** + * Gets a vector of the type of each motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \return A vector with one of MotorType according to the type of the motor, + * or pros::MotorType::invalid if the operation failed for each motor. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg ({1,3}, E_MOTOR_GEARSET_06, false, E_MOTOR_ENCODER_COUNTS); + * std::cout << "Motor Type: " << mg.get_type_all()[0]; + * } + * \endcode + */ + std::vector get_type_all(void) const; + + /** + * Sets one of MotorBrake to a motor in the motor group. Works with the C enum * and the C++ enum class. * * This function uses the following values of errno when an error state is @@ -1660,13 +1673,13 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * * \param mode - * The Motor_Brake to set for the motor - * + * The MotorBrake to set for the motor + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * + * * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. @@ -1682,7 +1695,7 @@ class MotorGroup : public virtual AbstractMotor { */ std::int32_t set_brake_mode(const MotorBrake mode, const std::uint8_t index = 0) const; /** - * Sets one of Motor_Brake to a motor in the motor group. Works with the C enum + * Sets one of MotorBrake to a motor in the motor group. Works with the C enum * and the C++ enum class. * * This function uses the following values of errno when an error state is @@ -1690,13 +1703,13 @@ class MotorGroup : public virtual AbstractMotor { * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * * \param mode - * The Motor_Brake to set for the motor - * + * The MotorBrake to set for the motor + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * + * * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. @@ -1712,17 +1725,17 @@ class MotorGroup : public virtual AbstractMotor { */ std::int32_t set_brake_mode(const pros::motor_brake_mode_e_t mode, const std::uint8_t index = 0) const; /** - * Sets one of Motor_Brake all the motors in the motor group. Works with the C enum + * Sets one of MotorBrake all the motors in the motor group. Works with the C enum * and the C++ enum class. * * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty - * + * * \param mode - * The Motor_Brake to set for the motor - * + * The MotorBrake to set for the motor + * * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. @@ -1738,18 +1751,18 @@ class MotorGroup : public virtual AbstractMotor { */ std::int32_t set_brake_mode_all(const MotorBrake mode) const; /** - * Sets one of Motor_Brake to a motor in the motor group. Works with the C enum + * Sets one of MotorBrake to a motor in the motor group. Works with the C enum * and the C++ enum class. * * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty - * + * * \param mode - * The Motor_Brake to set for the motor + * The MotorBrake to set for the motor + * * - * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. * @@ -1774,11 +1787,11 @@ class MotorGroup : public virtual AbstractMotor { * * \param limit * The new current limit in mA - * + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * - * + * + * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. * @@ -1829,20 +1842,20 @@ class MotorGroup : public virtual AbstractMotor { */ std::int32_t set_current_limit_all(const std::int32_t limit) const; /** - * Sets one of Motor_Units for one motor in the motor group's motor encoder. Works with the C + * Sets one of MotorUnits for one motor in the motor group's 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 * reached: * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty - * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() * * \param units * The new motor encoder units * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * + * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. * @@ -1857,20 +1870,20 @@ class MotorGroup : public virtual AbstractMotor { */ std::int32_t set_encoder_units(const MotorUnits units, const std::uint8_t index = 0) const; /** - * Sets one of Motor_Units for one motor in the motor group's motor encoder. Works with the C + * Sets one of MotorUnits for one motor in the motor group's 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 * reached: * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty - * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() * * \param units * The new motor encoder units * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * + * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. * @@ -1885,17 +1898,17 @@ class MotorGroup : public virtual AbstractMotor { */ std::int32_t set_encoder_units(const pros::motor_encoder_units_e_t units, const std::uint8_t index = 0) const; /** - * Sets one of Motor_Units for every motor in the motor group's motor encoder. Works with the C + * Sets one of MotorUnits for every motor in the motor group's 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 * reached: * ENODEV - The port cannot be configured as a motor - * EDOM - The motor group is empty + * EDOM - The motor group is empty * * \param units * The new motor encoder units - * + * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. * @@ -1910,17 +1923,17 @@ class MotorGroup : public virtual AbstractMotor { */ std::int32_t set_encoder_units_all(const MotorUnits units) const; /** - * Sets one of Motor_Units for every motor in the motor group's motor encoder. Works with the C + * Sets one of MotorUnits for every motor in the motor group's 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 * reached: * ENODEV - The port cannot be configured as a motor - * EDOM - The motor group is empty + * EDOM - The motor group is empty * * \param units * The new motor encoder units - * + * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. * @@ -1934,6 +1947,7 @@ class MotorGroup : public virtual AbstractMotor { * \endcode */ std::int32_t set_encoder_units_all(const pros::motor_encoder_units_e_t units) const; + /** * Sets one of the gear cartridge (red, green, blue) for one motor in the motor group. Usable with * the C++ enum class and the C enum. @@ -1942,14 +1956,20 @@ class MotorGroup : public virtual AbstractMotor { * reached: * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty - * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * E2BIG - The size of the vector mismatches the number of motors in the motor group + * + * \note If there are more motors than gearsets passed in, + * only the first n motors will have their gearsets changed where n is the number of gearsets passed in. + * If there are more gearsets passed in than motors, then the only the first m gearsets will be used, + * where m is the number of motors. In either case, errno will be set to E2BIG, but the operation still occurs + * * * \param gearset * The new geatset of the motor - * + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * + * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. * @@ -1962,7 +1982,7 @@ class MotorGroup : public virtual AbstractMotor { * } * \endcode */ - std::int32_t set_gearing(const MotorGears gearset, const std::uint8_t index = 0) const; + std::int32_t set_gearing(std::vector gearsets) const; /** * Sets one of the gear cartridge (red, green, blue) for one motor in the motor group. Usable with * the C++ enum class and the C enum. @@ -1971,14 +1991,14 @@ class MotorGroup : public virtual AbstractMotor { * reached: * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty - * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() * * \param gearset * The new geatset of the motor - * + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * + * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. * @@ -1992,6 +2012,39 @@ class MotorGroup : public virtual AbstractMotor { * \endcode */ std::int32_t set_gearing(const pros::motor_gearset_e_t gearset, const std::uint8_t index = 0) const; + + /** + * Sets the gear cartridge (red, green, blue) for each motor in the motor group by taking in a vector of the + * cartridges. Usable with the C++ enum class and the C enum. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * E2BIG - The size of the vector mismatches the number of motors in the motor group + * + * \note If there are more motors than gearsets passed in, + * only the first n motors will have their gearsets changed where n is the number of gearsets passed in. + * If there are more gearsets passed in than motors, then the only the first m gearsets will be used, + * where m is the number of motors. In either case, errno will be set to E2BIG, but the operation still occurs + * + * \param gearset + * The a vector containing the new geatsets of the motors + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_gearing(pros::MotorGears::blue, 1); + * std::cout << "Gearset: " << mg.get_gearing(); + * } + * \endcode + */ + std::int32_t set_gearing(std::vector gearsets) const; + /** * Sets one of the gear cartridge (red, green, blue) for one motor in the motor group. Usable with * the C++ enum class and the C enum. @@ -2000,10 +2053,39 @@ class MotorGroup : public virtual AbstractMotor { * reached: * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() * * \param gearset * The new geatset of the motor - * + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_gearing(E_MOTOR_GEARSET_06, 1); + * std::cout << "Gearset: " << mg.get_gearing(); + * } + * \endcode + */ + std::int32_t set_gearing(const MotorGears gearset, const std::uint8_t index = 0) const; + /** + * Sets one of the gear cartridge (red, green, blue) for one motor in the motor group. Usable with + * the C++ enum class and the C enum. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \param gearset + * The new geatset of the motor + * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. * @@ -2028,7 +2110,7 @@ class MotorGroup : public virtual AbstractMotor { * * \param gearset * The new geatset of the motor - * + * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. * @@ -2051,8 +2133,8 @@ class MotorGroup : public virtual AbstractMotor { * This function uses the following values of errno when an error state is * reached: * EDOM - The motor group is empty - * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * * \param reverse * True reverses the motor, false is default * @@ -2082,7 +2164,7 @@ class MotorGroup : public virtual AbstractMotor { * This function uses the following values of errno when an error state is * reached: * EDOM - The motor group is empty - * + * * \param reverse * True reverses the motor, false is default * @@ -2107,11 +2189,11 @@ class MotorGroup : public virtual AbstractMotor { * reached: * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty - * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() * * \param limit * The new voltage limit in Volts - * + * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group * @@ -2176,8 +2258,8 @@ class MotorGroup : public virtual AbstractMotor { * reached: * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty - * EOVERFLOW - The index is greater than or equal to MotorGroup::size() - * + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * * \param position * The new reference position in its encoder units * \param index Optional parameter, 0 by default. @@ -2194,7 +2276,7 @@ class MotorGroup : public virtual AbstractMotor { * mg.move_absolute(100, 100); // This does not cause a movement * mg.set_zero_position(80); * mg.set_zero_position(80, 1); - * mg.move_absolute(100, 100); // Moves 80 units forward + * mg.move_absolute(100, 100); // Moves 20 units forward * } * \endcode * @@ -2225,7 +2307,7 @@ class MotorGroup : public virtual AbstractMotor { * mg.move_absolute(100, 100); // This does not cause a movement * * mg.set_zero_position_all(80); - * mg.move_absolute(100, 100); // Moves 80 units forward + * mg.move_absolute(100, 100); // Moves 20 units forward * } * \endcode * @@ -2239,11 +2321,11 @@ class MotorGroup : public virtual AbstractMotor { * reached: * ENODEV - The port cannot be configured as a motor * EDOM - The motor group is empty - * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() * * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * + * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. * @@ -2255,14 +2337,14 @@ class MotorGroup : public virtual AbstractMotor { * mg.move_absolute(100, 100); // This does not cause a movement * * mg.tare_position(); - * mg.tare_position(1); - * + * mg.tare_position(1); + * * mg.move_absolute(100, 100); // Moves 100 units forward * } * \endcode */ std::int32_t tare_position(const std::uint8_t index = 0) const; - + /** * Sets the "absolute" zero position of every motor in the motor group to its current position. * @@ -2294,37 +2376,37 @@ class MotorGroup : public virtual AbstractMotor { std::int8_t size(void) const; /** - * Gets the port of a motor in the motor group - * - * * \param index Optional parameter, 0 by default. + * Gets the port of a motor in the motor group via index + * + * \param index Optional parameter, 0 by default. * The zero indexed index of the motor in the motor group - * - * \return The port of the motor at the specified index. + * + * \return The port of the motor at the specified index. * The return value is negative if the corresponding motor is reversed - */ + */ std::int8_t get_port(const std::uint8_t index = 0) const; /** * Appends all the motors in the other motor group reference to this motor group - * + * * Maintains the order of the other motor group * */ - void operator+=(MotorGroup&); + void operator+=(AbstractMotor&); /** * Appends all the motors in the other motor group reference to this motor group - * + * * Maintains the order of the other motor group * */ - void append(MotorGroup&); + void append(AbstractMotor&); /** * Removes the all motors on the port (regardless of reversal) from the motor group * * \param port The port to remove from the motor group - * + * */ void erase_port(std::int8_t port); @@ -2332,7 +2414,7 @@ class MotorGroup : public virtual AbstractMotor { private: /** * The ordered vector of ports used by the motor group - */ + */ std::vector _ports; mutable pros::Mutex _MotorGroup_mutex; }; diff --git a/include/pros/motors.h b/include/pros/motors.h index ad6ef34a..3c99f03b 100644 --- a/include/pros/motors.h +++ b/include/pros/motors.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 @@ -241,7 +241,7 @@ int32_t motor_move_relative(int8_t port, double position, const int32_t velocity int32_t motor_move_velocity(int8_t port, const int32_t velocity); /** - * Sets the output voltage for the motor from -12000 to 12000 in millivolts + * Sets the output voltage for the motor from -12000 to 12000 in millivolts. * * \note A negative port negates the voltage * @@ -900,6 +900,16 @@ typedef enum motor_gearset_e { E_MOTOR_GEARSET_INVALID = INT32_MAX, // Error: Invalid Gearset } motor_gearset_e_t; +/** + * \enum motor_type_e_t + * Indicates the type of a motor + */ +typedef enum motor_type_e { + E_MOTOR_TYPE_V5 = 0, // 11 watt V5 motor + E_MOTOR_TYPE_EXP = 1, // 5.5 watt EXP motor + E_MOTOR_TYPE_INVALID = INT32_MAX, // Error: invalid type +} motor_type_e_t; + #ifdef PROS_USE_SIMPLE_NAMES #ifdef __cplusplus #define MOTOR_BRAKE_COAST pros::E_MOTOR_BRAKE_COAST @@ -921,6 +931,9 @@ typedef enum motor_gearset_e { #define MOTOR_GEAR_BLUE pros::E_MOTOR_GEAR_BLUE #define MOTOR_GEAR_600 pros::E_MOTOR_GEAR_600 #define MOTOR_GEARSET_INVALID pros::E_MOTOR_GEARSET_INVALID +#define MOTOR_TYPE_V5 pros::E_MOTOR_TYPE_V5 +#define MOTOR_TYPE_EXP pros::E_MOTOR_TYPE_EXP +#define MOTOR_TYPE_INVALID pros::E_MOTOR_TYPE_INVALID #else #define MOTOR_BRAKE_COAST E_MOTOR_BRAKE_COAST #define MOTOR_BRAKE_BRAKE E_MOTOR_BRAKE_BRAKE @@ -941,6 +954,9 @@ typedef enum motor_gearset_e { #define MOTOR_GEAR_BLUE E_MOTOR_GEAR_BLUE #define MOTOR_GEAR_600 E_MOTOR_GEAR_600 #define MOTOR_GEARSET_INVALID E_MOTOR_GEARSET_INVALID +#define MOTOR_TYPE_V5 E_MOTOR_TYPE_V5 +#define MOTOR_TYPE_EXP E_MOTOR_TYPE_EXP +#define MOTOR_TYPE_INVALID E_MOTOR_TYPE_INVALID #endif #endif @@ -1027,7 +1043,7 @@ namespace c { * } * * motor_set_zero_position(1, 80); - * motor_move_absolute(1, 100, 100); // Moves 80 units forward + * motor_move_absolute(1, 100, 100); // Moves 20 units forward * while (!((motor_get_position(1) - 100 < 105) && (motor_get_position(1) - 100 > 95))) { * delay(2); * } @@ -1328,6 +1344,30 @@ motor_gearset_e_t motor_get_gearing(int8_t port); */ int32_t motor_get_voltage_limit(int8_t port); +/** + * Get the type of the motor + * + * 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 motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return One of motor_type_e_t according to the type of the motor, or + * E_MOTOR_TYPE_INVALID if the operation failed. + * + * \b Example + * \code + * void initialize() { + * printf("Motor Type: %d\n", motor_get_type(1)); + * // Prints the type of the motor + * } + * \endcode + */ +motor_type_e_t motor_get_type(int8_t port); + ///@} ///@} diff --git a/include/pros/motors.hpp b/include/pros/motors.hpp index f0de7ebc..6556aada 100644 --- a/include/pros/motors.hpp +++ b/include/pros/motors.hpp @@ -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 @@ -40,102 +40,45 @@ class Motor : public AbstractMotor, public Device { /** * Constructs a new Motor object. - * + * * 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 motor - * + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * * \param port - * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors. + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors. * A reversed motor will reverse the input or output movement functions and movement related * telemetry in order to produce consistant behavior with non-reversed motors - * - * \param gearset = pros::v5::MotorGears::green + * + * \param gearset = pros::v5::MotorGears::green * Optional parameter for the gearset for the motor. - * set to pros::v5::MotorGears::green if not specifed. - * + * Does not explicitly set the gearset if not specified or if the gearset is invalid + * * \param encoder_units = pros::v5::MotorUnits::degrees * Optional parameter for the encoder units of the motor - * set to pros::v5::MotorUnits::degrees if not specified by the user - * - * \b Example - * \code - * void opcontrol() { - * Motor first_motor(1); //Creates a motor on port 1 with green gearset and degrees as the encoder units - * Motor reversed_motor(-2); //Creates a reversed motor on port 1 with standard gearset and encoder units - * Motor blue_motor(3, pros::v5::MotorGears::blue); //Creates a motor on port 3 with blue gear set and degrees - * Motor rotations_motor(4, pros::v5::MotorGears::green, pros::v5::MotorUnits::rotations); port 4 w/ rotations - * - * } - * \endcode - * - */ - explicit Motor(const std::int8_t port, const pros::v5::MotorGears gearset = pros::v5::MotorGears::green, - const pros::v5::MotorUnits encoder_units = pros::v5::MotorUnits::degrees); - - - - /** - * Constructs a new Motor object. - * - * 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 motor - * - * \param The abstract motor to create into a motor - * Creates a new motor on the port of abstract_motor.get_port(), maintaining it's reversal status. - * - * - * \b Example - * \code - * void opcontrol() { - * Motor first_motor(1); //Creates a motor on port 1 with green gearset and degrees as the encoder units - * AbstractMotor abs_motor = first_motor; - * Motor new_motor = (Motor) abs_motor; - * - * } - * \endcode - * - */ - Motor(AbstractMotor& abstract_motor); - - - /// \name Motor movement functions - /// These functions allow programmers to make motors move - ///@{ - - /** - * Sets the voltage for the motor from -128 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. + * Does not explicitly set the gearset if not specified or if the gearset is invalid * * \b Example * \code * void opcontrol() { - * pros::Motor motor (1, E_MOTOR_GEARSET_18); - * pros::Controller master (E_CONTROLLER_MASTER); - * while (true) { - * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); - * pros::delay(2); - * } + * Motor first_motor(1); //Creates a motor on port 1 without altering gearset or encoder units + * Motor reversed_motor(-2); //Creates a reversed motor on port 1 port 1 without altering gearset or encoder units + * Motor blue_motor(3, pros::v5::MotorGears::blue); //Creates a motor on port 3 with blue gear set + * Motor rotations_motor(4, pros::v5::MotorGears::green, pros::v5::MotorUnits::rotations); //port 4 w/ rotations + * * } * \endcode + * */ - std::int32_t operator=(std::int32_t voltage) const; + Motor(const std::int8_t port, const pros::v5::MotorGears gearset = pros::v5::MotorGears::invalid, + const pros::v5::MotorUnits encoder_units = pros::v5::MotorUnits::invalid); + + Motor(const Device& device) : Motor(device.get_port()){}; + + /// \name Motor movement functions + /// These functions allow programmers to make motors move + ///@{ /** * Sets the voltage for the motor from -127 to 127. @@ -177,7 +120,7 @@ class Motor : public AbstractMotor, public Device { * * \note This function simply sets the target for the motor, it does not block * program execution until the movement finishes. - * + * * * This function uses the following values of errno when an error state is * reached: @@ -220,7 +163,7 @@ class Motor : public AbstractMotor, public Device { * This movement is relative to the current position of the motor as given in * pros::Motor::motor_get_position(). Providing 10.0 as the position parameter * would result in the motor moving clockwise 10 units (counter clockwise if reversed), - * no matter what the current position is. + * no matter what the current position is. * * \note This function simply sets the target for the motor, it does not block * program execution until the movement finishes. @@ -312,10 +255,10 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::int32_t move_voltage(const std::int32_t voltage) const; - + /** * Stops the motor using the currently configured brake mode. - * + * * This function sets motor velocity to zero, which will cause it to act * according to the set brake mode. If brake mode is set to MOTOR_BRAKE_HOLD, * this function may behave differently than calling move_absolute(0) @@ -324,20 +267,20 @@ class Motor : public AbstractMotor, public Device { * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor - * - * \return 1 if the operation was successful or PROS_ERR if the operation - * failed, setting errno. - * - * \b Example - * \code - * void autonomous() { - * Motor motor(1); - * motor.move_voltage(12000); - * pros::delay(1000); // Move at max voltage for 1 second - * motor.brake(); - * } - * \endcode - */ + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * Motor motor(1); + * motor.move_voltage(12000); + * pros::delay(1000); // Move at max voltage for 1 second + * motor.brake(); + * } + * \endcode + */ std::int32_t brake(void) const; /** @@ -355,7 +298,7 @@ class Motor : public AbstractMotor, public Device { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * void autonomous() { @@ -368,19 +311,25 @@ class Motor : public AbstractMotor, public Device { */ std::int32_t modify_profiled_velocity(const std::int32_t velocity) const; + ///@} + + /// \name Motor telemetry functions + /// These functions allow programmers to collect telemetry from motors + ///@{ + /** * Gets the target position set for the motor by the user * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -402,19 +351,19 @@ class Motor : public AbstractMotor, public Device { /** * Gets the velocity commanded to the motor by the user at the index specified. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index - * + * * \return The commanded motor velocity from +-100, +-200, or +-600, or * PROS_ERR if the operation failed, setting errno. * @@ -434,28 +383,22 @@ class Motor : public AbstractMotor, public Device { */ std::int32_t get_target_velocity(const std::uint8_t index = 0) const; - ///@} - - /// \name Motor telemetry functions - /// These functions allow programmers to collect telemetry from motors - ///@{ - /** * Gets the actual velocity of the motor. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: * ENODEV - The port cannot be configured as a motor * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. - * By default index is 0, and will return an error for a non-zero index - * + * By default index is 0, and will return an error for a non-zero index + * * \return The motor's actual velocity in RPM or PROS_ERR_F if the operation * failed, setting errno. * @@ -475,22 +418,22 @@ class Motor : public AbstractMotor, public Device { /** * Gets the current drawn by the motor in mA. - * - * \note This is one of many Motor functions that takes in an optional index parameter. + * + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index - * + * * \return The motor's current in mA or PROS_ERR if the operation failed, * setting errno. * @@ -512,21 +455,21 @@ class Motor : public AbstractMotor, public Device { /** * Gets the direction of movement for the motor. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index - * + * * \return 1 for moving in the positive direction, -1 for moving in the * negative direction, and PROS_ERR if the operation failed, setting errno. * @@ -552,19 +495,19 @@ class Motor : public AbstractMotor, public Device { * drawing no electrical power, and an efficiency of 0% means that the motor * is drawing power but not moving. * - * - * \note This is one of many Motor functions that takes in an optional index parameter. + * + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -591,18 +534,18 @@ class Motor : public AbstractMotor, public Device { * * Compare this bitfield to the bitmasks in pros::motor_fault_e_t. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -622,24 +565,24 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::uint32_t get_faults(const std::uint8_t index = 0) const; - + /** * Gets the flags set by the motor's operation. * * Compare this bitfield to the bitmasks in pros::motor_flag_e_t. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -663,18 +606,18 @@ class Motor : public AbstractMotor, public Device { /** * Gets the absolute position of the motor in its encoder units. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -699,21 +642,21 @@ class Motor : public AbstractMotor, public Device { /** * Gets the power drawn by the motor in Watts. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index - * + * * \return The motor's power draw in Watts or PROS_ERR_F if the operation * failed, setting errno. * @@ -735,28 +678,28 @@ class Motor : public AbstractMotor, public Device { /** * Gets the raw encoder count of the motor at a given timestamp. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * + * + * * \param timestamp * A pointer to a time in milliseconds for which the encoder count * will be returned. If NULL, the timestamp at which the encoder * count was read will not be supplied - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * - * + * * * \return The raw encoder count at the given timestamp or PROS_ERR if the * operation failed. @@ -779,19 +722,19 @@ class Motor : public AbstractMotor, public Device { /** * Gets the temperature of the motor in degrees Celsius. - - * \note This is one of many Motor functions that takes in an optional index parameter. + + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -816,18 +759,18 @@ class Motor : public AbstractMotor, public Device { /** * Gets the torque generated by the motor in Newton Meters (Nm). * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -852,21 +795,21 @@ class Motor : public AbstractMotor, public Device { /** * Gets the voltage delivered to the motor in millivolts. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index - * + * * \return The motor's voltage in mV or PROS_ERR_F if the operation failed, * setting errno. * @@ -888,18 +831,18 @@ class Motor : public AbstractMotor, public Device { /** * Checks if the motor is drawing over its current limit. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -925,21 +868,21 @@ class Motor : public AbstractMotor, public Device { /** * Gets the temperature limit flag for the motor. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index - * + * * \return 1 if the temperature limit is exceeded and 0 if the temperature is * below the limit, or PROS_ERR if the operation failed, setting errno. * @@ -967,22 +910,22 @@ class Motor : public AbstractMotor, public Device { /** * Gets the brake mode that was set for the motor. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero 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. * * \b Example @@ -999,21 +942,21 @@ class Motor : public AbstractMotor, public Device { /** * Gets the current limit for the motor in mA. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index - * + * * \return The motor's current limit in mA or PROS_ERR if the operation failed, * setting errno. * @@ -1029,26 +972,26 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::int32_t get_current_limit(const std::uint8_t index = 0) const; - + /** * Gets the encoder units that were set for the motor. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero 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. * * \b Example @@ -1064,23 +1007,23 @@ class Motor : public AbstractMotor, public Device { /** * Gets the gearset that was set for the motor. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero 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. * * \b Example * \code @@ -1098,18 +1041,18 @@ class Motor : public AbstractMotor, public Device { * Default value is 0V, which means that there is no software limitation * imposed on the voltage. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -1126,16 +1069,16 @@ class Motor : public AbstractMotor, public Device { /** * Gets whether the motor is reversed or not * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -1153,24 +1096,55 @@ class Motor : public AbstractMotor, public Device { */ std::int32_t is_reversed(const std::uint8_t index = 0) const; + /** + * Gets the type of the motor + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the type of. + * By default index is 0, and will return an error for a non-zero index + * + * \return One of MotorType according to the type of the motor, + * or pros::MotorType::invalid if the operation failed. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1, E_MOTOR_GEARSET_06, E_MOTOR_ENCODER_COUNTS); + * std::cout << "Motor Type: " << motor.get_type(); + * } + * \endcode + */ + MotorType get_type(const std::uint8_t index = 0) const; + /** * Sets one of Motor_Brake to the motor. - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * + * + * * \param mode - * The Motor_Brake to set for the motor - * - * \param index Optional parameter. + * The MotorBrake to set for the motor + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -1188,23 +1162,23 @@ class Motor : public AbstractMotor, public Device { */ std::int32_t set_brake_mode(const MotorBrake mode, const std::uint8_t index = 0) const; /** - * Sets one of Motor_Brake to the motor. - * \note This is one of many Motor functions that takes in an optional index parameter. + * Sets one of MotorBrake to the motor. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * + * + * * \param mode - * The Motor_Brake to set for the motor - * - * \param index Optional parameter. + * The MotorBrake to set for the motor + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -1221,25 +1195,24 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::int32_t set_brake_mode(const pros::motor_brake_mode_e_t mode, const std::uint8_t index = 0) const; - /** * Sets the current limit for the motor in mA. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * * \param limit + * + * \param limit * The new current limit in mA - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -1264,7 +1237,7 @@ class Motor : public AbstractMotor, public Device { std::int32_t set_current_limit(const std::int32_t limit, const std::uint8_t index = 0) const; /** - * 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 @@ -1288,24 +1261,24 @@ class Motor : public AbstractMotor, public Device { */ std::int32_t set_encoder_units(const MotorUnits units, const std::uint8_t index = 0) const; /** - * 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. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index - * + * * * \param units * The new motor encoder units * @@ -1322,23 +1295,22 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::int32_t set_encoder_units(const pros::motor_encoder_units_e_t units, const std::uint8_t index = 0) const; - /** * Sets one of the gear cartridge (red, green, blue) for the motor. Usable with * the C++ enum class and the C enum. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * \param gearset @@ -1357,26 +1329,26 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::int32_t set_gearing(const MotorGears gearset, const std::uint8_t index = 0) const; - + /** * Sets one of the gear cartridge (red, green, blue) for the motor. Usable with * the C++ enum class and the C enum. - - * \note This is one of many Motor functions that takes in an optional index parameter. + + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * + * * \param gearset * The new motor gearset - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -1400,19 +1372,19 @@ class Motor : public AbstractMotor, public Device { * * This will invert its movements and the values returned for its position. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * EOVERFLOW - The index is non 0 - * + * * \param reverse * True reverses the motor, false is default direction - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -1466,25 +1438,25 @@ class Motor : public AbstractMotor, public Device { * This will be the future reference point for the motor's "absolute" * position. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * + * * \param position * The new reference position in its encoder units - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index - * - * + * + * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. * @@ -1496,7 +1468,7 @@ class Motor : public AbstractMotor, public Device { * motor.move_absolute(100, 100); // This does not cause a movement * * motor.set_zero_position(80); - * motor.move_absolute(100, 100); // Moves 80 units forward + * motor.move_absolute(100, 100); // Moves 20 units forward * } * \endcode * @@ -1506,21 +1478,21 @@ class Motor : public AbstractMotor, public Device { /** * Sets the "absolute" zero position of the motor to its current position. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index - * + * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. * @@ -1540,18 +1512,32 @@ class Motor : public AbstractMotor, public Device { /** * Gets the number of motors. - * + * * \return Always returns 1 - * + * */ std::int8_t size(void) const; + /** + * Gets all motors. + * + * \return A vector of Motor objects. + * + * \b Example + * \code + * void opcontrol() { + * std::vector motor_all = pros::Motor::get_all_devices(); // All motors that are connected + * } + * \endcode + */ + static std::vector get_all_devices(); + /** * gets the port number of the motor * - * \return The signed port of the motor. (negative if the motor is reversed) - * - */ + * \return The signed port of the motor. (negative if the motor is reversed) + * + */ std::int8_t get_port(const std::uint8_t index = 0) const; ///@} @@ -1589,7 +1575,7 @@ class Motor : public AbstractMotor, public Device { * reached: * ENODEV - The port cannot be configured as a motor * - * \return A vector containing the commanded motor velocity from +-100, + * \return A vector containing the commanded motor velocity from +-100, * +-200, or +-600, or PROS_ERR if the operation failed, setting errno. * * \b Example @@ -1631,18 +1617,18 @@ class Motor : public AbstractMotor, public Device { * } * } * \endcode - */ + */ std::vector get_actual_velocity_all(void) const; /** * Gets a vector containing the current drawn by the motor in mA. - * + * * 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 containing the motor's current in mA or PROS_ERR if the operation failed, * setting errno. * @@ -1664,13 +1650,13 @@ class Motor : public AbstractMotor, public Device { /** * Gets a vector containing the direction of movement for 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 - * - * + * + * * \return A vector containing 1 for moving in the positive direction, -1 for moving in the * negative direction, and PROS_ERR if the operation failed, setting errno. * @@ -1695,12 +1681,12 @@ class Motor : public AbstractMotor, public Device { * An efficiency of 100% means that the motor is moving electrically while * drawing no electrical power, and an efficiency of 0% means that the motor * is drawing power but not moving. - * + * * 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 containing The motor's efficiency in percent or PROS_ERR_F if the operation * failed, setting errno. @@ -1719,15 +1705,15 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::vector get_efficiency_all(void) const; - + /** * Gets a vector of the faults experienced by the motor. * * Compare this bitfield to the bitmasks in pros::motor_fault_e_t. - * + * * 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 bitfield containing the motor's faults. @@ -1740,7 +1726,7 @@ class Motor : public AbstractMotor, public Device { * while (true) { * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); * std::cout << "Motor Faults: " << motor.get_faults_all()[0]; - * pros::delay(2); + * pros::delay(2); * } * } * \endcode @@ -1751,10 +1737,10 @@ class Motor : public AbstractMotor, public Device { * Gets a vector of the flags set by the motor's operation. * * Compare this bitfield to the bitmasks in pros::motor_flag_e_t. - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor * * @@ -1774,15 +1760,15 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::vector get_flags_all(void) const; - + /** * Gets a vector containing the absolute position of the motor in its encoder units. - * + * * 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 containing the motor's absolute position in its encoder units or PROS_ERR_F * if the operation failed, setting errno. @@ -1804,12 +1790,12 @@ class Motor : public AbstractMotor, public Device { /** * Gets a vector containing the power drawn by the motor in Watts. - * + * * 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 containing the motor's power draw in Watts or PROS_ERR_F if the operation * failed, setting errno. * @@ -1827,21 +1813,21 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::vector get_power_all(void) const; - + /** * Gets a vector of the raw encoder count of the motor at a given timestamp. * - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * \param timestamp * A pointer to a time in milliseconds for which the encoder count * will be returned. If NULL, the timestamp at which the encoder * count was read will not be supplied - * + * * \return A vector containing the raw encoder count at the given timestamp or PROS_ERR if the * operation failed. * @@ -1860,7 +1846,7 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::vector get_raw_position_all(std::uint32_t* const timestamp) const; - + /** * Gets a vector of the temperature of the motor in degrees Celsius. * @@ -1868,7 +1854,7 @@ class Motor : public AbstractMotor, public Device { * reached: * ENODEV - The port cannot be configured as a motor * - * \return A vector contaioning the motor's temperature in degrees Celsius + * \return A vector contaioning the motor's temperature in degrees Celsius * or PROS_ERR_F if the operation failed, setting errno. * * \b Example @@ -1892,7 +1878,7 @@ class Motor : public AbstractMotor, public Device { * 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 containing the motor's torque in Nm or PROS_ERR_F if the operation failed, * setting errno. * @@ -1910,14 +1896,14 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::vector get_torque_all(void) const; - + /** * Gets a vector of the voltage delivered to the motor in millivolts. * * 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 the motor's voltage in mV or PROS_ERR_F if the operation failed, * setting errno. @@ -1962,14 +1948,14 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::vector is_over_current_all(void) const; - + /** * Gets the temperature limit flag for 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 - * + * ENODEV - The port cannot be configured as a motor + * * \return A vector containing 1 if the temperature limit is exceeded and 0 if the temperature is * below the limit, or PROS_ERR if the operation failed, setting errno. * @@ -1987,7 +1973,7 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::vector is_over_temp_all(void) const; - + /** * Gets a vector containing the brake mode that was set for the motor. * @@ -2008,7 +1994,7 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::vector get_brake_mode_all(void) const; - + /** * Gets a vector containing the current limit for the motor in mA. * @@ -2053,7 +2039,7 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::vector get_encoder_units_all(void) const; - + /** * Gets a vector containing the gearset that was set for the motor. * @@ -2077,10 +2063,10 @@ class Motor : public AbstractMotor, public Device { /** * Gets returns a vector with all the port numbers in the motor group. * - * \return A vector containing the signed port of the motor. (negative if the motor is reversed) + * \return A vector containing the signed port of the motor. (negative if the motor is reversed) */ std::vector get_port_all(void) const; - + /** * Gets a vector of the voltage limit set by the user. * @@ -2120,9 +2106,29 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::vector is_reversed_all(void) const; - + /** - * Sets one of Motor_Brake to the motor. + * Gets a vector containing 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 + * + * \return A vector containing one of MotorType according to the type of the motor, + * or pros::MotorType::invalid if the operation failed. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1, E_MOTOR_GEARSET_06, E_MOTOR_ENCODER_COUNTS); + * std::cout << "Motor Type: " << motor.get_type_all()[0]; + * } + * \endcode + */ + std::vector get_type_all(void) const; + + /** + * Sets one of Motor_Brake to the motor. * * This function uses the following values of errno when an error state is * reached: @@ -2144,9 +2150,9 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::int32_t set_brake_mode_all(const MotorBrake mode) const; - + /** - * Sets one of Motor_Brake to the motor. + * Sets one of Motor_Brake to the motor. * * This function uses the following values of errno when an error state is * reached: @@ -2203,21 +2209,21 @@ class Motor : public AbstractMotor, public Device { * Sets one of Motor_Units for the motor encoder. Works with the C * enum and the C++ enum class. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * + * * * \param units * The new motor encoder units - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -2234,7 +2240,7 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::int32_t set_encoder_units_all(const MotorUnits units) const; - + /** * Sets one of Motor_Units for the motor encoder. Works with the C * enum and the C++ enum class. @@ -2259,8 +2265,7 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::int32_t set_encoder_units_all(const pros::motor_encoder_units_e_t units) const; - - + /** * Sets one of the gear cartridge (red, green, blue) for the motor. Usable with * the C++ enum class and the C enum. @@ -2285,7 +2290,7 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::int32_t set_gearing_all(const MotorGears gearset) const; - + /** * Sets one of the gear cartridge (red, green, blue) for the motor. Usable with * the C++ enum class and the C enum. @@ -2310,7 +2315,7 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::int32_t set_gearing_all(const pros::motor_gearset_e_t gearset) const; - + /** * Sets the reverse flag for the motor. * @@ -2320,7 +2325,7 @@ class Motor : public AbstractMotor, public Device { * \param reverse * True reverses the motor, false is default direction * - * \return 1 + * \return 1 * * \b Example * \code @@ -2332,25 +2337,25 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::int32_t set_reversed_all(const bool reverse); - + /** * Sets the voltage limit for the motor in Volts. * - * \note This is one of many Motor functions that takes in an optional index parameter. + * \note This is one of many Motor functions that takes in an optional index parameter. * This parameter can be ignored by most users but exists to give a shared base class * for motors and motor groups - * + * * This function uses the following values of errno when an error state is * reached: - * + * * ENODEV - The port cannot be configured as a motor - * + * * EOVERFLOW - The index is non 0 - * + * * \param limit * The new voltage limit in Volts - * - * \param index Optional parameter. + * + * \param index Optional parameter. * The zero-indexed index of the motor to get the target position of. * By default index is 0, and will return an error for a non-zero index * @@ -2373,7 +2378,7 @@ class Motor : public AbstractMotor, public Device { * \endcode */ std::int32_t set_voltage_limit_all(const std::int32_t limit) const; - + /** * Sets the position for the motor in its encoder units. * @@ -2398,7 +2403,7 @@ class Motor : public AbstractMotor, public Device { * motor.move_absolute(100, 100); // This does not cause a movement * * motor.set_zero_position_all(80); - * motor.move_absolute(100, 100); // Moves 80 units forward + * motor.move_absolute(100, 100); // Moves 20 units forward * } * \endcode * @@ -2432,10 +2437,39 @@ class Motor : public AbstractMotor, public Device { ///@} private: + /** + * The port of the motor. Negative ports indicate that the motor is reversed + */ std::int8_t _port; }; namespace literals { +/** + * Constructs a Motor from a literal ending in _mtr + * + * \return a pros::Motor for the corresponding port + * + * \b Example + * \code + * using namespace pros::literals; + * void opcontrol() { + * pros::Motor motor = 2_mtr; //Makes an Motor object on port 2 + * } + * \endcode + */ const pros::Motor operator"" _mtr(const unsigned long long int m); +/** + * Constructs a reversed Motor from a literal ending in _rmtr + * + * \return a pros::Motor for the corresponding port that is reversed + * + * \b Example + * \code + * using namespace pros::literals; + * void opcontrol() { + * pros::motor motor = 2_rmtr; //Makes an reversed Motor object on port 2 + * } + * \endcode + */ const pros::Motor operator"" _rmtr(const unsigned long long int m); } // namespace literals } // namespace v5 diff --git a/include/pros/optical.h b/include/pros/optical.h index 049c395b..bc124919 100644 --- a/include/pros/optical.h +++ b/include/pros/optical.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 @@ -460,6 +460,39 @@ int32_t optical_enable_gesture(uint8_t port); */ int32_t optical_disable_gesture(uint8_t port); +/** + * Get integration time (update rate) of the optical sensor in milliseconds, with + * minimum time being + * + * 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 Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return Integration time in milliseconds if the operation is successful + * or PROS_ERR_F if the operation failed, setting errno. + */ +double optical_get_integration_time(uint8_t port); + +/** + * Set integration time (update rate) of the optical sensor in milliseconds. + * + * 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 Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \param time + * The desired integration time in milliseconds + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t optical_set_integration_time(uint8_t port, double time); + ///@} ///@} diff --git a/include/pros/optical.hpp b/include/pros/optical.hpp index 3f700d41..3cb55d91 100644 --- a/include/pros/optical.hpp +++ b/include/pros/optical.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-optical VEX Optical Sensor C++ API */ @@ -24,8 +24,8 @@ #include #include -#include "pros/optical.h" #include "pros/device.hpp" +#include "pros/optical.h" namespace pros { inline namespace v5 { @@ -48,13 +48,30 @@ class Optical : public Device { * * \param port * The V5 port number from 1-21 - * - * \b Example: + * + * \b Example: * \code{.cpp} * pros::Optical optical(1); * \endcode */ - explicit Optical(const std::uint8_t port); + Optical(const std::uint8_t port); + + Optical(const Device& device) : Optical(device.get_port()){}; + + + /** + * Gets all optical sensors. + * + * \return A vector of Optical sensor objects. + * + * \b Example + * \code + * void opcontrol() { + * std::vector optical_all = pros::Optical::get_all_devices(); // All optical sensors that are connected + * } + * \endcode + */ + static std::vector get_all_devices(); /** * Get the detected color hue @@ -93,7 +110,7 @@ class Optical : public Device { * * \return saturation value if the operation was successful or PROS_ERR_F if * the operation failed, setting errno. - * + * * \b Example: * \code{.cpp} * void opcontrol() { @@ -124,6 +141,7 @@ class Optical : public Device { * pros::Optical optical(1); * std::cout << "Brightness: " << optical.get_brightness() << std::endl; * } + * \endcode */ virtual double get_brightness(); @@ -161,8 +179,8 @@ class Optical : public Device { * ENXIO - The given value is not within the range of V5 ports (1-21). * ENODEV - The port cannot be configured as an Optical Sensor * - * \return The Error code encountered or PROS_SUCCESS. - * + * \return The Error code encountered or PROS_SUCCESS. + * * \b Example: * \code{.cpp} * void initialize() { @@ -205,9 +223,9 @@ class Optical : public Device { * ENXIO - The given value is not within the range of V5 ports (1-21). * ENODEV - The port cannot be configured as an Optical Sensor * - * \return rgb value if the operation was successful or an optical_rgb_s_t + * \return rgb value if the operation was successful or an optical_rgb_s_t * with all fields set to PROS_ERR if the operation failed, setting errno. - * + * * \b Example: * \code{.cpp} * void opcontrol() { @@ -233,8 +251,23 @@ class Optical : public Device { * ENXIO - The given value is not within the range of V5 ports (1-21). * ENODEV - The port cannot be configured as an Optical Sensor * - * \return raw rgb value if the operation was successful or an optical_raw_s_t + * \return raw rgb value if the operation was successful or an optical_raw_s_t * with all fields set to PROS_ERR if the operation failed, setting errno. + * + * \b Example: + * \code{.cpp} + * void opcontrol() { + * pros::Optical optical(1); + * pros::c::optical_raw_s_t raw = optical.get_raw(); + * while (1) { + * std::cout << "Red: " << raw.red << std::endl; + * std::cout << "Green: " << raw.green << std::endl; + * std::cout << "Blue: " << raw.blue << std::endl; + * std::cout << "Clear: " << raw.clear << std::endl; + * pros::delay(20); + * } + * } + * \endcode */ virtual pros::c::optical_raw_s_t get_raw(); @@ -242,10 +275,12 @@ class Optical : public Device { * Get the most recent gesture data from the sensor * * Gestures will be cleared after 500mS - * 0 = no gesture - * 1 = up (towards cable) - * 2 = down - * 3 = right + * + * + * 0 = no gesture, + * 1 = up (towards cable), + * 2 = down, + * 3 = right, * 4 = left * * This function uses the following values of errno when an error state is @@ -277,7 +312,7 @@ class Optical : public Device { * ENXIO - The given value is not within the range of V5 ports (1-21). * ENODEV - The port cannot be configured as an Optical Sensor * - * \return gesture value if the operation was successful or an optical_gesture_s_t + * \return gesture value if the operation was successful or an optical_gesture_s_t * with all fields set to PROS_ERR if the operation failed, setting errno. * * \b Example: @@ -311,8 +346,8 @@ class Optical : public Device { * ENODEV - The port cannot be configured as an Optical Sensor * * \return 1 if the operation is successful or PROS_ERR if the operation failed, - * setting errno. - * + * setting errno. + * * \b Example: * \code{.cpp} * void opcontrol() { @@ -331,6 +366,7 @@ class Optical : public Device { * pros::delay(20); * } * } + * \endcode */ virtual std::int32_t enable_gesture(); @@ -343,7 +379,7 @@ class Optical : public Device { * ENODEV - The port cannot be configured as an Optical Sensor * * \return 1 if the operation is successful or PROS_ERR if the operation failed, - * setting errno. + * setting errno. * * \b Example: * \code{.cpp} @@ -362,12 +398,40 @@ class Optical : public Device { */ virtual std::int32_t disable_gesture(); + /** + * Get integration time (update rate) of the optical sensor in milliseconds. + * + * 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 Optical Sensor + * + * \return Integration time in milliseconds if the operation is successful + * or PROS_ERR_F if the operation failed, setting errno. + */ + double get_integration_time(); /** - * 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): - * Optical [port: (port number), hue: (hue), saturation: (saturation), + * Set integration time (update rate) of the optical sensor in milliseconds, with + * minimum time being 3 ms and maximum time being 712 ms. Default is 100 ms, with the + * optical sensor communciating with the V5 brain every 20 ms. + * + * 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 Optical Sensor + * + * \param time The desired integration time in milliseconds + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + */ + std::int32_t set_integration_time(double time); + + /** + * 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): + * Optical [port: (port number), hue: (hue), saturation: (saturation), * brightness: (brightness), proximity: (proximity), rgb: {red, green, blue}] * * \b Example: @@ -377,15 +441,28 @@ class Optical : public Device { * \endcode */ friend std::ostream& operator<<(std::ostream& os, pros::Optical& optical); - + private: ///@} }; namespace literals { +/** + * Constructs a Optical sensor from a literal ending in _opt + * + * \return a pros::Optical for the corresponding port + * + * \b Example + * \code + * using namespace pros::literals; + * void opcontrol() { + * pros::Optical opt = 2_opt; //Makes an Optical object on port 2 + * } + * \endcode + */ const pros::Optical operator"" _opt(const unsigned long long int o); } // namespace literals -} +} // namespace v5 } // namespace pros #endif diff --git a/include/pros/rotation.h b/include/pros/rotation.h index 1c1c7317..5a904414 100644 --- a/include/pros/rotation.h +++ b/include/pros/rotation.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 @@ -132,7 +132,7 @@ int32_t rotation_set_data_rate(uint8_t port, uint32_t rate); * } * \endcode */ -int32_t rotation_set_position(uint8_t port, uint32_t position); +int32_t rotation_set_position(uint8_t port, int32_t position); /** * Reset the Rotation Sensor position to 0 diff --git a/include/pros/rotation.hpp b/include/pros/rotation.hpp index 25806c3f..1e6dda9d 100644 --- a/include/pros/rotation.hpp +++ b/include/pros/rotation.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-rotation VEX Rotation Sensor C++ API */ #ifndef _PROS_ROTATION_HPP_ @@ -21,8 +21,8 @@ #include #include -#include "pros/rotation.h" #include "pros/device.hpp" +#include "pros/rotation.h" namespace pros { inline namespace v5 { @@ -38,22 +38,25 @@ class Rotation : public Device { public: /** * Constructs a new Rotation Sensor object - * + * * ENXIO - The given value is not within the range of V5 ports |1-21|. - * ENODEV - The port cannot be configured as a Rotation Sensor - * + * ENODEV - The port cannot be configured as a Rotation Sensor + * * \param port - * The V5 port number from 1 to 21, or from -21 to -1 for reversed Rotation Sensors. - * + * The V5 port number from 1 to 21, or from -21 to -1 for reversed Rotation Sensors. + * * \b Example - * \code - * void opcontrol() { + * \code + * void opcontrol() { * pros::Rotation rotation_sensor(1); //Creates a Rotation Sensor on port 1 * pros::Rotation reversed_rotation_sensor(-2); //Creates a reversed Rotation Sensor on port 2 - * } - * \endcode - */ - explicit Rotation(const std::int8_t port); + * } + * \endcode + */ + Rotation(const std::int8_t port); + + Rotation(const Device& device) : Rotation(device.get_port()){}; + /** * Reset the Rotation Sensor @@ -68,7 +71,7 @@ class Rotation : public Device { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * void opcontrol() { @@ -105,14 +108,14 @@ class Rotation : public Device { * \param rate The data refresh interval in milliseconds * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example - * \code - * void initialize() { - * pros::Rotation rotation_sensor(1); - * rotation_sensor.set_data_rate(5); - * } - * \endcode + * \code + * void initialize() { + * pros::Rotation rotation_sensor(1); + * rotation_sensor.set_data_rate(5); + * } + * \endcode */ virtual std::int32_t set_data_rate(std::uint32_t rate) const; @@ -128,7 +131,7 @@ class Rotation : public Device { * The position in terms of ticks * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * void opcontrol() { @@ -143,7 +146,7 @@ class Rotation : public Device { * } * \endcode */ - virtual std::int32_t set_position(std::uint32_t position) const; + virtual std::int32_t set_position(std::int32_t position) const; /** * Reset the Rotation Sensor position to 0 @@ -157,7 +160,7 @@ class Rotation : public Device { * The position in terms of ticks * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * void opcontrol() { @@ -174,6 +177,20 @@ class Rotation : public Device { */ virtual std::int32_t reset_position(void) const; + /** + * Gets all rotation sensors. + * + * \return A vector of Rotation sensor objects. + * + * \b Example + * \code + * void opcontrol() { + * std::vector rotation_all = pros::Rotation::get_all_devices(); // All rotation sensors that are connected + * } + * \endcode + */ + static std::vector get_all_devices(); + /** * Get the Rotation Sensor's current position in centidegrees * @@ -184,17 +201,17 @@ class Rotation : public Device { * * \return The position value or PROS_ERR if the operation failed, setting * errno. - * + * * \b Example - * \code - * void opcontrol() { + * \code + * void opcontrol() { * pros::Rotation rotation_sensor(1); - * while (true) { - * printf("Position: %d Ticks \n", rotation_sensor.get_position()); - * delay(20); - * } - * } - * \endcode + * while (true) { + * printf("Position: %d Ticks \n", rotation_sensor.get_position()); + * delay(20); + * } + * } + * \endcode */ virtual std::int32_t get_position() const; @@ -210,17 +227,17 @@ class Rotation : public Device { * The V5 Rotation Sensor port number from 1-21 * \return The velocity value or PROS_ERR if the operation failed, setting * errno. - * + * * \b Example - * \code - * void opcontrol() { + * \code + * void opcontrol() { * pros::Rotation rotation_sensor(1); - * while (true) { - * printf("Velocity: %d centidegrees per second \n", rotation_sensor.get_velocity)); - * delay(20); - * } - * } - * \endcode + * while (true) { + * printf("Velocity: %d centidegrees per second \n", rotation_sensor.get_velocity)); + * delay(20); + * } + * } + * \endcode */ virtual std::int32_t get_velocity() const; @@ -234,17 +251,17 @@ class Rotation : public Device { * * \return The angle value or PROS_ERR if the operation failed, setting * errno. - * + * * \b Example - * \code - * void opcontrol() { + * \code + * void opcontrol() { * pros::Rotation rotation_sensor(1); - * while (true) { - * printf("Angle: %d centidegrees \n", rotation_sensor.get_angle()); - * delay(20); - * } - * } - * \endcode + * while (true) { + * printf("Angle: %d centidegrees \n", rotation_sensor.get_angle()); + * delay(20); + * } + * } + * \endcode */ virtual std::int32_t get_angle() const; @@ -262,7 +279,7 @@ class Rotation : public Device { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * void opcontrol() { @@ -289,7 +306,7 @@ class Rotation : public Device { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * void opcontrol() { @@ -316,27 +333,27 @@ class Rotation : public Device { * * \return Reversed value or PROS_ERR if the operation failed, setting * errno. - * + * * \b Example - * \code - * void opcontrol() { + * \code + * void opcontrol() { * pros::Rotation rotation_sensor(1); - * while (true) { - * printf("Reversed: %d \n", rotation_sensor.get_reversed()); - * delay(20); - * } - * } - * \endcode + * while (true) { + * printf("Reversed: %d \n", rotation_sensor.get_reversed()); + * delay(20); + * } + * } + * \endcode */ virtual std::int32_t get_reversed() const; /** * 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): - * Rotation [port: rotation._port, position: (rotation position), velocity: (rotation velocity), + * Rotation [port: rotation._port, position: (rotation position), velocity: (rotation velocity), * angle: (rotation angle), reversed: (reversed boolean)] - * + * * \b Example * \code * #define ROTATION_PORT 1 @@ -352,13 +369,26 @@ class Rotation : public Device { */ friend std::ostream& operator<<(std::ostream& os, const pros::Rotation& rotation); -///@} + ///@} }; namespace literals { +/** + * Constructs a Rotation sensor from a literal ending in _rot + * + * \return a pros::Rotation for the corresponding port + * + * \b Example + * \code + * using namespace pros::literals; + * void opcontrol() { + * pros::Rotation rotation = 2_rot; //Makes an Motor object on port 2 + * } + * \endcode + */ const pros::Rotation operator"" _rot(const unsigned long long int r); } // namespace literals -} +} // namespace v5 } // namespace pros #endif diff --git a/include/pros/rtos.h b/include/pros/rtos.h index d6b9be48..b5ae33bf 100644 --- a/include/pros/rtos.h +++ b/include/pros/rtos.h @@ -8,7 +8,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. * All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public @@ -74,7 +74,7 @@ namespace pros { /** * The minimal stack size for a task. * - * This equates to 512 words, or 2,048 bytes. + * This equates to 512 words, or 2,048 bytes. */ #define TASK_STACK_DEPTH_MIN 0x200 @@ -94,7 +94,7 @@ namespace pros { /// @{ /** - * An opaque type that pontis to a task handle. This is used for referencing a + * An opaque type that points to a task handle. This is used for referencing a * task. */ typedef void* task_t; @@ -1076,7 +1076,87 @@ bool mutex_take(mutex_t mutex, uint32_t timeout); bool mutex_give(mutex_t mutex); /** - * Deletes a mutex + * Creates a recursive mutex which can be locked recursively by the owner. + * + * \return A newly created recursive mutex. + * + * \b Example: + * \code + * mutex_t mutex = mutex_recursive_create(); + * + * void task_fn(void* param) { + * while(1) { + * mutex_recursive_take(mutex, 1000); + * // critical section + * mutex_recursive_give(mutex); + * task_delay(1000); + * } + * } + * task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "task_fn"); + * + * \endcode + */ +mutex_t mutex_recursive_create(void); + +/** + * Takes a recursive mutex. + * + * \param mutex + * A mutex handle created by mutex_recursive_create + * \param wait_time + * Amount of time to wait before timing out + * + * \return 1 if the mutex was obtained, 0 otherwise + * + * \b Example: + * \code + * mutex_t mutex = mutex_recursive_create(); + * + * void task_fn(void* param) { + * while(1) { + * mutex_recursive_take(mutex, 1000); + * // critical section + * mutex_recursive_give(mutex); + * task_delay(1000); + * } + * } + * task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "task_fn"); + * + * \endcode + */ +bool mutex_recursive_take(mutex_t mutex, uint32_t timeout); + +/** + * Gives a recursive mutex. + * + * \param mutex + * A mutex handle created by mutex_recursive_create + * + * \return 1 if the mutex was obtained, 0 otherwise + * + * \b Example: + * \code + * mutex_t mutex = mutex_recursive_create(); + * + * void task_fn(void* param) { + * while(1) { + * mutex_recursive_take(mutex, 1000); + * // critical section + * mutex_recursive_give(mutex); + * task_delay(1000); + * } + * } + * task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "task_fn"); + * + * \endcode + */ +bool mutex_recursive_give(mutex_t mutex); + +/** + * Deletes a mutex or recursive mutex * * \param mutex * Mutex to unlock. diff --git a/include/pros/rtos.hpp b/include/pros/rtos.hpp index f02495c2..d6c2d890 100644 --- a/include/pros/rtos.hpp +++ b/include/pros/rtos.hpp @@ -8,7 +8,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. * All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public @@ -24,6 +24,7 @@ #include "pros/rtos.h" #undef delay +#include #include #include #include @@ -821,10 +822,14 @@ struct Clock { }; class Mutex { - std::shared_ptr> mutex; - + std::atomic mutex{nullptr}; + mutex_t lazy_init(); public: - Mutex(); + constexpr Mutex() { + if (!std::is_constant_evaluated()) { + lazy_init(); + } + } // disable copy and move construction and assignment per Mutex requirements // (see https://en.cppreference.com/w/cpp/named_req/Mutex) @@ -1278,7 +1283,7 @@ class Mutex { * } * } */ - bool try_lock(); + [[nodiscard]] bool try_lock(); /** * Takes and locks a mutex, waiting for a specified duration. @@ -1308,7 +1313,7 @@ class Mutex { * \endcode */ template - bool try_lock_for(const std::chrono::duration& rel_time) { + [[nodiscard]] bool try_lock_for(const std::chrono::duration& rel_time) { return take(std::chrono::duration_cast(rel_time).count()); } @@ -1346,6 +1351,542 @@ class Mutex { bool try_lock_until(const std::chrono::time_point& abs_time) { return take(std::max(static_cast(0), (abs_time - Clock::now()).count())); } + ~Mutex(); + ///@} +}; + +class RecursiveMutex { + std::atomic mutex{nullptr}; + mutex_t lazy_init(); + public: + constexpr RecursiveMutex() { + if (!std::is_constant_evaluated()) { + lazy_init(); + } + } + + // disable copy and move construction and assignment per Mutex requirements + // (see https://en.cppreference.com/w/cpp/named_req/Mutex) + RecursiveMutex(const RecursiveMutex&) = delete; + RecursiveMutex(RecursiveMutex&&) = delete; + + RecursiveMutex& operator=(const RecursiveMutex&) = delete; + RecursiveMutex& operator=(RecursiveMutex&&) = delete; + + /** + * Takes and locks a mutex indefinetly. + * + * See + * https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes + * for details. + * + * \return True if the mutex was successfully taken, false otherwise. If false + * is returned, then errno is set with a hint about why the the mutex + * couldn't be taken + * + * \b Example + * \code + * // Global variables for the robot's odometry, which the rest of the robot's + * // subsystems will utilize + * double odom_x = 0.0; + * double odom_y = 0.0; + * double odom_heading = 0.0; + * + * // This mutex protects the odometry data. Whenever we read or write to the + * // odometry data, we should make copies into the local variables, and read + * // all 3 values at once to avoid errors. + * pros::RecursiveMutex odom_mutex; + * + * void odom_task(void* param) { + * while(true) { + * // First we fetch the odom coordinates from the previous iteration of the + * // odometry task. These are put into local variables so that we can + * // keep the size of the critical section as small as possible. This lets + * // other tasks that need to use the odometry data run until we need to + * // update it again. + * odom_mutex.take(); + * double x_old = odom_x; + * double y_old = odom_y; + * double heading_old = odom_heading; + * odom_mutex.give(); + * + * double x_new = 0.0; + * double y_new = 0.0; + * double heading_new = 0.0; + * + * // --- Calculate new pose for the robot here --- + * + * // Now that we have the new pose, we can update the global variables + * odom_mutex.take(); + * odom_x = x_new; + * odom_y = y_new; + * odom_heading = heading_new; + * odom_mutex.give(); + * + * delay(10); + * } + * } + * + * void chassis_task(void* param) { + * while(true) { + * // Here we copy the current odom values into local variables so that + * // we can use them without worrying about the odometry task changing say, + * // the y value right after we've read the x. This ensures our values are + * // sound. + * odom_mutex.take(); + * double current_x = odom_x; + * double current_y = odom_y; + * double current_heading = odom_heading; + * odom_mutex.give(); + * + * // ---- Move the robot using the current locations goes here ---- + * + * delay(10); + * } + * } + * + * void initialize() { + * odom_mutex = pros::RecursiveMutex(); + * + * pros::Task odom_task(odom_task, "Odometry Task"); + * pros::Task chassis_task(odom_task, "Chassis Control Task"); + * } + * \endcode. + */ + bool take(); + + /** + * Takes and locks a mutex, waiting for up to a certain number of milliseconds + * before timing out. + * + * See + * https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes + * for details. + * + * \param timeout + * Time to wait before the mutex becomes available. A timeout of 0 can + * be used to poll the mutex. TIMEOUT_MAX can be used to block + * indefinitely. + * + * \return True if the mutex was successfully taken, false otherwise. If false + * is returned, then errno is set with a hint about why the the mutex + * couldn't be taken. + * + * \b Example + * \code + * // Global variables for the robot's odometry, which the rest of the robot's + * // subsystems will utilize + * double odom_x = 0.0; + * double odom_y = 0.0; + * double odom_heading = 0.0; + * + * // This mutex protects the odometry data. Whenever we read or write to the + * // odometry data, we should make copies into the local variables, and read + * // all 3 values at once to avoid errors. + * pros::RecursiveMutex odom_mutex; + * + * void odom_task(void* param) { + * while(true) { + * // First we fetch the odom coordinates from the previous iteration of the + * // odometry task. These are put into local variables so that we can + * // keep the size of the critical section as small as possible. This lets + * // other tasks that need to use the odometry data run until we need to + * // update it again. + * odom_mutex.take(); + * double x_old = odom_x; + * double y_old = odom_y; + * double heading_old = odom_heading; + * odom_mutex.give(); + * + * double x_new = 0.0; + * double y_new = 0.0; + * double heading_new = 0.0; + * + * // --- Calculate new pose for the robot here --- + * + * // Now that we have the new pose, we can update the global variables + * odom_mutex.take(); + * odom_x = x_new; + * odom_y = y_new; + * odom_heading = heading_new; + * odom_mutex.give(); + * + * delay(10); + * } + * } + * + * void chassis_task(void* param) { + * while(true) { + * // Here we copy the current odom values into local variables so that + * // we can use them without worrying about the odometry task changing say, + * // the y value right after we've read the x. This ensures our values are + * // sound. + * odom_mutex.take(); + * double current_x = odom_x; + * double current_y = odom_y; + * double current_heading = odom_heading; + * odom_mutex.give(); + * + * // ---- Move the robot using the current locations goes here ---- + * + * delay(10); + * } + * } + * + * void initialize() { + * odom_mutex = pros::RecursiveMutex(); + * + * pros::Task odom_task(odom_task, "Odometry Task"); + * pros::Task chassis_task(odom_task, "Chassis Control Task"); + * } + * \endcode. + */ + bool take(std::uint32_t timeout); + + /** + * Unlocks a mutex. + * + * See + * https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes + * for details. + * + * \return True if the mutex was successfully returned, false otherwise. If + * false is returned, then errno is set with a hint about why the mutex + * couldn't be returned. + * + * \b Example + * \code + * // Global variables for the robot's odometry, which the rest of the robot's + * // subsystems will utilize + * double odom_x = 0.0; + * double odom_y = 0.0; + * double odom_heading = 0.0; + * + * // This mutex protects the odometry data. Whenever we read or write to the + * // odometry data, we should make copies into the local variables, and read + * // all 3 values at once to avoid errors. + * pros::RecursiveMutex odom_mutex; + * + * void odom_task(void* param) { + * while(true) { + * // First we fetch the odom coordinates from the previous iteration of the + * // odometry task. These are put into local variables so that we can + * // keep the size of the critical section as small as possible. This lets + * // other tasks that need to use the odometry data run until we need to + * // update it again. + * odom_mutex.take(); + * double x_old = odom_x; + * double y_old = odom_y; + * double heading_old = odom_heading; + * odom_mutex.give(); + * + * double x_new = 0.0; + * double y_new = 0.0; + * double heading_new = 0.0; + * + * // --- Calculate new pose for the robot here --- + * + * // Now that we have the new pose, we can update the global variables + * odom_mutex.take(); + * odom_x = x_new; + * odom_y = y_new; + * odom_heading = heading_new; + * odom_mutex.give(); + * + * delay(10); + * } + * } + * + * void chassis_task(void* param) { + * while(true) { + * // Here we copy the current odom values into local variables so that + * // we can use them without worrying about the odometry task changing say, + * // the y value right after we've read the x. This ensures our values are + * // sound. + * odom_mutex.take(); + * double current_x = odom_x; + * double current_y = odom_y; + * double current_heading = odom_heading; + * odom_mutex.give(); + * + * // ---- Move the robot using the current locations goes here ---- + * + * delay(10); + * } + * } + * + * void initialize() { + * odom_mutex = pros::RecursiveMutex(); + * + * pros::Task odom_task(odom_task, "Odometry Task"); + * pros::Task chassis_task(odom_task, "Chassis Control Task"); + * } + * \endcode. + */ + bool give(); + + /** + * Takes and locks a mutex, waiting for up to TIMEOUT_MAX milliseconds. + * + * Effectively equivalent to calling pros::RecursiveMutex::take with TIMEOUT_MAX as + * the parameter. + * + * Conforms to named requirment BasicLockable + * \see https://en.cppreference.com/w/cpp/named_req/BasicLockable + * + * \note Consider using a std::unique_lock, std::lock_guard, or + * std::scoped_lock instead of interacting with the Mutex directly. + * + * \exception std::system_error Mutex could not be locked within TIMEOUT_MAX + * milliseconds. see errno for details. + * + * \b Example + * \code + * // Global variables for the robot's odometry, which the rest of the robot's + * // subsystems will utilize + * double odom_x = 0.0; + * double odom_y = 0.0; + * double odom_heading = 0.0; + * + * // This mutex protects the odometry data. Whenever we read or write to the + * // odometry data, we should make copies into the local variables, and read + * // all 3 values at once to avoid errors. + * pros::RecursiveMutex odom_mutex; + * + * void odom_task(void* param) { + * while(true) { + * // First we fetch the odom coordinates from the previous iteration of the + * // odometry task. These are put into local variables so that we can + * // keep the size of the critical section as small as possible. This lets + * // other tasks that need to use the odometry data run until we need to + * // update it again. + * odom_mutex.lock(); + * double x_old = odom_x; + * double y_old = odom_y; + * double heading_old = odom_heading; + * odom_mutex.unlock(); + * + * double x_new = 0.0; + * double y_new = 0.0; + * double heading_new = 0.0; + * + * // --- Calculate new pose for the robot here --- + * + * // Now that we have the new pose, we can update the global variables + * odom_mutex.lock(); + * odom_x = x_new; + * odom_y = y_new; + * odom_heading = heading_new; + * odom_mutex.unlock(); + * + * delay(10); + * } + * } + * + * void chassis_task(void* param) { + * while(true) { + * // Here we copy the current odom values into local variables so that + * // we can use them without worrying about the odometry task changing say, + * // the y value right after we've read the x. This ensures our values are + * // sound. + * odom_mutex.lock(); + * double current_x = odom_x; + * double current_y = odom_y; + * double current_heading = odom_heading; + * odom_mutex.unlock(); + * + * // ---- Move the robot using the current locations goes here ---- + * + * delay(10); + * } + * } + * + * void initialize() { + * odom_mutex = pros::RecursiveMutex(); + * + * pros::Task odom_task(odom_task, "Odometry Task"); + * pros::Task chassis_task(odom_task, "Chassis Control Task"); + * } + * \endcode. + */ + void lock(); + + /** + * Unlocks a mutex. + * + * Equivalent to calling pros::RecursiveMutex::give. + * + * Conforms to named requirement BasicLockable + * \see https://en.cppreference.com/w/cpp/named_req/BasicLockable + * + * \note Consider using a std::unique_lock, std::lock_guard, or + * std::scoped_lock instead of interacting with the Mutex direcly. + * + * \b Example + * \code + * // Global variables for the robot's odometry, which the rest of the robot's + * // subsystems will utilize + * double odom_x = 0.0; + * double odom_y = 0.0; + * double odom_heading = 0.0; + * + * // This mutex protects the odometry data. Whenever we read or write to the + * // odometry data, we should make copies into the local variables, and read + * // all 3 values at once to avoid errors. + * pros::RecursiveMutex odom_mutex; + * + * void odom_task(void* param) { + * while(true) { + * // First we fetch the odom coordinates from the previous iteration of the + * // odometry task. These are put into local variables so that we can + * // keep the size of the critical section as small as possible. This lets + * // other tasks that need to use the odometry data run until we need to + * // update it again. + * odom_mutex.lock(); + * double x_old = odom_x; + * double y_old = odom_y; + * double heading_old = odom_heading; + * odom_mutex.unlock(); + * + * double x_new = 0.0; + * double y_new = 0.0; + * double heading_new = 0.0; + * + * // --- Calculate new pose for the robot here --- + * + * // Now that we have the new pose, we can update the global variables + * odom_mutex.lock(); + * odom_x = x_new; + * odom_y = y_new; + * odom_heading = heading_new; + * odom_mutex.unlock(); + * + * delay(10); + * } + * } + * + * void chassis_task(void* param) { + * while(true) { + * // Here we copy the current odom values into local variables so that + * // we can use them without worrying about the odometry task changing say, + * // the y value right after we've read the x. This ensures our values are + * // sound. + * odom_mutex.lock(); + * double current_x = odom_x; + * double current_y = odom_y; + * double current_heading = odom_heading; + * odom_mutex.unlock(); + * + * // ---- Move the robot using the current locations goes here ---- + * + * delay(10); + * } + * } + * + * void initialize() { + * odom_mutex = pros::RecursiveMutex(); + * + * pros::Task odom_task(odom_task, "Odometry Task"); + * pros::Task chassis_task(odom_task, "Chassis Control Task"); + * } + * \endcode. + */ + void unlock(); + + /** + * Try to lock a mutex. + * + * Returns immediately if unsucessful. + * + * Conforms to named requirement Lockable + * \see https://en.cppreference.com/w/cpp/named_req/Lockable + * + * \return True when lock was acquired succesfully, or false otherwise. + * + * pros::RecursiveMutex mutex; + * + * void my_task_fn(void* param) { + * while (true) { + * if(mutex.try_lock()) { + * printf("Mutex aquired successfully!\n"); + * // Do stuff that requires the protected resource here + * } + * else { + * printf("Mutex not aquired!\n"); + * } + * } + * } + */ + [[nodiscard]] bool try_lock(); + + /** + * Takes and locks a mutex, waiting for a specified duration. + * + * Equivalent to calling pros::RecursiveMutex::take with a duration specified in + * milliseconds. + * + * Conforms to named requirement TimedLockable + * \see https://en.cppreference.com/w/cpp/named_req/TimedLockable + * + * \param rel_time Time to wait before the mutex becomes available. + * \return True if the lock was acquired succesfully, otherwise false. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * while (true) { + * if(mutex.try_lock_for(std::chrono::milliseconds(100))) { + * printf("Mutex aquired successfully!\n"); + * // Do stuff that requires the protected resource here + * } + * else { + * printf("Mutex not aquired after 100 milliseconds!\n"); + * } + * } + * } + * \endcode + */ + template + [[nodiscard]] bool try_lock_for(const std::chrono::duration& rel_time) { + return take(std::chrono::duration_cast(rel_time).count()); + } + + /** + * Takes and locks a mutex, waiting until a specified time. + * + * Conforms to named requirement TimedLockable + * \see https://en.cppreference.com/w/cpp/named_req/TimedLockable + * + * \param abs_time Time point until which to wait for the mutex. + * \return True if the lock was acquired succesfully, otherwise false. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * while (true) { + * // Get the current time point + * auto now = std::chrono::system_clock::now(); + * + * // Calculate the time point 100 milliseconds from now + * auto abs_time = now + std::chrono::milliseconds(100); + * + * if(mutex.try_lock_until(abs_time)) { + * printf("Mutex aquired successfully!\n"); + * // Do stuff that requires the protected resource here + * } + * else { + * printf("Mutex not aquired after 100 milliseconds!\n"); + * } + * } + * } + * \endcode + */ + template + bool try_lock_until(const std::chrono::time_point& abs_time) { + return take(std::max(static_cast(0), (abs_time - Clock::now()).count())); + } + + ~RecursiveMutex(); ///@} }; diff --git a/include/pros/screen.h b/include/pros/screen.h index 2e1592b7..c1e567bc 100644 --- a/include/pros/screen.h +++ b/include/pros/screen.h @@ -6,7 +6,7 @@ * * Contains user calls to the v5 screen for touching and displaying graphics. * - * \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 @@ -79,16 +79,11 @@ typedef enum { * Struct representing screen touch status, screen last x, screen last y, press count, release count. */ typedef struct screen_touch_status_s { - /// Represents if the screen is being held, released, or pressed. - last_touch_e_t touch_status; - /// Represents the x value of the location of the touch. - int16_t x; - /// Represents the y value of the location of the touch. - int16_t y; - /// Represents how many times the screen has be pressed. - int32_t press_count; - /// Represents how many times the user released after a touch on the screen. - int32_t release_count; + last_touch_e_t touch_status; ///< Represents if the screen is being held, released, or pressed. + int16_t x; ///< Represents the x value of the location of the touch. + int16_t y; ///< Represents the y value of the location of the touch. + int32_t press_count; ///< Represents how many times the screen has be pressed. + int32_t release_count; ///< Represents how many times the user released after a touch on the screen. } screen_touch_status_s_t; #ifdef PROS_USE_SIMPLE_NAMES @@ -97,7 +92,7 @@ typedef struct screen_touch_status_s { #define TEXT_MEDIUM pros::E_TEXT_MEDIUM #define TEXT_LARGE pros::E_TEXT_LARGE #define TEXT_MEDIUM_CENTER pros::E_TEXT_MEDIUM_CENTER -#define TEXT_LARGE_CENTER pros::E_LARGE_CENTER +#define TEXT_LARGE_CENTER pros::E_TEXT_LARGE_CENTER #define TOUCH_RELEASED pros::E_TOUCH_RELEASED #define TOUCH_PRESSED pros::E_TOUCH_PRESSED #define TOUCH_HELD pros::E_TOUCH_HELD diff --git a/include/pros/screen.hpp b/include/pros/screen.hpp index c3980e1f..cbfe2fcf 100644 --- a/include/pros/screen.hpp +++ b/include/pros/screen.hpp @@ -6,7 +6,7 @@ * * Contains user calls to the v5 screen for touching and displaying graphics. * - * \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/serial.h b/include/pros/serial.h index dc9ead56..4bda6069 100644 --- a/include/pros/serial.h +++ b/include/pros/serial.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/serial.hpp b/include/pros/serial.hpp index a2490e23..1996aef1 100644 --- a/include/pros/serial.hpp +++ b/include/pros/serial.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-serial Generic Serial C++ API */ @@ -20,8 +20,9 @@ #define _PROS_SERIAL_HPP_ #include -#include "pros/serial.h" + #include "pros/device.hpp" +#include "pros/serial.h" namespace pros { /** @@ -46,8 +47,8 @@ class Serial : public Device { * The V5 port number from 1-21 * \param baudrate * The baudrate to run the port at - * - * \b Example: + * + * \b Example: * \code * pros::Serial serial(1, 9600); * \endcode @@ -91,7 +92,7 @@ class Serial : public Device { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example: * \code * pros::Serial serial(1); @@ -142,7 +143,7 @@ class Serial : public Device { * * \return The number of bytes avaliable to be read or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example: * \code * void opcontrol() { @@ -192,7 +193,7 @@ class Serial : public Device { * * \return The next byte avaliable to be read, -1 if none are available, or * PROS_ERR if the operation failed, setting errno. - * + * * \b Example: * \code * void opcontrol() { @@ -318,12 +319,25 @@ class Serial : public Device { * \endcode */ virtual std::int32_t write(std::uint8_t* buffer, std::int32_t length) const; - + private: ///@} }; namespace literals { +/** + * Constructs a Serial device from a litteral ending in _ser + * + * \return a pros::Serial for the corresponding port + * + * \b Example + * \code + * using namespace pros::literals; + * void opcontrol() { + * pros::Serial serial = 2_ser; //Makes an Serial device object on port 2 + * } + * \endcode + */ const pros::Serial operator"" _ser(const unsigned long long int m); } // namespace literals } // namespace pros diff --git a/include/pros/version.h b/include/pros/version.h new file mode 100644 index 00000000..8804838a --- /dev/null +++ b/include/pros/version.h @@ -0,0 +1,23 @@ +/** +* \file version.h +* +* PROS Version Information +* +* Contains PROS kernel version information +* +* +* \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. +* All rights reserved. +* +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#define PROS_VERSION_MAJOR 4 +#define PROS_VERSION_MINOR 2 + +#define PROS_VERSION_PATCH 1 +#define PROS_VERSION_STRING "4.2.1" diff --git a/include/pros/vision.h b/include/pros/vision.h index dbda3fc7..6b3f104c 100644 --- a/include/pros/vision.h +++ b/include/pros/vision.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. * All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public diff --git a/include/pros/vision.hpp b/include/pros/vision.hpp index b8676794..0a845f6b 100644 --- a/include/pros/vision.hpp +++ b/include/pros/vision.hpp @@ -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. * All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public @@ -23,6 +23,7 @@ #include +#include "pros/device.hpp" #include "pros/vision.h" namespace pros { @@ -48,7 +49,7 @@ class Vision : public Device { * The V5 port number from 1-21 * \param zero_point * One of vision_zero_e_t to set the (0,0) coordinate for the FOV - * + * * \b Example * \code * void opcontrol() { @@ -56,7 +57,9 @@ class Vision : public Device { * } * \endcode */ - explicit Vision(std::uint8_t port, vision_zero_e_t zero_point = E_VISION_ZERO_TOPLEFT); + Vision(std::uint8_t port, vision_zero_e_t zero_point = E_VISION_ZERO_TOPLEFT); + + Vision(const Device& device) : Vision(device.get_port()){}; /** * Clears the vision sensor LED color, reseting it back to its default @@ -68,14 +71,14 @@ class Vision : public Device { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example - * \code - * void initialize() { + * \code + * void initialize() { * pros::Vision vision_sensor(1); - * vision_sensor.clear_led(); - * } - * \endcode + * vision_sensor.clear_led(); + * } + * \endcode */ std::int32_t clear_led(void) const; @@ -102,27 +105,27 @@ class Vision : public Device { * Signature type * * \return A vision_signature_s_t that can be set using Vision::set_signature - * + * * \b Example - * \code - * #define VISION_PORT 1 - * #define EXAMPLE_SIG 1 - * - * void opcontrol() { + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * + * void opcontrol() { * pros::Vision vision_sensor(VISION_PORT); - * // values acquired from the vision utility - * vision_signature_s_t RED_SIG = - * vision_signature_from_utility(EXAMPLE_SIG, 8973, 11143, 10058, -2119, -1053, -1586, 5.4, 0); - * vision_sensor.set_signature(EXAMPLE_SIG, &RED_SIG); - * while (true) { - * vision_signature_s_t rtn = vision_sensor.get_by_sig(VISION_PORT, 0, EXAMPLE_SIG); - * // Gets the largest object of the EXAMPLE_SIG signature - * printf("sig: %d", rtn.signature); - * // Prints "sig: 1" - * delay(2); - * } - * } - * \endcode + * // values acquired from the vision utility + * vision_signature_s_t RED_SIG = + * vision_signature_from_utility(EXAMPLE_SIG, 8973, 11143, 10058, -2119, -1053, -1586, 5.4, 0); + * vision_sensor.set_signature(EXAMPLE_SIG, &RED_SIG); + * while (true) { + * vision_signature_s_t rtn = vision_sensor.get_by_sig(VISION_PORT, 0, EXAMPLE_SIG); + * // Gets the largest object of the EXAMPLE_SIG signature + * printf("sig: %d", rtn.signature); + * // Prints "sig: 1" + * delay(2); + * } + * } + * \endcode */ static vision_signature_s_t signature_from_utility(const std::int32_t id, const std::int32_t u_min, const std::int32_t u_max, const std::int32_t u_mean, @@ -151,23 +154,37 @@ class Vision : public Device { * The fifth signature id [1-7] to add to the color code * * \return A vision_color_code_t object containing the color code information. - * + * * \b Example - * \code - * #define VISION_PORT 1 - * #define EXAMPLE_SIG 1 - * #define OTHER_SIG 2 - * - * void opcontrol() { + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * #define OTHER_SIG 2 + * + * void opcontrol() { * pros::Vision vision_sensor(VISION_PORT); - * vision_color_code_t code1 = vision_sensor.create_color_code(EXAMPLE_SIG, OTHER_SIG); - * } - * \endcode + * vision_color_code_t code1 = vision_sensor.create_color_code(EXAMPLE_SIG, OTHER_SIG); + * } + * \endcode */ vision_color_code_t create_color_code(const std::uint32_t sig_id1, const std::uint32_t sig_id2, const std::uint32_t sig_id3 = 0, const std::uint32_t sig_id4 = 0, const std::uint32_t sig_id5 = 0) const; + /** + * Gets all vision sensors. + * + * \return A vector of Vision sensor objects. + * + * \b Example + * \code + * void opcontrol() { + * std::vector vision_all = pros::Vision::get_all_devices(); // All vision sensors that are connected + * } + * \endcode + */ + static std::vector get_all_devices(); + /** * Gets the nth largest object according to size_id. * @@ -183,21 +200,21 @@ class Vision : public Device { * * \return The vision_object_s_t object corresponding to the given size id, or * PROS_ERR if an error occurred. - * + * * \b Example - * \code - * #define VISION_PORT 1 - * - * void opcontrol() { + * \code + * #define VISION_PORT 1 + * + * void opcontrol() { * pros::Vision vision_sensor(VISION_PORT); - * while (true) { - * vision_object_s_t rtn = vision_sensor.get_by_size(0); - * // Gets the largest object - * printf("sig: %d", rtn.signature); - * delay(2); - * } - * } - * \endcode + * while (true) { + * vision_object_s_t rtn = vision_sensor.get_by_size(0); + * // Gets the largest object + * printf("sig: %d", rtn.signature); + * delay(2); + * } + * } + * \endcode */ vision_object_s_t get_by_size(const std::uint32_t size_id) const; @@ -220,23 +237,23 @@ class Vision : public Device { * * \return The vision_object_s_t object corresponding to the given signature * and size_id, or PROS_ERR if an error occurred. - * + * * \b Example - * \code - * #define VISION_PORT 1 - * #define EXAMPLE_SIG 1 - * - * void opcontrol() { + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * + * void opcontrol() { * pros::Vision vision_sensor(VISION_PORT); - * while (true) { - * vision_object_s_t rtn = vision_sensor.get_by_sig(0, EXAMPLE_SIG); - * // Gets the largest object of the EXAMPLE_SIG signature - * printf("sig: %d", rtn.signature); - * // Prints "sig: 1" - * delay(2); - * } - * } - * \endcode + * while (true) { + * vision_object_s_t rtn = vision_sensor.get_by_sig(0, EXAMPLE_SIG); + * // Gets the largest object of the EXAMPLE_SIG signature + * printf("sig: %d", rtn.signature); + * // Prints "sig: 1" + * delay(2); + * } + * } + * \endcode */ vision_object_s_t get_by_sig(const std::uint32_t size_id, const std::uint32_t sig_id) const; @@ -256,29 +273,29 @@ class Vision : public Device { * * \return The vision_object_s_t object corresponding to the given color code * and size_id, or PROS_ERR if an error occurred. - * + * * \b Example - * \code - * #define VISION_PORT 1 - * #define EXAMPLE_SIG 1 - * #define OTHER_SIG 2 - * - * void opcontrol() { + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * #define OTHER_SIG 2 + * + * void opcontrol() { * pros::Vision vision_sensor(VISION_PORT); - * vision_color_code_t code1 = vision_sensor.create_color_code(EXAMPLE_SIG, OTHER_SIG); - * while (true) { - * vision_object_s_t rtn = vision_sensor.get_by_code(0, code1); - * // Gets the largest object - * printf("sig: %d", rtn.signature); - * delay(2); - * } - * } - * \endcode + * vision_color_code_t code1 = vision_sensor.create_color_code(EXAMPLE_SIG, OTHER_SIG); + * while (true) { + * vision_object_s_t rtn = vision_sensor.get_by_code(0, code1); + * // Gets the largest object + * printf("sig: %d", rtn.signature); + * delay(2); + * } + * } + * \endcode */ vision_object_s_t get_by_code(const std::uint32_t size_id, const vision_color_code_t color_code) const; /** - * Gets the exposure parameter of the Vision Sensor. + * Gets the exposure parameter of the Vision Sensor. * * This function uses the following values of errno when an error state is * reached: @@ -286,17 +303,17 @@ class Vision : public Device { * * \return The current exposure parameter from [0,150], * PROS_ERR if an error occurred - * + * * \b Example - * \code - * #define VISION_PORT 1 - * - * void initialize() { + * \code + * #define VISION_PORT 1 + * + * void initialize() { * pros::Vision vision_sensor(VISION_PORT); - * if (vision_sensor.get_exposure() < 50) - * vision_sensor.set_exposure(50); - * } - * \endcode + * if (vision_sensor.get_exposure() < 50) + * vision_sensor.set_exposure(50); + * } + * \endcode */ std::int32_t get_exposure(void) const; @@ -309,19 +326,19 @@ class Vision : public Device { * * \return The number of objects detected on the specified vision sensor. * Returns PROS_ERR if the port was invalid or an error occurred. - * + * * \b Example - * \code - * #define VISION_PORT 1 - * - * void opcontrol() { + * \code + * #define VISION_PORT 1 + * + * void opcontrol() { * pros::Vision vision_sensor(VISION_PORT); - * while (true) { - * printf("Number of Objects Detected: %d\n", vision_sensor.get_object_count()); - * delay(2); - * } - * } - * \endcode + * while (true) { + * printf("Number of Objects Detected: %d\n", vision_sensor.get_object_count()); + * delay(2); + * } + * } + * \endcode */ std::int32_t get_object_count(void) const; @@ -336,18 +353,18 @@ class Vision : public Device { * The signature id to read * * \return A vision_signature_s_t containing information about the signature. - * + * * \b Example - * \code - * #define VISION_PORT 1 - * #define EXAMPLE_SIG 1 - * - * void opcontrol() { + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * + * void opcontrol() { * pros::Vision vision_sensor(VISION_PORT); - * vision_signature_s_t sig = vision_sensor.get_signature(EXAMPLE_SIG); - * vision_sensor.print_signature(sig); - * } - * \endcode + * vision_signature_s_t sig = vision_sensor.get_signature(EXAMPLE_SIG); + * vision_sensor.print_signature(sig); + * } + * \endcode */ vision_signature_s_t get_signature(const std::uint8_t signature_id) const; @@ -359,22 +376,21 @@ class Vision : public Device { * ENODEV - The port cannot be configured as a vision sensor * * \return The current RGB white balance setting of the sensor - * + * * \b Example - * \code - * #define VISION_PORT 1 - * #define VISION_WHITE 0xff - * - * void initialize() { + * \code + * #define VISION_PORT 1 + * #define VISION_WHITE 0xff + * + * void initialize() { * pros::Vision vision_sensor(VISION_PORT); - * if (vision_sensor.get_white_balance() != VISION_WHITE) - * vision_sensor.set_white_balance(VISION_WHITE); - * } - * \endcode + * if (vision_sensor.get_white_balance() != VISION_WHITE) + * vision_sensor.set_white_balance(VISION_WHITE); + * } + * \endcode */ std::int32_t get_white_balance(void) const; - /** * Reads up to object_count object descriptors into object_arr. * @@ -397,23 +413,23 @@ class Vision : public Device { * Returns PROS_ERR if the port was invalid, an error occurred, or fewer objects * than size_id were found. All objects in object_arr that were not found are * given VISION_OBJECT_ERR_SIG as their signature. - * + * * \b Example - * \code - * #define VISION_PORT 1 - * #define NUM_VISION_OBJECTS 4 - * - * void opcontrol() { + * \code + * #define VISION_PORT 1 + * #define NUM_VISION_OBJECTS 4 + * + * void opcontrol() { * pros::Vision vision_sensor(VISION_PORT); - * vision_object_s_t object_arr[NUM_VISION_OBJECTS]; - * while (true) { - * vision_sensor.read_by_size(0, NUM_VISION_OBJECTS, object_arr); - * printf("sig: %d", object_arr[0].signature); - * // Prints the signature of the largest object found - * delay(2); - * } - * } - * \endcode + * vision_object_s_t object_arr[NUM_VISION_OBJECTS]; + * while (true) { + * vision_sensor.read_by_size(0, NUM_VISION_OBJECTS, object_arr); + * printf("sig: %d", object_arr[0].signature); + * // Prints the signature of the largest object found + * delay(2); + * } + * } + * \endcode */ std::int32_t read_by_size(const std::uint32_t size_id, const std::uint32_t object_count, vision_object_s_t* const object_arr) const; @@ -444,19 +460,19 @@ class Vision : public Device { * Returns PROS_ERR if the port was invalid, an error occurred, or fewer objects * than size_id were found. All objects in object_arr that were not found are * given VISION_OBJECT_ERR_SIG as their signature. - * + * * \b Example - * \code - * #define VISION_PORT 1 - * #define EXAMPLE_SIG 1 - * #define NUM_VISION_OBJECTS 4 - * - * void opcontrol() { + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * #define NUM_VISION_OBJECTS 4 + * + * void opcontrol() { * pros::Vision vision_sensor(VISION_PORT); - * vision_object_s_t object_arr[NUM_VISION_OBJECTS]; - * while (true) { - * vision_sensor.read_by_sig(0, EXAMPLE_SIG, NUM_VISION_OBJECTS, object_arr); - * printf("sig: %d", object_arr[0].signature); + * vision_object_s_t object_arr[NUM_VISION_OBJECTS]; + * while (true) { + * vision_sensor.read_by_sig(0, EXAMPLE_SIG, NUM_VISION_OBJECTS, object_arr); + * printf("sig: %d", object_arr[0].signature); * // Prints "sig: 1" * delay(2); * } @@ -490,14 +506,14 @@ class Vision : public Device { * Returns PROS_ERR if the port was invalid, an error occurred, or fewer objects * than size_id were found. All objects in object_arr that were not found are * given VISION_OBJECT_ERR_SIG as their signature. - * + * * \b Example - * \code + * \code * #define VISION_PORT 1 * #define EXAMPLE_SIG 1 * #define OTHER_SIG 2 * #define NUM_VISION_OBJECTS 4 - * + * * void opcontrol() { * pros::Vision vision_sensor(VISION_PORT); * vision_object_s_t object_arr[NUM_VISION_OBJECTS]; @@ -521,12 +537,12 @@ class Vision : public Device { * The signature for which the contents will be printed * * \return 1 if no errors occured, PROS_ERR otherwise - * + * * \b Example * \code - * #define VISION_PORT 1 + * #define VISION_PORT 1 * #define EXAMPLE_SIG 1 - * + * * void opcontrol() { * pros::Vision vision_sensor(VISION_PORT); * vision_signature_s_t sig = visionsensor.get_signature(EXAMPLE_SIG); @@ -548,11 +564,11 @@ class Vision : public Device { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example - * \code - * #define VISION_PORT 1 - * + * \code + * #define VISION_PORT 1 + * * void initialize() { * pros::Vision vision_sensor(VISION_PORT); * vision_sensor.set_auto_white_balance(true); @@ -562,7 +578,7 @@ class Vision : public Device { std::int32_t set_auto_white_balance(const std::uint8_t enable) const; /** - * Sets the exposure parameter of the Vision Sensor. + * Sets the exposure parameter of the Vision Sensor. * * This function uses the following values of errno when an error state is * reached: @@ -573,11 +589,11 @@ class Vision : public Device { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * #define VISION_PORT 1 - * + * * void initialize() { * pros::Vision vision_sensor(VISION_PORT); * if (vision_sensor.get_exposure() < 50) @@ -599,11 +615,11 @@ class Vision : public Device { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example * \code * #define VISION_PORT 1 - * + * * void initialize() { * pros::Vision vision_sensor(VISION_PORT); * vision_sensor.set_led(COLOR_BLANCHED_ALMOND); @@ -629,12 +645,12 @@ class Vision : public Device { * A pointer to the signature to save * * \return 1 if no errors occured, PROS_ERR otherwise - * + * * \b Example * \code * #define VISION_PORT 1 * #define EXAMPLE_SIG 1 - * + * * void opcontrol() { * pros::Vision vision_sensor(VISION_PORT); * vision_signature_s_t sig = vision_sensor.get_signature(EXAMPLE_SIG); @@ -657,12 +673,12 @@ class Vision : public Device { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example - * \code + * \code * #define VISION_PORT 1 * #define VISION_WHITE 0xff - * + * * void initialize() { * pros::Vision vision_sensor(VISION_PORT); * vision_sensor.set_white_balance(VISION_WHITE); @@ -687,11 +703,11 @@ class Vision : public Device { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example - * \code + * \code * #define VISION_PORT 1 - * + * * void initialize() { * pros::Vision vision_sensor(VISION_PORT); * vision_sensor.set_zero_point(E_VISION_ZERO_CENTER); @@ -712,22 +728,60 @@ class Vision : public Device { * * \return 1 if the operation was successful or PROS_ERR if the operation * failed, setting errno. - * + * * \b Example - * \code - * #define VISION_PORT 1 - * - * void initialize() { + * \code + * #define VISION_PORT 1 + * + * void initialize() { * pros::Vision vision_sensor(VISION_PORT); - * vision_sensor.set_wifi_mode(0); - * } - * \endcode + * vision_sensor.set_wifi_mode(0); + * } + * \endcode */ std::int32_t set_wifi_mode(const std::uint8_t enable) const; - + + /** + * Gets a vision sensor that is plugged in to the brain + * + * \note The first time this function is called it returns the vision sensor at the lowest port + * If this function is called multiple times, it will cycle through all the ports. + * For example, if you have 1 vision sensor on the robot + * this function will always return a vision sensor object for that port. + * If you have 2 vision sensors, all the odd numered calls to this function will return objects + * for the lower port number, + * all the even number calls will return vision objects for the higher port number + * + * + * This functions uses the following values of errno when an error state is + * reached: + * ENODEV - No vision sensor is plugged into the brain + * + * \return A vision object corresponding to a port that a vision sensor is connected to the brain + * If no vision sensor is plugged in, it returns a vision sensor on port PROS_ERR_BYTE + * + */ + static Vision get_vision(); + private: ///@} }; } // namespace v5 +namespace literals { +/** + * Constructs a Vision sensor from a litteral ending in _vis + * + * \return a pros::Vision for the corresponding port + * + * \b Example + * \code + * using namespace pros::literals; + * void opcontrol() { + * pros::Vision vision = 2_vis; //Makes an Vision sensor object on port 2 + * } + * \endcode + */ +const pros::Vision operator"" _vis(const unsigned long long int m); +} // namespace literals } // namespace pros #endif // _PROS_VISION_HPP_ diff --git a/include/robodash/api.h b/include/robodash/api.h index 66c880dd..8c497f9a 100644 --- a/include/robodash/api.h +++ b/include/robodash/api.h @@ -9,8 +9,8 @@ #define ROBODASH #define RD_VERSION_MAJOR 2 -#define RD_VERSION_MINOR 0 -#define RD_VERSION_PATCH 0 +#define RD_VERSION_MINOR 3 +#define RD_VERSION_PATCH 1 #include "liblvgl/lvgl.h" diff --git a/include/robodash/impl/styles.h b/include/robodash/impl/styles.h index ebc3ad59..f317f810 100644 --- a/include/robodash/impl/styles.h +++ b/include/robodash/impl/styles.h @@ -49,6 +49,7 @@ extern void _init_style_misc(); extern lv_style_t style_list; extern lv_style_t style_list_btn; extern lv_style_t style_list_btn_pr; +extern lv_style_t style_list_btn_ch; extern void _init_style_list(); diff --git a/include/robodash/views/image.hpp b/include/robodash/views/image.hpp index f9d27082..cd82d7e2 100644 --- a/include/robodash/views/image.hpp +++ b/include/robodash/views/image.hpp @@ -40,18 +40,26 @@ class Image { /** * @brief Create a new Image * - * @param name File path to the binary-formatted image on SD card - * @param path Name to display on screen + * @param path File path to the binary-formatted image on SD card + * @param name Name to display on screen */ Image(std::string path, std::string name = "Image"); /** * @brief Create a new Image * - * @param image_dsc LVGL image descriptor object + * @param image_dsc Pointer to LVGL image descriptor object + * @param name Name to display on screen + */ + Image(lv_img_dsc_t *image_dsc, std::string name = "Image"); + + /** + * @brief Create a new Image + * + * @param image_dsc Pointer to constant LVGL image descriptor object * @param name Name to display on screen */ - Image(lv_img_dsc_t image_dsc, std::string name = "Image"); + Image(const lv_img_dsc_t *image_dsc, std::string name = "Image"); /** * @brief Set this view to the active view @@ -61,4 +69,4 @@ class Image { /// @} }; -} // namespace rd \ No newline at end of file +} // namespace rd diff --git a/include/robodash/views/selector.hpp b/include/robodash/views/selector.hpp index 885ad675..dfa87286 100644 --- a/include/robodash/views/selector.hpp +++ b/include/robodash/views/selector.hpp @@ -7,6 +7,7 @@ #pragma once #include "robodash/api.h" #include +#include #include #include @@ -17,8 +18,9 @@ namespace rd { * @brief A function selector * @image html selector.png * - * A function selector for easily managing autonomous routines. Supports saving a configuration to - * an SD card, and automatically loading it on the next run. + * A function selector for easily managing autonomous routines. If available, automatically saves + * the current configuration to an SD card and loads it on the next run. Also supports displaying + * images from the SD card. */ /** @@ -28,20 +30,31 @@ namespace rd { class Selector { /// @addtogroup selector /// @{ - private: - rd_view_t *view; - public: /// @name Selector Typedefs typedef std::function routine_action_t; - typedef std::pair routine_t; + + typedef struct routine { + std::string name; + routine_action_t action; + std::string img = ""; + int color_hue = -1; + } routine_t; + + typedef std::function)> select_action_t; /// @name Selector Functions + /** + * @brief Create autonomous selector + * @param name Name of the autonomous selector + * @param autons Vector of autonomous rotuines + */ + Selector(std::string name, std::vector autons); + /** * @brief Create autonomous selector * @param autons Vector of autonomous rotuines - * @bug Multiple selectors cannot be active at the same time. */ Selector(std::vector autons); @@ -50,12 +63,64 @@ class Selector { */ void run_auton(); + /** + * Get the selected auton + * @return Selected auton + */ + std::optional get_auton(); + + /** + * @brief Add a selection callback + * @param callback The callback function + */ + void on_select(select_action_t callback); + + /** + * @brief Select the next auton in the list + * @param wrap_around Whether to wrap around to the beginning once the last auton is reached + * + * Selects the next auton in the list for use with physical buttons such as limit switches. + */ + void next_auton(bool wrap_around = true); + + /** + * @brief Select the previous auton in the list + * @param wrap_around Whether to wrap around to the end once the first auton is reached + * + * Selects the previous auton in the list for use with physical buttons such as limit switches. + */ + void prev_auton(bool wrap_around = true); + /** * @brief Set this view to the active view */ void focus(); /// @} + + private: + rd_view_t *view; + + lv_obj_t *routine_list; + lv_obj_t *selected_cont; + lv_obj_t *selected_label; + lv_obj_t *selected_img; + + std::string name; + std::vector routines; + std::vector select_callbacks; + rd::Selector::routine_t *selected_routine; + + void sd_save(); + void sd_load(); + + void run_callbacks(); + + static void select_cb(lv_event_t *event); + static void up_cb(lv_event_t *event); + static void down_cb(lv_event_t *event); + static void pg_up_cb(lv_event_t *event); + static void pg_down_cb(lv_event_t *event); }; } // namespace rd \ No newline at end of file diff --git a/project.pros b/project.pros index 03391d72..586256c6 100644 --- a/project.pros +++ b/project.pros @@ -5,260 +5,266 @@ "target": "v5", "templates": { "kernel": { - "location": "/Users/alex/Library/Application Support/PROS/templates/kernel@4.0.6", + "location": "C:\\Users\\thurs\\AppData\\Roaming\\PROS\\templates\\kernel@4.2.1", "metadata": { "cold_addr": "58720256", "cold_output": "bin/cold.package.bin", "hot_addr": "125829120", "hot_output": "bin/hot.package.bin", - "origin": "kernel-beta-mainline", + "origin": "pros-mainline", "output": "bin/monolith.bin" }, "name": "kernel", "py/object": "pros.conductor.templates.local_template.LocalTemplate", "supported_kernels": null, "system_files": [ - "firmware\\v5.ld", - "include\\pros\\colors.h", - "include\\pros\\distance.hpp", - "include\\pros\\llemu.hpp", - "firmware\\libm.a", - "include\\pros\\motor_group.hpp", - "include\\pros\\serial.hpp", + "include/pros/rotation.hpp", + "include/pros/rotation.h", + "include/pros/colors.hpp", + "include/pros/llemu.h", + "firmware/v5-common.ld", + "include/pros/imu.h", + "include/pros/vision.hpp", + "include/pros/abstract_motor.hpp", + "include/pros/misc.hpp", + "include/pros/adi.hpp", + "firmware/v5-hot.ld", + "include/pros/screen.h", + "include/pros/adi.h", + "include/pros/ai_vision.hpp", + "include/pros/gps.hpp", + "include/pros/rtos.hpp", + "include/pros/misc.h", + "include/pros/colors.h", + "include/pros/ai_vision.h", + "include/pros/imu.hpp", + "firmware/libpros.a", + "include/pros/motors.hpp", + "include/api.h", "common.mk", - "include\\pros\\device.hpp", - "include\\pros\\screen.hpp", - "include\\pros\\abstract_motor.hpp", - "include\\pros\\gps.h", - "include\\pros\\colors.hpp", - "include\\pros\\adi.h", - "include\\pros\\screen.h", - "include\\pros\\rotation.hpp", - "firmware\\v5-hot.ld", - "include\\pros\\link.h", - "include\\pros\\rotation.h", - "include\\api.h", - "include\\pros\\ext_adi.h", - "include\\pros\\device.h", - "include\\pros\\motors.hpp", - "firmware\\v5-common.ld", - "include\\pros\\apix.h", - "include\\pros\\rtos.hpp", - "include\\pros\\vision.hpp", - "include\\pros\\vision.h", - "include\\pros\\gps.hpp", - "include\\pros\\motors.h", - "include\\pros\\rtos.h", - "include\\pros\\imu.hpp", - "include\\pros\\llemu.h", - "include\\pros\\distance.h", - "firmware\\libc.a", - "include\\pros\\misc.hpp", - "include\\pros\\error.h", - "include\\pros\\serial.h", - "firmware\\libpros.a", - "include\\pros\\optical.h", - "include\\pros\\optical.hpp", - "include\\pros\\misc.h", - "include\\pros\\imu.h", - "include\\pros\\adi.hpp", - "include\\pros\\link.hpp" + "include/pros/link.h", + "include/pros/device.h", + "include/pros/link.hpp", + "include/pros/gps.h", + "include/pros/motor_group.hpp", + "include/pros/motors.h", + "include/pros/ext_adi.h", + "include/pros/optical.h", + "include/pros/serial.h", + "include/pros/distance.h", + "include/pros/llemu.hpp", + "include/pros/device.hpp", + "include/pros/rtos.h", + "firmware/libc.a", + "include/pros/vision.h", + "include/pros/screen.hpp", + "include/pros/error.h", + "include/pros/serial.hpp", + "firmware/v5.ld", + "include/pros/distance.hpp", + "include/pros/apix.h", + "firmware/libm.a", + "include/pros/optical.hpp", + "include/pros/version.h" ], "target": "v5", "user_files": [ - "include\\main.hpp", ".gitignore", - "include\\main.h", - "src\\main.cpp", + "src/main.cc", + "src/main.c", + "src/main.cpp", "Makefile", - "include\\main.hh", - "src\\main.c", - "src\\main.cc" + "include/main.hh", + "include/main.hpp", + "include/main.h", + "src\\main.cpp", + "include\\main.h" ], - "version": "4.0.6" + "version": "4.2.1" }, "liblvgl": { - "location": "/Users/alex/Library/Application Support/PROS/templates/liblvgl@8.3.7", + "location": "C:\\Users\\thurs\\AppData\\Roaming\\PROS\\templates\\liblvgl@8.3.9", "metadata": { - "origin": "kernel-beta-mainline" + "origin": "pros-mainline" }, "name": "liblvgl", "py/object": "pros.conductor.templates.local_template.LocalTemplate", - "supported_kernels": ">=4.0.0", + "supported_kernels": ">=4.2.0", "system_files": [ - "include\\liblvgl\\draw\\lv_draw_line.h", - "include\\liblvgl\\draw\\lv_draw_triangle.h", - "include\\liblvgl\\extra\\others\\gridnav\\lv_gridnav.h", - "include\\liblvgl\\extra\\others\\ime\\lv_ime_pinyin.h", - "include\\liblvgl\\widgets\\lv_slider.h", - "include\\liblvgl\\extra\\libs\\freetype\\lv_freetype.h", - "include\\liblvgl\\extra\\widgets\\span\\lv_span.h", - "include\\liblvgl\\misc\\lv_assert.h", - "include\\liblvgl\\misc\\lv_async.h", - "include\\liblvgl\\widgets\\lv_line.h", - "include\\liblvgl\\core\\lv_indev_scroll.h", - "include\\liblvgl\\draw\\sw\\lv_draw_sw_dither.h", - "include\\liblvgl\\extra\\widgets\\spinner\\lv_spinner.h", - "include\\liblvgl\\extra\\others\\monkey\\lv_monkey.h", - "include\\liblvgl\\draw\\nxp\\vglite\\lv_draw_vglite_blend.h", - "include\\liblvgl\\draw\\sdl\\lv_draw_sdl.h", - "include\\liblvgl\\extra\\libs\\png\\lv_png.h", - "include\\liblvgl\\widgets\\lv_label.h", - "include\\liblvgl\\widgets\\lv_btnmatrix.h", - "include\\liblvgl\\extra\\layouts\\lv_layouts.h", - "include\\liblvgl\\extra\\libs\\gif\\gifdec.h", - "include\\liblvgl\\extra\\widgets\\list\\lv_list.h", - "include\\liblvgl\\draw\\lv_draw_label.h", - "include\\liblvgl\\extra\\others\\snapshot\\lv_snapshot.h", - "include\\liblvgl\\draw\\lv_draw_arc.h", - "include\\liblvgl\\extra\\themes\\lv_themes.h", - "include\\liblvgl\\extra\\widgets\\msgbox\\lv_msgbox.h", - "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_layer.h", - "include\\liblvgl\\lv_version.h", - "include\\liblvgl\\font\\lv_font_fmt_txt.h", - "include\\liblvgl\\core\\lv_disp.h", - "include\\liblvgl\\draw\\sw\\lv_draw_sw.h", - "include\\liblvgl\\core\\lv_obj_class.h", - "include\\liblvgl\\extra\\others\\imgfont\\lv_imgfont.h", - "include\\liblvgl\\extra\\themes\\basic\\lv_theme_basic.h", - "include\\liblvgl\\extra\\widgets\\calendar\\lv_calendar.h", - "include\\liblvgl\\misc\\lv_anim.h", - "include\\liblvgl\\misc\\lv_utils.h", - "include\\liblvgl\\misc\\lv_style.h", - "include\\liblvgl\\draw\\nxp\\pxp\\lv_gpu_nxp_pxp.h", - "include\\liblvgl\\widgets\\lv_objx_templ.h", - "include\\liblvgl\\draw\\nxp\\vglite\\lv_draw_vglite_rect.h", - "include\\liblvgl\\extra\\layouts\\grid\\lv_grid.h", - "include\\liblvgl\\lv_conf_kconfig.h", - "include\\liblvgl\\draw\\lv_img_decoder.h", - "include\\liblvgl\\hal\\lv_hal_disp.h", - "include\\liblvgl\\llemu.hpp", - "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_priv.h", - "include\\liblvgl\\draw\\sw\\lv_draw_sw_gradient.h", - "include\\liblvgl\\extra\\widgets\\calendar\\lv_calendar_header_arrow.h", - "include\\liblvgl\\extra\\widgets\\calendar\\lv_calendar_header_dropdown.h", - "include\\liblvgl\\core\\lv_obj.h", - "include\\liblvgl\\extra\\libs\\sjpg\\lv_sjpg.h", - "include\\liblvgl\\extra\\widgets\\lv_widgets.h", - "include\\liblvgl\\lvgl.h", - "include\\liblvgl\\draw\\lv_img_buf.h", - "include\\liblvgl\\extra\\widgets\\spinbox\\lv_spinbox.h", - "include\\liblvgl\\draw\\nxp\\vglite\\lv_gpu_nxp_vglite.h", - "include\\liblvgl\\draw\\lv_draw_rect.h", - "include\\liblvgl\\draw\\lv_img_cache.h", - "include\\liblvgl\\extra\\libs\\sjpg\\tjpgd.h", - "include\\liblvgl\\draw\\sw\\lv_draw_sw_blend.h", - "include\\liblvgl\\extra\\others\\fragment\\lv_fragment.h", - "include\\liblvgl\\widgets\\lv_dropdown.h", - "include\\liblvgl\\draw\\lv_draw_layer.h", - "include\\liblvgl\\extra\\libs\\qrcode\\qrcodegen.h", - "include\\liblvgl\\core\\lv_obj_style_gen.h", - "include\\liblvgl\\core\\lv_theme.h", - "include\\liblvgl\\widgets\\lv_arc.h", - "include\\liblvgl\\extra\\widgets\\tileview\\lv_tileview.h", - "include\\liblvgl\\llemu.h", - "include\\liblvgl\\misc\\lv_tlsf.h", - "include\\liblvgl\\misc\\lv_log.h", - "include\\liblvgl\\extra\\libs\\fsdrv\\lv_fsdrv.h", - "include\\liblvgl\\misc\\lv_ll.h", - "include\\liblvgl\\widgets\\lv_btn.h", - "include\\liblvgl\\misc\\lv_area.h", - "include\\liblvgl\\misc\\lv_fs.h", - "include\\liblvgl\\extra\\libs\\gif\\lv_gif.h", - "include\\liblvgl\\misc\\lv_txt_ap.h", - "include\\liblvgl\\draw\\stm32_dma2d\\lv_gpu_stm32_dma2d.h", - "include\\liblvgl\\misc\\lv_style_gen.h", - "include\\liblvgl\\widgets\\lv_canvas.h", - "include\\liblvgl\\font\\lv_font_loader.h", - "firmware\\liblvgl.a", - "include\\liblvgl\\core\\lv_obj_scroll.h", - "include\\liblvgl\\core\\lv_indev.h", - "include\\liblvgl\\extra\\libs\\ffmpeg\\lv_ffmpeg.h", - "include\\liblvgl\\extra\\widgets\\imgbtn\\lv_imgbtn.h", - "include\\liblvgl\\core\\lv_obj_pos.h", - "include\\liblvgl\\core\\lv_obj_style.h", - "include\\liblvgl\\widgets\\lv_table.h", - "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_stack_blur.h", - "include\\liblvgl\\lv_conf_internal.h", - "include\\liblvgl\\misc\\lv_timer.h", - "include\\liblvgl\\core\\lv_obj_draw.h", - "include\\liblvgl\\draw\\nxp\\lv_gpu_nxp.h", - "include\\liblvgl\\extra\\widgets\\win\\lv_win.h", - "include\\liblvgl\\extra\\others\\msg\\lv_msg.h", - "include\\liblvgl\\extra\\libs\\lv_libs.h", - "include\\liblvgl\\widgets\\lv_bar.h", - "include\\liblvgl\\extra\\others\\lv_others.h", - "include\\liblvgl\\misc\\lv_math.h", - "include\\liblvgl\\widgets\\lv_img.h", - "include\\liblvgl\\lv_conf_checker.h", - "include\\liblvgl\\misc\\lv_mem.h", - "include\\liblvgl\\widgets\\lv_textarea.h", - "include\\liblvgl\\lv_conf.h", - "include\\liblvgl\\extra\\widgets\\keyboard\\lv_keyboard.h", - "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_mask.h", - "include\\liblvgl\\draw\\lv_draw_mask.h", - "include\\liblvgl\\core\\lv_obj_tree.h", - "include\\liblvgl\\extra\\themes\\default\\lv_theme_default.h", - "include\\liblvgl\\extra\\lv_extra.h", - "include\\liblvgl\\extra\\widgets\\colorwheel\\lv_colorwheel.h", - "include\\liblvgl\\core\\lv_group.h", - "include\\liblvgl\\hal\\lv_hal_indev.h", - "include\\liblvgl\\draw\\nxp\\vglite\\lv_draw_vglite_arc.h", - "include\\liblvgl\\draw\\arm2d\\lv_gpu_arm2d.h", - "include\\liblvgl\\widgets\\lv_checkbox.h", - "include\\liblvgl\\draw\\swm341_dma2d\\lv_gpu_swm341_dma2d.h", - "include\\liblvgl\\extra\\themes\\mono\\lv_theme_mono.h", - "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_img.h", - "include\\liblvgl\\misc\\lv_bidi.h", - "include\\liblvgl\\misc\\lv_txt.h", - "include\\liblvgl\\extra\\widgets\\led\\lv_led.h", - "include\\liblvgl\\extra\\libs\\rlottie\\lv_rlottie.h", - "include\\liblvgl\\misc\\lv_printf.h", - "include\\liblvgl\\font\\lv_font.h", - "include\\liblvgl\\core\\lv_refr.h", - "include\\liblvgl\\lv_api_map.h", - "include\\liblvgl\\misc\\lv_color.h", - "include\\liblvgl\\misc\\lv_gc.h", - "include\\liblvgl\\misc\\lv_templ.h", - "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_composite.h", - "include\\liblvgl\\hal\\lv_hal_tick.h", - "include\\liblvgl\\misc\\lv_types.h", - "include\\liblvgl\\draw\\nxp\\pxp\\lv_draw_pxp_blend.h", - "include\\liblvgl\\draw\\lv_draw.h", - "include\\liblvgl\\extra\\libs\\bmp\\lv_bmp.h", - "include\\liblvgl\\extra\\libs\\qrcode\\lv_qrcode.h", - "include\\liblvgl\\extra\\widgets\\meter\\lv_meter.h", - "include\\liblvgl\\font\\lv_symbol_def.h", - "include\\liblvgl\\extra\\layouts\\flex\\lv_flex.h", - "include\\liblvgl\\widgets\\lv_roller.h", - "include\\liblvgl\\draw\\lv_draw_transform.h", - "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_utils.h", - "include\\liblvgl\\lv_conf.old.h", - "include\\liblvgl\\misc\\lv_anim_timeline.h", - "include\\liblvgl\\misc\\lv_lru.h", - "include\\liblvgl\\hal\\lv_hal.h", - "include\\liblvgl\\extra\\libs\\sjpg\\tjpgdcnf.h", - "include\\liblvgl\\extra\\widgets\\tabview\\lv_tabview.h", - "include\\liblvgl\\extra\\widgets\\menu\\lv_menu.h", - "include\\liblvgl\\extra\\widgets\\animimg\\lv_animimg.h", - "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_texture_cache.h", - "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_rect.h", - "include\\liblvgl\\extra\\widgets\\chart\\lv_chart.h", - "include\\liblvgl\\core\\lv_event.h", - "include\\liblvgl\\draw\\lv_draw_img.h", - "include\\liblvgl\\widgets\\lv_switch.h", - "include\\liblvgl\\draw\\nxp\\pxp\\lv_gpu_nxp_pxp_osa.h", - "include\\liblvgl\\extra\\libs\\png\\lodepng.h" + "include/liblvgl/core/lv_theme.h", + "include/liblvgl/draw/sdl/lv_draw_sdl_texture_cache.h", + "include/liblvgl/extra/libs/png/lv_png.h", + "include/liblvgl/extra/libs/freetype/lv_freetype.h", + "include/liblvgl/draw/sdl/lv_draw_sdl_utils.h", + "include/liblvgl/draw/sw/lv_draw_sw_dither.h", + "include/liblvgl/extra/widgets/menu/lv_menu.h", + "include/liblvgl/extra/libs/sjpg/tjpgd.h", + "include/liblvgl/extra/others/imgfont/lv_imgfont.h", + "include/liblvgl/draw/nxp/lv_gpu_nxp.h", + "firmware/liblvgl.a", + "include/liblvgl/misc/lv_txt.h", + "include/liblvgl/lvgl.h", + "include/liblvgl/misc/lv_assert.h", + "include/liblvgl/widgets/lv_btnmatrix.h", + "include/liblvgl/extra/libs/rlottie/lv_rlottie.h", + "include/liblvgl/misc/lv_color.h", + "include/liblvgl/extra/widgets/led/lv_led.h", + "include/liblvgl/widgets/lv_label.h", + "include/liblvgl/core/lv_disp.h", + "include/liblvgl/extra/libs/ffmpeg/lv_ffmpeg.h", + "include/liblvgl/extra/themes/basic/lv_theme_basic.h", + "include/liblvgl/lv_conf.h", + "include/liblvgl/extra/layouts/flex/lv_flex.h", + "include/liblvgl/widgets/lv_img.h", + "include/liblvgl/misc/lv_anim.h", + "include/liblvgl/draw/nxp/vglite/lv_gpu_nxp_vglite.h", + "include/liblvgl/core/lv_obj_class.h", + "include/liblvgl/draw/lv_draw_triangle.h", + "include/liblvgl/lv_conf.old.h", + "include/liblvgl/extra/widgets/animimg/lv_animimg.h", + "include/liblvgl/draw/nxp/pxp/lv_gpu_nxp_pxp.h", + "include/liblvgl/lv_conf_kconfig.h", + "include/liblvgl/misc/lv_mem.h", + "include/liblvgl/misc/lv_async.h", + "include/liblvgl/draw/sdl/lv_draw_sdl.h", + "include/liblvgl/draw/lv_draw_mask.h", + "include/liblvgl/extra/widgets/tabview/lv_tabview.h", + "include/liblvgl/misc/lv_bidi.h", + "include/liblvgl/font/lv_font_loader.h", + "include/liblvgl/core/lv_indev.h", + "include/liblvgl/widgets/lv_table.h", + "include/liblvgl/hal/lv_hal_tick.h", + "include/liblvgl/extra/layouts/grid/lv_grid.h", + "include/liblvgl/misc/lv_templ.h", + "include/liblvgl/extra/libs/gif/lv_gif.h", + "include/liblvgl/extra/themes/default/lv_theme_default.h", + "include/liblvgl/draw/sw/lv_draw_sw.h", + "include/liblvgl/draw/lv_draw_label.h", + "include/liblvgl/extra/widgets/calendar/lv_calendar.h", + "include/liblvgl/widgets/lv_canvas.h", + "include/liblvgl/widgets/lv_roller.h", + "include/liblvgl/draw/sdl/lv_draw_sdl_rect.h", + "include/liblvgl/hal/lv_hal_indev.h", + "include/liblvgl/extra/libs/sjpg/lv_sjpg.h", + "include/liblvgl/core/lv_indev_scroll.h", + "include/liblvgl/draw/lv_draw_line.h", + "include/liblvgl/draw/nxp/vglite/lv_draw_vglite_arc.h", + "include/liblvgl/draw/sdl/lv_draw_sdl_mask.h", + "include/liblvgl/font/lv_font_fmt_txt.h", + "include/liblvgl/extra/widgets/colorwheel/lv_colorwheel.h", + "include/liblvgl/llemu.h", + "include/liblvgl/misc/lv_tlsf.h", + "include/liblvgl/core/lv_obj.h", + "include/liblvgl/extra/widgets/imgbtn/lv_imgbtn.h", + "include/liblvgl/draw/lv_draw.h", + "include/liblvgl/font/lv_symbol_def.h", + "include/liblvgl/draw/lv_draw_rect.h", + "include/liblvgl/extra/libs/qrcode/lv_qrcode.h", + "include/liblvgl/draw/sdl/lv_draw_sdl_priv.h", + "include/liblvgl/hal/lv_hal_disp.h", + "include/liblvgl/widgets/lv_objx_templ.h", + "include/liblvgl/misc/lv_timer.h", + "include/liblvgl/draw/sdl/lv_draw_sdl_composite.h", + "include/liblvgl/misc/lv_fs.h", + "include/liblvgl/draw/lv_draw_arc.h", + "include/liblvgl/draw/sdl/lv_draw_sdl_img.h", + "include/liblvgl/draw/lv_draw_img.h", + "include/liblvgl/extra/libs/fsdrv/lv_fsdrv.h", + "include/liblvgl/draw/lv_img_decoder.h", + "include/liblvgl/extra/widgets/calendar/lv_calendar_header_arrow.h", + "include/liblvgl/extra/widgets/calendar/lv_calendar_header_dropdown.h", + "include/liblvgl/extra/others/gridnav/lv_gridnav.h", + "include/liblvgl/lv_version.h", + "include/liblvgl/core/lv_refr.h", + "include/liblvgl/extra/others/msg/lv_msg.h", + "include/liblvgl/widgets/lv_line.h", + "include/liblvgl/extra/libs/sjpg/tjpgdcnf.h", + "include/liblvgl/misc/lv_area.h", + "include/liblvgl/widgets/lv_btn.h", + "include/liblvgl/extra/lv_extra.h", + "include/liblvgl/extra/libs/bmp/lv_bmp.h", + "include/liblvgl/misc/lv_printf.h", + "include/liblvgl/extra/widgets/meter/lv_meter.h", + "include/liblvgl/extra/widgets/win/lv_win.h", + "include/liblvgl/widgets/lv_checkbox.h", + "include/liblvgl/extra/widgets/msgbox/lv_msgbox.h", + "include/liblvgl/draw/nxp/pxp/lv_draw_pxp_blend.h", + "include/liblvgl/draw/swm341_dma2d/lv_gpu_swm341_dma2d.h", + "include/liblvgl/draw/lv_img_cache.h", + "include/liblvgl/extra/widgets/spinner/lv_spinner.h", + "include/liblvgl/widgets/lv_slider.h", + "include/liblvgl/misc/lv_math.h", + "include/liblvgl/misc/lv_txt_ap.h", + "include/liblvgl/extra/libs/lv_libs.h", + "include/liblvgl/misc/lv_lru.h", + "include/liblvgl/extra/widgets/list/lv_list.h", + "include/liblvgl/extra/others/fragment/lv_fragment.h", + "include/liblvgl/misc/lv_types.h", + "include/liblvgl/extra/widgets/keyboard/lv_keyboard.h", + "include/liblvgl/extra/widgets/lv_widgets.h", + "include/liblvgl/widgets/lv_switch.h", + "include/liblvgl/draw/lv_draw_transform.h", + "include/liblvgl/core/lv_obj_style_gen.h", + "include/liblvgl/extra/themes/mono/lv_theme_mono.h", + "include/liblvgl/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h", + "include/liblvgl/extra/others/snapshot/lv_snapshot.h", + "include/liblvgl/extra/themes/lv_themes.h", + "include/liblvgl/widgets/lv_bar.h", + "include/liblvgl/core/lv_event.h", + "include/liblvgl/core/lv_group.h", + "include/liblvgl/misc/lv_log.h", + "include/liblvgl/widgets/lv_dropdown.h", + "include/liblvgl/hal/lv_hal.h", + "include/liblvgl/draw/sdl/lv_draw_sdl_stack_blur.h", + "include/liblvgl/draw/sw/lv_draw_sw_blend.h", + "include/liblvgl/extra/widgets/spinbox/lv_spinbox.h", + "include/liblvgl/misc/lv_style_gen.h", + "include/liblvgl/extra/layouts/lv_layouts.h", + "include/liblvgl/misc/lv_style.h", + "include/liblvgl/draw/lv_img_buf.h", + "include/liblvgl/extra/others/lv_others.h", + "include/liblvgl/lv_conf_internal.h", + "include/liblvgl/draw/sw/lv_draw_sw_gradient.h", + "include/liblvgl/draw/sdl/lv_draw_sdl_layer.h", + "include/liblvgl/lv_conf_checker.h", + "include/liblvgl/misc/lv_gc.h", + "include/liblvgl/core/lv_obj_draw.h", + "include/liblvgl/extra/widgets/span/lv_span.h", + "include/liblvgl/llemu.hpp", + "include/liblvgl/misc/lv_ll.h", + "include/liblvgl/extra/others/monkey/lv_monkey.h", + "include/liblvgl/extra/widgets/chart/lv_chart.h", + "include/liblvgl/font/lv_font.h", + "include/liblvgl/core/lv_obj_tree.h", + "include/liblvgl/draw/arm2d/lv_gpu_arm2d.h", + "include/liblvgl/draw/nxp/vglite/lv_draw_vglite_rect.h", + "include/liblvgl/core/lv_obj_scroll.h", + "include/liblvgl/extra/libs/png/lodepng.h", + "include/liblvgl/extra/libs/gif/gifdec.h", + "include/liblvgl/lv_api_map.h", + "include/liblvgl/misc/lv_anim_timeline.h", + "include/liblvgl/extra/others/ime/lv_ime_pinyin.h", + "include/liblvgl/core/lv_obj_pos.h", + "include/liblvgl/misc/lv_utils.h", + "include/liblvgl/draw/lv_draw_layer.h", + "include/liblvgl/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.h", + "include/liblvgl/widgets/lv_arc.h", + "include/liblvgl/core/lv_obj_style.h", + "include/liblvgl/extra/widgets/tileview/lv_tileview.h", + "include/liblvgl/widgets/lv_textarea.h", + "include/liblvgl/extra/libs/qrcode/qrcodegen.h", + "include/liblvgl/draw/nxp/vglite/lv_draw_vglite_blend.h" ], "target": "v5", "user_files": [], - "version": "8.3.7" + "version": "8.3.9" } }, "upload_options": { "description": "robodash demo ", "icon": "pros", "slot": 3 - } + }, + "use_early_access": false } } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index baeff1b2..81e668f9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,14 +6,16 @@ void best_auton() { std::cout << "Running best auton" << std::endl; } void simple_auton() { std::cout << "Running simple auton " << std::endl; } void good_auton() { std::cout << "Running good auton" << std::endl; } +void skills() { std::cout << "Running skills" << std::endl; } // ================================= Views ================================= // // Create robodash selector rd::Selector selector({ - {"Best auton", &best_auton }, - {"Simple auton", &simple_auton}, - {"Good auton", &good_auton } + {"Best auton", &best_auton, "", 0}, + {"Simple auton", &simple_auton, "", 220}, + {"Good auton", &good_auton, "", 100}, + {"Skills", &skills}, }); // Create robodash console @@ -21,7 +23,16 @@ rd::Console console; // ========================= Competition Functions ========================= // -void initialize() {} +void initialize() { + // Selector callback example, prints selected auton to the console + selector.on_select([](std::optional routine) { + if (routine == std::nullopt) { + std::cout << "No routine selected" << std::endl; + } else { + std::cout << "Selected Routine: " << routine.value().name << std::endl; + } + }); +} void disabled() {} diff --git a/src/robodash/styles/colors.c b/src/robodash/styles/colors.c index 7de79912..9d639aa9 100644 --- a/src/robodash/styles/colors.c +++ b/src/robodash/styles/colors.c @@ -1,3 +1,4 @@ +#include "liblvgl/misc/lv_color.h" #include "robodash/apix.h" // ================================= Colors ================================= // diff --git a/src/robodash/styles/list.c b/src/robodash/styles/list.c index 81f30de4..1146ca77 100644 --- a/src/robodash/styles/list.c +++ b/src/robodash/styles/list.c @@ -5,6 +5,7 @@ lv_style_t style_list; lv_style_t style_list_btn; lv_style_t style_list_btn_pr; +lv_style_t style_list_btn_ch; void _init_style_list() { // List @@ -13,9 +14,7 @@ void _init_style_list() { lv_style_set_border_width(&style_list, 1); lv_style_set_border_opa(&style_list, LV_OPA_COVER); lv_style_set_bg_color(&style_list, color_bg); - lv_style_set_pad_ver(&style_list, 0); - lv_style_set_pad_hor(&style_list, 8); - lv_style_set_pad_gap(&style_list, 0); + lv_style_set_pad_hor(&style_list, 0); // List button lv_style_init(&style_list_btn); @@ -31,4 +30,9 @@ void _init_style_list() { // List button pressed lv_style_init(&style_list_btn_pr); lv_style_set_bg_color(&style_list_btn_pr, color_shade); -} \ No newline at end of file + + // List button checked + lv_style_init(&style_list_btn_ch); + lv_style_set_bg_color(&style_list_btn_ch, lv_color_darken(color_shade, 64)); + lv_style_set_transform_width(&style_list_btn_ch, 0); +} diff --git a/src/robodash/styles/text.c b/src/robodash/styles/text.c index b3cefbcd..fbb20468 100644 --- a/src/robodash/styles/text.c +++ b/src/robodash/styles/text.c @@ -21,14 +21,12 @@ void _init_style_text() { lv_style_set_text_color(&style_text_small, color_text); lv_style_set_text_opa(&style_text_small, LV_OPA_COVER); lv_style_set_text_font(&style_text_small, &lv_font_montserrat_12); - lv_style_set_text_letter_space(&style_text_small, 1); // Medium text lv_style_init(&style_text_medium); lv_style_set_text_color(&style_text_medium, color_text); lv_style_set_text_opa(&style_text_medium, LV_OPA_COVER); lv_style_set_text_font(&style_text_medium, &lv_font_montserrat_14); - lv_style_set_text_letter_space(&style_text_medium, 1); // Large text lv_style_init(&style_text_large); diff --git a/src/robodash/views/image.cpp b/src/robodash/views/image.cpp index 99e62153..3329da85 100644 --- a/src/robodash/views/image.cpp +++ b/src/robodash/views/image.cpp @@ -3,16 +3,17 @@ // ============================= Core Functions ============================= // -rd::Image::Image(lv_img_dsc_t image_dsc, std::string name) { - if (!pros::usd::is_installed()) return; - +rd::Image::Image(const lv_img_dsc_t *image_dsc, std::string name) { this->view = rd_view_create(name.c_str()); lv_obj_t *image = lv_img_create(view->obj); - lv_img_set_src(image, &image_dsc); + lv_img_set_src(image, image_dsc); lv_obj_align(image, LV_ALIGN_CENTER, 0, 0); rd_view_set_anims(this->view, RD_ANIM_OFF); } +rd::Image::Image(lv_img_dsc_t *image_dsc, std::string name) + : Image(const_cast(image_dsc), name) {} + rd::Image::Image(std::string path, std::string name) { if (!pros::usd::is_installed()) return; diff --git a/src/robodash/views/selector.cpp b/src/robodash/views/selector.cpp index 1f9e9333..54f984ee 100644 --- a/src/robodash/views/selector.cpp +++ b/src/robodash/views/selector.cpp @@ -1,127 +1,272 @@ +#include "selector.hpp" #include "api.h" #include "robodash/apix.h" +#include "robodash/impl/styles.h" +#include -// =============================== Variables =============================== // +const char *file_name = "/usd/rd_auton.txt"; -// TODO: Make variables members, so multiple selectors can be used +// ============================= SD Card Saving ============================= // -std::vector routines; -rd::Selector::routine_t *selected_routine = nullptr; +void rd::Selector::sd_save() { + FILE *save_file; -lv_obj_t *select_cont; -lv_obj_t *selected_label; -lv_obj_t *saved_toast; + // Ensure the file exists + save_file = fopen(file_name, "a"); + fclose(save_file); -lv_anim_t anim_toast; + // Open in read mode + save_file = fopen(file_name, "r"); + if (!save_file) return; -// ============================= SD Card Saving ============================= // + // Get file size + fseek(save_file, 0L, SEEK_END); + int file_size = ftell(save_file); + rewind(save_file); -void sd_save() { - FILE *save_file; - save_file = fopen("/usd/rd_auton.txt", "w"); + char new_text[file_size]; + char line[256]; + char saved_selector[256]; + + new_text[0] = '\0'; // THIS IS VERY IMPORTANT + + // Find and remove keys for our selector + while (fgets(line, 256, save_file)) { + sscanf(line, "%[^:] \n", saved_selector); + if (saved_selector == this->name) continue; + strcat(new_text, line); + } - if (selected_routine == nullptr) { - fputs("", save_file); - } else { - std::string routine_name = selected_routine->first; + fclose(save_file); + save_file = fopen(file_name, "w"); + fputs(new_text, save_file); - char file_data[sizeof(routine_name)]; - sprintf(file_data, "%s", routine_name.c_str()); + // Write save data + if (selected_routine != nullptr) { + const char *selector_name = this->name.c_str(); + const char *routine_name = selected_routine->name.c_str(); + char file_data[strlen(selector_name) + strlen(routine_name) + 2]; + sprintf(file_data, "%s: %s\n", selector_name, routine_name); fputs(file_data, save_file); } fclose(save_file); } -void sd_load() { +void rd::Selector::sd_load() { FILE *save_file; - save_file = fopen("/usd/rd_auton.txt", "r"); + save_file = fopen(file_name, "r"); if (!save_file) return; - // Get file size - fseek(save_file, 0L, SEEK_END); - int file_size = ftell(save_file); - rewind(save_file); - // Read contents - char saved_name[file_size]; - fscanf(save_file, "%[^\n]", saved_name); - fclose(save_file); + char line[256]; + char saved_selector[256]; + char saved_name[256]; - // None selected condition - if (strcmp(saved_name, "") == 0) { - lv_label_set_text(selected_label, "No routine\nselected"); - lv_obj_align(selected_label, LV_ALIGN_CENTER, 120, 0); + while (fgets(line, 256, save_file)) { + sscanf(line, "%[^:]: %[^\n\0]", saved_selector, saved_name); + if (saved_selector == this->name) break; + } - selected_routine = nullptr; + fclose(save_file); + + // None selected or not our selector + if (strcmp(saved_name, "") == 0 || saved_selector != this->name) { return; } - for (rd::Selector::routine_t &r : routines) { - if (strcmp(r.first.c_str(), saved_name) == 0) selected_routine = &r; - } - - if (selected_routine != nullptr) { - // Update routine label - char label_str[sizeof(saved_name) + 20]; - sprintf(label_str, "Selected routine:\n%s", selected_routine->first.c_str()); - lv_label_set_text(selected_label, label_str); - lv_obj_align(selected_label, LV_ALIGN_CENTER, 120, 0); + // Press button for selected auton + for (int id = 0; id < lv_obj_get_child_cnt(routine_list); id++) { + lv_obj_t *list_child = lv_obj_get_child(routine_list, id); + if (list_child == nullptr) continue; + if (strcmp(lv_list_get_btn_text(routine_list, list_child), saved_name) != 0) continue; + lv_event_send(list_child, LV_EVENT_CLICKED, selected_routine); + break; } } // ============================== UI Callbacks ============================== // -void r_select_act(lv_event_t *event) { +void rd::Selector::select_cb(lv_event_t *event) { lv_obj_t *obj = lv_event_get_target(event); rd::Selector::routine_t *routine = (rd::Selector::routine_t *)lv_event_get_user_data(event); + rd::Selector *selector = (rd::Selector *)lv_obj_get_user_data(obj); + if (selector == nullptr) return; + + selector->selected_routine = routine; + selector->sd_save(); + + selector->run_callbacks(); + + // Clear other checked buttons, make this auton's button the checked one + for (int id = 0; id < lv_obj_get_child_cnt(selector->routine_list); id++) { + lv_obj_t *list_child = lv_obj_get_child(selector->routine_list, id); + lv_obj_clear_state(list_child, LV_STATE_CHECKED); + } + lv_obj_add_state(obj, LV_STATE_CHECKED); if (routine == nullptr) { - lv_label_set_text(selected_label, "No routine\nselected"); - lv_obj_align(selected_label, LV_ALIGN_CENTER, 120, 0); - } else { - const char *routine_name = routine->first.c_str(); - - char label_str[sizeof(routine_name) + 20]; - sprintf(label_str, "Selected routine:\n%s", routine_name); - lv_label_set_text(selected_label, label_str); - lv_obj_align(selected_label, LV_ALIGN_CENTER, 120, 0); + lv_label_set_text(selector->selected_label, "No routine\nselected"); + lv_obj_add_flag(selector->selected_img, LV_OBJ_FLAG_HIDDEN); + return; } - selected_routine = routine; + const char *routine_name = routine->name.c_str(); + + char label_str[strlen(routine_name) + 20]; + sprintf(label_str, "Selected routine:\n%s", routine_name); + lv_label_set_text(selector->selected_label, label_str); + lv_obj_align(selector->selected_label, LV_ALIGN_CENTER, 120, 0); + + if (routine->img.empty() || !pros::usd::is_installed()) { + lv_obj_add_flag(selector->selected_img, LV_OBJ_FLAG_HIDDEN); + return; + } + + lv_img_set_src(selector->selected_img, routine->img.c_str()); + lv_obj_clear_flag(selector->selected_img, LV_OBJ_FLAG_HIDDEN); +} + +void rd::Selector::pg_up_cb(lv_event_t *event) { + rd::Selector *selector = (rd::Selector *)lv_obj_get_user_data(lv_event_get_target(event)); + lv_coord_t scroll_y = lv_obj_get_height(selector->routine_list); + lv_obj_scroll_by_bounded(selector->routine_list, 0, scroll_y, LV_ANIM_ON); +} + +void rd::Selector::pg_down_cb(lv_event_t *event) { + rd::Selector *selector = (rd::Selector *)lv_obj_get_user_data(lv_event_get_target(event)); + lv_coord_t scroll_y = lv_obj_get_height(selector->routine_list) * -1; + lv_obj_scroll_by_bounded(selector->routine_list, 0, scroll_y, LV_ANIM_ON); +} + +void rd::Selector::up_cb(lv_event_t *event) { + rd::Selector *selector = (rd::Selector *)lv_obj_get_user_data(lv_event_get_target(event)); + if (!selector) return; + selector->prev_auton(); } -void save_act(lv_event_t *event) { - sd_save(); - lv_obj_clear_flag(saved_toast, LV_OBJ_FLAG_HIDDEN); - lv_anim_start(&anim_toast); +void rd::Selector::down_cb(lv_event_t *event) { + rd::Selector *selector = (rd::Selector *)lv_obj_get_user_data(lv_event_get_target(event)); + if (!selector) return; + selector->next_auton(); } // ============================== Constructor ============================== // -rd::Selector::Selector(std::vector new_routines) { +rd::Selector::Selector(std::vector autons) : Selector("Auton Selector", autons) {} + +rd::Selector::Selector(std::string name, std::vector new_routines) { + this->name = name; + this->selected_routine = nullptr; // ----------------------------- Create UI ----------------------------- // - this->view = rd_view_create("Auton Selector"); + this->view = rd_view_create(name.c_str()); lv_obj_set_style_bg_color(view->obj, color_bg, 0); - lv_obj_t *routine_list = lv_list_create(view->obj); + routine_list = lv_list_create(view->obj); lv_obj_set_size(routine_list, 228, 192); - lv_obj_align(routine_list, LV_ALIGN_BOTTOM_LEFT, 8, -8); + lv_obj_align(routine_list, LV_ALIGN_TOP_LEFT, 8, 40); lv_obj_add_style(routine_list, &style_list, 0); - selected_label = lv_label_create(view->obj); + selected_cont = lv_obj_create(view->obj); + lv_obj_add_style(selected_cont, &style_transp, 0); + lv_obj_set_layout(selected_cont, LV_LAYOUT_FLEX); + lv_obj_set_size(selected_cont, 240, 240); + lv_obj_align(selected_cont, LV_ALIGN_CENTER, 120, 0); + lv_obj_set_flex_align( + selected_cont, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER + ); + lv_obj_set_flex_flow(selected_cont, LV_FLEX_FLOW_COLUMN); + + selected_label = lv_label_create(selected_cont); lv_label_set_text(selected_label, "No routine\nselected"); lv_obj_add_style(selected_label, &style_text_centered, 0); - lv_obj_align(selected_label, LV_ALIGN_CENTER, 120, 0); - + lv_obj_add_style(selected_label, &style_text_medium, 0); + + selected_img = lv_img_create(selected_cont); + lv_obj_set_size(selected_img, 168, 168); + lv_obj_add_flag(selected_img, LV_OBJ_FLAG_HIDDEN); + + // Routine list button cluster + lv_obj_t *list_btns = lv_obj_create(view->obj); + lv_obj_add_style(list_btns, &style_transp, 0); + lv_obj_set_size(list_btns, 32, 192); + lv_obj_align(list_btns, LV_ALIGN_TOP_LEFT, 236, 40); + lv_obj_clear_flag(list_btns, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_set_layout(list_btns, LV_LAYOUT_FLEX); + lv_obj_set_flex_flow(list_btns, LV_FLEX_FLOW_COLUMN); + lv_obj_set_flex_align( + list_btns, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER + ); + + // Up page button + lv_obj_t *pg_up_btn = lv_btn_create(list_btns); + lv_obj_add_style(pg_up_btn, &style_transp, 0); + lv_obj_set_size(pg_up_btn, 32, 32); + lv_obj_add_event_cb(pg_up_btn, &pg_up_cb, LV_EVENT_CLICKED, NULL); + lv_obj_set_user_data(pg_up_btn, this); + lv_obj_add_flag(pg_up_btn, LV_OBJ_FLAG_HIDDEN); + lv_obj_set_style_text_opa(pg_up_btn, 128, LV_STATE_PRESSED); + lv_obj_set_flex_grow(pg_up_btn, 1); + + lv_obj_t *pg_up_img = lv_img_create(pg_up_btn); + lv_obj_align(pg_up_img, LV_ALIGN_CENTER, 0, 0); + lv_img_set_src(pg_up_img, LV_SYMBOL_UP "\n" LV_SYMBOL_UP); + lv_obj_set_style_text_line_space(pg_up_img, -10, LV_PART_MAIN); + + // Up button + lv_obj_t *up_btn = lv_btn_create(list_btns); + lv_obj_add_style(up_btn, &style_transp, 0); + lv_obj_set_size(up_btn, 32, 32); + lv_obj_add_event_cb(up_btn, &up_cb, LV_EVENT_CLICKED, NULL); + lv_obj_set_user_data(up_btn, this); + lv_obj_set_style_text_opa(up_btn, 128, LV_STATE_PRESSED); + lv_obj_set_flex_grow(up_btn, 1); + + lv_obj_t *up_img = lv_img_create(up_btn); + lv_obj_align(up_img, LV_ALIGN_CENTER, 0, 0); + lv_img_set_src(up_img, LV_SYMBOL_UP); + + // Down button + lv_obj_t *down_btn = lv_btn_create(list_btns); + lv_obj_add_style(down_btn, &style_transp, 0); + lv_obj_set_size(down_btn, 32, 32); + lv_obj_add_event_cb(down_btn, &down_cb, LV_EVENT_CLICKED, NULL); + lv_obj_set_user_data(down_btn, this); + lv_obj_set_style_text_opa(down_btn, 128, LV_STATE_PRESSED); + lv_obj_set_flex_grow(down_btn, 1); + + lv_obj_t *down_img = lv_img_create(down_btn); + lv_obj_align(down_img, LV_ALIGN_CENTER, 0, 0); + lv_img_set_src(down_img, LV_SYMBOL_DOWN); + + // Down page button + lv_obj_t *pg_down_btn = lv_btn_create(list_btns); + lv_obj_add_style(pg_down_btn, &style_transp, 0); + lv_obj_set_size(pg_down_btn, 32, 32); + lv_obj_add_event_cb(pg_down_btn, &pg_down_cb, LV_EVENT_CLICKED, NULL); + lv_obj_set_user_data(pg_down_btn, this); + lv_obj_add_flag(pg_down_btn, LV_OBJ_FLAG_HIDDEN); + lv_obj_set_style_text_opa(pg_down_btn, 128, LV_STATE_PRESSED); + lv_obj_set_flex_grow(pg_down_btn, 1); + + lv_obj_t *pg_down_img = lv_img_create(pg_down_btn); + lv_obj_align(pg_down_img, LV_ALIGN_CENTER, 0, 0); + lv_img_set_src(pg_down_img, LV_SYMBOL_DOWN "\n" LV_SYMBOL_DOWN); + lv_obj_set_style_text_line_space(pg_down_img, -10, LV_PART_MAIN); + + // Nothing auton lv_obj_t *nothing_btn = lv_list_add_btn(routine_list, NULL, "Nothing"); - lv_obj_add_event_cb(nothing_btn, &r_select_act, LV_EVENT_PRESSED, nullptr); + lv_obj_add_event_cb(nothing_btn, &select_cb, LV_EVENT_CLICKED, nullptr); + lv_obj_set_user_data(nothing_btn, this); lv_obj_add_style(nothing_btn, &style_list_btn, 0); lv_obj_add_style(nothing_btn, &style_list_btn_pr, LV_STATE_PRESSED); + lv_obj_add_style(nothing_btn, &style_list_btn_ch, LV_STATE_CHECKED); + lv_obj_set_style_transform_width(nothing_btn, -8, 0); + lv_obj_add_state(nothing_btn, LV_STATE_CHECKED); lv_obj_t *title = lv_label_create(view->obj); lv_label_set_text(title, "Select autonomous routine"); @@ -129,45 +274,49 @@ rd::Selector::Selector(std::vector new_routines) { lv_obj_align(title, LV_ALIGN_TOP_LEFT, 8, 12); if (pros::usd::is_installed()) { - saved_toast = lv_label_create(view->obj); - lv_label_set_text(saved_toast, "Saved to SD"); - lv_obj_add_style(saved_toast, &style_text_centered, 0); - lv_obj_add_style(saved_toast, &style_text_small, 0); - lv_obj_align(saved_toast, LV_ALIGN_BOTTOM_RIGHT, -16, -16); - lv_obj_add_flag(saved_toast, LV_OBJ_FLAG_HIDDEN); - - lv_obj_t *save_btn = lv_btn_create(view->obj); - lv_obj_set_size(save_btn, 64, 32); - lv_obj_align(save_btn, LV_ALIGN_BOTTOM_RIGHT, -172, -8); - lv_obj_add_event_cb(save_btn, &save_act, LV_EVENT_PRESSED, NULL); - lv_obj_add_style(save_btn, &style_btn, 0); - lv_obj_add_style(save_btn, &style_btn_outline, 0); - lv_obj_add_style(save_btn, &style_btn_outline_pr, LV_STATE_PRESSED); - - lv_obj_t *save_img = lv_img_create(save_btn); - lv_img_set_src(save_img, LV_SYMBOL_SAVE); - lv_obj_set_align(save_img, LV_ALIGN_CENTER); + lv_obj_t *save_icon = lv_label_create(list_btns); + lv_obj_add_style(save_icon, &style_text_medium, 0); + lv_obj_add_style(save_icon, &style_text_centered, 0); + lv_label_set_text(save_icon, LV_SYMBOL_SD_CARD "\nSD"); } - lv_anim_init(&anim_toast); - lv_anim_set_var(&anim_toast, saved_toast); - lv_anim_set_time(&anim_toast, 255); - lv_anim_set_delay(&anim_toast, 3000); - lv_anim_set_exec_cb(&anim_toast, &anim_text_opa_cb); - lv_anim_set_deleted_cb(&anim_toast, &anim_del_cb); - lv_anim_set_values(&anim_toast, 255, 0); - // ----------------------------- Add autons ----------------------------- // for (routine_t routine : new_routines) { + if (!routine.img.empty()) { + routine.img.insert(0, "S:"); + } + routines.push_back(routine); } for (routine_t &routine : routines) { - lv_obj_t *new_btn = lv_list_add_btn(routine_list, NULL, routine.first.c_str()); + lv_obj_t *new_btn = lv_list_add_btn(routine_list, NULL, routine.name.c_str()); + lv_obj_add_style(new_btn, &style_list_btn, 0); lv_obj_add_style(new_btn, &style_list_btn_pr, LV_STATE_PRESSED); - lv_obj_add_event_cb(new_btn, &r_select_act, LV_EVENT_PRESSED, &routine); + lv_obj_add_style(new_btn, &style_list_btn_ch, LV_STATE_CHECKED); + lv_obj_set_style_transform_width(new_btn, -8, 0); + lv_obj_set_user_data(new_btn, this); + lv_obj_add_event_cb(new_btn, &select_cb, LV_EVENT_CLICKED, &routine); + + if (routine.color_hue > -1) { + lv_obj_t *color_chip = lv_obj_create(new_btn); + lv_obj_set_size(color_chip, 16, 16); + lv_obj_set_style_bg_color( + color_chip, lv_color_hsv_to_rgb(routine.color_hue, 75, 80), 0 + ); + lv_obj_set_style_border_opa(color_chip, LV_OPA_0, 0); + lv_obj_set_style_radius(color_chip, 4, 0); + lv_obj_align(color_chip, LV_ALIGN_RIGHT_MID, -4, 8); + lv_obj_clear_flag(color_chip, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_clear_flag(color_chip, LV_OBJ_FLAG_CLICKABLE); + } + } + + if (routines.size() > 3) { + lv_obj_clear_flag(pg_down_btn, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(pg_up_btn, LV_OBJ_FLAG_HIDDEN); } if (pros::usd::is_installed()) sd_load(); @@ -175,9 +324,72 @@ rd::Selector::Selector(std::vector new_routines) { // ============================= Other Methods ============================= // +void rd::Selector::next_auton(bool wrap_around) { + for (int id = 0; id < lv_obj_get_child_cnt(routine_list); id++) { + lv_obj_t *list_child = lv_obj_get_child(routine_list, id); + if (!lv_obj_has_state(list_child, LV_STATE_CHECKED)) continue; + + if (id == lv_obj_get_child_cnt(routine_list) - 1) { + if (!wrap_around) return; + // nullptr because the "Nothing" button is always first, and doesnt have user data + lv_event_send(lv_obj_get_child(routine_list, 0), LV_EVENT_CLICKED, nullptr); + } else { + lv_obj_t *next_child = lv_obj_get_child(routine_list, id + 1); + if (next_child == nullptr) return; + lv_event_send(next_child, LV_EVENT_CLICKED, &routines[id + 1]); + } + + return; + } +} + +void rd::Selector::prev_auton(bool wrap_around) { + lv_obj_t *prev_child = nullptr; + int child_count = lv_obj_get_child_cnt(routine_list); + for (int id = 0; id < child_count; id++) { + lv_obj_t *list_child = lv_obj_get_child(routine_list, id); + if (!lv_obj_has_state(list_child, LV_STATE_CHECKED)) { + prev_child = list_child; + continue; + }; + + if (id == 0) { + if (!wrap_around) return; + lv_event_send( + lv_obj_get_child(routine_list, child_count - 1), LV_EVENT_CLICKED, + &routines[child_count - 1] + ); + } else { + if (prev_child == nullptr) return; + lv_event_send(prev_child, LV_EVENT_CLICKED, &routines[id - 1]); + } + + return; + } +} + +void rd::Selector::run_callbacks() { + for (select_action_t callback : this->select_callbacks) { + if (this->selected_routine == nullptr) { + callback(std::nullopt); + } else { + callback(*this->selected_routine); + } + } +} + void rd::Selector::run_auton() { if (selected_routine == nullptr) return; // If commanded to do nothing then return - selected_routine->second(); + selected_routine->action(); +} + +std::optional rd::Selector::get_auton() { + if (selected_routine == nullptr) return std::nullopt; + return *selected_routine; +} + +void rd::Selector::on_select(rd::Selector::select_action_t callback) { + select_callbacks.push_back(callback); } void rd::Selector::focus() { rd_view_focus(this->view); } \ No newline at end of file