diff --git a/.catkin_workspace b/.catkin_workspace new file mode 100644 index 00000000..52fd97e7 --- /dev/null +++ b/.catkin_workspace @@ -0,0 +1 @@ +# This file currently only serves to mark the location of a catkin workspace for tool integration diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..92e46c99 --- /dev/null +++ b/.clang-format @@ -0,0 +1,19 @@ +# Use the Google style in this project. +BasedOnStyle: Google + +# int& format +DerivePointerAlignment: false +PointerAlignment: Left + +# const value +QualifierAlignment: Left + +# Custom stuff for us: +AlignAfterOpenBracket: AlwaysBreak +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Always +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +# There shouldn't be short empty loops, but fine +AllowShortLoopsOnASingleLine: true diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..a5a77c46 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,37 @@ +{ + "image": "docker.io/raiderrobotics/container-registry:rr-noetic-base", + // Causes permission errors when running make (i.e. colcon build) without sudo? + // "remoteUser": "ros", + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.profiles.linux": { + "bash": { + "path": "bash" + } + }, + "terminal.integrated.defaultProfile.linux": "bash" + }, + "extensions": [ + "ms-azuretools.vscode-docker", + "ms-vscode.cpptools", + "twxs.cmake", + "ms-iot.vscode-ros", + "streetsidesoftware.code-spell-checker", + "GitHub.vscode-pull-request-github", + "DotJoshJohnson.xml", + "redhat.vscode-yaml", + "yzhang.markdown-all-in-one" + ] + } + }, + // This will launch the container as a non-root user + "runArgs": [ + // This will allow you to use a ptrace-based debugger like C++ + "--network=host", + "--cap-add=SYS_PTRACE", + "--security-opt=seccomp:unconfined", + "--security-opt=apparmor:unconfined" + // "--volume=/tmp/.X11-unix:/tmp/.X11-unix" + ] +} \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..5dc46e6b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +* text=auto eol=lf +*.{cmd,[cC][mM][dD]} text eol=crlf +*.{bat,[bB][aA][tT]} text eol=crlf \ No newline at end of file diff --git a/.github/workflows/code-check.yml b/.github/workflows/code-check.yml new file mode 100644 index 00000000..2d7cf9dc --- /dev/null +++ b/.github/workflows/code-check.yml @@ -0,0 +1,26 @@ +name: Robot Code Checks +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-20.04 + container: raiderrobotics/container-registry:rr-noetic-base + steps: + - name: ✔️ Checkout Repository and Submodules + uses: actions/checkout@v2 + with: + submodules: recursive + - name: 🔨 Build Project + run: | + /bin/bash -c "source /opt/ros/noetic/setup.bash && catkin_make v5_hal_firmware_build" + test: + needs: build + runs-on: ubuntu-20.04 + container: raiderrobotics/container-registry:rr-noetic-base + steps: + - name: ✔️ Checkout Repository and Submodules + uses: actions/checkout@v2 + with: + submodules: recursive + - name: 🧪 Execute v5_hal Unit Tests + run: | + /bin/bash -c "source /opt/ros/noetic/setup.bash && catkin_make run_tests_v5_hal" \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..207a051b --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Catkin build files +build/ +devel/ +install/ +src/v5_hal/firmware/include/ros_lib/* +src/CMakeLists.txt + +# Compiled Object files +*.o +*.obj + +# Executables +*.bin +*.elf + +# PROS +bin/ +compile_commands.json +temp.log +temp.errors +*.ini +.d/ + +# VSCode +.history/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..b480933e --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "src/rosserial"] + path = src/rosserial + url = https://github.com/msoe-vex/rosserial.git +[submodule "src/navx_publisher/src/navXTimeSync"] + path = src/navx_publisher/src/navXTimeSync + url = https://github.com/FRC900/navXTimeSync.git +[submodule "src/v5_hal/firmware/include/eigen"] + path = src/v5_hal/firmware/include/eigen + url = https://gitlab.com/libeigen/eigen diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 00000000..4dd13d15 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,22 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "/opt/ros/noetic/include/**", + "${workspaceFolder}/src", + "${workspaceFolder}/pros" + ], + "compilerPath": "/usr/bin/gcc", + "cppStandard": "c++20", + "intelliSenseMode": "linux-gcc-x64", + "browse": { + "path": [ + "${workspaceFolder}/src" + ], + "limitSymbolsToIncludedHeaders": true + } + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..ceca3aed --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,9 @@ +{ + "configurations": [ + { + "name": "ROS: Attach", + "type": "ros", + "request": "attach" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..8e1d83fc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,123 @@ +{ + "task.autoDetect": "off", + "task.allowAutomaticTasks": "off", + "C_Cpp.default.intelliSenseMode": "linux-gcc-x86", + "C_Cpp.formatting": "clangFormat", + "search.exclude": { + "**/node_modules": true, + "**/bower_components": true, + "**/*.code-search": true, + "**/build": true, + "**/install": true, + "**/log": true, + "**/pros": true + }, + "cSpell.allowCompoundWords": true, + "cSpell.ignorePaths": [ + "**/package-lock.json", + "**/node_modules/**", + "**/vscode-extension/**", + "**/.git/objects/**", + ".vscode", + ".vscode-insiders", + ".devcontainer/devcontainer.json" + ], + "cSpell.words": [ + "COMMS", + "Holonomic", + "libeigen", + "nodiscard", + "opcontrol", + "proto", + "rclcpp", + "rosdep", + "rpms", + "struct", + "Structs", + "VEXU" + ], + "files.associations": { + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "condition_variable": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "list": "cpp", + "map": "cpp", + "set": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "future": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "ostream": "cpp", + "shared_mutex": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "unordered_set": "cpp", + "strstream": "cpp", + "bitset": "cpp", + "codecvt": "cpp", + "complex": "cpp", + "iomanip": "cpp", + "cfenv": "cpp", + "cinttypes": "cpp", + "valarray": "cpp", + "variant": "cpp", + "dense": "cpp" + }, + "files.autoSave": "afterDelay", + "files.autoSaveDelay": 1000, + "editor.formatOnSave": true, + "editor.formatOnSaveMode": "file", + // Python stuff + "python.envFile": "${workspaceFolder}/.env", + "python.analysis.extraPaths": [ + "/opt/ros/humble/lib/python3.8/site-packages/" + ], + "python.autoComplete.extraPaths": [ + "/opt/ros/humble/lib/python3.8/site-packages/" + ], + "cmake.configureOnOpen": false +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..efc2aef3 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,204 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "presentation": { + "panel": "new" + }, + "tasks": [ + { + "label": "v5_hal Firmware Build", + "type": "shell", + "windows": { + "command": ". /opt/ros/noetic/setup.sh && catkin_make v5_hal_firmware_build" + }, + "linux": { + "command": ". /opt/ros/noetic/setup.sh && catkin_make v5_hal_firmware_build" + }, + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": { + "owner": "prosv5", + "fileLocation": [ + "relative", + "${workspaceRoot}" + ], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+): +(warning|error): +(.*)", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "v5_hal Firmware Clean", + "type": "shell", + "windows": { + "command": "catkin_make v5_hal_firmware_clean_all" + }, + "linux": { + "command": "catkin_make v5_hal_firmware_clean_all" + }, + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [] + }, + { + "label": "v5_hal Firmware Test", + "type": "shell", + "windows": { + "command": "catkin_make run_tests_v5_hal" + }, + "linux": { + "command": "catkin_make run_tests_v5_hal" + }, + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": { + "owner": "prosv5", + "fileLocation": [ + "relative", + "${workspaceRoot}" + ], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+): +(warning|error): +(.*)", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "v5_hal Firmware Upload", + "type": "shell", + "windows": { + "command": "prosv5.exe upload" + }, + "linux": { + "command": "prosv5 upload" + }, + "options": { + "cwd": "${workspaceFolder}/src/v5_hal/firmware" + }, + "problemMatcher": { + "owner": "prosv5", + "fileLocation": [ + "relative", + "${workspaceRoot}" + ], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+): +(warning|error): +(.*)", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + }, + "group": "build" + }, + { + "label": "v5_hal Firmware Build (WSL1)", + "type": "shell", + "command": "catkin_make v5_hal_firmware_build", + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": { + "owner": "prosv5", + "fileLocation": [ + "relative", + "${workspaceRoot}" + ], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+): +(warning|error): +(.*)", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "v5_hal Firmware Clean (WSL1)", + "type": "shell", + "command": "catkin_make v5_hal_firmware_clean_all", + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [] + }, + { + "label": "v5_hal Firmware Test (WSL1)", + "type": "shell", + "command": "catkin_make run_tests_v5_hal", + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": { + "owner": "prosv5", + "fileLocation": [ + "relative", + "${workspaceRoot}" + ], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+): +(warning|error): +(.*)", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "v5_hal Firmware WSL Upload (WSL1)", + "type": "shell", + "command": "catkin_make v5_hal_firmware_wsl_upload", + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": { + "owner": "prosv5", + "fileLocation": [ + "relative", + "${workspaceRoot}" + ], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+): +(warning|error): +(.*)", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + }, + "group": "build" + } + ] +} \ No newline at end of file diff --git a/C++ Guide.md b/C++ Guide.md new file mode 100644 index 00000000..d7ab0304 --- /dev/null +++ b/C++ Guide.md @@ -0,0 +1,65 @@ +# C++ Guide +## Purpose +This document is meant as a guide for people who has at lesat a little bit of programming knowledge. If you have never done C++ before, I reccomend checking out the Resources below to learn C++. + +The Syntax Guide is meant to help someone with a little bit of C++ experience understand some strange syntax in C++. This language is exceptionally powerful but also exceptionally confusing sometimes. If something doesn't make sense or is missing from this list, feel free to make a change and make a merge request with it. Remember to ask questions! + +## Resources: +**The Cherno YouTube channel:** The Cherno is a channel that makes a lot of C++ content and has a full [C++ tutuorial playlist](https://www.youtube.com/watch?v=SfGuIVzE_Os&list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb&index=5&ab_channel=TheCherno). This playlist, along with this document, is meant for people who have at least a little experience in programming. If you are going through that playlist or any other tutorial and are getting very lost, please reach out to a veteran member of the team. + +**W3 Schools tutorial:** [This series](https://www.w3schools.com/cpp/cpp_pointers.asp) of articles has some code running tools to test out yourself but mainly contains all the information you would need to know to be successful on this team. + +**C++ Code Shell**: [This](https://cpp.sh/) browser based tool allows you to quickly run C++ code. You should use it get some experience C++ coding and for practicing what you learn from videos or articles. + +## Syntax Guide + +### Deconstructor: `~()` +If there is a `~` before what looks like a constructor, that is a deconstructor. It is called when an object is destroyed and should be used to `delete` any dynamically allocated memory with `new`. + +### Initializer List: ` : ()` +Constructors are typically used to assign their parameters to member variables. C++ makes this process simpler with initializer lists. After the constructor name, but before the body, there is a `:` that defines the start of the initalizer list. The list itself is a comma seperated list of variables with the values to initialize them to in paranethis after them like parameters. + +### `enum class {}` +Class enums are both strongly typed and strongly scoped. This means that they do not automatically convert to ints and do not compare themselves to other enumerations. This helps avoid mistakes with many different enums. [More Info](https://www.geeksforgeeks.org/enum-classes-in-c-and-their-advantage-over-enum-datatype/). + +### `namespace \` +Everything after this line will be defined within the specified namespace. Namespaces define a name scope in C++. An object name can exist in one namespace and the same object name can exists in another namespace. In the same way that a variable name can exist in one class and the same variable name can exist in anther class. Usage: `::`. [More Info](https://www.geeksforgeeks.org/namespace-in-c/). + +### `using namespace {}` +Inside of this closure, the C++ compiler will assume that you want to use the specified namespace. This is useful if many of your namespace uses are the same within a file. You can still use a typical namespace reference if you want within a `using namespace` closure. + +### `[[nodiscard]]` +Welcome to the weirdest syntax you will ever seen in a programming language. This keyword goes before a method declaration and will give a warning if the return value of said method is discarded, i.e. not put into a variable. [More Info](https://en.cppreference.com/w/cpp/language/attributes/nodiscard). + +### `virtual` +C++ functions are not able to be overriden by default. This keyword goes before a method declaration and allows it to be overriden. [More Info](https://www.geeksforgeeks.org/virtual-function-cpp/). + +### ` const` +When the `const` keyword is used after a method name in a declaration it makes it a const member function. Const member functions cannot change the values of memebr variables. Therefore, you can use a const method and be sure that you will not alter the state of the object you are calling it on. This is often used on getters. [More Info](https://www.geeksforgeeks.org/const-member-functions-c/#). + +### ` = 0` +This syntax makes the method a pure virtual function. This makes a class in which the method a part of abstract and unable to be instantiated without subclassing. In other words. This method does not have a body and MUST be overriden by a subclass. [More Info](https://www.geeksforgeeks.org/pure-virtual-functions-and-abstract-classes/). + +### ` = delete` +This syntax tells the compiler to disable the usages of this method. This is typically used on implicitly defined functions like copy constructor or copy assignment operator to ensure that they are not used. [More Info](https://www.ibm.com/docs/en/i/7.4?topic=definitions-deleted-functions-c11). + +### ` = default` +This explicitely tells the compiler to create the compiler default for this method. For example, if we wanted the deconstrcutor of a class to be overridable, we would need to declare it as such. However, the default deconstructor calls the destructors of the base class and members of the derived class. It would not do that if we defined it as virtual. Defining it as virtual default allows it to be overriden but if we do not is uses the default that is very helpful. [More Info](https://stackoverflow.com/questions/6502828/what-does-default-mean-after-a-class-function-declaration). + +## Moving and Copying Data +The following section covers various topics on moving and copying data and should hopfully clear up some of that standard syntax you see in our classes. Here are some relevent Cherno videos that you can follow up with some research: +- [lvalues and rvalues in C++](https://www.youtube.com/watch?v=fbYknr-HPYE&ab_channel=TheCherno) +- [Move Semantics in C++](https://www.youtube.com/watch?v=ehMg6zvXuMY&ab_channel=TheCherno) +- [std::move and the Move Assignment Operator in C++](https://www.youtube.com/watch?v=OWNeCTd7yQE&t=848s&ab_channel=TheCherno) + +### `lvalues` and `rvalues` +These are different ways to describe how values are stored. You should watch [this video](https://www.youtube.com/watch?v=fbYknr-HPYE&ab_channel=TheCherno) to get a good in-depth explanation of `lvalues` and `rvalues`. Summed up, `lvalues` are values that have a storage location, like variables. `rvalues` are temporary values that do not have a location in memory, like literals. This matters most for method parameters. To specify a method parameter is an `lvalue`, use a single `&` after the parameter name. Just like you would for creating a reference variable. To specify a method parameter is an `rvalue`, use `&&` after the parameter name. + +### Copy Constructor: `(const &)` +Copy constructors are called whenever a `lvalue`, or object with a permanent location in memory is assigned to another `lvalue`. The compiler then assumes that you would like to make a copy of the object and then put that object in the new object. The copy operation can also be written as `& operator=(const &)` which denotes the exact operation described above. Typically we `delete` these constructors and operators in most of our classes as we do not want to copy them. Additionally, moving is much more memory and time efficient compared to copying. + +### Move Constructor: `(&&)` +The move operation is called whenever an `rvalue`, or value without a permanent location in memory, is assigned to an `lvalue`. In this case the compiler assumes that you would like to move the temporary `rvalue` into the `lvalue`. the move operation can also be written like this: `& operator=(&&)` which denotes the equal sign to move an object when the input is a temporary `rvalue`. Typically we explicitly set the move operation and constructor of our classes to `default` to ensure that we have proper move operations. We tend to move data to new owners when creating larger data structures. + +### `std::move()` +This may look like a move operation, but although it is used often when moving, it is not. All that this method does is return the input as an `rvalue` allowing move operations to be called on the value. If you are planning on moving an object into ownership of another object, you should use this method to create an `rvalue` of that object and then assign it to it's new owner. diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 00000000..c6260799 --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,79 @@ +# spin-up design + +## Style +This code loosely follows the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html). + +Some notable exceptions are as follows: +1. A few custom formatting rules are defined and automatically configured by the compiler. Use VS Code's autoformater (default: *Ctrl + Shift + F*) to format files. +2. `#pragma once` may be used in header files over `include` guards. +3. `src` files are named using `.cpp` instead of `.cc`. +4. Exceptions are allowed to be used to demark states which are clearly illegal and should never be reached. + +# Organization +Each file should have a namespace; even classes. Namespaces should be organized by folder; e.g. everything in the `hardware` folder should have the `hardware` namespace. Nested namespaces may be used if additional granularity is necessary, but this use case should be rare. + +The [Purdue Robot Operating System](https://pros.cs.purdue.edu/v5/index.html#) (pros) is available via the header `#include "pros.h"`. In general, `pros` code should be wrapped into generic implementations in `hardware`; thus, it shouldn't be necessary to import `pros` outside of that folder. + +# Code Flow and Constructs +Virtual interfaces are used to create an abstraction layer between use cases on the robot and physical hardware. Interfaces are defined in `interface` and describe a minimal set of methods necessary for using/interacting with an object. Since these `interface`s are generic, any class which fulfills their basic requirements may be substituted as the concrete implementation. + +In contrast, subsystems should interact with `interface`s only (and not concrete implementations). For example, a drivetrain should receive `interface::Motor`s and an `interface::Controller` rather than, say, `ProsMotor` and `ProsController`. This enables these implementations to be freely swapped. Generally, users should only take references to specific `interface`s needed since taking the entire `std::unique_ptr` takes ownership of that object. For example, `HolonomicDrivetrain` may receive a controller to work with using the signature `Drive(const interface::Controller& controller) {}`. This method should be called by dereferencing the `std::unique_ptr` pointer managed by main, e.g. `drivetrain.Drive(*controller_ptr);`. + +# Header and Source Files +`.h` files are called header files and define static information about c++ constructs. They are used by the compiler to separate the linking of code constructs from the concrete implementations, which improves the performance of the c++ compiler. + +Header files (`.h`) should observe the following rules: +1. Begin with `#pragma once`. `#pragma once` is a directive which ensures the c++ compiler will not link the same header file more than once. +2. References to the c++ standard library are enclosed in carets, e.g. `#include `. +3. References to other files in the project are enclosed in double quotes and always use the full file path, e.g. `#include "hardware/pros_controller.h"`. +4. References should always point to other header files (`.h`), never implementations (`.cpp`). +5. Define a namespace which matches the folder. Header files should always define a namespace which matches the folder the file is in. +6. If the `pros` library is needed, it may be included as `#include pros.h`. Note `pros` should only generally be used within the `hardware` folder. +7. Header files with non-trivial functions or methods should also have a single corresponding `.cpp` source file with the same name. + +Header files may also optionally include implementations for constructors, methods and functions (instead of putting the implementation in a `.cpp` source file). Generally speaking, constructors should be written in-line, as should trivial getters. Methods and functions (but not constructors) which have their implementation in the `.h` file should always include the `inline` keyword, which hints to the compiler that the function call should be expanded into the actual function code at compile time. + +Source files (`.cpp`) should observe the following rules: +1. Reference the header file of the same name. For example, `main.cpp` should always start with `#include "main.h"`. No other references are allowed in a source file. Note that references from the header file propagate to the corresponding implementation file, so adding `#include ` in the header file will make `std::vector` available in the corresponding source file. +2. Use the same namespace as the header file. Source files should have the same namespace declaration as the header file. + +# Classes and Structs +`class`es are collections of data and and methods. Methods are functions which can operate on the data of a class. +`struct`s are functionally very similar to classes; key differences are: +1. `struct`s primarily exist to hold data, whereas `class`es also include operations on their data. +2. `class` data members are named with a trailing underscore, e.g. `my_class_member_`, whereas `struct` members are named without, e.g. `my_struct_member`. +3. `class` data is should be marked private and exposed via a getter method, whereas `struct` data is typically marked public and thus exposed directly. + +### const Methods +`const` is used to indicate whether a method mutates class members. Note a class member may have both a `const` and a non-`const` getter; the appropriate one will be chosen based on whether it is called from within a `const` or non-`const` method or external context. + +To prevent issues with `const` from arising in regards to `pros` implementations, some `hardware` classes mark `pros` objects as `mutable`, which allows non-`const` methods on these `pros` to manipulated in a `const` context. To help facilitate this, `const` getters return non-`const` references to the `pros` object. + +### Getters +A getter is a method which is used to retrive a value from a class. Methods (but not functions) which behave like simple getters should be named like a standard variable instead of using standard method naming convetions (e.g. `velocity()` instead of `Velocity()` or `GetVelocity()`). Note getters should also often be annotated with `[[nodiscard]]` since a call to a getter which does not use the result is redundant. + +## \[\[nodiscard\]\] +`[[nodiscard]]` may be prepended to a function or method declaration with a non-void return type to indicate that calling code should actually use the return type in some way. This is enforced by the compiler at compile time via a warning. `[[nodiscard]]` should be used to annotate methods which return values and have no side-effects: +``` +// function declaration +[[nodiscard]] int getValue() { return 5; }; + +getValue(); // compiler warning; result of getValue() should be used +if (getValue() == 1) {} // okay; getValue() is used +int value = getValue(); // also okay +``` + +### Factory Methods +Factory methods should be `static` methods belonging to either a concrete implementation or a subsystem. Their name should be `Make`, e.g. `MakeDriverController`. They should return one or more `std::unique_ptr`s which are set to the concrete implementation rather than the underlying interface (e.g. `ProsController`, not `interface::Controller`). This enables useage of additional, non-interface methods in `main` and supports classes which implement more than one interface (like `ProsMotor`). + +## Class Members +Classes which take ownership over one or more concrete implementations, such as `HolonomicMotors`, by taking as members `std::unique_ptr`s or other non-copyable data, should have their copy constructor and copy assignment operators deleted and the rest of its constructors defined (in order to properly observe the rule of 5). As a reminder, classes which own `std::unique_ptr` cannot be copied, only moved; this can be accomplished with `std::move`. To facilitate error checking and prevent hard to detect bugs, the copy constructor and copy assignment operator should be deleted, and the other constructors/destructors (move constructor, move assignment, destructor) should be specified/assigned to `default` . See `holonomic_motors.h` for an example. + +# Functions +Formally, functions behave similarity to methods, but methods are defined as a part of a class whereas functions are located in a namespace scope. + +## Use Cases +Functions should be used in cases where access to encapsulated data is not required. As a reminder, you should avoid using classes to arbitrarily group similar functions together; use a namespace instead. + +## Naming +Non-method functions which do more computation or which do not expose (or pretend to expose) a field on a class should be written as `Get`, e.g. `GetProsJoystick`. Keep in mind that classes should not be used to group arbitrary functions together; namespaces already serve this purpose. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..4b2eec54 --- /dev/null +++ b/Makefile @@ -0,0 +1,47 @@ +################################################################################ +######################### User configurable parameters ######################### +# filename extensions +CEXTS:=c +ASMEXTS:=s S +CXXEXTS:=cpp c++ cc + +# probably shouldn't modify these, but you may need them below +ROOT=. +FWDIR:=$(ROOT)/firmware +BINDIR=$(ROOT)/bin +SRCDIR=$(ROOT)/src +INCDIR=$(ROOT)/src $(ROOT)/pros + +WARNFLAGS+= +EXTRA_CFLAGS= +EXTRA_CXXFLAGS= + +# Set to 1 to enable hot/cold linking +USE_PACKAGE:=1 + +# Add libraries you do not wish to include in the cold image here +# EXCLUDE_COLD_LIBRARIES:= $(FWDIR)/your_library.a +EXCLUDE_COLD_LIBRARIES:= + +# Set this to 1 to add additional rules to compile your project as a PROS library template +IS_LIBRARY:=0 +# TODO: CHANGE THIS! +LIBNAME:=libbest +VERSION:=1.0.0 +# EXCLUDE_SRC_FROM_LIB= $(SRCDIR)/unpublishedfile.c +# this line excludes opcontrol.c and similar files +EXCLUDE_SRC_FROM_LIB+=$(foreach file, $(SRCDIR)/main,$(foreach cext,$(CEXTS),$(file).$(cext)) $(foreach cxxext,$(CXXEXTS),$(file).$(cxxext))) + +# EXCLUDE_SRC_FROM_LIB+=$(foreach file, $(SRCDIR)/main,$(foreach cext,$(CEXTS),$(file).$(cext)) $(foreach cxxext,$(CXXEXTS),$(file).$(cxxext))) + +# files that get distributed to every user (beyond your source archive) - add +# whatever files you want here. This line is configured to add all header files +# that are in the the include directory get exported +TEMPLATE_FILES=$(INCDIR)/**/*.h $(INCDIR)/**/*.hpp + +.DEFAULT_GOAL=quick + +################################################################################ +################################################################################ +########## Nothing below this line should be edited by typical users ########### +-include ./common.mk diff --git a/README-SpinUp.md b/README-SpinUp.md new file mode 100644 index 00000000..8614427b --- /dev/null +++ b/README-SpinUp.md @@ -0,0 +1,27 @@ +# spin-up +A Raider Robotics repository for VEXU Spin Up, with tooling for working inside a preconfigured vs-code dev container. + +### Setup +This repository is setup as a visual studio code dev container. To work on code: +1. Install [Docker Desktop](https://www.docker.com/products/docker-desktop/). +2. Install [VS Code](https://code.visualstudio.com/). Note this is different from Visual Studio (which has a purple icon rather than a blue one). +3. Add the Dev Containers extension. +4. Open the command pallette using *Ctrl + Shift + P*, then search for *Dev Containers: Open Folder in Container* and select the folder containing a local copy of this repository. + + +### Organization +C++ source code is in `src`. Header files are defined in `include`. +Header files which use pros should include `main.h`, as that defines the pros library. + +### Commands +Use `pros make` to build code. + +In the event `pros make` builds successfully but fails to Link the project, try running `make clean` to delete any generated build files, then run `pros make` again. + + + +### Maintenance +* Programs which can be run should have corresponding tasks defined in `launch.json`, `tasks.json`, and `Makefile`. +* Packages are defined in `Dockerfile`. +* VSCode extensions are defined in `devcontainer.json`. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..319925e7 --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +# Raider Robotics Over Under Project + + +PROS workspace for the 2023-2024 VEX U game Over Under. + +## Reccomended Tools +[Visual Studio Code](https://code.visualstudio.com/) + +### Git Tools: +We use Git to organize our software development. There are two main ways to interact with Git. There is the [Command Line Interface (CLI)](https://git-scm.com/downloads) that has you using commands in shell. There are also a few different GUI applications that can be used to interact with Git. My personal favorites are [GitHub Desktop](https://desktop.github.com/) and [Sublime Merge](https://www.sublimemerge.com/). GitHub Desktop is a little more user friendly but Sublime Merge has a better branch visualizer. I personally user GitHub Desktop most of the time. + +## Cloning the Repository + +You can clone the resposity using the built in funtionality in most Git GUI applications once you login with your GitHub account. If you choose to do it using the command line, you can do it through HTTPS or SSH. Either will work just fine but I reccomend setting up SSH at some point in your GitHub account as it is more secure and professional. + +If you are using the command line, run the below command in the folder that you want the the `over-under` project folder to exist INSIDE OF. In other words, don't make an `over-under` folder and run the command inside of that, you will have two layers of `over-under`. You should create a folder to hold repositories in and run the below command in there. Command to run: `git clone` followed by the path copies from the repo's green Code button like the image below. If you are using SSH, it should look like: `git clone git@github.com:msoe-vex/over-under.git` + +![Code button dialog popup](image.png) + +## Development Environment Options +There are two main options for development environments: + +### Option 1: Install only the required extentions in VSCode +This option is definitely the more lightweight option. All you have to do is install a few VSCode extensions that will give you basic C++ usage, compilation, and the ability to upload to the robot. This is NOT a full C++ development environment, which is not required to work with the project. If you are not familiar with VSCode or extensions read some of [this](https://code.visualstudio.com/docs/editor/extension-marketplace). + +#### 1. Install the C/C++ Extension Pack +C++ intellisense, code completion, and basic linking through Cmake. + +#### 2. Install the PROS extension +[PROS](https://pros.cs.purdue.edu/) is the library that we use to communicate with our robot. It is an open-source project updated and maintained by students and faculty from Purdue University. This extention gives us easy access to the PROS CLI commands through the PROS Terminal. PROS compiles and uploads our code for us which is why we don't need a full C++ development environment. + +### Option 2: Docker Containers through VSCode's Dev Containers +This option utilizes VSCode's Dev Containers extension to open the project within a Linux Docker Container that has a full C++ development environment as well as all required and reccomended extentions. This option also containerizes this development environment so that it doesn't mess with anything else on your computer. This is the more complicated of the two options as a full C++ development environment is not required. + +#### **The rest of this section is under construction, only use this option if you know what you are doing.** + +## Using PROS +**From Dev environmet Option 1:** Clicking on the PROS icon in the extentions list will bring up a list of different commands to click on where the file system would normally be. Almost everything in PROS is available here but I reccomend clicking on the `Integrated Terminal` option to bring up the PROS Terminal which gives you access to the PROS CLI inside of this terminal. + +**From Dev Environment Option 2:** Opening a terminal in VSCode should gain you access to the PROS CLI. + +**Once you get access to the PROS CLI:** There are two main comands to know. `pros make` or `pros build` will compile all of the C++ code in the current PROS Project. If there are any comile errors, they will show up in this terminal after running one of those commands. `pros upload` will upload the code to the currently connected VEX Brain or Controller. Brains or Controllers should be connected to laptops with a USB cable. + +## Troubleshooting +### PROS +If you have any issues with PROS, especially if you are getting error messages about the PROS Toolchain. Restarting your computer works more often than it should. You can also try uninstalling PROS from the Exention and doing the same with the extension yourself. If you are still having issues or are having other issues, constact a veteran member. + +### C++ +If you are having issues with C++, start by referring to the C++ Guide in the top level of this project. If the answers aren't there, Google is always your friend as a software engineer. If you are still stumped, contact a veteran member. diff --git a/common.mk b/common.mk new file mode 100644 index 00000000..84f7e219 --- /dev/null +++ b/common.mk @@ -0,0 +1,295 @@ +ARCHTUPLE=arm-none-eabi- +DEVICE=VEX EDR V5 + +MFLAGS=-mcpu=cortex-a9 -mfpu=neon-fp16 -mfloat-abi=softfp -Os -g +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 + +WARNFLAGS+=-Wno-psabi + +SPACE := $() $() +COMMA := , + +DEPDIR := .d +$(shell mkdir -p $(DEPDIR)) +DEPFLAGS = -MT $$@ -MMD -MP -MF $(DEPDIR)/$$*.Td +MAKEDEPFOLDER = -$(VV)mkdir -p $(DEPDIR)/$$(dir $$(patsubst $(BINDIR)/%, %, $(ROOT)/$$@)) +RENAMEDEPENDENCYFILE = -$(VV)mv -f $(DEPDIR)/$$*.Td $$(patsubst $(SRCDIR)/%, $(DEPDIR)/%.d, $(ROOT)/$$<) && touch $$@ + +LIBRARIES+=$(wildcard $(FWDIR)/*.a) +# Cannot include newlib and libc because not all of the req'd stubs are implemented +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 + +ASMFLAGS=$(MFLAGS) $(WARNFLAGS) +CFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) $(GCCFLAGS) --std=gnu11 +CXXFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) $(GCCFLAGS) --std=gnu++17 +LDFLAGS=$(MFLAGS) $(WARNFLAGS) -nostdlib $(GCCFLAGS) +SIZEFLAGS=-d --common +NUMFMTFLAGS=--to=iec --format %.2f --suffix=B + +AR:=$(ARCHTUPLE)ar +# using arm-none-eabi-as generates a listing by default. This produces a super verbose output. +# Using gcc accomplishes the same thing without the extra output +AS:=$(ARCHTUPLE)gcc +CC:=$(ARCHTUPLE)gcc +CXX:=$(ARCHTUPLE)g++ +LD:=$(ARCHTUPLE)g++ +OBJCOPY:=$(ARCHTUPLE)objcopy +SIZETOOL:=$(ARCHTUPLE)size +READELF:=$(ARCHTUPLE)readelf +STRIP:=$(ARCHTUPLE)strip + +ifneq (, $(shell command -v gnumfmt 2> /dev/null)) + SIZES_NUMFMT:=| gnumfmt --field=-4 --header $(NUMFMTFLAGS) +else +ifneq (, $(shell command -v numfmt 2> /dev/null)) + SIZES_NUMFMT:=| numfmt --field=-4 --header $(NUMFMTFLAGS) +else + SIZES_NUMFMT:= +endif +endif + +ifneq (, $(shell command -v sed 2> /dev/null)) +SIZES_SED:=| sed -e 's/ dec/total/' +else +SIZES_SED:= +endif + +rwildcard=$(foreach d,$(filter-out $3,$(wildcard $1*)),$(call rwildcard,$d/,$2,$3)$(filter $(subst *,%,$2),$d)) + +# Colors +NO_COLOR=$(shell printf "%b" "\033[0m") +OK_COLOR=$(shell printf "%b" "\033[32;01m") +ERROR_COLOR=$(shell printf "%b" "\033[31;01m") +WARN_COLOR=$(shell printf "%b" "\033[33;01m") +STEP_COLOR=$(shell printf "%b" "\033[37;01m") +OK_STRING=$(OK_COLOR)[OK]$(NO_COLOR) +DONE_STRING=$(OK_COLOR)[DONE]$(NO_COLOR) +ERROR_STRING=$(ERROR_COLOR)[ERRORS]$(NO_COLOR) +WARN_STRING=$(WARN_COLOR)[WARNINGS]$(NO_COLOR) +ECHO=/bin/printf "%s\n" +echo=@$(ECHO) "$2$1$(NO_COLOR)" +echon=@/bin/printf "%s" "$2$1$(NO_COLOR)" + +define test_output_2 +@if test $(BUILD_VERBOSE) -eq $(or $4,1); then printf "%s\n" "$2"; fi; +@output="$$($2 2>&1)"; exit=$$?; \ +if test 0 -ne $$exit; then \ + printf "%s%s\n" "$1" "$(ERROR_STRING)"; \ + printf "%s\n" "$$output"; \ + exit $$exit; \ +elif test -n "$$output"; then \ + printf "%s%s\n" "$1" "$(WARN_STRING)"; \ + printf "%s\n" "$$output"; \ +else \ + printf "%s%s\n" "$1" "$3"; \ +fi; +endef + +define test_output +@output=$$($1 2>&1); exit=$$?; \ +if test 0 -ne $$exit; then \ + printf "%s\n" "$(ERROR_STRING)" $$?; \ + printf "%s\n" $$output; \ + exit $$exit; \ +elif test -n "$$output"; then \ + printf "%s\n" "$(WARN_STRING)"; \ + printf "%s" $$output; \ +else \ + printf "%s\n" "$2"; \ +fi; +endef + +# Makefile Verbosity +ifeq ("$(origin VERBOSE)", "command line") +BUILD_VERBOSE = $(VERBOSE) +endif +ifeq ("$(origin V)", "command line") +BUILD_VERBOSE = $(V) +endif + +ifndef BUILD_VERBOSE +BUILD_VERBOSE = 0 +endif + +# R is reduced (default messages) - build verbose = 0 +# V is verbose messages - verbosity = 1 +# VV is super verbose - verbosity = 2 +ifeq ($(BUILD_VERBOSE), 0) +R = @echo +D = @ +VV = @ +endif +ifeq ($(BUILD_VERBOSE), 1) +R = @echo +D = +VV = @ +endif +ifeq ($(BUILD_VERBOSE), 2) +R = +D = +VV = +endif + +INCLUDE=$(foreach dir,$(INCDIR) $(EXTRA_INCDIR),-iquote"$(dir)") + +ASMSRC=$(foreach asmext,$(ASMEXTS),$(call rwildcard, $(SRCDIR),*.$(asmext), $1)) +ASMOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call ASMSRC,$1))) +CSRC=$(foreach cext,$(CEXTS),$(call rwildcard, $(SRCDIR),*.$(cext), $1)) +COBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CSRC, $1))) +CXXSRC=$(foreach cxxext,$(CXXEXTS),$(call rwildcard, $(SRCDIR),*.$(cxxext), $1)) +CXXOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CXXSRC,$1))) + +GETALLOBJ=$(sort $(call ASMOBJ,$1) $(call COBJ,$1) $(call CXXOBJ,$1)) + +ARCHIVE_TEXT_LIST=$(subst $(SPACE),$(COMMA),$(notdir $(basename $(LIBRARIES)))) + +LDTIMEOBJ:=$(BINDIR)/_pros_ld_timestamp.o + +MONOLITH_BIN:=$(BINDIR)/monolith.bin +MONOLITH_ELF:=$(basename $(MONOLITH_BIN)).elf + +HOT_BIN:=$(BINDIR)/hot.package.bin +HOT_ELF:=$(basename $(HOT_BIN)).elf +COLD_BIN:=$(BINDIR)/cold.package.bin +COLD_ELF:=$(basename $(COLD_BIN)).elf + +# Check if USE_PACKAGE is defined to check for migration steps from purduesigbots/pros#87 +ifndef USE_PACKAGE +$(error Your Makefile must be migrated! Visit https://pros.cs.purdue.edu/v5/releases/kernel3.1.6.html to learn how) +endif + +DEFAULT_BIN=$(MONOLITH_BIN) +ifeq ($(USE_PACKAGE),1) +DEFAULT_BIN=$(HOT_BIN) +endif + +-include $(wildcard $(FWDIR)/*.mk) + +.PHONY: all clean quick + +quick: $(DEFAULT_BIN) + +all: clean $(DEFAULT_BIN) + +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") +endif + +LIBAR=$(BINDIR)/$(LIBNAME).a +TEMPLATE_DIR=$(ROOT)/template + +clean-template: + @echo Cleaning $(TEMPLATE_DIR) + -$Drm -rf $(TEMPLATE_DIR) + +$(LIBAR): $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)) $(EXTRA_LIB_DEPS) + -$Drm -f $@ + $(call test_output_2,Creating $@ ,$(AR) rcs $@ $^, $(DONE_STRING)) + +.PHONY: library +library: $(LIBAR) + +.PHONY: template +template: clean-template $(LIBAR) + $Dprosv5 c create-template . $(LIBNAME) $(VERSION) $(foreach file,$(TEMPLATE_FILES) $(LIBAR),--system "$(file)") --target v5 $(CREATE_TEMPLATE_FLAGS) +endif + +# if project is a library source, compile the archive and link output.elf against the archive rather than source objects +ifeq ($(IS_LIBRARY),1) +ELF_DEPS+=$(filter-out $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)), $(call GETALLOBJ,$(EXCLUDE_SRCDIRS))) +LIBRARIES+=$(LIBAR) +else +ELF_DEPS+=$(call GETALLOBJ,$(EXCLUDE_SRCDIRS)) +endif + +$(MONOLITH_BIN): $(MONOLITH_ELF) $(BINDIR) + $(call test_output_2,Creating $@ for $(DEVICE) ,$(OBJCOPY) $< -O binary -R .hot_init $@,$(DONE_STRING)) + +$(MONOLITH_ELF): $(ELF_DEPS) $(LIBRARIES) + $(call _pros_ld_timestamp) + $(call test_output_2,Linking project with $(ARCHIVE_TEXT_LIST) ,$(LD) $(LDFLAGS) $(ELF_DEPS) $(LDTIMEOBJ) $(call wlprefix,-T$(FWDIR)/v5.ld $(LNK_FLAGS)) -o $@,$(OK_STRING)) + @echo Section sizes: + -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) + +$(COLD_BIN): $(COLD_ELF) + $(call test_output_2,Creating cold package binary for $(DEVICE) ,$(OBJCOPY) $< -O binary -R .hot_init $@,$(DONE_STRING)) + +$(COLD_ELF): $(COLD_LIBRARIES) + $(VV)mkdir -p $(dir $@) + $(call test_output_2,Creating cold package with $(ARCHIVE_TEXT_LIST) ,$(LD) $(LDFLAGS) $(call wlprefix,--gc-keep-exported --whole-archive $^ -lstdc++ --no-whole-archive) $(call wlprefix,-T$(FWDIR)/v5.ld $(LNK_FLAGS) -o $@),$(OK_STRING)) + $(call test_output_2,Stripping cold package ,$(OBJCOPY) --strip-symbol=install_hot_table --strip-symbol=__libc_init_array --strip-symbol=_PROS_COMPILE_DIRECTORY --strip-symbol=_PROS_COMPILE_TIMESTAMP --strip-symbol=_PROS_COMPILE_TIMESTAMP_INT $@ $@, $(DONE_STRING)) + @echo Section sizes: + -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) + +$(HOT_BIN): $(HOT_ELF) $(COLD_BIN) + $(call test_output_2,Creating $@ for $(DEVICE) ,$(OBJCOPY) $< -O binary $@,$(DONE_STRING)) + +$(HOT_ELF): $(COLD_ELF) $(ELF_DEPS) + $(call _pros_ld_timestamp) + $(call test_output_2,Linking hot project with $(COLD_ELF) and $(ARCHIVE_TEXT_LIST) ,$(LD) -nostartfiles $(LDFLAGS) $(call wlprefix,-R $<) $(filter-out $<,$^) $(LDTIMEOBJ) $(LIBRARIES) $(call wlprefix,-T$(FWDIR)/v5-hot.ld $(LNK_FLAGS) -o $@),$(OK_STRING)) + @printf "%s\n" "Section sizes:" + -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) + +define asm_rule +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 + $(VV)mkdir -p $$(dir $$@) + $$(call test_output_2,Compiled $$< ,$(AS) -c $(ASMFLAGS) -o $$@ $$<,$(OK_STRING)) +endef +$(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 + $(VV)mkdir -p $$(dir $$@) + $(MAKEDEPFOLDER) + $$(call test_output_2,Compiled $$< ,$(CC) -c $(INCLUDE) -iquote"$(INCDIR)/$$(dir $$*)" $(CFLAGS) $(EXTRA_CFLAGS) $(DEPFLAGS) -o $$@ $$<,$(OK_STRING)) + $(RENAMEDEPENDENCYFILE) +endef +$(foreach cext,$(CEXTS),$(eval $(call c_rule,$(cext)))) + +define cxx_rule +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 $(DEPDIR)/$(basename %).d + $(VV)mkdir -p $$(dir $$@) + $(MAKEDEPFOLDER) + $$(call test_output_2,Compiled $$< ,$(CXX) -c $(INCLUDE) -iquote"$(INCDIR)/$$(dir $$*)" $(CXXFLAGS) $(EXTRA_CXXFLAGS) $(DEPFLAGS) -o $$@ $$<,$(OK_STRING)) + $(RENAMEDEPENDENCYFILE) +endef +$(foreach cxxext,$(CXXEXTS),$(eval $(call cxx_rule,$(cxxext)))) + +define _pros_ld_timestamp +$(VV)mkdir -p $(dir $(LDTIMEOBJ)) +@# Pipe a line of code defining _PROS_COMPILE_TOOLSTAMP and _PROS_COMPILE_DIRECTORY into GCC, +@# which allows compilation from stdin. We define _PROS_COMPILE_DIRECTORY using a command line-defined macro +@# which is the pwd | tail bit, which will truncate the path to the last 23 characters +@# +@# const int _PROS_COMPILE_TIMESTAMP_INT = $(( $(date +%s) - $(date +%z) * 3600 )) +@# char const * const _PROS_COMPILE_TIEMSTAMP = __DATE__ " " __TIME__ +@# char const * const _PROS_COMPILE_DIRECTORY = "$(shell pwd | tail -c 23)"; +@# +@# The shell command $$(($$(date +%s)+($$(date +%-z)/100*3600))) fetches the current +@# unix timestamp, and then adds the UTC timezone offset to account for time zones. + +$(call test_output_2,Adding timestamp ,echo 'const int _PROS_COMPILE_TIMESTAMP_INT = $(shell echo $$(($$(date +%s)+($$(date +%-z)/100*3600)))); char const * const _PROS_COMPILE_TIMESTAMP = __DATE__ " " __TIME__; char const * const _PROS_COMPILE_DIRECTORY = "$(shell pwd | tail -c 23)";' | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) -o $(LDTIMEOBJ) -,$(OK_STRING)) +endef + +# these rules are for build-compile-commands, which just print out sysroot information +cc-sysroot: + @echo | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) --verbose -o /dev/null - +cxx-sysroot: + @echo | $(CXX) -c -x c++ $(CXXFLAGS) $(EXTRA_CXXFLAGS) --verbose -o /dev/null - + +$(DEPDIR)/%.d: ; +.PRECIOUS: $(DEPDIR)/%.d + +include $(wildcard $(patsubst $(SRCDIR)/%,$(DEPDIR)/%.d,$(CSRC) $(CXXSRC))) diff --git a/firmware/libc.a b/firmware/libc.a new file mode 100644 index 00000000..51439b99 Binary files /dev/null and b/firmware/libc.a differ diff --git a/firmware/libm.a b/firmware/libm.a new file mode 100644 index 00000000..3d4066d5 Binary files /dev/null and b/firmware/libm.a differ diff --git a/firmware/libpros.a b/firmware/libpros.a new file mode 100644 index 00000000..db5ad452 Binary files /dev/null and b/firmware/libpros.a differ diff --git a/firmware/okapilib.a b/firmware/okapilib.a new file mode 100644 index 00000000..ae1c4df5 Binary files /dev/null and b/firmware/okapilib.a differ diff --git a/firmware/squiggles.mk b/firmware/squiggles.mk new file mode 100644 index 00000000..f970674a --- /dev/null +++ b/firmware/squiggles.mk @@ -0,0 +1 @@ +INCLUDE+=-iquote"$(ROOT)/include/okapi/squiggles" diff --git a/firmware/v5-common.ld b/firmware/v5-common.ld new file mode 100644 index 00000000..762a9055 --- /dev/null +++ b/firmware/v5-common.ld @@ -0,0 +1,263 @@ +/* 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 = .; +} diff --git a/firmware/v5-hot.ld b/firmware/v5-hot.ld new file mode 100644 index 00000000..017cb356 --- /dev/null +++ b/firmware/v5-hot.ld @@ -0,0 +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) diff --git a/firmware/v5.ld b/firmware/v5.ld new file mode 100644 index 00000000..7cbd06f3 --- /dev/null +++ b/firmware/v5.ld @@ -0,0 +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) diff --git a/images/image.png b/images/image.png new file mode 100644 index 00000000..c2f314a0 Binary files /dev/null and b/images/image.png differ diff --git a/old-code/navx_publisher/CMakeLists.txt b/old-code/navx_publisher/CMakeLists.txt new file mode 100644 index 00000000..34118bd3 --- /dev/null +++ b/old-code/navx_publisher/CMakeLists.txt @@ -0,0 +1,216 @@ +cmake_minimum_required(VERSION 3.0.2) +project(navx_publisher) + +# include ("../cmake_modules/CMakeOpt.cmake") + +## Find catkin macros and libraries +## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) +## is used, also find other catkin packages +find_package(catkin REQUIRED COMPONENTS + roscpp + geometry_msgs + sensor_msgs + message_generation + tf +) + +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) + + +## Uncomment this if the package has a setup.py. This macro ensures +## modules and global scripts declared therein get installed +## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html +# catkin_python_setup() + +################################################ +## Declare ROS messages, services and actions ## +################################################ + +## To declare and build messages, services or actions from within this +## package, follow these steps: +## * Let MSG_DEP_SET be the set of packages whose message types you use in +## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). +## * In the file package.xml: +## * add a build_depend tag for "message_generation" +## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET +## * If MSG_DEP_SET isn't empty the following dependency has been pulled in +## but can be declared for certainty nonetheless: +## * add a run_depend tag for "message_runtime" +## * In this file (CMakeLists.txt): +## * add "message_generation" and every package in MSG_DEP_SET to +## find_package(catkin REQUIRED COMPONENTS ...) +## * add "message_runtime" and every package in MSG_DEP_SET to +## catkin_package(CATKIN_DEPENDS ...) +## * uncomment the add_*_files sections below as needed +## and list every .msg/.srv/.action file to be processed +## * uncomment the generate_messages entry below +## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) + +## Generate messages in the 'msg' folder +add_message_files( + FILES + stampedUInt64.msg + RollPitchYaw.msg +) + +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) + +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# Action1.action +# Action2.action +# ) + +## Generate added messages and services with any dependencies listed here +generate_messages( + DEPENDENCIES + std_msgs + geometry_msgs + navx_publisher +) + +################################################ +## Declare ROS dynamic reconfigure parameters ## +################################################ + +## To declare and build dynamic reconfigure parameters within this +## package, follow these steps: +## * In the file package.xml: +## * add a build_depend and a run_depend tag for "dynamic_reconfigure" +## * In this file (CMakeLists.txt): +## * add "dynamic_reconfigure" to +## find_package(catkin REQUIRED COMPONENTS ...) +## * uncomment the "generate_dynamic_reconfigure_options" section below +## and list every .cfg file to be processed + +## Generate dynamic reconfigure parameters in the 'cfg' folder +# generate_dynamic_reconfigure_options( +# cfg/DynReconf1.cfg +# cfg/DynReconf2.cfg +# ) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## INCLUDE_DIRS: uncomment this if you package contains header files +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( +# INCLUDE_DIRS include +# LIBRARIES goal_detection +# CATKIN_DEPENDS roscpp +# DEPENDS system_lib + CATKIN_DEPENDS message_runtime +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +# include_directories(include) +include_directories( + ${catkin_INCLUDE_DIRS} + src/navXTimeSync +) + +## Declare a C++ library +# add_library(goal_detection +# src/${PROJECT_NAME}/goal_detection.cpp +# ) + +set (NAVX_SRCS + src/navXTimeSync/AHRS.cpp + src/navXTimeSync/ContinuousAngleTracker.cpp + src/navXTimeSync/InertialDataIntegrator.cpp + src/navXTimeSync/OffsetTracker.cpp + src/navXTimeSync/SerialIO.cpp + src/navXTimeSync/SerialPort.cpp ) + +## Declare a C++ executable +add_executable(navx_publisher_node src/navx_publisher.cpp ${NAVX_SRCS}) + +## Add cmake target dependencies of the executable +## same as for the library above +add_dependencies(navx_publisher_node + ${${PROJECT_NAME}_EXPORTED_TARGETS} + ${catkin_EXPORTED_TARGETS} +) + +## Specify libraries to link a library or executable target against +target_link_libraries(navx_publisher_node + ${catkin_LIBRARIES} +) + +## Declare a C++ executable +add_executable(imu_to_rpy src/imu_to_rpy.cpp) + +## Add cmake target dependencies of the executable +## same as for the library above +add_dependencies(imu_to_rpy + ${${PROJECT_NAME}_EXPORTED_TARGETS} + ${catkin_EXPORTED_TARGETS} +) + +## Specify libraries to link a library or executable target against +target_link_libraries(imu_to_rpy + ${catkin_LIBRARIES} +) +############# +## Install ## +############# + +# all install targets should use catkin DESTINATION variables +# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +# install(PROGRAMS +# scripts/my_python_script +# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +# Mark executables and/or libraries for installation + install(TARGETS navx_publisher_node imu_to_rpy + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} + ) + +# Mark cpp header files for installation +#install(DIRECTORY include/${PROJECT_NAME}/ +# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +# FILES_MATCHING PATTERN "*.h" +# PATTERN ".svn" EXCLUDE +#) + +## Mark other files for installation (e.g. launch and bag files, etc.) +install(FILES + navx_publisher.launch + # myfile2 + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +) + +############# +## Testing ## +############# + +## Add gtest based cpp test target and link libraries +# catkin_add_gtest(${PROJECT_NAME}-test test/test_goal_detection.cpp) +# if(TARGET ${PROJECT_NAME}-test) +# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) +# endif() + +## Add folders to be run by python nosetests +# catkin_add_nosetests(test) diff --git a/old-code/navx_publisher/msg/RollPitchYaw.msg b/old-code/navx_publisher/msg/RollPitchYaw.msg new file mode 100644 index 00000000..84885f7f --- /dev/null +++ b/old-code/navx_publisher/msg/RollPitchYaw.msg @@ -0,0 +1,3 @@ +float32 roll +float32 pitch +float32 yaw \ No newline at end of file diff --git a/old-code/navx_publisher/msg/stampedUInt64.msg b/old-code/navx_publisher/msg/stampedUInt64.msg new file mode 100644 index 00000000..1bb0f27d --- /dev/null +++ b/old-code/navx_publisher/msg/stampedUInt64.msg @@ -0,0 +1,2 @@ +Header header +uint64 data diff --git a/old-code/navx_publisher/navx_calib.dat b/old-code/navx_publisher/navx_calib.dat new file mode 100644 index 00000000..90416e01 --- /dev/null +++ b/old-code/navx_publisher/navx_calib.dat @@ -0,0 +1,67 @@ +3.53722 +-0.136126 +0.149526 +-0.136126 +0.0720577 +0.0242997 +0.149526 +0.0242997 +0.0588951 + +0.00120166 +-7.13396e-05 +4.45998e-05 +-7.13396e-05 +0.0013117 +0.00010394 +4.45998e-05 +0.00010394 +0.00343147 + +0.018 +0 +0 +0 +0.018 +0 +0 +0 +0.018 + +0.00120166 +-7.13396e-05 +4.45998e-05 +-0.00183434 +0.000726158 +-0.000196458 +-7.13396e-05 +0.0013117 +0.00010394 +0.00340265 +-0.00128863 +-0.000176971 +4.45998e-05 +0.00010394 +0.00343147 +0.00669213 +-0.000603925 +0.000649451 +-0.00183434 +0.00340265 +0.00669213 +3.53722 +-0.136126 +0.149526 +0.000726158 +-0.00128863 +-0.000603925 +-0.136126 +0.0720577 +0.0242997 +-0.000196458 +-0.000176971 +0.000649451 +0.149526 +0.0242997 +0.0588951 + diff --git a/old-code/navx_publisher/navx_publisher.launch b/old-code/navx_publisher/navx_publisher.launch new file mode 100644 index 00000000..3c0e6f57 --- /dev/null +++ b/old-code/navx_publisher/navx_publisher.launch @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/old-code/navx_publisher/package.xml b/old-code/navx_publisher/package.xml new file mode 100644 index 00000000..f8240ac8 --- /dev/null +++ b/old-code/navx_publisher/package.xml @@ -0,0 +1,59 @@ + + + navx_publisher + 0.0.0 + Publishes a timestamp from the navX + + + + + ubuntu + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + roscpp + message_generation + geometry_msgs + sensor_msgs + tf + roscpp + message_runtime + geometry_msgs + sensor_msgs + tf + + + + + + + diff --git a/old-code/navx_publisher/src/imu_to_rpy.cpp b/old-code/navx_publisher/src/imu_to_rpy.cpp new file mode 100644 index 00000000..3111d473 --- /dev/null +++ b/old-code/navx_publisher/src/imu_to_rpy.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** + +Conversion from a quaternion to roll, pitch and yaw. + +Nodes: +subscribed /rotation_quaternion (message of type geometry_msgs::Quaternion) +published /rpy_angles (message oftype geometry_msgs::Vector3.h) + +****************************************************************************/ + +#include "ros/ros.h" +#include "geometry_msgs/Vector3.h" +#include "geometry_msgs/Quaternion.h" +#include "sensor_msgs/Imu.h" +#include "tf/transform_datatypes.h" + +// Here I use global publisher and subscriber, since I want to access the +// publisher in the function MsgCallback: +ros::Publisher rpy_publisher; +ros::Subscriber quat_subscriber; + +// Function for conversion of quaternion to roll pitch and yaw. The angles +// are published here too. +void MsgCallback(const sensor_msgs::Imu msg) +{ + // the incoming geometry_msgs::Quaternion is transformed to a tf::Quaterion + tf::Quaternion quat; + tf::quaternionMsgToTF(msg.orientation, quat); + + // the tf::Quaternion has a method to acess roll pitch and yaw + double roll, pitch, yaw; + tf::Matrix3x3(quat).getRPY(roll, pitch, yaw); + + // the found angles are written in a geometry_msgs::Vector3 + geometry_msgs::Vector3 rpy; + rpy.x = roll; + rpy.y = pitch; + rpy.z = yaw; + + // this Vector is then published: + rpy_publisher.publish(rpy); + ROS_INFO("r=% 3.3f p=% 3.3f y=% 3.5f vr=% 3.3f vp=% 3.3f vy=% 3.3f", rpy.x, rpy.y, rpy.z, msg.angular_velocity.x, msg.angular_velocity.y, msg.angular_velocity.z); +} + +int main(int argc, char **argv) +{ + ros::init(argc, argv, "imu_to_rpy"); + ros::NodeHandle n; + rpy_publisher = n.advertise("rpy_angles", 100); + quat_subscriber = n.subscribe("zeroed_imu", 100, MsgCallback); + + // check for incoming quaternions untill ctrl+c is pressed + ROS_INFO("waiting for zeroed_imu"); + ros::spin(); + return 0; +} diff --git a/old-code/navx_publisher/src/navx_publisher.cpp b/old-code/navx_publisher/src/navx_publisher.cpp new file mode 100644 index 00000000..71226714 --- /dev/null +++ b/old-code/navx_publisher/src/navx_publisher.cpp @@ -0,0 +1,278 @@ +#include + +#include +#include +#include +#include +#include + +#include "geometry_msgs/Quaternion.h" +#include "sensor_msgs/Imu.h" +#include "nav_msgs/Odometry.h" +#include "navXTimeSync/AHRS.h" +#include "navx_publisher/stampedUInt64.h" +#include "navx_publisher/RollPitchYaw.h" +#include + +using namespace std; +static const boost::array STANDARD_POSE_COVARIANCE = +{ + { + 0.1, 0, 0, 0, 0, 0, + 0, 0.1, 0, 0, 0, 0, + 0, 0, 0.1, 0, 0, 0, + 0, 0, 0, 0.17, 0, 0, + 0, 0, 0, 0, 0.17, 0, + 0, 0, 0, 0, 0, 0.17 + } +}; +static const boost::array STANDARD_TWIST_COVARIANCE = +{ + { + 0.05, 0, 0, 0, 0, 0, + 0, 0.05, 0, 0, 0, 0, + 0, 0, 0.05, 0, 0, 0, + 0, 0, 0, 0.09, 0, 0, + 0, 0, 0, 0, 0.09, 0, + 0, 0, 0, 0, 0, 0.09 + } +}; + +static const boost::array STANDARD_ORIENTATION_COVARIANCE = +{ + { + 0.00015, 0, 0, + 0, 0.00015, 0, + 0, 0, 0.00015 + } +}; + +static const boost::array STANDARD_VELOCITY_COVARIANCE = +{ + { + 0.0015, 0, 0, + 0, 0.0015, 0, + 0, 0, 0.0015 + } +}; + +static const boost::array STANDARD_ACCELERATION_COVARIANCE = +{ + { + 0.05, 0, 0, + 0, 0.05, 0, + 0, 0, 0.05 + } +}; + +int main(int argc, char **argv) +{ + ros::init(argc, argv, "navx_publisher"); + + ros::NodeHandle nh; + // Set up publishers + // Raw_pub publishes in the ENU (east north up) orientation + // instead of NED (north east down) + ros::Publisher time_pub = nh.advertise("time", 5); + ros::Publisher imu_pub = nh.advertise("navx/data", 5); + ros::Publisher imu_rpy_pub = nh.advertise("navx/rpy", 5); + ros::Publisher raw_pub = nh.advertise("navx/raw", 5); + ros::Publisher odom_pub = nh.advertise("odom", 5); + navx_publisher::stampedUInt64 timestamp; + navx_publisher::RollPitchYaw imu_rpy_msg; + sensor_msgs::Imu imu_msg; + sensor_msgs::Imu imu_msg_raw; + nav_msgs::Odometry odom; + + imu_msg.linear_acceleration_covariance = imu_msg_raw.linear_acceleration_covariance = STANDARD_ACCELERATION_COVARIANCE; + imu_msg.angular_velocity_covariance = imu_msg_raw.angular_velocity_covariance = STANDARD_VELOCITY_COVARIANCE; + imu_msg.orientation_covariance = imu_msg_raw.orientation_covariance = STANDARD_ORIENTATION_COVARIANCE; + + odom.twist.covariance = STANDARD_TWIST_COVARIANCE; + odom.pose.covariance = STANDARD_POSE_COVARIANCE; + + imu_msg_raw.header.frame_id = "navx_frame"; + imu_msg.header.frame_id = "navx_frame"; + odom.header.frame_id = "nav_current_frame"; + + { + // TODO - these should be params instead + //read the file with covariances and apply it to the odometry and IMU + ifstream infile("/home/ubuntu/2020RobotCode/zebROS_ws/src/navx_publisher/navx_calib.dat"); + if (!infile.good()) + cerr << "navx_calib.dat file not opened!" << endl; + std::string line; + int ln = 0; + while (std::getline(infile, line)) + { + if (line == "") break; + imu_msg.linear_acceleration_covariance[ln] = std::stod(line); + ln++; + } + ln = 0; + while (std::getline(infile, line)) + { + if (line == "") break; + imu_msg.angular_velocity_covariance[ln] = std::stod(line); + ln++; + } + ln = 0; + while (std::getline(infile, line)) + { + if (line == "") break; + imu_msg.orientation_covariance[ln] = std::stod(line); + ln++; + } + ln = 0; + while (std::getline(infile, line)) + { + if (line == "") break; + odom.twist.covariance[ln] = std::stod(line); + odom.pose.covariance[ln] = std::stod(line); + ln++; + } + } + imu_msg_raw.linear_acceleration_covariance = imu_msg.linear_acceleration_covariance; + imu_msg_raw.angular_velocity_covariance = imu_msg.angular_velocity_covariance; + imu_msg_raw.orientation_covariance = imu_msg.orientation_covariance; + + ros::Time last_time; + tf::Quaternion last_rot (tf::Vector3(0., 0., 0.), 0.); + + bool firstrun = true; + + ros::Rate loop_time(100); + ros::NodeHandle nh_local("~"); + const std::string device(nh_local.param("device", std::string("/dev/ttyACM0"))); + + AHRS nx(device, AHRS::SerialDataType::kProcessedData, 200); + nx.ZeroYaw(); + while (ros::ok()) + { + unsigned long long nxstamp = nx.GetLastSensorTimestamp(); + if (firstrun || (nxstamp != timestamp.data)) + { + //set the timestamp for all headers + odom.header.stamp = + imu_msg.header.stamp = + imu_msg_raw.header.stamp = + timestamp.header.stamp = ros::Time::now(); + + float nx_roll; + float nx_pitch; + float nx_yaw; + float nx_qx; + float nx_qy; + float nx_qz; + float nx_qw; + float nx_ax; + float nx_ay; + float nx_az; + long nx_stamp; + + //pull orientation data from NavX + //all in one shot + // TODO - revise to use fusedHeading for nx_yaw + // or not, depending on debugging fusedHeading drift problem + // nx.GetRPYQAccel(nx_roll, nx_pitch, nx_yaw, + // nx_qx, nx_qy, nx_qz, nx_qw, + // nx_ax, nx_ay, nx_az, + // nx_stamp); + + nx_roll = nx.GetRoll(); + nx_pitch = nx.GetPitch(); + nx_yaw = nx.GetYaw(); + nx_qx = nx.GetQuaternionX(); + nx_qy = nx.GetQuaternionY(); + nx_qz = nx.GetQuaternionZ(); + nx_qw = nx.GetQuaternionW(); + nx_ax = nx.GetWorldLinearAccelX(); + nx_ay = nx.GetWorldLinearAccelY(); + nx_az = nx.GetWorldLinearAccelZ(); + nx_stamp = nx.GetLastSensorTimestamp(); + + nx_roll *= -M_PI / 180.; + nx_pitch *= M_PI / 180.; + nx_yaw *= -M_PI / 180.; + + // roll and pitch are swapped from navx convention to the ros expected one + tf::Quaternion q = tf::createQuaternionFromRPY(nx_pitch, nx_roll, nx_yaw); + + //std::cout << "From NX : " << nx_qx << " " << nx_qy << " " << nx_qz << " " << nx_qw << std::endl; + //std::cout << "From RPY : " << q.x() << " " << q.y() << " " << q.z() << " " << q.w() << std::endl; + + tf::quaternionTFToMsg(q, imu_msg.orientation); + imu_msg.linear_acceleration.x = nx_ax; + imu_msg.linear_acceleration.y = nx_ay; + imu_msg.linear_acceleration.z = nx_az; + timestamp.data = nx_stamp; + + imu_msg_raw.orientation.x = imu_msg.orientation.x; + imu_msg_raw.orientation.y = imu_msg.orientation.y; + imu_msg_raw.orientation.z = -imu_msg.orientation.z; + imu_msg_raw.orientation.w = imu_msg.orientation.w; + + constexpr double grav = 9.80665; + imu_msg.linear_acceleration.x *= grav; + imu_msg.linear_acceleration.y *= grav; + imu_msg.linear_acceleration.z *= grav; + +#if 1 + imu_msg_raw.linear_acceleration = imu_msg.linear_acceleration; +#else + //uncomment this to add gravity back into /navx/raw + nx_yaw *= M_PI / 180.; + nx_pitch *= M_PI / 180.; + nx_roll *= M_PI / 180.; + imu_msg_raw.linear_acceleration.x = imu_msg.linear_acceleration.x + sin(nx_roll) * cos(nx_pitch) * grav; + imu_msg_raw.linear_acceleration.y = imu_msg.linear_acceleration.y + cos(nx_roll) * sin(nx_pitch) * grav; + imu_msg_raw.linear_acceleration.z = imu_msg.linear_acceleration.z + cos(nx_pitch) * cos(nx_roll) * grav; +#endif + + tf::Quaternion pose; + double yaw; + double pitch; + double roll; + tf::quaternionMsgToTF(imu_msg_raw.orientation, pose); // or imu_msg? they differ in the z value + if (firstrun) last_rot = pose; + tf::Quaternion rot = pose * last_rot.inverse(); + tf::Matrix3x3(rot).getRPY(roll, pitch, yaw); + const double dTime = odom.header.stamp.toSec() - last_time.toSec(); + imu_msg.angular_velocity.x = roll / dTime; + imu_msg.angular_velocity.y = pitch / dTime; + imu_msg.angular_velocity.z = -yaw / dTime; + imu_msg_raw.angular_velocity = imu_msg.angular_velocity; + last_rot = pose; + last_time = odom.header.stamp; + + firstrun = false; + + //pull position data (all this is the integral of velocity so it's not very good) + odom.pose.pose.position.x = nx.GetDisplacementX(); + odom.pose.pose.position.y = nx.GetDisplacementY(); + odom.pose.pose.position.z = nx.GetDisplacementZ(); + odom.pose.pose.orientation = imu_msg_raw.orientation; // or imu_msg? see above question + + odom.twist.twist.linear.x = nx.GetVelocityX(); + odom.twist.twist.linear.y = nx.GetVelocityY(); + odom.twist.twist.linear.z = nx.GetVelocityZ(); + + odom.twist.twist.angular = imu_msg.angular_velocity; + + // Gather RPY into custom message + imu_rpy_msg.roll = nx.GetRoll(); + imu_rpy_msg.pitch = nx.GetPitch(); + imu_rpy_msg.yaw = nx.GetYaw(); + + //publish to ROS topics + time_pub.publish(timestamp); + imu_pub.publish(imu_msg); + imu_rpy_pub.publish(imu_rpy_msg); + odom_pub.publish(odom); + raw_pub.publish(imu_msg_raw); + } + loop_time.sleep(); + } + + return 0; +} diff --git a/old-code/v5_hal/CMakeLists.txt b/old-code/v5_hal/CMakeLists.txt new file mode 100644 index 00000000..9e2dcf27 --- /dev/null +++ b/old-code/v5_hal/CMakeLists.txt @@ -0,0 +1,235 @@ +cmake_minimum_required(VERSION 3.0.2) +project(v5_hal) + +## Compile as C++11, supported in ROS Kinetic and newer +# add_compile_options(-std=c++11) + +## Find catkin macros and libraries +## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) +## is used, also find other catkin packages +find_package(catkin REQUIRED COMPONENTS + message_generation + genmsg + roscpp + rosserial_vex_v5 + std_msgs +) + +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) + + +## Uncomment this if the package has a setup.py. This macro ensures +## modules and global scripts declared therein get installed +## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html +# catkin_python_setup() + +################################################ +## Declare ROS messages, services and actions ## +################################################ + +## To declare and build messages, services or actions from within this +## package, follow these steps: +## * Let MSG_DEP_SET be the set of packages whose message types you use in +## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). +## * In the file package.xml: +## * add a build_depend tag for "message_generation" +## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET +## * If MSG_DEP_SET isn't empty the following dependency has been pulled in +## but can be declared for certainty nonetheless: +## * add a exec_depend tag for "message_runtime" +## * In this file (CMakeLists.txt): +## * add "message_generation" and every package in MSG_DEP_SET to +## find_package(catkin REQUIRED COMPONENTS ...) +## * add "message_runtime" and every package in MSG_DEP_SET to +## catkin_package(CATKIN_DEPENDS ...) +## * uncomment the add_*_files sections below as needed +## and list every .msg/.srv/.action file to be processed +## * uncomment the generate_messages entry below +## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) + +# Generate messages in the 'msg' folder + add_message_files( + FILES + CompetitionStatus.msg + RollPitchYaw.msg + V5Battery.msg + V5Controller.msg + V5InertialSensor.msg + V5Motor.msg + # V5RotationSensor.msg + ) + +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) + +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# ) + +## Generate added messages and services with any dependencies listed here + generate_messages( + DEPENDENCIES + std_msgs # Or other packages containing msgs + ) + +################################################ +## Declare ROS dynamic reconfigure parameters ## +################################################ + +## To declare and build dynamic reconfigure parameters within this +## package, follow these steps: +## * In the file package.xml: +## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" +## * In this file (CMakeLists.txt): +## * add "dynamic_reconfigure" to +## find_package(catkin REQUIRED COMPONENTS ...) +## * uncomment the "generate_dynamic_reconfigure_options" section below +## and list every .cfg file to be processed + +## Generate dynamic reconfigure parameters in the 'cfg' folder +# generate_dynamic_reconfigure_options( +# cfg/DynReconf1.cfg +# cfg/DynReconf2.cfg +# ) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## INCLUDE_DIRS: uncomment this if your package contains header files +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( +# INCLUDE_DIRS include +# LIBRARIES change_up_robot_code + CATKIN_DEPENDS message_runtime roscpp rosserial_vex_v5 +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( + firmware/include + ${catkin_INCLUDE_DIRS} +) + +# Declare a C++ library +add_library(${PROJECT_NAME} + firmware/src/swerve/SwerveModule.cpp + firmware/src/pathing/PathPoint.cpp +) + +## Add cmake target dependencies of the library +## as an example, code may need to be generated before libraries +## either from message generation or dynamic reconfigure +# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Declare a C++ executable +## With catkin_make all packages are built within a single CMake context +## The recommended prefix ensures that target names across packages don't collide +# add_executable(${PROJECT_NAME}_node src/change_up_robot_code_node.cpp) + +## Rename C++ executable without prefix +## The above recommended prefix causes long target names, the following renames the +## target back to the shorter version for ease of user use +## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" +# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") + +## Add cmake target dependencies of the executable +## same as for the library above +# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Specify libraries to link a library or executable target against +# target_link_libraries(${PROJECT_NAME}_node +# ${catkin_LIBRARIES} +# ) + +############# +## Install ## +############# + +# all install targets should use catkin DESTINATION variables +# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +# catkin_install_python(PROGRAMS +# scripts/my_python_script +# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark executables for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html +# install(TARGETS ${PROJECT_NAME}_node +# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark libraries for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html +# install(TARGETS ${PROJECT_NAME} +# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} +# ) + +## Mark cpp header files for installation +# install(DIRECTORY include/${PROJECT_NAME}/ +# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +# FILES_MATCHING PATTERN "*.h" +# PATTERN ".svn" EXCLUDE +# ) + +## Mark other files for installation (e.g. launch and bag files, etc.) +# install(FILES +# # myfile1 +# # myfile2 +# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +# ) + +############# +## Testing ## +############# + +## Add gtest based cpp test target and link libraries +catkin_add_gtest(${PROJECT_NAME}_test + test/swerve/test_SwerveModule.cpp + test/pathing/test_PathPoint.cpp +) + +if(TARGET ${PROJECT_NAME}_test) + target_link_libraries(${PROJECT_NAME}_test ${PROJECT_NAME}) +endif() +## Add folders to be run by python nosetests +# catkin_add_nosetests(test) + + +################################ +## Custom PROS Build Commands ## +################################ + +rosserial_generate_ros_lib ( + PACKAGE rosserial_vex_v5 + SCRIPT make_libraries.py +) + +rosserial_configure_client ( + DIRECTORY firmware +) + +rosserial_add_client_target(firmware build) +add_dependencies(${PROJECT_NAME}_firmware_build ${PROJECT_NAME}_generate_messages) + +rosserial_add_client_target(firmware clean_all) +rosserial_add_client_target(firmware wsl_upload) \ No newline at end of file diff --git a/old-code/v5_hal/README.md b/old-code/v5_hal/README.md new file mode 100644 index 00000000..91534499 --- /dev/null +++ b/old-code/v5_hal/README.md @@ -0,0 +1 @@ +# change-up-robot-code diff --git a/old-code/v5_hal/firmware/CMakeLists.txt b/old-code/v5_hal/firmware/CMakeLists.txt new file mode 100644 index 00000000..f760c473 --- /dev/null +++ b/old-code/v5_hal/firmware/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required(VERSION 3.0.2) + +project(v5_hal_firmware) + +add_custom_target(build + COMMENT "BUILDING PROS" +) + +add_custom_command(TARGET build PRE_BUILD + COMMENT "COPYING ROS_LIB INTO INCLUDE" + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${ROS_LIB_DIR} ${PROJECT_SOURCE_DIR}/include/ros_lib +) + +add_custom_command(TARGET build PRE_BUILD + COMMENT "FIXING ROS_LIB INCLUDE PATHS" + COMMAND sh ${PROJECT_SOURCE_DIR}/fixIncludes.sh ${PROJECT_SOURCE_DIR}/include/ros_lib +) + + +add_custom_command(TARGET build PRE_BUILD + COMMENT "RUNNING PROSV5 BUILD" + COMMAND prosv5 build + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} +) + +add_custom_target(clean_all + COMMENT "CLEANING PROS" + COMMAND prosv5 make clean + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} +) + +add_custom_command(TARGET clean_all PRE_BUILD + COMMENT "REMOVING ROS_LIB" + COMMAND rm -rf ${PROJECT_SOURCE_DIR}/include/ros_lib +) + +add_custom_target(wsl_upload + COMMENT "UPLOADING THROUGH PROS.EXE" + COMMAND prosv5.exe upload + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} +) \ No newline at end of file diff --git a/old-code/v5_hal/firmware/Makefile b/old-code/v5_hal/firmware/Makefile new file mode 100644 index 00000000..c9c38269 --- /dev/null +++ b/old-code/v5_hal/firmware/Makefile @@ -0,0 +1,45 @@ +################################################################################ +######################### User configurable parameters ######################### +# filename extensions +CEXTS:=c +ASMEXTS:=s S +CXXEXTS:=cpp c++ cc + +# probably shouldn't modify these, but you may need them below +ROOT=. +FWDIR:=$(ROOT)/firmware +BINDIR=$(ROOT)/bin +SRCDIR=$(ROOT)/src +INCDIR=$(ROOT)/include + +WARNFLAGS+= +EXTRA_CFLAGS= +EXTRA_CXXFLAGS= + +# Set to 1 to enable hot/cold linking +USE_PACKAGE:=1 + +# Add libraries you do not wish to include in the cold image here +# EXCLUDE_COLD_LIBRARIES:= $(FWDIR)/your_library.a +EXCLUDE_COLD_LIBRARIES:= + +# Set this to 1 to add additional rules to compile your project as a PROS library template +IS_LIBRARY:=0 +# TODO: CHANGE THIS! +LIBNAME:=libbest +VERSION:=1.0.0 +# EXCLUDE_SRC_FROM_LIB= $(SRCDIR)/unpublishedfile.c +# this line excludes opcontrol.c and similar files +EXCLUDE_SRC_FROM_LIB+=$(foreach file, $(SRCDIR)/main,$(foreach cext,$(CEXTS),$(file).$(cext)) $(foreach cxxext,$(CXXEXTS),$(file).$(cxxext))) + +# files that get distributed to every user (beyond your source archive) - add +# whatever files you want here. This line is configured to add all header files +# that are in the the include directory get exported +TEMPLATE_FILES=$(INCDIR)/**/*.h $(INCDIR)/**/*.hpp + +.DEFAULT_GOAL=quick + +################################################################################ +################################################################################ +########## Nothing below this line should be edited by typical users ########### +-include ./common.mk diff --git a/old-code/v5_hal/firmware/common.mk b/old-code/v5_hal/firmware/common.mk new file mode 100644 index 00000000..778e6c70 --- /dev/null +++ b/old-code/v5_hal/firmware/common.mk @@ -0,0 +1,287 @@ +ARCHTUPLE=arm-none-eabi- +DEVICE=VEX EDR V5 + +MFLAGS=-mcpu=cortex-a9 -mfpu=neon-fp16 -mfloat-abi=softfp -Os -g +CPPFLAGS=-D_POSIX_THREADS -D_UNIX98_THREAD_MUTEX_ATTRIBUTES +GCCFLAGS=-ffunction-sections -fdata-sections -fdiagnostics-color -funwind-tables + +WARNFLAGS+=-Wno-psabi + +SPACE := $() $() +COMMA := , + +DEPDIR := .d +$(shell mkdir -p $(DEPDIR)) +DEPFLAGS = -MT $$@ -MMD -MP -MF $(DEPDIR)/$$*.Td +MAKEDEPFOLDER = -$(VV)mkdir -p $(DEPDIR)/$$(dir $$(patsubst $(BINDIR)/%, %, $(ROOT)/$$@)) +RENAMEDEPENDENCYFILE = -$(VV)mv -f $(DEPDIR)/$$*.Td $$(patsubst $(SRCDIR)/%, $(DEPDIR)/%.d, $(ROOT)/$$<) && touch $$@ + +LIBRARIES+=$(wildcard $(FWDIR)/*.a) +# Cannot include newlib and libc because not all of the req'd stubs are implemented +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 + +ASMFLAGS=$(MFLAGS) $(WARNFLAGS) +CFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) $(GCCFLAGS) --std=gnu11 +CXXFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) $(GCCFLAGS) --std=gnu++17 +LDFLAGS=$(MFLAGS) $(WARNFLAGS) -nostdlib $(GCCFLAGS) +SIZEFLAGS=-d --common +NUMFMTFLAGS=--to=iec --format %.2f --suffix=B + +AR:=$(ARCHTUPLE)ar +# using arm-none-eabi-as generates a listing by default. This produces a super verbose output. +# Using gcc accomplishes the same thing without the extra output +AS:=$(ARCHTUPLE)gcc +CC:=$(ARCHTUPLE)gcc +CXX:=$(ARCHTUPLE)g++ +LD:=$(ARCHTUPLE)g++ +OBJCOPY:=$(ARCHTUPLE)objcopy +SIZETOOL:=$(ARCHTUPLE)size +READELF:=$(ARCHTUPLE)readelf +STRIP:=$(ARCHTUPLE)strip + +ifneq (, $(shell command -v gnumfmt 2> /dev/null)) + SIZES_NUMFMT:=| gnumfmt --field=-4 --header $(NUMFMTFLAGS) +else +ifneq (, $(shell command -v numfmt 2> /dev/null)) + SIZES_NUMFMT:=| numfmt --field=-4 --header $(NUMFMTFLAGS) +else + SIZES_NUMFMT:= +endif +endif + +ifneq (, $(shell command -v sed 2> /dev/null)) +SIZES_SED:=| sed -e 's/ dec/total/' +else +SIZES_SED:= +endif + +rwildcard=$(foreach d,$(filter-out $3,$(wildcard $1*)),$(call rwildcard,$d/,$2,$3)$(filter $(subst *,%,$2),$d)) + +# Colors +NO_COLOR=$(shell printf "%b" "\033[0m") +OK_COLOR=$(shell printf "%b" "\033[32;01m") +ERROR_COLOR=$(shell printf "%b" "\033[31;01m") +WARN_COLOR=$(shell printf "%b" "\033[33;01m") +STEP_COLOR=$(shell printf "%b" "\033[37;01m") +OK_STRING=$(OK_COLOR)[OK]$(NO_COLOR) +DONE_STRING=$(OK_COLOR)[DONE]$(NO_COLOR) +ERROR_STRING=$(ERROR_COLOR)[ERRORS]$(NO_COLOR) +WARN_STRING=$(WARN_COLOR)[WARNINGS]$(NO_COLOR) +ECHO=/bin/printf "%s\n" +echo=@$(ECHO) "$2$1$(NO_COLOR)" +echon=@/bin/printf "%s" "$2$1$(NO_COLOR)" + +define test_output_2 +@if test $(BUILD_VERBOSE) -eq $(or $4,1); then printf "%s\n" "$2"; fi; +@output="$$($2 2>&1)"; exit=$$?; \ +if test 0 -ne $$exit; then \ + printf "%s%s\n" "$1" "$(ERROR_STRING)"; \ + printf "%s\n" "$$output"; \ + exit $$exit; \ +elif test -n "$$output"; then \ + printf "%s%s\n" "$1" "$(WARN_STRING)"; \ + printf "%s\n" "$$output"; \ +else \ + printf "%s%s\n" "$1" "$3"; \ +fi; +endef + +define test_output +@output=$$($1 2>&1); exit=$$?; \ +if test 0 -ne $$exit; then \ + printf "%s\n" "$(ERROR_STRING)" $$?; \ + printf "%s\n" $$output; \ + exit $$exit; \ +elif test -n "$$output"; then \ + printf "%s\n" "$(WARN_STRING)"; \ + printf "%s" $$output; \ +else \ + printf "%s\n" "$2"; \ +fi; +endef + +# Makefile Verbosity +ifeq ("$(origin VERBOSE)", "command line") +BUILD_VERBOSE = $(VERBOSE) +endif +ifeq ("$(origin V)", "command line") +BUILD_VERBOSE = $(V) +endif + +ifndef BUILD_VERBOSE +BUILD_VERBOSE = 0 +endif + +# R is reduced (default messages) - build verbose = 0 +# V is verbose messages - verbosity = 1 +# VV is super verbose - verbosity = 2 +ifeq ($(BUILD_VERBOSE), 0) +R = @echo +D = @ +VV = @ +endif +ifeq ($(BUILD_VERBOSE), 1) +R = @echo +D = +VV = @ +endif +ifeq ($(BUILD_VERBOSE), 2) +R = +D = +VV = +endif + +INCLUDE=$(foreach dir,$(INCDIR) $(EXTRA_INCDIR),-iquote"$(dir)") + +ASMSRC=$(foreach asmext,$(ASMEXTS),$(call rwildcard, $(SRCDIR),*.$(asmext), $1)) +ASMOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call ASMSRC,$1))) +CSRC=$(foreach cext,$(CEXTS),$(call rwildcard, $(SRCDIR),*.$(cext), $1)) +COBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CSRC, $1))) +CXXSRC=$(foreach cxxext,$(CXXEXTS),$(call rwildcard, $(SRCDIR),*.$(cxxext), $1)) +CXXOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CXXSRC,$1))) + +GETALLOBJ=$(sort $(call ASMOBJ,$1) $(call COBJ,$1) $(call CXXOBJ,$1)) + +ARCHIVE_TEXT_LIST=$(subst $(SPACE),$(COMMA),$(notdir $(basename $(LIBRARIES)))) + +LDTIMEOBJ:=$(BINDIR)/_pros_ld_timestamp.o + +MONOLITH_BIN:=$(BINDIR)/monolith.bin +MONOLITH_ELF:=$(basename $(MONOLITH_BIN)).elf + +HOT_BIN:=$(BINDIR)/hot.package.bin +HOT_ELF:=$(basename $(HOT_BIN)).elf +COLD_BIN:=$(BINDIR)/cold.package.bin +COLD_ELF:=$(basename $(COLD_BIN)).elf + +# Check if USE_PACKAGE is defined to check for migration steps from purduesigbots/pros#87 +ifndef USE_PACKAGE +$(error Your Makefile must be migrated! Visit https://pros.cs.purdue.edu/v5/releases/kernel3.1.6.html to learn how) +endif + +DEFAULT_BIN=$(MONOLITH_BIN) +ifeq ($(USE_PACKAGE),1) +DEFAULT_BIN=$(HOT_BIN) +endif + +-include $(wildcard $(FWDIR)/*.mk) + +.PHONY: all clean quick + +quick: $(DEFAULT_BIN) + +all: clean $(DEFAULT_BIN) + +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") +endif + +LIBAR=$(BINDIR)/$(LIBNAME).a +TEMPLATE_DIR=$(ROOT)/template + +clean-template: + @echo Cleaning $(TEMPLATE_DIR) + -$Drm -rf $(TEMPLATE_DIR) + +$(LIBAR): $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)) $(EXTRA_LIB_DEPS) + -$Drm -f $@ + $(call test_output_2,Creating $@ ,$(AR) rcs $@ $^, $(DONE_STRING)) + +.PHONY: library +library: $(LIBAR) + +.PHONY: template +template: clean-template $(LIBAR) + $Dprosv5 c create-template . $(LIBNAME) $(VERSION) $(foreach file,$(TEMPLATE_FILES) $(LIBAR),--system "$(file)") --target v5 $(CREATE_TEMPLATE_FLAGS) +endif + +# if project is a library source, compile the archive and link output.elf against the archive rather than source objects +ifeq ($(IS_LIBRARY),1) +ELF_DEPS+=$(filter-out $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)), $(call GETALLOBJ,$(EXCLUDE_SRCDIRS))) +LIBRARIES+=$(LIBAR) +else +ELF_DEPS+=$(call GETALLOBJ,$(EXCLUDE_SRCDIRS)) +endif + +$(MONOLITH_BIN): $(MONOLITH_ELF) $(BINDIR) + $(call test_output_2,Creating $@ for $(DEVICE) ,$(OBJCOPY) $< -O binary -R .hot_init $@,$(DONE_STRING)) + +$(MONOLITH_ELF): $(ELF_DEPS) $(LIBRARIES) + $(call _pros_ld_timestamp) + $(call test_output_2,Linking project with $(ARCHIVE_TEXT_LIST) ,$(LD) $(LDFLAGS) $(ELF_DEPS) $(LDTIMEOBJ) $(call wlprefix,-T$(FWDIR)/v5.ld $(LNK_FLAGS)) -o $@,$(OK_STRING)) + @echo Section sizes: + -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) + +$(COLD_BIN): $(COLD_ELF) + $(call test_output_2,Creating cold package binary for $(DEVICE) ,$(OBJCOPY) $< -O binary -R .hot_init $@,$(DONE_STRING)) + +$(COLD_ELF): $(COLD_LIBRARIES) + $(VV)mkdir -p $(dir $@) + $(call test_output_2,Creating cold package with $(ARCHIVE_TEXT_LIST) ,$(LD) $(LDFLAGS) $(call wlprefix,--gc-keep-exported --whole-archive $^ -lstdc++ --no-whole-archive) $(call wlprefix,-T$(FWDIR)/v5.ld $(LNK_FLAGS) -o $@),$(OK_STRING)) + $(call test_output_2,Stripping cold package ,$(OBJCOPY) --strip-symbol=install_hot_table --strip-symbol=__libc_init_array --strip-symbol=_PROS_COMPILE_DIRECTORY --strip-symbol=_PROS_COMPILE_TIMESTAMP $@ $@, $(DONE_STRING)) + @echo Section sizes: + -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) + +$(HOT_BIN): $(HOT_ELF) $(COLD_BIN) + $(call test_output_2,Creating $@ for $(DEVICE) ,$(OBJCOPY) $< -O binary $@,$(DONE_STRING)) + +$(HOT_ELF): $(COLD_ELF) $(ELF_DEPS) + $(call _pros_ld_timestamp) + $(call test_output_2,Linking hot project with $(COLD_ELF) and $(ARCHIVE_TEXT_LIST) ,$(LD) $(LDFLAGS) $(call wlprefix,-nostartfiles -R $<) $(filter-out $<,$^) $(LDTIMEOBJ) $(LIBRARIES) $(call wlprefix,-T$(FWDIR)/v5-hot.ld $(LNK_FLAGS) -o $@),$(OK_STRING)) + @printf "%s\n" "Section sizes:" + -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) + +define asm_rule +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 + $(VV)mkdir -p $$(dir $$@) + $$(call test_output_2,Compiled $$< ,$(AS) -c $(ASMFLAGS) -o $$@ $$<,$(OK_STRING)) +endef +$(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 + $(VV)mkdir -p $$(dir $$@) + $(MAKEDEPFOLDER) + $$(call test_output_2,Compiled $$< ,$(CC) -c $(INCLUDE) -iquote"$(INCDIR)/$$(dir $$*)" $(CFLAGS) $(EXTRA_CFLAGS) $(DEPFLAGS) -o $$@ $$<,$(OK_STRING)) + $(RENAMEDEPENDENCYFILE) +endef +$(foreach cext,$(CEXTS),$(eval $(call c_rule,$(cext)))) + +define cxx_rule +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 $(DEPDIR)/$(basename %).d + $(VV)mkdir -p $$(dir $$@) + $(MAKEDEPFOLDER) + $$(call test_output_2,Compiled $$< ,$(CXX) -c $(INCLUDE) -iquote"$(INCDIR)/$$(dir $$*)" $(CXXFLAGS) $(EXTRA_CXXFLAGS) $(DEPFLAGS) -o $$@ $$<,$(OK_STRING)) + $(RENAMEDEPENDENCYFILE) +endef +$(foreach cxxext,$(CXXEXTS),$(eval $(call cxx_rule,$(cxxext)))) + +define _pros_ld_timestamp +$(VV)mkdir -p $(dir $(LDTIMEOBJ)) +@# Pipe a line of code defining _PROS_COMPILE_TOOLSTAMP and _PROS_COMPILE_DIRECTORY into GCC, +@# which allows compilation from stdin. We define _PROS_COMPILE_DIRECTORY using a command line-defined macro +@# which is the pwd | tail bit, which will truncate the path to the last 23 characters +$(call test_output_2,Adding timestamp ,echo 'char const * const _PROS_COMPILE_TIMESTAMP = __DATE__ " " __TIME__; char const * const _PROS_COMPILE_DIRECTORY = "$(shell pwd | tail -c 23)";' | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) -o $(LDTIMEOBJ) -,$(OK_STRING)) +endef + +# these rules are for build-compile-commands, which just print out sysroot information +cc-sysroot: + @echo | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) --verbose -o /dev/null - +cxx-sysroot: + @echo | $(CXX) -c -x c++ $(CXXFLAGS) $(EXTRA_CXXFLAGS) --verbose -o /dev/null - + +$(DEPDIR)/%.d: ; +.PRECIOUS: $(DEPDIR)/%.d + +include $(wildcard $(patsubst $(SRCDIR)/%,$(DEPDIR)/%.d,$(CSRC) $(CXXSRC))) diff --git a/old-code/v5_hal/firmware/firmware/libc.a b/old-code/v5_hal/firmware/firmware/libc.a new file mode 100644 index 00000000..51439b99 Binary files /dev/null and b/old-code/v5_hal/firmware/firmware/libc.a differ diff --git a/old-code/v5_hal/firmware/firmware/libm.a b/old-code/v5_hal/firmware/firmware/libm.a new file mode 100644 index 00000000..3d4066d5 Binary files /dev/null and b/old-code/v5_hal/firmware/firmware/libm.a differ diff --git a/old-code/v5_hal/firmware/firmware/libpros.a b/old-code/v5_hal/firmware/firmware/libpros.a new file mode 100644 index 00000000..39803bbb Binary files /dev/null and b/old-code/v5_hal/firmware/firmware/libpros.a differ diff --git a/old-code/v5_hal/firmware/firmware/okapilib.a b/old-code/v5_hal/firmware/firmware/okapilib.a new file mode 100644 index 00000000..27d39ca3 Binary files /dev/null and b/old-code/v5_hal/firmware/firmware/okapilib.a differ diff --git a/old-code/v5_hal/firmware/firmware/v5-common.ld b/old-code/v5_hal/firmware/firmware/v5-common.ld new file mode 100644 index 00000000..f1b64f01 --- /dev/null +++ b/old-code/v5_hal/firmware/firmware/v5-common.ld @@ -0,0 +1,263 @@ +/* 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_execpt_table) + *(.glue_7) + *(.glue_7t) + *(.vfp11_veneer) + *(.ARM.extab) + *(.gnu.linkonce.armextab.*) +} > MEMORY + +.init : { + KEEP (*(.init)) +} > MEMORY + +.fini : { + KEEP (*(.fini)) +} > MEMORY + +.rodata : { + __rodata_start = .; + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + __rodata_end = .; +} > MEMORY + +.rodata1 : { + __rodata1_start = .; + *(.rodata1) + *(.rodata1.*) + __rodata1_end = .; +} > MEMORY + +.sdata2 : { + __sdata2_start = .; + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + __sdata2_end = .; +} > MEMORY + +.sbss2 : { + __sbss2_start = .; + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + __sbss2_end = .; +} > MEMORY + +.data : { + __data_start = .; + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.jcr) + *(.got) + *(.got.plt) + __data_end = .; +} > MEMORY + +.data1 : { + __data1_start = .; + *(.data1) + *(.data1.*) + __data1_end = .; +} > MEMORY + +.got : { + *(.got) +} > MEMORY + +.ctors : { + __CTOR_LIST__ = .; + ___CTORS_LIST___ = .; + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + __CTOR_END__ = .; + ___CTORS_END___ = .; +} > MEMORY + +.dtors : { + __DTOR_LIST__ = .; + ___DTORS_LIST___ = .; + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + __DTOR_END__ = .; + ___DTORS_END___ = .; +} > MEMORY + +.fixup : { + __fixup_start = .; + *(.fixup) + __fixup_end = .; +} > MEMORY + +.eh_frame : { + *(.eh_frame) +} > MEMORY + +.eh_framehdr : { + __eh_framehdr_start = .; + *(.eh_framehdr) + __eh_framehdr_end = .; +} > MEMORY + +.gcc_except_table : { + *(.gcc_except_table) +} > MEMORY + +.mmu_tbl (ALIGN(16384)) : { + __mmu_tbl_start = .; + *(.mmu_tbl) + __mmu_tbl_end = .; +} > MEMORY + +.ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + *(.gnu.linkonce.armexidix.*.*) + __exidx_end = .; +} > MEMORY + +.preinit_array : { + __preinit_array_start = .; + KEEP (*(SORT(.preinit_array.*))) + KEEP (*(.preinit_array)) + __preinit_array_end = .; +} > MEMORY + +.init_array : { + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; +} > MEMORY + +.fini_array : { + __fini_array_start = .; + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array)) + __fini_array_end = .; +} > MEMORY + +.ARM.attributes : { + __ARM.attributes_start = .; + *(.ARM.attributes) + __ARM.attributes_end = .; +} > MEMORY + +.sdata : { + __sdata_start = .; + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + __sdata_end = .; +} > MEMORY + +.sbss (NOLOAD) : { + __sbss_start = .; + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + __sbss_end = .; +} > MEMORY + +.tdata : { + __tdata_start = .; + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + __tdata_end = .; +} > MEMORY + +.tbss : { + __tbss_start = .; + *(.tbss) + *(.tbss.*) + *(.gnu.linkonce.tb.*) + __tbss_end = .; +} > MEMORY + +.bss (NOLOAD) : { + __bss_start = .; + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + __bss_end = .; +} > MEMORY + +_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 = .; +} diff --git a/old-code/v5_hal/firmware/firmware/v5-hot.ld b/old-code/v5_hal/firmware/firmware/v5-hot.ld new file mode 100644 index 00000000..259bab9b --- /dev/null +++ b/old-code/v5_hal/firmware/firmware/v5-hot.ld @@ -0,0 +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("MEMORY", HOT_MEMORY); + +ENTRY(install_hot_table) diff --git a/old-code/v5_hal/firmware/firmware/v5.ld b/old-code/v5_hal/firmware/firmware/v5.ld new file mode 100644 index 00000000..d6933d9d --- /dev/null +++ b/old-code/v5_hal/firmware/firmware/v5.ld @@ -0,0 +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("MEMORY", COLD_MEMORY); + +ENTRY(vexStartup) diff --git a/old-code/v5_hal/firmware/fixIncludes.sh b/old-code/v5_hal/firmware/fixIncludes.sh new file mode 100644 index 00000000..2551e1cd --- /dev/null +++ b/old-code/v5_hal/firmware/fixIncludes.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +grep -irl '#include' $1 | xargs perl -pi \ + -e 's/^#include "(?!main)(?!pros)(?!stddef)(?!stdlib)(?!string)(?!stdint)(?!math)(?!ros_lib)/#include "ros_lib\//g' \ diff --git a/old-code/v5_hal/firmware/include/3rdparty/json.hpp b/old-code/v5_hal/firmware/include/3rdparty/json.hpp new file mode 100644 index 00000000..a70aaf8c --- /dev/null +++ b/old-code/v5_hal/firmware/include/3rdparty/json.hpp @@ -0,0 +1,25447 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.9.1 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 9 +#define NLOHMANN_JSON_VERSION_PATCH 1 + +#include // all_of, find, for_each +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // random_access_iterator_tag +#include // unique_ptr +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include + + +#include + +// #include + + +#include // transform +#include // array +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + +// #include + + +#include // size_t + +namespace nlohmann +{ +namespace detail +{ +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // pair +// #include +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to + * the public domain worldwide. This software is distributed without + * any warranty. + * + * For details, see . + * SPDX-License-Identifier: CC0-1.0 + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 13) +#if defined(JSON_HEDLEY_VERSION) + #undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 13 + +#if defined(JSON_HEDLEY_STRINGIFY_EX) + #undef JSON_HEDLEY_STRINGIFY_EX +#endif +#define JSON_HEDLEY_STRINGIFY_EX(x) #x + +#if defined(JSON_HEDLEY_STRINGIFY) + #undef JSON_HEDLEY_STRINGIFY +#endif +#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + +#if defined(JSON_HEDLEY_CONCAT_EX) + #undef JSON_HEDLEY_CONCAT_EX +#endif +#define JSON_HEDLEY_CONCAT_EX(a,b) a##b + +#if defined(JSON_HEDLEY_CONCAT) + #undef JSON_HEDLEY_CONCAT +#endif +#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) + +#if defined(JSON_HEDLEY_CONCAT3_EX) + #undef JSON_HEDLEY_CONCAT3_EX +#endif +#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c + +#if defined(JSON_HEDLEY_CONCAT3) + #undef JSON_HEDLEY_CONCAT3 +#endif +#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) + +#if defined(JSON_HEDLEY_VERSION_ENCODE) + #undef JSON_HEDLEY_VERSION_ENCODE +#endif +#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) + #undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) + #undef JSON_HEDLEY_VERSION_DECODE_MINOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) + #undef JSON_HEDLEY_VERSION_DECODE_REVISION +#endif +#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + +#if defined(JSON_HEDLEY_GNUC_VERSION) + #undef JSON_HEDLEY_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) + #undef JSON_HEDLEY_GNUC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION) + #undef JSON_HEDLEY_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) + #undef JSON_HEDLEY_MSVC_VERSION_CHECK +#endif +#if !defined(_MSC_VER) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION) + #undef JSON_HEDLEY_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_VERSION) + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION) + #undef JSON_HEDLEY_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) + #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) + #undef JSON_HEDLEY_PGI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #undef JSON_HEDLEY_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) + #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION) + #undef JSON_HEDLEY_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) + #undef JSON_HEDLEY_ARM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_ARM_VERSION) + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION) + #undef JSON_HEDLEY_IBM_VERSION +#endif +#if defined(__ibmxl__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) + #undef JSON_HEDLEY_IBM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IBM_VERSION) + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION) + #undef JSON_HEDLEY_TI_VERSION +#endif +#if \ + defined(__TI_COMPILER_VERSION__) && \ + ( \ + defined(__TMS470__) || defined(__TI_ARM__) || \ + defined(__MSP430__) || \ + defined(__TMS320C2000__) \ + ) +#if (__TI_COMPILER_VERSION__ >= 16000000) + #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif +#endif + +#if defined(JSON_HEDLEY_TI_VERSION_CHECK) + #undef JSON_HEDLEY_TI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_VERSION) + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #undef JSON_HEDLEY_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) + #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #undef JSON_HEDLEY_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) + #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #undef JSON_HEDLEY_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) + #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) + #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #undef JSON_HEDLEY_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) + #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #undef JSON_HEDLEY_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) + #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #undef JSON_HEDLEY_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) + #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION) + #undef JSON_HEDLEY_CRAY_VERSION +#endif +#if defined(_CRAYC) + #if defined(_RELEASE_PATCHLEVEL) + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) + #else + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) + #undef JSON_HEDLEY_CRAY_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_CRAY_VERSION) + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION) + #undef JSON_HEDLEY_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) + #if __VER__ > 1000 + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) + #else + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) + #undef JSON_HEDLEY_IAR_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IAR_VERSION) + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION) + #undef JSON_HEDLEY_TINYC_VERSION +#endif +#if defined(__TINYC__) + #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) + #undef JSON_HEDLEY_TINYC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION) + #undef JSON_HEDLEY_DMC_VERSION +#endif +#if defined(__DMC__) + #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) + #undef JSON_HEDLEY_DMC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_DMC_VERSION) + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #undef JSON_HEDLEY_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) + #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) + #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION) + #undef JSON_HEDLEY_PELLES_VERSION +#endif +#if defined(__POCC__) + #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) + #undef JSON_HEDLEY_PELLES_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PELLES_VERSION) + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION) + #undef JSON_HEDLEY_GCC_VERSION +#endif +#if \ + defined(JSON_HEDLEY_GNUC_VERSION) && \ + !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ + !defined(__COMPCERT__) + #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#endif +#if \ + defined(__has_cpp_attribute) && \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) + #undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else + #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) + #undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else + #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + #undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) + #undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else + #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) + #undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else + #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + #undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + #undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# endif +#endif +#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + ((T) (expr)) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("diag_suppress=Pe137") \ + JSON_HEDLEY_DIAGNOSTIC_POP \ +# else +# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) +# endif +#else +# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) + #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#else + #define JSON_HEDLEY_PRAGMA(value) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) + #undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) + #undef JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#if defined(__clang__) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) + #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_PUSH + #define JSON_HEDLEY_DIAGNOSTIC_POP +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(JSON_HEDLEY_DEPRECATED) + #undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) + #undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif defined(__cplusplus) && (__cplusplus >= 201402L) + #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ + JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else + #define JSON_HEDLEY_DEPRECATED(since) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(JSON_HEDLEY_UNAVAILABLE) + #undef JSON_HEDLEY_UNAVAILABLE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else + #define JSON_HEDLEY_UNAVAILABLE(available_since) +#endif + +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT +#endif +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#endif +#if (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) +#elif defined(_Check_return_) /* SAL */ + #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ +#else + #define JSON_HEDLEY_WARN_UNUSED_RESULT + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) +#endif + +#if defined(JSON_HEDLEY_SENTINEL) + #undef JSON_HEDLEY_SENTINEL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) + #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#else + #define JSON_HEDLEY_SENTINEL(position) +#endif + +#if defined(JSON_HEDLEY_NO_RETURN) + #undef JSON_HEDLEY_NO_RETURN +#endif +#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NO_RETURN __noreturn +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define JSON_HEDLEY_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) + #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#else + #define JSON_HEDLEY_NO_RETURN +#endif + +#if defined(JSON_HEDLEY_NO_ESCAPE) + #undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else + #define JSON_HEDLEY_NO_ESCAPE +#endif + +#if defined(JSON_HEDLEY_UNREACHABLE) + #undef JSON_HEDLEY_UNREACHABLE +#endif +#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if defined(JSON_HEDLEY_ASSUME) + #undef JSON_HEDLEY_ASSUME +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) + #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) + #else + #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) + #endif +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif defined(JSON_HEDLEY_ASSUME) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif +#if !defined(JSON_HEDLEY_ASSUME) + #if defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) + #else + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) + #endif +#endif +#if defined(JSON_HEDLEY_UNREACHABLE) + #if \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) + #else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() + #endif +#else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif + +JSON_HEDLEY_DIAGNOSTIC_PUSH +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + #pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) + #if defined(__clang__) + #pragma clang diagnostic ignored "-Wvariadic-macros" + #elif defined(JSON_HEDLEY_GCC_VERSION) + #pragma GCC diagnostic ignored "-Wvariadic-macros" + #endif +#endif +#if defined(JSON_HEDLEY_NON_NULL) + #undef JSON_HEDLEY_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else + #define JSON_HEDLEY_NON_NULL(...) +#endif +JSON_HEDLEY_DIAGNOSTIC_POP + +#if defined(JSON_HEDLEY_PRINTF_FORMAT) + #undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(JSON_HEDLEY_CONSTEXPR) + #undef JSON_HEDLEY_CONSTEXPR +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) + #endif +#endif +#if !defined(JSON_HEDLEY_CONSTEXPR) + #define JSON_HEDLEY_CONSTEXPR +#endif + +#if defined(JSON_HEDLEY_PREDICT) + #undef JSON_HEDLEY_PREDICT +#endif +#if defined(JSON_HEDLEY_LIKELY) + #undef JSON_HEDLEY_LIKELY +#endif +#if defined(JSON_HEDLEY_UNLIKELY) + #undef JSON_HEDLEY_UNLIKELY +#endif +#if defined(JSON_HEDLEY_UNPREDICTABLE) + #undef JSON_HEDLEY_UNPREDICTABLE +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) +#elif \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(JSON_HEDLEY_UNPREDICTABLE) + #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#endif + +#if defined(JSON_HEDLEY_MALLOC) + #undef JSON_HEDLEY_MALLOC +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) + #define JSON_HEDLEY_MALLOC __declspec(restrict) +#else + #define JSON_HEDLEY_MALLOC +#endif + +#if defined(JSON_HEDLEY_PURE) + #undef JSON_HEDLEY_PURE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) +# define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) +# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ + ) +# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else +# define JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_CONST) + #undef JSON_HEDLEY_CONST +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#else + #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_RESTRICT) + #undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT restrict +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) + #define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT _Restrict +#else + #define JSON_HEDLEY_RESTRICT +#endif + +#if defined(JSON_HEDLEY_INLINE) + #undef JSON_HEDLEY_INLINE +#endif +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) + #define JSON_HEDLEY_INLINE inline +#elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) + #define JSON_HEDLEY_INLINE __inline__ +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_INLINE __inline +#else + #define JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_ALWAYS_INLINE) + #undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) +# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) +# define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ + ) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else +# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_NEVER_INLINE) + #undef JSON_HEDLEY_NEVER_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#else + #define JSON_HEDLEY_NEVER_INLINE +#endif + +#if defined(JSON_HEDLEY_PRIVATE) + #undef JSON_HEDLEY_PRIVATE +#endif +#if defined(JSON_HEDLEY_PUBLIC) + #undef JSON_HEDLEY_PUBLIC +#endif +#if defined(JSON_HEDLEY_IMPORT) + #undef JSON_HEDLEY_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC __declspec(dllexport) +# define JSON_HEDLEY_IMPORT __declspec(dllimport) +#else +# if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + ( \ + defined(__TI_EABI__) && \ + ( \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ + ) \ + ) +# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +# else +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC +# endif +# define JSON_HEDLEY_IMPORT extern +#endif + +#if defined(JSON_HEDLEY_NO_THROW) + #undef JSON_HEDLEY_NO_THROW +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#else + #define JSON_HEDLEY_NO_THROW +#endif + +#if defined(JSON_HEDLEY_FALL_THROUGH) + #undef JSON_HEDLEY_FALL_THROUGH +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else + #define JSON_HEDLEY_FALL_THROUGH +#endif + +#if defined(JSON_HEDLEY_RETURNS_NON_NULL) + #undef JSON_HEDLEY_RETURNS_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) + #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ + #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#else + #define JSON_HEDLEY_RETURNS_NON_NULL +#endif + +#if defined(JSON_HEDLEY_ARRAY_PARAM) + #undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#else + #define JSON_HEDLEY_ARRAY_PARAM(name) +#endif + +#if defined(JSON_HEDLEY_IS_CONSTANT) + #undef JSON_HEDLEY_IS_CONSTANT +#endif +#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) + #undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#endif +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) + #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +#endif +# elif \ + ( \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +#endif +# elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || \ + defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ + defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ + defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ + defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ + defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ + defined(__clang__) +# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ + sizeof(void) != \ + sizeof(*( \ + 1 ? \ + ((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ + ) \ + ) \ + ) +# endif +#endif +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) (0) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(JSON_HEDLEY_BEGIN_C_DECLS) + #undef JSON_HEDLEY_BEGIN_C_DECLS +#endif +#if defined(JSON_HEDLEY_END_C_DECLS) + #undef JSON_HEDLEY_END_C_DECLS +#endif +#if defined(JSON_HEDLEY_C_DECL) + #undef JSON_HEDLEY_C_DECL +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { + #define JSON_HEDLEY_END_C_DECLS } + #define JSON_HEDLEY_C_DECL extern "C" +#else + #define JSON_HEDLEY_BEGIN_C_DECLS + #define JSON_HEDLEY_END_C_DECLS + #define JSON_HEDLEY_C_DECL +#endif + +#if defined(JSON_HEDLEY_STATIC_ASSERT) + #undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if \ + !defined(__cplusplus) && ( \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + JSON_HEDLEY_HAS_FEATURE(c_static_assert) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + defined(_Static_assert) \ + ) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#endif + +#if defined(JSON_HEDLEY_NULL) + #undef JSON_HEDLEY_NULL +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + #elif defined(NULL) + #define JSON_HEDLEY_NULL NULL + #else + #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + #endif +#elif defined(NULL) + #define JSON_HEDLEY_NULL NULL +#else + #define JSON_HEDLEY_NULL ((void*) 0) +#endif + +#if defined(JSON_HEDLEY_MESSAGE) + #undef JSON_HEDLEY_MESSAGE +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_WARNING) + #undef JSON_HEDLEY_WARNING +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif +#if defined(JSON_HEDLEY_REQUIRE_MSG) + #undef JSON_HEDLEY_REQUIRE_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) +# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +# define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define JSON_HEDLEY_REQUIRE(expr) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) +#endif + +#if defined(JSON_HEDLEY_FLAGS) + #undef JSON_HEDLEY_FLAGS +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) + #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#endif + +#if defined(JSON_HEDLEY_FLAGS_CAST) + #undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) +# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)") \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#endif + +#if defined(JSON_HEDLEY_EMPTY_BASES) + #undef JSON_HEDLEY_EMPTY_BASES +#endif +#if JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0) + #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else + #define JSON_HEDLEY_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) + #undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#endif +#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + +#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) + #undef JSON_HEDLEY_CLANG_HAS_FEATURE +#endif +#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + +#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) + #undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#endif +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) + +#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) + #undef JSON_HEDLEY_CLANG_HAS_WARNING +#endif +#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + +#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// allow to override assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer, \ + class BinaryType> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + NLOHMANN_JSON_PASTE64, \ + NLOHMANN_JSON_PASTE63, \ + NLOHMANN_JSON_PASTE62, \ + NLOHMANN_JSON_PASTE61, \ + NLOHMANN_JSON_PASTE60, \ + NLOHMANN_JSON_PASTE59, \ + NLOHMANN_JSON_PASTE58, \ + NLOHMANN_JSON_PASTE57, \ + NLOHMANN_JSON_PASTE56, \ + NLOHMANN_JSON_PASTE55, \ + NLOHMANN_JSON_PASTE54, \ + NLOHMANN_JSON_PASTE53, \ + NLOHMANN_JSON_PASTE52, \ + NLOHMANN_JSON_PASTE51, \ + NLOHMANN_JSON_PASTE50, \ + NLOHMANN_JSON_PASTE49, \ + NLOHMANN_JSON_PASTE48, \ + NLOHMANN_JSON_PASTE47, \ + NLOHMANN_JSON_PASTE46, \ + NLOHMANN_JSON_PASTE45, \ + NLOHMANN_JSON_PASTE44, \ + NLOHMANN_JSON_PASTE43, \ + NLOHMANN_JSON_PASTE42, \ + NLOHMANN_JSON_PASTE41, \ + NLOHMANN_JSON_PASTE40, \ + NLOHMANN_JSON_PASTE39, \ + NLOHMANN_JSON_PASTE38, \ + NLOHMANN_JSON_PASTE37, \ + NLOHMANN_JSON_PASTE36, \ + NLOHMANN_JSON_PASTE35, \ + NLOHMANN_JSON_PASTE34, \ + NLOHMANN_JSON_PASTE33, \ + NLOHMANN_JSON_PASTE32, \ + NLOHMANN_JSON_PASTE31, \ + NLOHMANN_JSON_PASTE30, \ + NLOHMANN_JSON_PASTE29, \ + NLOHMANN_JSON_PASTE28, \ + NLOHMANN_JSON_PASTE27, \ + NLOHMANN_JSON_PASTE26, \ + NLOHMANN_JSON_PASTE25, \ + NLOHMANN_JSON_PASTE24, \ + NLOHMANN_JSON_PASTE23, \ + NLOHMANN_JSON_PASTE22, \ + NLOHMANN_JSON_PASTE21, \ + NLOHMANN_JSON_PASTE20, \ + NLOHMANN_JSON_PASTE19, \ + NLOHMANN_JSON_PASTE18, \ + NLOHMANN_JSON_PASTE17, \ + NLOHMANN_JSON_PASTE16, \ + NLOHMANN_JSON_PASTE15, \ + NLOHMANN_JSON_PASTE14, \ + NLOHMANN_JSON_PASTE13, \ + NLOHMANN_JSON_PASTE12, \ + NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, \ + NLOHMANN_JSON_PASTE9, \ + NLOHMANN_JSON_PASTE8, \ + NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, \ + NLOHMANN_JSON_PASTE5, \ + NLOHMANN_JSON_PASTE4, \ + NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, \ + NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; +#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_USE_IMPLICIT_CONVERSIONS 1 +#endif + +#if JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_EXPLICIT +#else + #define JSON_EXPLICIT explicit +#endif + + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + JSON_HEDLEY_RETURNS_NON_NULL + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + + protected: + JSON_HEDLEY_NON_NULL(3) + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. +json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). +json.exception.parse_error.115 | parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1A | A UBJSON high-precision number could not be parsed. + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] pos the position where the error occurred (or with + chars_read_total=0 if the position cannot be + determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id_, const position_t& pos, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + position_string(pos) + ": " + what_arg; + return parse_error(id_, pos.chars_read_total, w.c_str()); + } + + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + + ": " + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} + + static std::string position_string(const position_t& pos) + { + return " at line " + std::to_string(pos.lines_read + 1) + + ", column " + std::to_string(pos.chars_read_current_line); + } +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + static invalid_iterator create(int id_, const std::string& what_arg) + { + std::string w = exception::name("invalid_iterator", id_) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | +json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + static type_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("type_error", id_) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. (until version 3.8.0) | +json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | +json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + static out_of_range create(int id_, const std::string& what_arg) + { + std::string w = exception::name("out_of_range", id_) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + static other_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("other_error", id_) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + + +#include // random_access_iterator_tag + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + + +#include + +// #include + + +// https://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template class Op, class... Args> +using is_detected = typename detector::value_t; + +template class Op, class... Args> +using detected_t = typename detector::type; + +template class Op, class... Args> +using detected_or = detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = + std::is_convertible, To>; +} // namespace detail +} // namespace nlohmann + +// #include +#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ +#define INCLUDE_NLOHMANN_JSON_FWD_HPP_ + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer, + class BinaryType = std::vector> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +template +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; + +template +struct ordered_map; + +/*! +@brief ordered JSON class + +This type preserves the insertion order of object keys. + +@since version 3.9.0 +*/ +using ordered_json = basic_json; + +} // namespace nlohmann + +#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + +namespace nlohmann +{ +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ +///////////// +// helpers // +///////////// + +// Note to maintainers: +// +// Every trait in this file expects a non CV-qualified type. +// The only exceptions are in the 'aliases for detected' section +// (i.e. those of the form: decltype(T::member_function(std::declval()))) +// +// In this case, T has to be properly CV-qualified to constraint the function arguments +// (e.g. to_json(BasicJsonType&, const T&)) + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +////////////////////// +// json_ref helpers // +////////////////////// + +template +class json_ref; + +template +struct is_json_ref : std::false_type {}; + +template +struct is_json_ref> : std::true_type {}; + +////////////////////////// +// aliases for detected // +////////////////////////// + +template +using mapped_type_t = typename T::mapped_type; + +template +using key_type_t = typename T::key_type; + +template +using value_type_t = typename T::value_type; + +template +using difference_type_t = typename T::difference_type; + +template +using pointer_t = typename T::pointer; + +template +using reference_t = typename T::reference; + +template +using iterator_category_t = typename T::iterator_category; + +template +using iterator_t = typename T::iterator; + +template +using to_json_function = decltype(T::to_json(std::declval()...)); + +template +using from_json_function = decltype(T::from_json(std::declval()...)); + +template +using get_template_function = decltype(std::declval().template get()); + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json : std::false_type {}; + +// trait checking if j.get is valid +// use this trait instead of std::is_constructible or std::is_convertible, +// both rely on, or make use of implicit conversions, and thus fail when T +// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) +template +struct is_getable +{ + static constexpr bool value = is_detected::value; +}; + +template +struct has_from_json < BasicJsonType, T, + enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json : std::false_type {}; + +template +struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template +struct has_to_json : std::false_type {}; + +template +struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + + +/////////////////// +// is_ functions // +/////////////////// + +template +struct is_iterator_traits : std::false_type {}; + +template +struct is_iterator_traits> +{ + private: + using traits = iterator_traits; + + public: + static constexpr auto value = + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value; +}; + +// source: https://stackoverflow.com/a/37193089/4116453 + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl < + BasicJsonType, CompatibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + + using object_t = typename BasicJsonType::object_t; + + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + std::is_constructible::value && + std::is_constructible::value; +}; + +template +struct is_compatible_object_type + : is_compatible_object_type_impl {}; + +template +struct is_constructible_object_type_impl : std::false_type {}; + +template +struct is_constructible_object_type_impl < + BasicJsonType, ConstructibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + static constexpr bool value = + (std::is_default_constructible::value && + (std::is_move_assignable::value || + std::is_copy_assignable::value) && + (std::is_constructible::value && + std::is_same < + typename object_t::mapped_type, + typename ConstructibleObjectType::mapped_type >::value)) || + (has_from_json::value || + has_non_default_from_json < + BasicJsonType, + typename ConstructibleObjectType::mapped_type >::value); +}; + +template +struct is_constructible_object_type + : is_constructible_object_type_impl {}; + +template +struct is_compatible_string_type_impl : std::false_type {}; + +template +struct is_compatible_string_type_impl < + BasicJsonType, CompatibleStringType, + enable_if_t::value >> +{ + static constexpr auto value = + std::is_constructible::value; +}; + +template +struct is_compatible_string_type + : is_compatible_string_type_impl {}; + +template +struct is_constructible_string_type_impl : std::false_type {}; + +template +struct is_constructible_string_type_impl < + BasicJsonType, ConstructibleStringType, + enable_if_t::value >> +{ + static constexpr auto value = + std::is_constructible::value; +}; + +template +struct is_constructible_string_type + : is_constructible_string_type_impl {}; + +template +struct is_compatible_array_type_impl : std::false_type {}; + +template +struct is_compatible_array_type_impl < + BasicJsonType, CompatibleArrayType, + enable_if_t < is_detected::value&& + is_detected::value&& +// This is needed because json_reverse_iterator has a ::iterator type... +// Therefore it is detected as a CompatibleArrayType. +// The real fix would be to have an Iterable concept. + !is_iterator_traits < + iterator_traits>::value >> +{ + static constexpr bool value = + std::is_constructible::value; +}; + +template +struct is_compatible_array_type + : is_compatible_array_type_impl {}; + +template +struct is_constructible_array_type_impl : std::false_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t::value >> + : std::true_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t < !std::is_same::value&& + std::is_default_constructible::value&& +(std::is_move_assignable::value || + std::is_copy_assignable::value)&& +is_detected::value&& +is_detected::value&& +is_complete_type < +detected_t>::value >> +{ + static constexpr bool value = + // This is needed because json_reverse_iterator has a ::iterator type, + // furthermore, std::back_insert_iterator (and other iterators) have a + // base class `iterator`... Therefore it is detected as a + // ConstructibleArrayType. The real fix would be to have an Iterable + // concept. + !is_iterator_traits>::value && + + (std::is_same::value || + has_from_json::value || + has_non_default_from_json < + BasicJsonType, typename ConstructibleArrayType::value_type >::value); +}; + +template +struct is_constructible_array_type + : is_constructible_array_type_impl {}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl < + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t < std::is_integral::value&& + std::is_integral::value&& + !std::is_same::value >> +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + std::is_constructible::value && + CompatibleLimits::is_integer && + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type + : is_compatible_integer_type_impl {}; + +template +struct is_compatible_type_impl: std::false_type {}; + +template +struct is_compatible_type_impl < + BasicJsonType, CompatibleType, + enable_if_t::value >> +{ + static constexpr bool value = + has_to_json::value; +}; + +template +struct is_compatible_type + : is_compatible_type_impl {}; + +// https://en.cppreference.com/w/cpp/types/conjunction +template struct conjunction : std::true_type { }; +template struct conjunction : B1 { }; +template +struct conjunction +: std::conditional, B1>::type {}; + +template +struct is_constructible_tuple : std::false_type {}; + +template +struct is_constructible_tuple> : conjunction...> {}; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // array +#include // size_t +#include // uint8_t +#include // string + +namespace nlohmann +{ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + binary, ///< binary array (ordered collection of bytes) + discarded ///< discarded by the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string < binary +- furthermore, each type is not smaller than itself +- discarded values are not comparable +- binary is represented as a b"" string in python and directly comparable to a + string; however, making a binary array directly comparable with a string would + be surprising behavior in a JSON file. + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, + 6 /* binary */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); + return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; +} +} // namespace detail +} // namespace nlohmann + + +namespace nlohmann +{ +namespace detail +{ +template +void from_json(const BasicJsonType& j, typename std::nullptr_t& n) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_null())) + { + JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name()))); + } + n = nullptr; +} + +// overloads for basic_json template parameters +template < typename BasicJsonType, typename ArithmeticType, + enable_if_t < std::is_arithmetic::value&& + !std::is_same::value, + int > = 0 > +void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_boolean())) + { + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); + } + b = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); + } + s = *j.template get_ptr(); +} + +template < + typename BasicJsonType, typename ConstructibleStringType, + enable_if_t < + is_constructible_string_type::value&& + !std::is_same::value, + int > = 0 > +void from_json(const BasicJsonType& j, ConstructibleStringType& s) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); + } + + s = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +{ + get_arithmetic_value(j, val); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, EnumType& e) +{ + typename std::underlying_type::type val; + get_arithmetic_value(j, val); + e = static_cast(val); +} + +// forward_list doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::forward_list& l) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + l.clear(); + std::transform(j.rbegin(), j.rend(), + std::front_inserter(l), [](const BasicJsonType & i) + { + return i.template get(); + }); +} + +// valarray doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::valarray& l) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + l.resize(j.size()); + std::transform(j.begin(), j.end(), std::begin(l), + [](const BasicJsonType & elem) + { + return elem.template get(); + }); +} + +template +auto from_json(const BasicJsonType& j, T (&arr)[N]) +-> decltype(j.template get(), void()) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template +void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/) +{ + arr = *j.template get_ptr(); +} + +template +auto from_json_array_impl(const BasicJsonType& j, std::array& arr, + priority_tag<2> /*unused*/) +-> decltype(j.template get(), void()) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template +auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/) +-> decltype( + arr.reserve(std::declval()), + j.template get(), + void()) +{ + using std::end; + + ConstructibleArrayType ret; + ret.reserve(j.size()); + std::transform(j.begin(), j.end(), + std::inserter(ret, end(ret)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); + arr = std::move(ret); +} + +template +void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, + priority_tag<0> /*unused*/) +{ + using std::end; + + ConstructibleArrayType ret; + std::transform( + j.begin(), j.end(), std::inserter(ret, end(ret)), + [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); + arr = std::move(ret); +} + +template < typename BasicJsonType, typename ConstructibleArrayType, + enable_if_t < + is_constructible_array_type::value&& + !is_constructible_object_type::value&& + !is_constructible_string_type::value&& + !std::is_same::value&& + !is_basic_json::value, + int > = 0 > +auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) +-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), +j.template get(), +void()) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + + std::string(j.type_name()))); + } + + from_json_array_impl(j, arr, priority_tag<3> {}); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_binary())) + { + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name()))); + } + + bin = *j.template get_ptr(); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_object())) + { + JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); + } + + ConstructibleObjectType ret; + auto inner_object = j.template get_ptr(); + using value_type = typename ConstructibleObjectType::value_type; + std::transform( + inner_object->begin(), inner_object->end(), + std::inserter(ret, ret.begin()), + [](typename BasicJsonType::object_t::value_type const & p) + { + return value_type(p.first, p.second.template get()); + }); + obj = std::move(ret); +} + +// overload for arithmetic types, not chosen for basic_json template arguments +// (BooleanType, etc..); note: Is it really necessary to provide explicit +// overloads for boolean_t etc. in case of a custom BooleanType which is not +// an arithmetic type? +template < typename BasicJsonType, typename ArithmeticType, + enable_if_t < + std::is_arithmetic::value&& + !std::is_same::value&& + !std::is_same::value&& + !std::is_same::value&& + !std::is_same::value, + int > = 0 > +void from_json(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::boolean: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, std::pair& p) +{ + p = {j.at(0).template get(), j.at(1).template get()}; +} + +template +void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence /*unused*/) +{ + t = std::make_tuple(j.at(Idx).template get::type>()...); +} + +template +void from_json(const BasicJsonType& j, std::tuple& t) +{ + from_json_tuple_impl(j, t, index_sequence_for {}); +} + +template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, + typename = enable_if_t < !std::is_constructible < + typename BasicJsonType::string_t, Key >::value >> +void from_json(const BasicJsonType& j, std::map& m) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + m.clear(); + for (const auto& p : j) + { + if (JSON_HEDLEY_UNLIKELY(!p.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + +template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, + typename = enable_if_t < !std::is_constructible < + typename BasicJsonType::string_t, Key >::value >> +void from_json(const BasicJsonType& j, std::unordered_map& m) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + m.clear(); + for (const auto& p : j) + { + if (JSON_HEDLEY_UNLIKELY(!p.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + +struct from_json_fn +{ + template + auto operator()(const BasicJsonType& j, T& val) const + noexcept(noexcept(from_json(j, val))) + -> decltype(from_json(j, val), void()) + { + return from_json(j, val); + } +}; +} // namespace detail + +/// namespace to hold default `from_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace +{ +constexpr const auto& from_json = detail::static_const::value; +} // namespace +} // namespace nlohmann + +// #include + + +#include // copy +#include // begin, end +#include // string +#include // tuple, get +#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type +#include // move, forward, declval, pair +#include // valarray +#include // vector + +// #include + + +#include // size_t +#include // input_iterator_tag +#include // string, to_string +#include // tuple_size, get, tuple_element + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +void int_to_string( string_type& target, std::size_t value ) +{ + // For ADL + using std::to_string; + target = to_string(value); +} +template class iteration_proxy_value +{ + public: + using difference_type = std::ptrdiff_t; + using value_type = iteration_proxy_value; + using pointer = value_type * ; + using reference = value_type & ; + using iterator_category = std::input_iterator_tag; + using string_type = typename std::remove_cv< typename std::remove_reference().key() ) >::type >::type; + + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + std::size_t array_index = 0; + /// last stringified array index + mutable std::size_t array_index_last = 0; + /// a string representation of the array index + mutable string_type array_index_str = "0"; + /// an empty string (to return a reference for primitive values) + const string_type empty_str = ""; + + public: + explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {} + + /// dereference operator (needed for range-based for) + iteration_proxy_value& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_value& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// equality operator (needed for InputIterator) + bool operator==(const iteration_proxy_value& o) const + { + return anchor == o.anchor; + } + + /// inequality operator (needed for range-based for) + bool operator!=(const iteration_proxy_value& o) const + { + return anchor != o.anchor; + } + + /// return key of the iterator + const string_type& key() const + { + JSON_ASSERT(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + { + if (array_index != array_index_last) + { + int_to_string( array_index_str, array_index ); + array_index_last = array_index; + } + return array_index_str; + } + + // use key from the object + case value_t::object: + return anchor.key(); + + // use an empty key for all primitive types + default: + return empty_str; + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } +}; + +/// proxy class for the items() function +template class iteration_proxy +{ + private: + /// the container to iterate + typename IteratorType::reference container; + + public: + /// construct iteration proxy from a container + explicit iteration_proxy(typename IteratorType::reference cont) noexcept + : container(cont) {} + + /// return iterator begin (needed for range-based for) + iteration_proxy_value begin() noexcept + { + return iteration_proxy_value(container.begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_value end() noexcept + { + return iteration_proxy_value(container.end()); + } +}; +// Structured Bindings Support +// For further reference see https://blog.tartanllama.xyz/structured-bindings/ +// And see https://github.com/nlohmann/json/pull/1391 +template = 0> +auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.key()) +{ + return i.key(); +} +// Structured Bindings Support +// For further reference see https://blog.tartanllama.xyz/structured-bindings/ +// And see https://github.com/nlohmann/json/pull/1391 +template = 0> +auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.value()) +{ + return i.value(); +} +} // namespace detail +} // namespace nlohmann + +// The Addition to the STD Namespace is required to add +// Structured Bindings Support to the iteration_proxy_value class +// For further reference see https://blog.tartanllama.xyz/structured-bindings/ +// And see https://github.com/nlohmann/json/pull/1391 +namespace std +{ +#if defined(__clang__) + // Fix: https://github.com/nlohmann/json/issues/1401 + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wmismatched-tags" +#endif +template +class tuple_size<::nlohmann::detail::iteration_proxy_value> + : public std::integral_constant {}; + +template +class tuple_element> +{ + public: + using type = decltype( + get(std::declval < + ::nlohmann::detail::iteration_proxy_value> ())); +}; +#if defined(__clang__) + #pragma clang diagnostic pop +#endif +} // namespace std + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +////////////////// +// constructors // +////////////////// + +template struct external_constructor; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept + { + j.m_type = value_t::boolean; + j.m_value = b; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) + { + j.m_type = value_t::string; + j.m_value = s; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) + { + j.m_type = value_t::string; + j.m_value = std::move(s); + j.assert_invariant(); + } + + template < typename BasicJsonType, typename CompatibleStringType, + enable_if_t < !std::is_same::value, + int > = 0 > + static void construct(BasicJsonType& j, const CompatibleStringType& str) + { + j.m_type = value_t::string; + j.m_value.string = j.template create(str); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) + { + j.m_type = value_t::binary; + typename BasicJsonType::binary_t value{b}; + j.m_value = value; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) + { + j.m_type = value_t::binary; + typename BasicJsonType::binary_t value{std::move(b)}; + j.m_value = value; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept + { + j.m_type = value_t::number_float; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept + { + j.m_type = value_t::number_unsigned; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept + { + j.m_type = value_t::number_integer; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) + { + j.m_type = value_t::array; + j.m_value = arr; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) + { + j.m_type = value_t::array; + j.m_value = std::move(arr); + j.assert_invariant(); + } + + template < typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < !std::is_same::value, + int > = 0 > + static void construct(BasicJsonType& j, const CompatibleArrayType& arr) + { + using std::begin; + using std::end; + j.m_type = value_t::array; + j.m_value.array = j.template create(begin(arr), end(arr)); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, const std::vector& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->reserve(arr.size()); + for (const bool x : arr) + { + j.m_value.array->push_back(x); + } + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const std::valarray& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->resize(arr.size()); + if (arr.size() > 0) + { + std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); + } + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) + { + j.m_type = value_t::object; + j.m_value = obj; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) + { + j.m_type = value_t::object; + j.m_value = std::move(obj); + j.assert_invariant(); + } + + template < typename BasicJsonType, typename CompatibleObjectType, + enable_if_t < !std::is_same::value, int > = 0 > + static void construct(BasicJsonType& j, const CompatibleObjectType& obj) + { + using std::begin; + using std::end; + + j.m_type = value_t::object; + j.m_value.object = j.template create(begin(obj), end(obj)); + j.assert_invariant(); + } +}; + +///////////// +// to_json // +///////////// + +template::value, int> = 0> +void to_json(BasicJsonType& j, T b) noexcept +{ + external_constructor::construct(j, b); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleString& s) +{ + external_constructor::construct(j, s); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) +{ + external_constructor::construct(j, std::move(s)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, FloatType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, EnumType e) noexcept +{ + using underlying_type = typename std::underlying_type::type; + external_constructor::construct(j, static_cast(e)); +} + +template +void to_json(BasicJsonType& j, const std::vector& e) +{ + external_constructor::construct(j, e); +} + +template < typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < is_compatible_array_type::value&& + !is_compatible_object_type::value&& + !is_compatible_string_type::value&& + !std::is_same::value&& + !is_basic_json::value, + int > = 0 > +void to_json(BasicJsonType& j, const CompatibleArrayType& arr) +{ + external_constructor::construct(j, arr); +} + +template +void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) +{ + external_constructor::construct(j, bin); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const std::valarray& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template < typename BasicJsonType, typename CompatibleObjectType, + enable_if_t < is_compatible_object_type::value&& !is_basic_json::value, int > = 0 > +void to_json(BasicJsonType& j, const CompatibleObjectType& obj) +{ + external_constructor::construct(j, obj); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) +{ + external_constructor::construct(j, std::move(obj)); +} + +template < + typename BasicJsonType, typename T, std::size_t N, + enable_if_t < !std::is_constructible::value, + int > = 0 > +void to_json(BasicJsonType& j, const T(&arr)[N]) +{ + external_constructor::construct(j, arr); +} + +template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible::value&& std::is_constructible::value, int > = 0 > +void to_json(BasicJsonType& j, const std::pair& p) +{ + j = { p.first, p.second }; +} + +// for https://github.com/nlohmann/json/pull/1134 +template>::value, int> = 0> +void to_json(BasicJsonType& j, const T& b) +{ + j = { {b.key(), b.value()} }; +} + +template +void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence /*unused*/) +{ + j = { std::get(t)... }; +} + +template::value, int > = 0> +void to_json(BasicJsonType& j, const T& t) +{ + to_json_tuple_impl(j, t, make_index_sequence::value> {}); +} + +struct to_json_fn +{ + template + auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward(val)))) + -> decltype(to_json(j, std::forward(val)), void()) + { + return to_json(j, std::forward(val)); + } +}; +} // namespace detail + +/// namespace to hold default `to_json` function +namespace +{ +constexpr const auto& to_json = detail::static_const::value; +} // namespace +} // namespace nlohmann + + +namespace nlohmann +{ + +template +struct adl_serializer +{ + /*! + @brief convert a JSON value to any value type + + This function is usually called by the `get()` function of the + @ref basic_json class (either explicit or via conversion operators). + + @param[in] j JSON value to read from + @param[in,out] val value to write to + */ + template + static auto from_json(BasicJsonType&& j, ValueType& val) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), val))) + -> decltype(::nlohmann::from_json(std::forward(j), val), void()) + { + ::nlohmann::from_json(std::forward(j), val); + } + + /*! + @brief convert any value type to a JSON value + + This function is usually called by the constructors of the @ref basic_json + class. + + @param[in,out] j JSON value to write to + @param[in] val value to read from + */ + template + static auto to_json(BasicJsonType& j, ValueType&& val) noexcept( + noexcept(::nlohmann::to_json(j, std::forward(val)))) + -> decltype(::nlohmann::to_json(j, std::forward(val)), void()) + { + ::nlohmann::to_json(j, std::forward(val)); + } +}; + +} // namespace nlohmann + +// #include + + +#include // uint8_t +#include // tie +#include // move + +namespace nlohmann +{ + +/*! +@brief an internal type for a backed binary type + +This type extends the template parameter @a BinaryType provided to `basic_json` +with a subtype used by BSON and MessagePack. This type exists so that the user +does not have to specify a type themselves with a specific naming scheme in +order to override the binary type. + +@tparam BinaryType container to store bytes (`std::vector` by + default) + +@since version 3.8.0 +*/ +template +class byte_container_with_subtype : public BinaryType +{ + public: + /// the type of the underlying container + using container_type = BinaryType; + + byte_container_with_subtype() noexcept(noexcept(container_type())) + : container_type() + {} + + byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) + : container_type(b) + {} + + byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) + {} + + byte_container_with_subtype(const container_type& b, std::uint8_t subtype) noexcept(noexcept(container_type(b))) + : container_type(b) + , m_subtype(subtype) + , m_has_subtype(true) + {} + + byte_container_with_subtype(container_type&& b, std::uint8_t subtype) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) + , m_subtype(subtype) + , m_has_subtype(true) + {} + + bool operator==(const byte_container_with_subtype& rhs) const + { + return std::tie(static_cast(*this), m_subtype, m_has_subtype) == + std::tie(static_cast(rhs), rhs.m_subtype, rhs.m_has_subtype); + } + + bool operator!=(const byte_container_with_subtype& rhs) const + { + return !(rhs == *this); + } + + /*! + @brief sets the binary subtype + + Sets the binary subtype of the value, also flags a binary JSON value as + having a subtype, which has implications for serialization. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref subtype() -- return the binary subtype + @sa @ref clear_subtype() -- clears the binary subtype + @sa @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 + */ + void set_subtype(std::uint8_t subtype) noexcept + { + m_subtype = subtype; + m_has_subtype = true; + } + + /*! + @brief return the binary subtype + + Returns the numerical subtype of the value if it has a subtype. If it does + not have a subtype, this function will return size_t(-1) as a sentinel + value. + + @return the numerical subtype of the binary value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref set_subtype() -- sets the binary subtype + @sa @ref clear_subtype() -- clears the binary subtype + @sa @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 + */ + constexpr std::uint8_t subtype() const noexcept + { + return m_subtype; + } + + /*! + @brief return whether the value has a subtype + + @return whether the value has a subtype + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref subtype() -- return the binary subtype + @sa @ref set_subtype() -- sets the binary subtype + @sa @ref clear_subtype() -- clears the binary subtype + + @since version 3.8.0 + */ + constexpr bool has_subtype() const noexcept + { + return m_has_subtype; + } + + /*! + @brief clears the binary subtype + + Clears the binary subtype and flags the value as not having a subtype, which + has implications for serialization; for instance MessagePack will prefer the + bin family over the ext family. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref subtype() -- return the binary subtype + @sa @ref set_subtype() -- sets the binary subtype + @sa @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 + */ + void clear_subtype() noexcept + { + m_subtype = 0; + m_has_subtype = false; + } + + private: + std::uint8_t m_subtype = 0; + bool m_has_subtype = false; +}; + +} // namespace nlohmann + +// #include + +// #include + +// #include + +// #include + + +#include // size_t, uint8_t +#include // hash + +namespace nlohmann +{ +namespace detail +{ + +// boost::hash_combine +inline std::size_t combine(std::size_t seed, std::size_t h) noexcept +{ + seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U); + return seed; +} + +/*! +@brief hash a JSON value + +The hash function tries to rely on std::hash where possible. Furthermore, the +type of the JSON value is taken into account to have different hash values for +null, 0, 0U, and false, etc. + +@tparam BasicJsonType basic_json specialization +@param j JSON value to hash +@return hash value of j +*/ +template +std::size_t hash(const BasicJsonType& j) +{ + using string_t = typename BasicJsonType::string_t; + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + + const auto type = static_cast(j.type()); + switch (j.type()) + { + case BasicJsonType::value_t::null: + case BasicJsonType::value_t::discarded: + { + return combine(type, 0); + } + + case BasicJsonType::value_t::object: + { + auto seed = combine(type, j.size()); + for (const auto& element : j.items()) + { + const auto h = std::hash {}(element.key()); + seed = combine(seed, h); + seed = combine(seed, hash(element.value())); + } + return seed; + } + + case BasicJsonType::value_t::array: + { + auto seed = combine(type, j.size()); + for (const auto& element : j) + { + seed = combine(seed, hash(element)); + } + return seed; + } + + case BasicJsonType::value_t::string: + { + const auto h = std::hash {}(j.template get_ref()); + return combine(type, h); + } + + case BasicJsonType::value_t::boolean: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case BasicJsonType::value_t::number_integer: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case nlohmann::detail::value_t::number_unsigned: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case nlohmann::detail::value_t::number_float: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case nlohmann::detail::value_t::binary: + { + auto seed = combine(type, j.get_binary().size()); + const auto h = std::hash {}(j.get_binary().has_subtype()); + seed = combine(seed, h); + seed = combine(seed, j.get_binary().subtype()); + for (const auto byte : j.get_binary()) + { + seed = combine(seed, std::hash {}(byte)); + } + return seed; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } +} + +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // generate_n +#include // array +#include // ldexp +#include // size_t +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // snprintf +#include // memcpy +#include // back_inserter +#include // numeric_limits +#include // char_traits, string +#include // make_pair, move + +// #include + +// #include + + +#include // array +#include // size_t +#include //FILE * +#include // strlen +#include // istream +#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next +#include // shared_ptr, make_shared, addressof +#include // accumulate +#include // string, char_traits +#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer +#include // pair, declval + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/// the supported input formats +enum class input_format_t { json, cbor, msgpack, ubjson, bson }; + +//////////////////// +// input adapters // +//////////////////// + +/*! +Input adapter for stdio file access. This adapter read only 1 byte and do not use any + buffer. This adapter is a very low level adapter. +*/ +class file_input_adapter +{ + public: + using char_type = char; + + JSON_HEDLEY_NON_NULL(2) + explicit file_input_adapter(std::FILE* f) noexcept + : m_file(f) + {} + + // make class move-only + file_input_adapter(const file_input_adapter&) = delete; + file_input_adapter(file_input_adapter&&) = default; + file_input_adapter& operator=(const file_input_adapter&) = delete; + file_input_adapter& operator=(file_input_adapter&&) = delete; + + std::char_traits::int_type get_character() noexcept + { + return std::fgetc(m_file); + } + + private: + /// the file pointer to read from + std::FILE* m_file; +}; + + +/*! +Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at +beginning of input. Does not support changing the underlying std::streambuf +in mid-input. Maintains underlying std::istream and std::streambuf to support +subsequent use of standard std::istream operations to process any input +characters following those used in parsing the JSON input. Clears the +std::istream flags; any input errors (e.g., EOF) will be detected by the first +subsequent call for input from the std::istream. +*/ +class input_stream_adapter +{ + public: + using char_type = char; + + ~input_stream_adapter() + { + // clear stream flags; we use underlying streambuf I/O, do not + // maintain ifstream flags, except eof + if (is != nullptr) + { + is->clear(is->rdstate() & std::ios::eofbit); + } + } + + explicit input_stream_adapter(std::istream& i) + : is(&i), sb(i.rdbuf()) + {} + + // delete because of pointer members + input_stream_adapter(const input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&& rhs) = delete; + + input_stream_adapter(input_stream_adapter&& rhs) noexcept : is(rhs.is), sb(rhs.sb) + { + rhs.is = nullptr; + rhs.sb = nullptr; + } + + // std::istream/std::streambuf use std::char_traits::to_int_type, to + // ensure that std::char_traits::eof() and the character 0xFF do not + // end up as the same value, eg. 0xFFFFFFFF. + std::char_traits::int_type get_character() + { + auto res = sb->sbumpc(); + // set eof manually, as we don't use the istream interface. + if (JSON_HEDLEY_UNLIKELY(res == EOF)) + { + is->clear(is->rdstate() | std::ios::eofbit); + } + return res; + } + + private: + /// the associated input stream + std::istream* is = nullptr; + std::streambuf* sb = nullptr; +}; + +// General-purpose iterator-based adapter. It might not be as fast as +// theoretically possible for some containers, but it is extremely versatile. +template +class iterator_input_adapter +{ + public: + using char_type = typename std::iterator_traits::value_type; + + iterator_input_adapter(IteratorType first, IteratorType last) + : current(std::move(first)), end(std::move(last)) {} + + typename std::char_traits::int_type get_character() + { + if (JSON_HEDLEY_LIKELY(current != end)) + { + auto result = std::char_traits::to_int_type(*current); + std::advance(current, 1); + return result; + } + else + { + return std::char_traits::eof(); + } + } + + private: + IteratorType current; + IteratorType end; + + template + friend struct wide_string_input_helper; + + bool empty() const + { + return current == end; + } + +}; + + +template +struct wide_string_input_helper; + +template +struct wide_string_input_helper +{ + // UTF-32 + static void fill_buffer(BaseInputAdapter& input, + std::array::int_type, 4>& utf8_bytes, + size_t& utf8_bytes_index, + size_t& utf8_bytes_filled) + { + utf8_bytes_index = 0; + + if (JSON_HEDLEY_UNLIKELY(input.empty())) + { + utf8_bytes[0] = std::char_traits::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const auto wc = input.get_character(); + + // UTF-32 to UTF-8 encoding + if (wc < 0x80) + { + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u) & 0x1Fu)); + utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 2; + } + else if (wc <= 0xFFFF) + { + utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u) & 0x0Fu)); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 3; + } + else if (wc <= 0x10FFFF) + { + utf8_bytes[0] = static_cast::int_type>(0xF0u | ((static_cast(wc) >> 18u) & 0x07u)); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 12u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); + utf8_bytes[3] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 4; + } + else + { + // unknown character + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + } + } +}; + +template +struct wide_string_input_helper +{ + // UTF-16 + static void fill_buffer(BaseInputAdapter& input, + std::array::int_type, 4>& utf8_bytes, + size_t& utf8_bytes_index, + size_t& utf8_bytes_filled) + { + utf8_bytes_index = 0; + + if (JSON_HEDLEY_UNLIKELY(input.empty())) + { + utf8_bytes[0] = std::char_traits::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const auto wc = input.get_character(); + + // UTF-16 to UTF-8 encoding + if (wc < 0x80) + { + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u))); + utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 2; + } + else if (0xD800 > wc || wc >= 0xE000) + { + utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u))); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 3; + } + else + { + if (JSON_HEDLEY_UNLIKELY(!input.empty())) + { + const auto wc2 = static_cast(input.get_character()); + const auto charcode = 0x10000u + (((static_cast(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); + utf8_bytes[0] = static_cast::int_type>(0xF0u | (charcode >> 18u)); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu)); + utf8_bytes[3] = static_cast::int_type>(0x80u | (charcode & 0x3Fu)); + utf8_bytes_filled = 4; + } + else + { + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + } + } + } +}; + +// Wraps another input apdater to convert wide character types into individual bytes. +template +class wide_string_input_adapter +{ + public: + using char_type = char; + + wide_string_input_adapter(BaseInputAdapter base) + : base_adapter(base) {} + + typename std::char_traits::int_type get_character() noexcept + { + // check if buffer needs to be filled + if (utf8_bytes_index == utf8_bytes_filled) + { + fill_buffer(); + + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index == 0); + } + + // use buffer + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled); + return utf8_bytes[utf8_bytes_index++]; + } + + private: + BaseInputAdapter base_adapter; + + template + void fill_buffer() + { + wide_string_input_helper::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); + } + + /// a buffer for UTF-8 bytes + std::array::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; + + /// index to the utf8_codes array for the next valid byte + std::size_t utf8_bytes_index = 0; + /// number of valid bytes in the utf8_codes array + std::size_t utf8_bytes_filled = 0; +}; + + +template +struct iterator_input_adapter_factory +{ + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using adapter_type = iterator_input_adapter; + + static adapter_type create(IteratorType first, IteratorType last) + { + return adapter_type(std::move(first), std::move(last)); + } +}; + +template +struct is_iterator_of_multibyte +{ + using value_type = typename std::iterator_traits::value_type; + enum + { + value = sizeof(value_type) > 1 + }; +}; + +template +struct iterator_input_adapter_factory::value>> +{ + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using base_adapter_type = iterator_input_adapter; + using adapter_type = wide_string_input_adapter; + + static adapter_type create(IteratorType first, IteratorType last) + { + return adapter_type(base_adapter_type(std::move(first), std::move(last))); + } +}; + +// General purpose iterator-based input +template +typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType first, IteratorType last) +{ + using factory_type = iterator_input_adapter_factory; + return factory_type::create(first, last); +} + +// Convenience shorthand from container to iterator +template +auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container))) +{ + // Enable ADL + using std::begin; + using std::end; + + return input_adapter(begin(container), end(container)); +} + +// Special cases with fast paths +inline file_input_adapter input_adapter(std::FILE* file) +{ + return file_input_adapter(file); +} + +inline input_stream_adapter input_adapter(std::istream& stream) +{ + return input_stream_adapter(stream); +} + +inline input_stream_adapter input_adapter(std::istream&& stream) +{ + return input_stream_adapter(stream); +} + +using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval(), std::declval())); + +// Null-delimited strings, and the like. +template < typename CharT, + typename std::enable_if < + std::is_pointer::value&& + !std::is_array::value&& + std::is_integral::type>::value&& + sizeof(typename std::remove_pointer::type) == 1, + int >::type = 0 > +contiguous_bytes_input_adapter input_adapter(CharT b) +{ + auto length = std::strlen(reinterpret_cast(b)); + const auto* ptr = reinterpret_cast(b); + return input_adapter(ptr, ptr + length); +} + +template +auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) +{ + return input_adapter(array, array + N); +} + +// This class only handles inputs of input_buffer_adapter type. +// It's required so that expressions like {ptr, len} can be implicitely casted +// to the correct adapter. +class span_input_adapter +{ + public: + template < typename CharT, + typename std::enable_if < + std::is_pointer::value&& + std::is_integral::type>::value&& + sizeof(typename std::remove_pointer::type) == 1, + int >::type = 0 > + span_input_adapter(CharT b, std::size_t l) + : ia(reinterpret_cast(b), reinterpret_cast(b) + l) {} + + template::iterator_category, std::random_access_iterator_tag>::value, + int>::type = 0> + span_input_adapter(IteratorType first, IteratorType last) + : ia(input_adapter(first, last)) {} + + contiguous_bytes_input_adapter&& get() + { + return std::move(ia); + } + + private: + contiguous_bytes_input_adapter ia; +}; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include +#include // string +#include // move +#include // vector + +// #include + +// #include + + +namespace nlohmann +{ + +/*! +@brief SAX interface + +This class describes the SAX interface used by @ref nlohmann::json::sax_parse. +Each function is called in different situations while the input is parsed. The +boolean return value informs the parser whether to continue processing the +input. +*/ +template +struct json_sax +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + /*! + @brief a null value was read + @return whether parsing should proceed + */ + virtual bool null() = 0; + + /*! + @brief a boolean value was read + @param[in] val boolean value + @return whether parsing should proceed + */ + virtual bool boolean(bool val) = 0; + + /*! + @brief an integer number was read + @param[in] val integer value + @return whether parsing should proceed + */ + virtual bool number_integer(number_integer_t val) = 0; + + /*! + @brief an unsigned integer number was read + @param[in] val unsigned integer value + @return whether parsing should proceed + */ + virtual bool number_unsigned(number_unsigned_t val) = 0; + + /*! + @brief an floating-point number was read + @param[in] val floating-point value + @param[in] s raw token value + @return whether parsing should proceed + */ + virtual bool number_float(number_float_t val, const string_t& s) = 0; + + /*! + @brief a string was read + @param[in] val string value + @return whether parsing should proceed + @note It is safe to move the passed string. + */ + virtual bool string(string_t& val) = 0; + + /*! + @brief a binary string was read + @param[in] val binary value + @return whether parsing should proceed + @note It is safe to move the passed binary. + */ + virtual bool binary(binary_t& val) = 0; + + /*! + @brief the beginning of an object was read + @param[in] elements number of object elements or -1 if unknown + @return whether parsing should proceed + @note binary formats may report the number of elements + */ + virtual bool start_object(std::size_t elements) = 0; + + /*! + @brief an object key was read + @param[in] val object key + @return whether parsing should proceed + @note It is safe to move the passed string. + */ + virtual bool key(string_t& val) = 0; + + /*! + @brief the end of an object was read + @return whether parsing should proceed + */ + virtual bool end_object() = 0; + + /*! + @brief the beginning of an array was read + @param[in] elements number of array elements or -1 if unknown + @return whether parsing should proceed + @note binary formats may report the number of elements + */ + virtual bool start_array(std::size_t elements) = 0; + + /*! + @brief the end of an array was read + @return whether parsing should proceed + */ + virtual bool end_array() = 0; + + /*! + @brief a parse error occurred + @param[in] position the position in the input where the error occurs + @param[in] last_token the last read token + @param[in] ex an exception object describing the error + @return whether parsing should proceed (must return false) + */ + virtual bool parse_error(std::size_t position, + const std::string& last_token, + const detail::exception& ex) = 0; + + virtual ~json_sax() = default; +}; + + +namespace detail +{ +/*! +@brief SAX implementation to create a JSON value from SAX events + +This class implements the @ref json_sax interface and processes the SAX events +to create a JSON value which makes it basically a DOM parser. The structure or +hierarchy of the JSON value is managed by the stack `ref_stack` which contains +a pointer to the respective array or object for each recursion depth. + +After successful parsing, the value that is passed by reference to the +constructor contains the parsed value. + +@tparam BasicJsonType the JSON type +*/ +template +class json_sax_dom_parser +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + /*! + @param[in, out] r reference to a JSON value that is manipulated while + parsing + @param[in] allow_exceptions_ whether parse errors yield exceptions + */ + explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true) + : root(r), allow_exceptions(allow_exceptions_) + {} + + // make class move-only + json_sax_dom_parser(const json_sax_dom_parser&) = delete; + json_sax_dom_parser(json_sax_dom_parser&&) = default; + json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete; + json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; + ~json_sax_dom_parser() = default; + + bool null() + { + handle_value(nullptr); + return true; + } + + bool boolean(bool val) + { + handle_value(val); + return true; + } + + bool number_integer(number_integer_t val) + { + handle_value(val); + return true; + } + + bool number_unsigned(number_unsigned_t val) + { + handle_value(val); + return true; + } + + bool number_float(number_float_t val, const string_t& /*unused*/) + { + handle_value(val); + return true; + } + + bool string(string_t& val) + { + handle_value(val); + return true; + } + + bool binary(binary_t& val) + { + handle_value(std::move(val)); + return true; + } + + bool start_object(std::size_t len) + { + ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); + + if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, + "excessive object size: " + std::to_string(len))); + } + + return true; + } + + bool key(string_t& val) + { + // add null at given key and store the reference for later + object_element = &(ref_stack.back()->m_value.object->operator[](val)); + return true; + } + + bool end_object() + { + ref_stack.pop_back(); + return true; + } + + bool start_array(std::size_t len) + { + ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); + + if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, + "excessive array size: " + std::to_string(len))); + } + + return true; + } + + bool end_array() + { + ref_stack.pop_back(); + return true; + } + + template + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, + const Exception& ex) + { + errored = true; + static_cast(ex); + if (allow_exceptions) + { + JSON_THROW(ex); + } + return false; + } + + constexpr bool is_errored() const + { + return errored; + } + + private: + /*! + @invariant If the ref stack is empty, then the passed value will be the new + root. + @invariant If the ref stack contains a value, then it is an array or an + object to which we can add elements + */ + template + JSON_HEDLEY_RETURNS_NON_NULL + BasicJsonType* handle_value(Value&& v) + { + if (ref_stack.empty()) + { + root = BasicJsonType(std::forward(v)); + return &root; + } + + JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); + + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_value.array->emplace_back(std::forward(v)); + return &(ref_stack.back()->m_value.array->back()); + } + + JSON_ASSERT(ref_stack.back()->is_object()); + JSON_ASSERT(object_element); + *object_element = BasicJsonType(std::forward(v)); + return object_element; + } + + /// the parsed JSON value + BasicJsonType& root; + /// stack to model hierarchy of values + std::vector ref_stack {}; + /// helper to hold the reference for the next object element + BasicJsonType* object_element = nullptr; + /// whether a syntax error occurred + bool errored = false; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; + +template +class json_sax_dom_callback_parser +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using parser_callback_t = typename BasicJsonType::parser_callback_t; + using parse_event_t = typename BasicJsonType::parse_event_t; + + json_sax_dom_callback_parser(BasicJsonType& r, + const parser_callback_t cb, + const bool allow_exceptions_ = true) + : root(r), callback(cb), allow_exceptions(allow_exceptions_) + { + keep_stack.push_back(true); + } + + // make class move-only + json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete; + json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; + json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete; + json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; + ~json_sax_dom_callback_parser() = default; + + bool null() + { + handle_value(nullptr); + return true; + } + + bool boolean(bool val) + { + handle_value(val); + return true; + } + + bool number_integer(number_integer_t val) + { + handle_value(val); + return true; + } + + bool number_unsigned(number_unsigned_t val) + { + handle_value(val); + return true; + } + + bool number_float(number_float_t val, const string_t& /*unused*/) + { + handle_value(val); + return true; + } + + bool string(string_t& val) + { + handle_value(val); + return true; + } + + bool binary(binary_t& val) + { + handle_value(std::move(val)); + return true; + } + + bool start_object(std::size_t len) + { + // check callback for object start + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::object_start, discarded); + keep_stack.push_back(keep); + + auto val = handle_value(BasicJsonType::value_t::object, true); + ref_stack.push_back(val.second); + + // check object limit + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len))); + } + + return true; + } + + bool key(string_t& val) + { + BasicJsonType k = BasicJsonType(val); + + // check callback for key + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::key, k); + key_keep_stack.push_back(keep); + + // add discarded value at given key and store the reference for later + if (keep && ref_stack.back()) + { + object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded); + } + + return true; + } + + bool end_object() + { + if (ref_stack.back() && !callback(static_cast(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) + { + // discard object + *ref_stack.back() = discarded; + } + + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(!keep_stack.empty()); + ref_stack.pop_back(); + keep_stack.pop_back(); + + if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured()) + { + // remove discarded value + for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) + { + if (it->is_discarded()) + { + ref_stack.back()->erase(it); + break; + } + } + } + + return true; + } + + bool start_array(std::size_t len) + { + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::array_start, discarded); + keep_stack.push_back(keep); + + auto val = handle_value(BasicJsonType::value_t::array, true); + ref_stack.push_back(val.second); + + // check array limit + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len))); + } + + return true; + } + + bool end_array() + { + bool keep = true; + + if (ref_stack.back()) + { + keep = callback(static_cast(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); + if (!keep) + { + // discard array + *ref_stack.back() = discarded; + } + } + + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(!keep_stack.empty()); + ref_stack.pop_back(); + keep_stack.pop_back(); + + // remove discarded value + if (!keep && !ref_stack.empty() && ref_stack.back()->is_array()) + { + ref_stack.back()->m_value.array->pop_back(); + } + + return true; + } + + template + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, + const Exception& ex) + { + errored = true; + static_cast(ex); + if (allow_exceptions) + { + JSON_THROW(ex); + } + return false; + } + + constexpr bool is_errored() const + { + return errored; + } + + private: + /*! + @param[in] v value to add to the JSON value we build during parsing + @param[in] skip_callback whether we should skip calling the callback + function; this is required after start_array() and + start_object() SAX events, because otherwise we would call the + callback function with an empty array or object, respectively. + + @invariant If the ref stack is empty, then the passed value will be the new + root. + @invariant If the ref stack contains a value, then it is an array or an + object to which we can add elements + + @return pair of boolean (whether value should be kept) and pointer (to the + passed value in the ref_stack hierarchy; nullptr if not kept) + */ + template + std::pair handle_value(Value&& v, const bool skip_callback = false) + { + JSON_ASSERT(!keep_stack.empty()); + + // do not handle this value if we know it would be added to a discarded + // container + if (!keep_stack.back()) + { + return {false, nullptr}; + } + + // create value + auto value = BasicJsonType(std::forward(v)); + + // check callback + const bool keep = skip_callback || callback(static_cast(ref_stack.size()), parse_event_t::value, value); + + // do not handle this value if we just learnt it shall be discarded + if (!keep) + { + return {false, nullptr}; + } + + if (ref_stack.empty()) + { + root = std::move(value); + return {true, &root}; + } + + // skip this value if we already decided to skip the parent + // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) + if (!ref_stack.back()) + { + return {false, nullptr}; + } + + // we now only expect arrays and objects + JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); + + // array + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_value.array->push_back(std::move(value)); + return {true, &(ref_stack.back()->m_value.array->back())}; + } + + // object + JSON_ASSERT(ref_stack.back()->is_object()); + // check if we should store an element for the current key + JSON_ASSERT(!key_keep_stack.empty()); + const bool store_element = key_keep_stack.back(); + key_keep_stack.pop_back(); + + if (!store_element) + { + return {false, nullptr}; + } + + JSON_ASSERT(object_element); + *object_element = std::move(value); + return {true, object_element}; + } + + /// the parsed JSON value + BasicJsonType& root; + /// stack to model hierarchy of values + std::vector ref_stack {}; + /// stack to manage which values to keep + std::vector keep_stack {}; + /// stack to manage which object keys to keep + std::vector key_keep_stack {}; + /// helper to hold the reference for the next object element + BasicJsonType* object_element = nullptr; + /// whether a syntax error occurred + bool errored = false; + /// callback function + const parser_callback_t callback = nullptr; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; + /// a discarded value for the callback + BasicJsonType discarded = BasicJsonType::value_t::discarded; +}; + +template +class json_sax_acceptor +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + bool null() + { + return true; + } + + bool boolean(bool /*unused*/) + { + return true; + } + + bool number_integer(number_integer_t /*unused*/) + { + return true; + } + + bool number_unsigned(number_unsigned_t /*unused*/) + { + return true; + } + + bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) + { + return true; + } + + bool string(string_t& /*unused*/) + { + return true; + } + + bool binary(binary_t& /*unused*/) + { + return true; + } + + bool start_object(std::size_t /*unused*/ = std::size_t(-1)) + { + return true; + } + + bool key(string_t& /*unused*/) + { + return true; + } + + bool end_object() + { + return true; + } + + bool start_array(std::size_t /*unused*/ = std::size_t(-1)) + { + return true; + } + + bool end_array() + { + return true; + } + + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) + { + return false; + } +}; +} // namespace detail + +} // namespace nlohmann + +// #include + + +#include // array +#include // localeconv +#include // size_t +#include // snprintf +#include // strtof, strtod, strtold, strtoll, strtoull +#include // initializer_list +#include // char_traits, string +#include // move +#include // vector + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////// +// lexer // +/////////// + +template +class lexer_base +{ + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value + value_integer, ///< a signed integer -- use get_number_integer() for actual value + value_float, ///< an floating point number -- use get_number_float() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input, ///< indicating the end of the input buffer + literal_or_value ///< a literal or the begin of a value (only for diagnostics) + }; + + /// return name of values of type token_type (only used for errors) + JSON_HEDLEY_RETURNS_NON_NULL + JSON_HEDLEY_CONST + static const char* token_type_name(const token_type t) noexcept + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case token_type::value_unsigned: + case token_type::value_integer: + case token_type::value_float: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + case token_type::literal_or_value: + return "'[', '{', or a literal"; + // LCOV_EXCL_START + default: // catch non-enum values + return "unknown token"; + // LCOV_EXCL_STOP + } + } +}; +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ +template +class lexer : public lexer_base +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using char_type = typename InputAdapterType::char_type; + using char_int_type = typename std::char_traits::int_type; + + public: + using token_type = typename lexer_base::token_type; + + explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) + : ia(std::move(adapter)) + , ignore_comments(ignore_comments_) + , decimal_point_char(static_cast(get_decimal_point())) + {} + + // delete because of pointer members + lexer(const lexer&) = delete; + lexer(lexer&&) = default; + lexer& operator=(lexer&) = delete; + lexer& operator=(lexer&&) = default; + ~lexer() = default; + + private: + ///////////////////// + // locales + ///////////////////// + + /// return the locale-dependent decimal point + JSON_HEDLEY_PURE + static char get_decimal_point() noexcept + { + const auto* loc = localeconv(); + JSON_ASSERT(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); + } + + ///////////////////// + // scan functions + ///////////////////// + + /*! + @brief get codepoint from 4 hex characters following `\u` + + For input "\u c1 c2 c3 c4" the codepoint is: + (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 + = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) + + Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' + must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The + conversion is done by subtracting the offset (0x30, 0x37, and 0x57) + between the ASCII value of the character and the desired integer value. + + @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or + non-hex character) + */ + int get_codepoint() + { + // this function only makes sense after reading `\u` + JSON_ASSERT(current == 'u'); + int codepoint = 0; + + const auto factors = { 12u, 8u, 4u, 0u }; + for (const auto factor : factors) + { + get(); + + if (current >= '0' && current <= '9') + { + codepoint += static_cast((static_cast(current) - 0x30u) << factor); + } + else if (current >= 'A' && current <= 'F') + { + codepoint += static_cast((static_cast(current) - 0x37u) << factor); + } + else if (current >= 'a' && current <= 'f') + { + codepoint += static_cast((static_cast(current) - 0x57u) << factor); + } + else + { + return -1; + } + } + + JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF); + return codepoint; + } + + /*! + @brief check if the next byte(s) are inside a given range + + Adds the current byte and, for each passed range, reads a new byte and + checks if it is inside the range. If a violation was detected, set up an + error message and return false. Otherwise, return true. + + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + + @return true if and only if no range violation was detected + */ + bool next_byte_in_range(std::initializer_list ranges) + { + JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6); + add(current); + + for (auto range = ranges.begin(); range != ranges.end(); ++range) + { + get(); + if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) + { + add(current); + } + else + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return false; + } + } + + return true; + } + + /*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 7159. While + scanning, bytes are escaped and copied into buffer token_buffer. Then the + function returns successfully, token_buffer is *not* null-terminated (as it + may contain \0 bytes), and token_buffer.size() is the number of bytes in the + string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ + token_type scan_string() + { + // reset token_buffer (ignore opening quote) + reset(); + + // we entered the function by reading an open quote + JSON_ASSERT(current == '\"'); + + while (true) + { + // get next character + switch (get()) + { + // end of file while parsing string + case std::char_traits::eof(): + { + error_message = "invalid string: missing closing quote"; + return token_type::parse_error; + } + + // closing quote + case '\"': + { + return token_type::value_string; + } + + // escapes + case '\\': + { + switch (get()) + { + // quotation mark + case '\"': + add('\"'); + break; + // reverse solidus + case '\\': + add('\\'); + break; + // solidus + case '/': + add('/'); + break; + // backspace + case 'b': + add('\b'); + break; + // form feed + case 'f': + add('\f'); + break; + // line feed + case 'n': + add('\n'); + break; + // carriage return + case 'r': + add('\r'); + break; + // tab + case 't': + add('\t'); + break; + + // unicode escapes + case 'u': + { + const int codepoint1 = get_codepoint(); + int codepoint = codepoint1; // start with codepoint1 + + if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if code point is a high surrogate + if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF) + { + // expect next \uxxxx entry + if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u')) + { + const int codepoint2 = get_codepoint(); + + if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if codepoint2 is a low surrogate + if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF)) + { + // overwrite codepoint + codepoint = static_cast( + // high surrogate occupies the most significant 22 bits + (static_cast(codepoint1) << 10u) + // low surrogate occupies the least significant 15 bits + + static_cast(codepoint2) + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00u); + } + else + { + error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF)) + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; + return token_type::parse_error; + } + } + + // result of the above calculation yields a proper codepoint + JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF); + + // translate codepoint into bytes + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + add(static_cast(codepoint)); + } + else if (codepoint <= 0x7FF) + { + // 2-byte characters: 110xxxxx 10xxxxxx + add(static_cast(0xC0u | (static_cast(codepoint) >> 6u))); + add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + } + else if (codepoint <= 0xFFFF) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + add(static_cast(0xE0u | (static_cast(codepoint) >> 12u))); + add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); + add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + } + else + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + add(static_cast(0xF0u | (static_cast(codepoint) >> 18u))); + add(static_cast(0x80u | ((static_cast(codepoint) >> 12u) & 0x3Fu))); + add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); + add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + } + + break; + } + + // other characters after escape + default: + error_message = "invalid string: forbidden character after backslash"; + return token_type::parse_error; + } + + break; + } + + // invalid control characters + case 0x00: + { + error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000"; + return token_type::parse_error; + } + + case 0x01: + { + error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001"; + return token_type::parse_error; + } + + case 0x02: + { + error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002"; + return token_type::parse_error; + } + + case 0x03: + { + error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003"; + return token_type::parse_error; + } + + case 0x04: + { + error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004"; + return token_type::parse_error; + } + + case 0x05: + { + error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005"; + return token_type::parse_error; + } + + case 0x06: + { + error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006"; + return token_type::parse_error; + } + + case 0x07: + { + error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007"; + return token_type::parse_error; + } + + case 0x08: + { + error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b"; + return token_type::parse_error; + } + + case 0x09: + { + error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t"; + return token_type::parse_error; + } + + case 0x0A: + { + error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n"; + return token_type::parse_error; + } + + case 0x0B: + { + error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B"; + return token_type::parse_error; + } + + case 0x0C: + { + error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f"; + return token_type::parse_error; + } + + case 0x0D: + { + error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r"; + return token_type::parse_error; + } + + case 0x0E: + { + error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E"; + return token_type::parse_error; + } + + case 0x0F: + { + error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F"; + return token_type::parse_error; + } + + case 0x10: + { + error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010"; + return token_type::parse_error; + } + + case 0x11: + { + error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011"; + return token_type::parse_error; + } + + case 0x12: + { + error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012"; + return token_type::parse_error; + } + + case 0x13: + { + error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013"; + return token_type::parse_error; + } + + case 0x14: + { + error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014"; + return token_type::parse_error; + } + + case 0x15: + { + error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015"; + return token_type::parse_error; + } + + case 0x16: + { + error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016"; + return token_type::parse_error; + } + + case 0x17: + { + error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017"; + return token_type::parse_error; + } + + case 0x18: + { + error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018"; + return token_type::parse_error; + } + + case 0x19: + { + error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019"; + return token_type::parse_error; + } + + case 0x1A: + { + error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A"; + return token_type::parse_error; + } + + case 0x1B: + { + error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B"; + return token_type::parse_error; + } + + case 0x1C: + { + error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C"; + return token_type::parse_error; + } + + case 0x1D: + { + error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D"; + return token_type::parse_error; + } + + case 0x1E: + { + error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E"; + return token_type::parse_error; + } + + case 0x1F: + { + error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F"; + return token_type::parse_error; + } + + // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) + case 0x20: + case 0x21: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + { + add(current); + break; + } + + // U+0080..U+07FF: bytes C2..DF 80..BF + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + { + if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF}))) + { + return token_type::parse_error; + } + break; + } + + // U+0800..U+0FFF: bytes E0 A0..BF 80..BF + case 0xE0: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF + // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xEE: + case 0xEF: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+D000..U+D7FF: bytes ED 80..9F 80..BF + case 0xED: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + case 0xF0: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + case 0xF1: + case 0xF2: + case 0xF3: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + case 0xF4: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // remaining bytes (80..C1 and F5..FF) are ill-formed + default: + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + } + } + } + + /*! + * @brief scan a comment + * @return whether comment could be scanned successfully + */ + bool scan_comment() + { + switch (get()) + { + // single-line comments skip input until a newline or EOF is read + case '/': + { + while (true) + { + switch (get()) + { + case '\n': + case '\r': + case std::char_traits::eof(): + case '\0': + return true; + + default: + break; + } + } + } + + // multi-line comments skip input until */ is read + case '*': + { + while (true) + { + switch (get()) + { + case std::char_traits::eof(): + case '\0': + { + error_message = "invalid comment; missing closing '*/'"; + return false; + } + + case '*': + { + switch (get()) + { + case '/': + return true; + + default: + { + unget(); + continue; + } + } + } + + default: + continue; + } + } + } + + // unexpected character after reading '/' + default: + { + error_message = "invalid comment; expecting '/' or '*' after '/'"; + return false; + } + } + } + + JSON_HEDLEY_NON_NULL(2) + static void strtof(float& f, const char* str, char** endptr) noexcept + { + f = std::strtof(str, endptr); + } + + JSON_HEDLEY_NON_NULL(2) + static void strtof(double& f, const char* str, char** endptr) noexcept + { + f = std::strtod(str, endptr); + } + + JSON_HEDLEY_NON_NULL(2) + static void strtof(long double& f, const char* str, char** endptr) noexcept + { + f = std::strtold(str, endptr); + } + + /*! + @brief scan a number literal + + This function scans a string according to Sect. 6 of RFC 7159. + + The function is realized with a deterministic finite state machine derived + from the grammar described in RFC 7159. Starting in state "init", the + input is read and used to determined the next state. Only state "done" + accepts the number. State "error" is a trap state to model errors. In the + table below, "anything" means any character but the ones listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | decimal2 | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in token_buffer. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ + token_type scan_number() // lgtm [cpp/use-of-goto] + { + // reset token_buffer to store the number's bytes + reset(); + + // the type of the parsed number; initially set to unsigned; will be + // changed if minus sign, decimal point or exponent is read + token_type number_type = token_type::value_unsigned; + + // state (init): we just found out we need to scan a number + switch (current) + { + case '-': + { + add(current); + goto scan_number_minus; + } + + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + // all other characters are rejected outside scan_number() + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + +scan_number_minus: + // state: we just parsed a leading minus sign + number_type = token_type::value_integer; + switch (get()) + { + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + error_message = "invalid number; expected digit after '-'"; + return token_type::parse_error; + } + } + +scan_number_zero: + // state: we just parse a zero (maybe with a leading minus sign) + switch (get()) + { + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_any1: + // state: we just parsed a number 0-9 (maybe with a leading minus sign) + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_decimal1: + // state: we just parsed a decimal point + number_type = token_type::value_float; + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + default: + { + error_message = "invalid number; expected digit after '.'"; + return token_type::parse_error; + } + } + +scan_number_decimal2: + // we just parsed at least one number after a decimal point + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_exponent: + // we just parsed an exponent + number_type = token_type::value_float; + switch (get()) + { + case '+': + case '-': + { + add(current); + goto scan_number_sign; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = + "invalid number; expected '+', '-', or digit after exponent"; + return token_type::parse_error; + } + } + +scan_number_sign: + // we just parsed an exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = "invalid number; expected digit after exponent sign"; + return token_type::parse_error; + } + } + +scan_number_any2: + // we just parsed a number after the exponent or exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + goto scan_number_done; + } + +scan_number_done: + // unget the character after the number (we only read it to know that + // we are done scanning a number) + unget(); + + char* endptr = nullptr; + errno = 0; + + // try to parse integers first and fall back to floats + if (number_type == token_type::value_unsigned) + { + const auto x = std::strtoull(token_buffer.data(), &endptr, 10); + + // we checked the number format before + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_unsigned = static_cast(x); + if (value_unsigned == x) + { + return token_type::value_unsigned; + } + } + } + else if (number_type == token_type::value_integer) + { + const auto x = std::strtoll(token_buffer.data(), &endptr, 10); + + // we checked the number format before + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_integer = static_cast(x); + if (value_integer == x) + { + return token_type::value_integer; + } + } + } + + // this code is reached if we parse a floating-point number or if an + // integer conversion above failed + strtof(value_float, token_buffer.data(), &endptr); + + // we checked the number format before + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + + return token_type::value_float; + } + + /*! + @param[in] literal_text the literal text to expect + @param[in] length the length of the passed literal text + @param[in] return_type the token type to return on success + */ + JSON_HEDLEY_NON_NULL(2) + token_type scan_literal(const char_type* literal_text, const std::size_t length, + token_type return_type) + { + JSON_ASSERT(std::char_traits::to_char_type(current) == literal_text[0]); + for (std::size_t i = 1; i < length; ++i) + { + if (JSON_HEDLEY_UNLIKELY(std::char_traits::to_char_type(get()) != literal_text[i])) + { + error_message = "invalid literal"; + return token_type::parse_error; + } + } + return return_type; + } + + ///////////////////// + // input management + ///////////////////// + + /// reset token_buffer; current character is beginning of token + void reset() noexcept + { + token_buffer.clear(); + token_string.clear(); + token_string.push_back(std::char_traits::to_char_type(current)); + } + + /* + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a + `std::char_traits::eof()` in that case. Stores the scanned characters + for use in error messages. + + @return character read from the input + */ + char_int_type get() + { + ++position.chars_read_total; + ++position.chars_read_current_line; + + if (next_unget) + { + // just reset the next_unget variable and work with current + next_unget = false; + } + else + { + current = ia.get_character(); + } + + if (JSON_HEDLEY_LIKELY(current != std::char_traits::eof())) + { + token_string.push_back(std::char_traits::to_char_type(current)); + } + + if (current == '\n') + { + ++position.lines_read; + position.chars_read_current_line = 0; + } + + return current; + } + + /*! + @brief unget current character (read it again on next get) + + We implement unget by setting variable next_unget to true. The input is not + changed - we just simulate ungetting by modifying chars_read_total, + chars_read_current_line, and token_string. The next call to get() will + behave as if the unget character is read again. + */ + void unget() + { + next_unget = true; + + --position.chars_read_total; + + // in case we "unget" a newline, we have to also decrement the lines_read + if (position.chars_read_current_line == 0) + { + if (position.lines_read > 0) + { + --position.lines_read; + } + } + else + { + --position.chars_read_current_line; + } + + if (JSON_HEDLEY_LIKELY(current != std::char_traits::eof())) + { + JSON_ASSERT(!token_string.empty()); + token_string.pop_back(); + } + } + + /// add a character to token_buffer + void add(char_int_type c) + { + token_buffer.push_back(static_cast(c)); + } + + public: + ///////////////////// + // value getters + ///////////////////// + + /// return integer value + constexpr number_integer_t get_number_integer() const noexcept + { + return value_integer; + } + + /// return unsigned integer value + constexpr number_unsigned_t get_number_unsigned() const noexcept + { + return value_unsigned; + } + + /// return floating-point value + constexpr number_float_t get_number_float() const noexcept + { + return value_float; + } + + /// return current string value (implicitly resets the token; useful only once) + string_t& get_string() + { + return token_buffer; + } + + ///////////////////// + // diagnostics + ///////////////////// + + /// return position of last read token + constexpr position_t get_position() const noexcept + { + return position; + } + + /// return the last read token (for errors only). Will never contain EOF + /// (an arbitrary value that is not a valid char value, often -1), because + /// 255 may legitimately occur. May contain NUL, which should be escaped. + std::string get_token_string() const + { + // escape control characters + std::string result; + for (const auto c : token_string) + { + if (static_cast(c) <= '\x1F') + { + // escape control characters + std::array cs{{}}; + (std::snprintf)(cs.data(), cs.size(), "", static_cast(c)); + result += cs.data(); + } + else + { + // add character as is + result.push_back(static_cast(c)); + } + } + + return result; + } + + /// return syntax error message + JSON_HEDLEY_RETURNS_NON_NULL + constexpr const char* get_error_message() const noexcept + { + return error_message; + } + + ///////////////////// + // actual scanner + ///////////////////// + + /*! + @brief skip the UTF-8 byte order mark + @return true iff there is no BOM or the correct BOM has been skipped + */ + bool skip_bom() + { + if (get() == 0xEF) + { + // check if we completely parse the BOM + return get() == 0xBB && get() == 0xBF; + } + + // the first character is not the beginning of the BOM; unget it to + // process is later + unget(); + return true; + } + + void skip_whitespace() + { + do + { + get(); + } + while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); + } + + token_type scan() + { + // initially, skip the BOM + if (position.chars_read_total == 0 && !skip_bom()) + { + error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; + return token_type::parse_error; + } + + // read next character and ignore whitespace + skip_whitespace(); + + // ignore comments + while (ignore_comments && current == '/') + { + if (!scan_comment()) + { + return token_type::parse_error; + } + + // skip following whitespace + skip_whitespace(); + } + + switch (current) + { + // structural characters + case '[': + return token_type::begin_array; + case ']': + return token_type::end_array; + case '{': + return token_type::begin_object; + case '}': + return token_type::end_object; + case ':': + return token_type::name_separator; + case ',': + return token_type::value_separator; + + // literals + case 't': + { + std::array true_literal = {{'t', 'r', 'u', 'e'}}; + return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true); + } + case 'f': + { + std::array false_literal = {{'f', 'a', 'l', 's', 'e'}}; + return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false); + } + case 'n': + { + std::array null_literal = {{'n', 'u', 'l', 'l'}}; + return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null); + } + + // string + case '\"': + return scan_string(); + + // number + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return scan_number(); + + // end of input (the null byte is needed when parsing from + // string literals) + case '\0': + case std::char_traits::eof(): + return token_type::end_of_input; + + // error + default: + error_message = "invalid literal"; + return token_type::parse_error; + } + } + + private: + /// input adapter + InputAdapterType ia; + + /// whether comments should be ignored (true) or signaled as errors (false) + const bool ignore_comments = false; + + /// the current character + char_int_type current = std::char_traits::eof(); + + /// whether the next get() call should just return current + bool next_unget = false; + + /// the start position of the current token + position_t position {}; + + /// raw input token string (for error messages) + std::vector token_string {}; + + /// buffer for variable-length tokens (numbers, strings) + string_t token_buffer {}; + + /// a description of occurred lexer errors + const char* error_message = ""; + + // number values + number_integer_t value_integer = 0; + number_unsigned_t value_unsigned = 0; + number_float_t value_float = 0; + + /// the decimal point + const char_int_type decimal_point_char = '.'; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // size_t +#include // declval +#include // string + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +using null_function_t = decltype(std::declval().null()); + +template +using boolean_function_t = + decltype(std::declval().boolean(std::declval())); + +template +using number_integer_function_t = + decltype(std::declval().number_integer(std::declval())); + +template +using number_unsigned_function_t = + decltype(std::declval().number_unsigned(std::declval())); + +template +using number_float_function_t = decltype(std::declval().number_float( + std::declval(), std::declval())); + +template +using string_function_t = + decltype(std::declval().string(std::declval())); + +template +using binary_function_t = + decltype(std::declval().binary(std::declval())); + +template +using start_object_function_t = + decltype(std::declval().start_object(std::declval())); + +template +using key_function_t = + decltype(std::declval().key(std::declval())); + +template +using end_object_function_t = decltype(std::declval().end_object()); + +template +using start_array_function_t = + decltype(std::declval().start_array(std::declval())); + +template +using end_array_function_t = decltype(std::declval().end_array()); + +template +using parse_error_function_t = decltype(std::declval().parse_error( + std::declval(), std::declval(), + std::declval())); + +template +struct is_sax +{ + private: + static_assert(is_basic_json::value, + "BasicJsonType must be of type basic_json<...>"); + + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using exception_t = typename BasicJsonType::exception; + + public: + static constexpr bool value = + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value; +}; + +template +struct is_sax_static_asserts +{ + private: + static_assert(is_basic_json::value, + "BasicJsonType must be of type basic_json<...>"); + + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using exception_t = typename BasicJsonType::exception; + + public: + static_assert(is_detected_exact::value, + "Missing/invalid function: bool null()"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool boolean(bool)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool boolean(bool)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool number_integer(number_integer_t)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool number_unsigned(number_unsigned_t)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool number_float(number_float_t, const string_t&)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool string(string_t&)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool binary(binary_t&)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool start_object(std::size_t)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool key(string_t&)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool end_object()"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool start_array(std::size_t)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool end_array()"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool parse_error(std::size_t, const " + "std::string&, const exception&)"); +}; +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +namespace detail +{ + +/// how to treat CBOR tags +enum class cbor_tag_handler_t +{ + error, ///< throw a parse_error exception in case of a tag + ignore ///< ignore tags +}; + +/*! +@brief determine system byte order + +@return true if and only if system's byte order is little endian + +@note from https://stackoverflow.com/a/1001328/266378 +*/ +static inline bool little_endianess(int num = 1) noexcept +{ + return *reinterpret_cast(&num) == 1; +} + + +/////////////////// +// binary reader // +/////////////////// + +/*! +@brief deserialization of CBOR, MessagePack, and UBJSON values +*/ +template> +class binary_reader +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using json_sax_t = SAX; + using char_type = typename InputAdapterType::char_type; + using char_int_type = typename std::char_traits::int_type; + + public: + /*! + @brief create a binary reader + + @param[in] adapter input adapter to read from + */ + explicit binary_reader(InputAdapterType&& adapter) : ia(std::move(adapter)) + { + (void)detail::is_sax_static_asserts {}; + } + + // make class move-only + binary_reader(const binary_reader&) = delete; + binary_reader(binary_reader&&) = default; + binary_reader& operator=(const binary_reader&) = delete; + binary_reader& operator=(binary_reader&&) = default; + ~binary_reader() = default; + + /*! + @param[in] format the binary format to parse + @param[in] sax_ a SAX event processor + @param[in] strict whether to expect the input to be consumed completed + @param[in] tag_handler how to treat CBOR tags + + @return + */ + JSON_HEDLEY_NON_NULL(3) + bool sax_parse(const input_format_t format, + json_sax_t* sax_, + const bool strict = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + sax = sax_; + bool result = false; + + switch (format) + { + case input_format_t::bson: + result = parse_bson_internal(); + break; + + case input_format_t::cbor: + result = parse_cbor_internal(true, tag_handler); + break; + + case input_format_t::msgpack: + result = parse_msgpack_internal(); + break; + + case input_format_t::ubjson: + result = parse_ubjson_internal(); + break; + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + + // strict mode: next byte must be EOF + if (result && strict) + { + if (format == input_format_t::ubjson) + { + get_ignore_noop(); + } + else + { + get(); + } + + if (JSON_HEDLEY_UNLIKELY(current != std::char_traits::eof())) + { + return sax->parse_error(chars_read, get_token_string(), + parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value"))); + } + } + + return result; + } + + private: + ////////// + // BSON // + ////////// + + /*! + @brief Reads in a BSON-object and passes it to the SAX-parser. + @return whether a valid BSON-value was passed to the SAX parser + */ + bool parse_bson_internal() + { + std::int32_t document_size{}; + get_number(input_format_t::bson, document_size); + + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false))) + { + return false; + } + + return sax->end_object(); + } + + /*! + @brief Parses a C-style string from the BSON input. + @param[in, out] result A reference to the string variable where the read + string is to be stored. + @return `true` if the \x00-byte indicating the end of the string was + encountered before the EOF; false` indicates an unexpected EOF. + */ + bool get_bson_cstr(string_t& result) + { + auto out = std::back_inserter(result); + while (true) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring"))) + { + return false; + } + if (current == 0x00) + { + return true; + } + *out++ = static_cast(current); + } + } + + /*! + @brief Parses a zero-terminated string of length @a len from the BSON + input. + @param[in] len The length (including the zero-byte at the end) of the + string to be read. + @param[in, out] result A reference to the string variable where the read + string is to be stored. + @tparam NumberType The type of the length @a len + @pre len >= 1 + @return `true` if the string was successfully parsed + */ + template + bool get_bson_string(const NumberType len, string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(len < 1)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "string length must be at least 1, is " + std::to_string(len), "string"))); + } + + return get_string(input_format_t::bson, len - static_cast(1), result) && get() != std::char_traits::eof(); + } + + /*! + @brief Parses a byte array input of length @a len from the BSON input. + @param[in] len The length of the byte array to be read. + @param[in, out] result A reference to the binary variable where the read + array is to be stored. + @tparam NumberType The type of the length @a len + @pre len >= 0 + @return `true` if the byte array was successfully parsed + */ + template + bool get_bson_binary(const NumberType len, binary_t& result) + { + if (JSON_HEDLEY_UNLIKELY(len < 0)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"))); + } + + // All BSON binary values have a subtype + std::uint8_t subtype{}; + get_number(input_format_t::bson, subtype); + result.set_subtype(subtype); + + return get_binary(input_format_t::bson, len, result); + } + + /*! + @brief Read a BSON document element of the given @a element_type. + @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html + @param[in] element_type_parse_position The position in the input stream, + where the `element_type` was read. + @warning Not all BSON element types are supported yet. An unsupported + @a element_type will give rise to a parse_error.114: + Unsupported BSON record type 0x... + @return whether a valid BSON-object/array was passed to the SAX parser + */ + bool parse_bson_element_internal(const char_int_type element_type, + const std::size_t element_type_parse_position) + { + switch (element_type) + { + case 0x01: // double + { + double number{}; + return get_number(input_format_t::bson, number) && sax->number_float(static_cast(number), ""); + } + + case 0x02: // string + { + std::int32_t len{}; + string_t value; + return get_number(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value); + } + + case 0x03: // object + { + return parse_bson_internal(); + } + + case 0x04: // array + { + return parse_bson_array(); + } + + case 0x05: // binary + { + std::int32_t len{}; + binary_t value; + return get_number(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value); + } + + case 0x08: // boolean + { + return sax->boolean(get() != 0); + } + + case 0x0A: // null + { + return sax->null(); + } + + case 0x10: // int32 + { + std::int32_t value{}; + return get_number(input_format_t::bson, value) && sax->number_integer(value); + } + + case 0x12: // int64 + { + std::int64_t value{}; + return get_number(input_format_t::bson, value) && sax->number_integer(value); + } + + default: // anything else not supported (yet) + { + std::array cr{{}}; + (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(element_type)); + return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data()))); + } + } + } + + /*! + @brief Read a BSON element list (as specified in the BSON-spec) + + The same binary layout is used for objects and arrays, hence it must be + indicated with the argument @a is_array which one is expected + (true --> array, false --> object). + + @param[in] is_array Determines if the element list being read is to be + treated as an object (@a is_array == false), or as an + array (@a is_array == true). + @return whether a valid BSON-object/array was passed to the SAX parser + */ + bool parse_bson_element_list(const bool is_array) + { + string_t key; + + while (auto element_type = get()) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list"))) + { + return false; + } + + const std::size_t element_type_parse_position = chars_read; + if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key))) + { + return false; + } + + if (!is_array && !sax->key(key)) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position))) + { + return false; + } + + // get_bson_cstr only appends + key.clear(); + } + + return true; + } + + /*! + @brief Reads an array from the BSON input and passes it to the SAX-parser. + @return whether a valid BSON-array was passed to the SAX parser + */ + bool parse_bson_array() + { + std::int32_t document_size{}; + get_number(input_format_t::bson, document_size); + + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true))) + { + return false; + } + + return sax->end_array(); + } + + ////////// + // CBOR // + ////////// + + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true) or whether the last read character should + be considered instead (false) + @param[in] tag_handler how CBOR tags should be treated + + @return whether a valid CBOR value was passed to the SAX parser + */ + bool parse_cbor_internal(const bool get_char, + const cbor_tag_handler_t tag_handler) + { + switch (get_char ? get() : current) + { + // EOF + case std::char_traits::eof(): + return unexpect_eof(input_format_t::cbor, "value"); + + // Integer 0x00..0x17 (0..23) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return sax->number_unsigned(static_cast(current)); + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + { + std::uint8_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + { + std::uint16_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x1A: // Unsigned integer (four-byte uint32_t follows) + { + std::uint32_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x1B: // Unsigned integer (eight-byte uint64_t follows) + { + std::uint64_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + return sax->number_integer(static_cast(0x20 - 1 - current)); + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + std::uint8_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + std::uint16_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) + { + std::uint32_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) + { + std::uint64_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) + - static_cast(number)); + } + + // Binary data (0x00..0x17 bytes follow) + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: // Binary data (one-byte uint8_t for n follows) + case 0x59: // Binary data (two-byte uint16_t for n follow) + case 0x5A: // Binary data (four-byte uint32_t for n follow) + case 0x5B: // Binary data (eight-byte uint64_t for n follow) + case 0x5F: // Binary data (indefinite length) + { + binary_t b; + return get_cbor_binary(b) && sax->binary(b); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7F: // UTF-8 string (indefinite length) + { + string_t s; + return get_cbor_string(s) && sax->string(s); + } + + // array (0x00..0x17 data items follow) + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + return get_cbor_array(static_cast(static_cast(current) & 0x1Fu), tag_handler); + + case 0x98: // array (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x9A: // array (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x9B: // array (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x9F: // array (indefinite length) + return get_cbor_array(std::size_t(-1), tag_handler); + + // map (0x00..0x17 pairs of data items follow) + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + return get_cbor_object(static_cast(static_cast(current) & 0x1Fu), tag_handler); + + case 0xB8: // map (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xB9: // map (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xBA: // map (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xBB: // map (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xBF: // map (indefinite length) + return get_cbor_object(std::size_t(-1), tag_handler); + + case 0xC6: // tagged item + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD8: // tagged item (1 bytes follow) + case 0xD9: // tagged item (2 bytes follow) + case 0xDA: // tagged item (4 bytes follow) + case 0xDB: // tagged item (8 bytes follow) + { + switch (tag_handler) + { + case cbor_tag_handler_t::error: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"))); + } + + case cbor_tag_handler_t::ignore: + { + switch (current) + { + case 0xD8: + { + std::uint8_t len{}; + get_number(input_format_t::cbor, len); + break; + } + case 0xD9: + { + std::uint16_t len{}; + get_number(input_format_t::cbor, len); + break; + } + case 0xDA: + { + std::uint32_t len{}; + get_number(input_format_t::cbor, len); + break; + } + case 0xDB: + { + std::uint64_t len{}; + get_number(input_format_t::cbor, len); + break; + } + default: + break; + } + return parse_cbor_internal(true, tag_handler); + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + } + + case 0xF4: // false + return sax->boolean(false); + + case 0xF5: // true + return sax->boolean(true); + + case 0xF6: // null + return sax->null(); + + case 0xF9: // Half-Precision Float (two-byte IEEE 754) + { + const auto byte1_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) + { + return false; + } + const auto byte2_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) + { + return false; + } + + const auto byte1 = static_cast(byte1_raw); + const auto byte2 = static_cast(byte2_raw); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const auto half = static_cast((byte1 << 8u) + byte2); + const double val = [&half] + { + const int exp = (half >> 10u) & 0x1Fu; + const unsigned int mant = half & 0x3FFu; + JSON_ASSERT(0 <= exp&& exp <= 32); + JSON_ASSERT(mant <= 1024); + switch (exp) + { + case 0: + return std::ldexp(mant, -24); + case 31: + return (mant == 0) + ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + default: + return std::ldexp(mant + 1024, exp - 25); + } + }(); + return sax->number_float((half & 0x8000u) != 0 + ? static_cast(-val) + : static_cast(val), ""); + } + + case 0xFA: // Single-Precision Float (four-byte IEEE 754) + { + float number{}; + return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + } + + case 0xFB: // Double-Precision Float (eight-byte IEEE 754) + { + double number{}; + return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + } + + default: // anything else (0xFF is handled inside the other types) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"))); + } + } + } + + /*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @param[out] result created string + + @return whether string creation completed + */ + bool get_cbor_string(string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string"))) + { + return false; + } + + switch (current) + { + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + { + return get_string(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + } + + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7F: // UTF-8 string (indefinite length) + { + while (get() != 0xFF) + { + string_t chunk; + if (!get_cbor_string(chunk)) + { + return false; + } + result.append(chunk); + } + return true; + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x" + last_token, "string"))); + } + } + } + + /*! + @brief reads a CBOR byte array + + This function first reads starting bytes to determine the expected + byte array length and then copies this number of bytes into the byte array. + Additionally, CBOR's byte arrays with indefinite lengths are supported. + + @param[out] result created byte array + + @return whether byte array creation completed + */ + bool get_cbor_binary(binary_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary"))) + { + return false; + } + + switch (current) + { + // Binary data (0x00..0x17 bytes follow) + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + { + return get_binary(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + } + + case 0x58: // Binary data (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x59: // Binary data (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5A: // Binary data (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5B: // Binary data (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5F: // Binary data (indefinite length) + { + while (get() != 0xFF) + { + binary_t chunk; + if (!get_cbor_binary(chunk)) + { + return false; + } + result.insert(result.end(), chunk.begin(), chunk.end()); + } + return true; + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x" + last_token, "binary"))); + } + } + } + + /*! + @param[in] len the length of the array or std::size_t(-1) for an + array of indefinite size + @param[in] tag_handler how CBOR tags should be treated + @return whether array creation completed + */ + bool get_cbor_array(const std::size_t len, + const cbor_tag_handler_t tag_handler) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) + { + return false; + } + + if (len != std::size_t(-1)) + { + for (std::size_t i = 0; i < len; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + } + } + else + { + while (get() != 0xFF) + { + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler))) + { + return false; + } + } + } + + return sax->end_array(); + } + + /*! + @param[in] len the length of the object or std::size_t(-1) for an + object of indefinite size + @param[in] tag_handler how CBOR tags should be treated + @return whether object creation completed + */ + bool get_cbor_object(const std::size_t len, + const cbor_tag_handler_t tag_handler) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) + { + return false; + } + + string_t key; + if (len != std::size_t(-1)) + { + for (std::size_t i = 0; i < len; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + key.clear(); + } + } + else + { + while (get() != 0xFF) + { + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + key.clear(); + } + } + + return sax->end_object(); + } + + ///////////// + // MsgPack // + ///////////// + + /*! + @return whether a valid MessagePack value was passed to the SAX parser + */ + bool parse_msgpack_internal() + { + switch (get()) + { + // EOF + case std::char_traits::eof(): + return unexpect_eof(input_format_t::msgpack, "value"); + + // positive fixint + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + return sax->number_unsigned(static_cast(current)); + + // fixmap + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + return get_msgpack_object(static_cast(static_cast(current) & 0x0Fu)); + + // fixarray + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + return get_msgpack_array(static_cast(static_cast(current) & 0x0Fu)); + + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + case 0xD9: // str 8 + case 0xDA: // str 16 + case 0xDB: // str 32 + { + string_t s; + return get_msgpack_string(s) && sax->string(s); + } + + case 0xC0: // nil + return sax->null(); + + case 0xC2: // false + return sax->boolean(false); + + case 0xC3: // true + return sax->boolean(true); + + case 0xC4: // bin 8 + case 0xC5: // bin 16 + case 0xC6: // bin 32 + case 0xC7: // ext 8 + case 0xC8: // ext 16 + case 0xC9: // ext 32 + case 0xD4: // fixext 1 + case 0xD5: // fixext 2 + case 0xD6: // fixext 4 + case 0xD7: // fixext 8 + case 0xD8: // fixext 16 + { + binary_t b; + return get_msgpack_binary(b) && sax->binary(b); + } + + case 0xCA: // float 32 + { + float number{}; + return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + } + + case 0xCB: // float 64 + { + double number{}; + return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + } + + case 0xCC: // uint 8 + { + std::uint8_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCD: // uint 16 + { + std::uint16_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCE: // uint 32 + { + std::uint32_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCF: // uint 64 + { + std::uint64_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xD0: // int 8 + { + std::int8_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD1: // int 16 + { + std::int16_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD2: // int 32 + { + std::int32_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD3: // int 64 + { + std::int64_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xDC: // array 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast(len)); + } + + case 0xDD: // array 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast(len)); + } + + case 0xDE: // map 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast(len)); + } + + case 0xDF: // map 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast(len)); + } + + // negative fixint + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + return sax->number_integer(static_cast(current)); + + default: // anything else + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, "invalid byte: 0x" + last_token, "value"))); + } + } + } + + /*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @param[out] result created string + + @return whether string creation completed + */ + bool get_msgpack_string(string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string"))) + { + return false; + } + + switch (current) + { + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + { + return get_string(input_format_t::msgpack, static_cast(current) & 0x1Fu, result); + } + + case 0xD9: // str 8 + { + std::uint8_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + case 0xDA: // str 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + case 0xDB: // str 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, "expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x" + last_token, "string"))); + } + } + } + + /*! + @brief reads a MessagePack byte array + + This function first reads starting bytes to determine the expected + byte array length and then copies this number of bytes into a byte array. + + @param[out] result created byte array + + @return whether byte array creation completed + */ + bool get_msgpack_binary(binary_t& result) + { + // helper function to set the subtype + auto assign_and_return_true = [&result](std::int8_t subtype) + { + result.set_subtype(static_cast(subtype)); + return true; + }; + + switch (current) + { + case 0xC4: // bin 8 + { + std::uint8_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC5: // bin 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC6: // bin 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC7: // ext 8 + { + std::uint8_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xC8: // ext 16 + { + std::uint16_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xC9: // ext 32 + { + std::uint32_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xD4: // fixext 1 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 1, result) && + assign_and_return_true(subtype); + } + + case 0xD5: // fixext 2 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 2, result) && + assign_and_return_true(subtype); + } + + case 0xD6: // fixext 4 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 4, result) && + assign_and_return_true(subtype); + } + + case 0xD7: // fixext 8 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 8, result) && + assign_and_return_true(subtype); + } + + case 0xD8: // fixext 16 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 16, result) && + assign_and_return_true(subtype); + } + + default: // LCOV_EXCL_LINE + return false; // LCOV_EXCL_LINE + } + } + + /*! + @param[in] len the length of the array + @return whether array creation completed + */ + bool get_msgpack_array(const std::size_t len) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) + { + return false; + } + + for (std::size_t i = 0; i < len; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) + { + return false; + } + } + + return sax->end_array(); + } + + /*! + @param[in] len the length of the object + @return whether object creation completed + */ + bool get_msgpack_object(const std::size_t len) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) + { + return false; + } + + string_t key; + for (std::size_t i = 0; i < len; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) + { + return false; + } + key.clear(); + } + + return sax->end_object(); + } + + //////////// + // UBJSON // + //////////// + + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return whether a valid UBJSON value was passed to the SAX parser + */ + bool parse_ubjson_internal(const bool get_char = true) + { + return get_ubjson_value(get_char ? get_ignore_noop() : current); + } + + /*! + @brief reads a UBJSON string + + This function is either called after reading the 'S' byte explicitly + indicating a string, or in case of an object key where the 'S' byte can be + left out. + + @param[out] result created string + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return whether string creation completed + */ + bool get_ubjson_string(string_t& result, const bool get_char = true) + { + if (get_char) + { + get(); // TODO(niels): may we ignore N here? + } + + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "value"))) + { + return false; + } + + switch (current) + { + case 'U': + { + std::uint8_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); + } + + case 'i': + { + std::int8_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); + } + + case 'I': + { + std::int16_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); + } + + case 'l': + { + std::int32_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); + } + + case 'L': + { + std::int64_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); + } + + default: + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string"))); + } + } + + /*! + @param[out] result determined size + @return whether size determination completed + */ + bool get_ubjson_size_value(std::size_t& result) + { + switch (get_ignore_noop()) + { + case 'U': + { + std::uint8_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'i': + { + std::int8_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'I': + { + std::int16_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'l': + { + std::int32_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'L': + { + std::int64_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size"))); + } + } + } + + /*! + @brief determine the type and size for a container + + In the optimized UBJSON format, a type and a size can be provided to allow + for a more compact representation. + + @param[out] result pair of the size and the type + + @return whether pair creation completed + */ + bool get_ubjson_size_type(std::pair& result) + { + result.first = string_t::npos; // size + result.second = 0; // type + + get_ignore_noop(); + + if (current == '$') + { + result.second = get(); // must not ignore 'N', because 'N' maybe the type + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "type"))) + { + return false; + } + + get_ignore_noop(); + if (JSON_HEDLEY_UNLIKELY(current != '#')) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "value"))) + { + return false; + } + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "expected '#' after type information; last byte: 0x" + last_token, "size"))); + } + + return get_ubjson_size_value(result.first); + } + + if (current == '#') + { + return get_ubjson_size_value(result.first); + } + + return true; + } + + /*! + @param prefix the previously read or set type prefix + @return whether value creation completed + */ + bool get_ubjson_value(const char_int_type prefix) + { + switch (prefix) + { + case std::char_traits::eof(): // EOF + return unexpect_eof(input_format_t::ubjson, "value"); + + case 'T': // true + return sax->boolean(true); + case 'F': // false + return sax->boolean(false); + + case 'Z': // null + return sax->null(); + + case 'U': + { + std::uint8_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_unsigned(number); + } + + case 'i': + { + std::int8_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); + } + + case 'I': + { + std::int16_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); + } + + case 'l': + { + std::int32_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); + } + + case 'L': + { + std::int64_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); + } + + case 'd': + { + float number{}; + return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast(number), ""); + } + + case 'D': + { + double number{}; + return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast(number), ""); + } + + case 'H': + { + return get_ubjson_high_precision_number(); + } + + case 'C': // char + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "char"))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(current > 127)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char"))); + } + string_t s(1, static_cast(current)); + return sax->string(s); + } + + case 'S': // string + { + string_t s; + return get_ubjson_string(s) && sax->string(s); + } + + case '[': // array + return get_ubjson_array(); + + case '{': // object + return get_ubjson_object(); + + default: // anything else + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "invalid byte: 0x" + last_token, "value"))); + } + } + } + + /*! + @return whether array creation completed + */ + bool get_ubjson_array() + { + std::pair size_and_type; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) + { + return false; + } + + if (size_and_type.first != string_t::npos) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first))) + { + return false; + } + + if (size_and_type.second != 0) + { + if (size_and_type.second != 'N') + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) + { + return false; + } + } + } + } + else + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + } + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) + { + return false; + } + + while (current != ']') + { + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false))) + { + return false; + } + get_ignore_noop(); + } + } + + return sax->end_array(); + } + + /*! + @return whether object creation completed + */ + bool get_ubjson_object() + { + std::pair size_and_type; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) + { + return false; + } + + string_t key; + if (size_and_type.first != string_t::npos) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first))) + { + return false; + } + + if (size_and_type.second != 0) + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) + { + return false; + } + key.clear(); + } + } + else + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + key.clear(); + } + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) + { + return false; + } + + while (current != '}') + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + get_ignore_noop(); + key.clear(); + } + } + + return sax->end_object(); + } + + // Note, no reader for UBJSON binary types is implemented because they do + // not exist + + bool get_ubjson_high_precision_number() + { + // get size of following number string + std::size_t size{}; + auto res = get_ubjson_size_value(size); + if (JSON_HEDLEY_UNLIKELY(!res)) + { + return res; + } + + // get number string + std::vector number_vector; + for (std::size_t i = 0; i < size; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "number"))) + { + return false; + } + number_vector.push_back(static_cast(current)); + } + + // parse number string + auto number_ia = detail::input_adapter(std::forward(number_vector)); + auto number_lexer = detail::lexer(std::move(number_ia), false); + const auto result_number = number_lexer.scan(); + const auto number_string = number_lexer.get_token_string(); + const auto result_remainder = number_lexer.scan(); + + using token_type = typename detail::lexer_base::token_type; + + if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input)) + { + return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"))); + } + + switch (result_number) + { + case token_type::value_integer: + return sax->number_integer(number_lexer.get_number_integer()); + case token_type::value_unsigned: + return sax->number_unsigned(number_lexer.get_number_unsigned()); + case token_type::value_float: + return sax->number_float(number_lexer.get_number_float(), std::move(number_string)); + default: + return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"))); + } + } + + /////////////////////// + // Utility functions // + /////////////////////// + + /*! + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a -'ve valued + `std::char_traits::eof()` in that case. + + @return character read from the input + */ + char_int_type get() + { + ++chars_read; + return current = ia.get_character(); + } + + /*! + @return character read from the input after ignoring all 'N' entries + */ + char_int_type get_ignore_noop() + { + do + { + get(); + } + while (current == 'N'); + + return current; + } + + /* + @brief read a number from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[out] result number of type @a NumberType + + @return whether conversion completed + + @note This function needs to respect the system's endianess, because + bytes in CBOR, MessagePack, and UBJSON are stored in network order + (big endian) and therefore need reordering on little endian systems. + */ + template + bool get_number(const input_format_t format, NumberType& result) + { + // step 1: read input into array with system's byte order + std::array vec; + for (std::size_t i = 0; i < sizeof(NumberType); ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) + { + return false; + } + + // reverse byte order prior to conversion if necessary + if (is_little_endian != InputIsLittleEndian) + { + vec[sizeof(NumberType) - i - 1] = static_cast(current); + } + else + { + vec[i] = static_cast(current); // LCOV_EXCL_LINE + } + } + + // step 2: convert array into number of type T and return + std::memcpy(&result, vec.data(), sizeof(NumberType)); + return true; + } + + /*! + @brief create a string by reading characters from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[in] len number of characters to read + @param[out] result string created by reading @a len bytes + + @return whether string creation completed + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of string memory. + */ + template + bool get_string(const input_format_t format, + const NumberType len, + string_t& result) + { + bool success = true; + for (NumberType i = 0; i < len; i++) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string"))) + { + success = false; + break; + } + result.push_back(static_cast(current)); + }; + return success; + } + + /*! + @brief create a byte array by reading bytes from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[in] len number of bytes to read + @param[out] result byte array created by reading @a len bytes + + @return whether byte array creation completed + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of memory. + */ + template + bool get_binary(const input_format_t format, + const NumberType len, + binary_t& result) + { + bool success = true; + for (NumberType i = 0; i < len; i++) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary"))) + { + success = false; + break; + } + result.push_back(static_cast(current)); + } + return success; + } + + /*! + @param[in] format the current format (for diagnostics) + @param[in] context further context information (for diagnostics) + @return whether the last read character is not EOF + */ + JSON_HEDLEY_NON_NULL(3) + bool unexpect_eof(const input_format_t format, const char* context) const + { + if (JSON_HEDLEY_UNLIKELY(current == std::char_traits::eof())) + { + return sax->parse_error(chars_read, "", + parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context))); + } + return true; + } + + /*! + @return a string representation of the last read byte + */ + std::string get_token_string() const + { + std::array cr{{}}; + (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(current)); + return std::string{cr.data()}; + } + + /*! + @param[in] format the current format + @param[in] detail a detailed error message + @param[in] context further context information + @return a message string to use in the parse_error exceptions + */ + std::string exception_message(const input_format_t format, + const std::string& detail, + const std::string& context) const + { + std::string error_msg = "syntax error while parsing "; + + switch (format) + { + case input_format_t::cbor: + error_msg += "CBOR"; + break; + + case input_format_t::msgpack: + error_msg += "MessagePack"; + break; + + case input_format_t::ubjson: + error_msg += "UBJSON"; + break; + + case input_format_t::bson: + error_msg += "BSON"; + break; + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + + return error_msg + " " + context + ": " + detail; + } + + private: + /// input adapter + InputAdapterType ia; + + /// the current character + char_int_type current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// whether we can assume little endianess + const bool is_little_endian = little_endianess(); + + /// the SAX parser + json_sax_t* sax = nullptr; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + + +#include // isfinite +#include // uint8_t +#include // function +#include // string +#include // move +#include // vector + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +//////////// +// parser // +//////////// + +enum class parse_event_t : uint8_t +{ + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value +}; + +template +using parser_callback_t = + std::function; + +/*! +@brief syntax analysis + +This class implements a recursive descent parser. +*/ +template +class parser +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using lexer_t = lexer; + using token_type = typename lexer_t::token_type; + + public: + /// a parser reading from an input adapter + explicit parser(InputAdapterType&& adapter, + const parser_callback_t cb = nullptr, + const bool allow_exceptions_ = true, + const bool skip_comments = false) + : callback(cb) + , m_lexer(std::move(adapter), skip_comments) + , allow_exceptions(allow_exceptions_) + { + // read first token + get_token(); + } + + /*! + @brief public parser interface + + @param[in] strict whether to expect the last token to be EOF + @param[in,out] result parsed JSON value + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse(const bool strict, BasicJsonType& result) + { + if (callback) + { + json_sax_dom_callback_parser sdp(result, callback, allow_exceptions); + sax_parse_internal(&sdp); + result.assert_invariant(); + + // in strict mode, input must be completely read + if (strict && (get_token() != token_type::end_of_input)) + { + sdp.parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"))); + } + + // in case of an error, return discarded value + if (sdp.is_errored()) + { + result = value_t::discarded; + return; + } + + // set top-level value to null if it was discarded by the callback + // function + if (result.is_discarded()) + { + result = nullptr; + } + } + else + { + json_sax_dom_parser sdp(result, allow_exceptions); + sax_parse_internal(&sdp); + result.assert_invariant(); + + // in strict mode, input must be completely read + if (strict && (get_token() != token_type::end_of_input)) + { + sdp.parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"))); + } + + // in case of an error, return discarded value + if (sdp.is_errored()) + { + result = value_t::discarded; + return; + } + } + } + + /*! + @brief public accept interface + + @param[in] strict whether to expect the last token to be EOF + @return whether the input is a proper JSON text + */ + bool accept(const bool strict = true) + { + json_sax_acceptor sax_acceptor; + return sax_parse(&sax_acceptor, strict); + } + + template + JSON_HEDLEY_NON_NULL(2) + bool sax_parse(SAX* sax, const bool strict = true) + { + (void)detail::is_sax_static_asserts {}; + const bool result = sax_parse_internal(sax); + + // strict mode: next byte must be EOF + if (result && strict && (get_token() != token_type::end_of_input)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"))); + } + + return result; + } + + private: + template + JSON_HEDLEY_NON_NULL(2) + bool sax_parse_internal(SAX* sax) + { + // stack to remember the hierarchy of structured values we are parsing + // true = array; false = object + std::vector states; + // value to avoid a goto (see comment where set to true) + bool skip_to_state_evaluation = false; + + while (true) + { + if (!skip_to_state_evaluation) + { + // invariant: get_token() was called before each iteration + switch (last_token) + { + case token_type::begin_object: + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) + { + return false; + } + + // closing } -> we are done + if (get_token() == token_type::end_object) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) + { + return false; + } + break; + } + + // parse key + if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::value_string, "object key"))); + } + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; + } + + // parse separator (:) + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::name_separator, "object separator"))); + } + + // remember we are now inside an object + states.push_back(false); + + // parse values + get_token(); + continue; + } + + case token_type::begin_array: + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) + { + return false; + } + + // closing ] -> we are done + if (get_token() == token_type::end_array) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) + { + return false; + } + break; + } + + // remember we are now inside an array + states.push_back(true); + + // parse values (no need to call get_token) + continue; + } + + case token_type::value_float: + { + const auto res = m_lexer.get_number_float(); + + if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res))) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'")); + } + + if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string()))) + { + return false; + } + + break; + } + + case token_type::literal_false: + { + if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false))) + { + return false; + } + break; + } + + case token_type::literal_null: + { + if (JSON_HEDLEY_UNLIKELY(!sax->null())) + { + return false; + } + break; + } + + case token_type::literal_true: + { + if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true))) + { + return false; + } + break; + } + + case token_type::value_integer: + { + if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer()))) + { + return false; + } + break; + } + + case token_type::value_string: + { + if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string()))) + { + return false; + } + break; + } + + case token_type::value_unsigned: + { + if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned()))) + { + return false; + } + break; + } + + case token_type::parse_error: + { + // using "uninitialized" to avoid "expected" message + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::uninitialized, "value"))); + } + + default: // the last token was unexpected + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::literal_or_value, "value"))); + } + } + } + else + { + skip_to_state_evaluation = false; + } + + // we reached this line after we successfully parsed a value + if (states.empty()) + { + // empty stack: we reached the end of the hierarchy: done + return true; + } + + if (states.back()) // array + { + // comma -> next value + if (get_token() == token_type::value_separator) + { + // parse a new value + get_token(); + continue; + } + + // closing ] + if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array)) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) + { + return false; + } + + // We are done with this array. Before we can parse a + // new value, we need to evaluate the new state first. + // By setting skip_to_state_evaluation to false, we + // are effectively jumping to the beginning of this if. + JSON_ASSERT(!states.empty()); + states.pop_back(); + skip_to_state_evaluation = true; + continue; + } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_array, "array"))); + } + else // object + { + // comma -> next value + if (get_token() == token_type::value_separator) + { + // parse key + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::value_string, "object key"))); + } + + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; + } + + // parse separator (:) + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::name_separator, "object separator"))); + } + + // parse values + get_token(); + continue; + } + + // closing } + if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) + { + return false; + } + + // We are done with this object. Before we can parse a + // new value, we need to evaluate the new state first. + // By setting skip_to_state_evaluation to false, we + // are effectively jumping to the beginning of this if. + JSON_ASSERT(!states.empty()); + states.pop_back(); + skip_to_state_evaluation = true; + continue; + } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_object, "object"))); + } + } + } + + /// get next token from lexer + token_type get_token() + { + return last_token = m_lexer.scan(); + } + + std::string exception_message(const token_type expected, const std::string& context) + { + std::string error_msg = "syntax error "; + + if (!context.empty()) + { + error_msg += "while parsing " + context + " "; + } + + error_msg += "- "; + + if (last_token == token_type::parse_error) + { + error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + + m_lexer.get_token_string() + "'"; + } + else + { + error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token)); + } + + if (expected != token_type::uninitialized) + { + error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); + } + + return error_msg; + } + + private: + /// callback function + const parser_callback_t callback = nullptr; + /// the type of the last read token + token_type last_token = token_type::uninitialized; + /// the lexer + lexer_t m_lexer; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; +} // namespace detail +} // namespace nlohmann + +// #include + + +// #include + + +#include // ptrdiff_t +#include // numeric_limits + +namespace nlohmann +{ +namespace detail +{ +/* +@brief an iterator for primitive JSON types + +This class models an iterator for primitive JSON types (boolean, number, +string). It's only purpose is to allow the iterator/const_iterator classes +to "iterate" over primitive values. Internally, the iterator is modeled by +a `difference_type` variable. Value begin_value (`0`) models the begin, +end_value (`1`) models past the end. +*/ +class primitive_iterator_t +{ + private: + using difference_type = std::ptrdiff_t; + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + /// iterator as signed integer type + difference_type m_it = (std::numeric_limits::min)(); + + public: + constexpr difference_type get_value() const noexcept + { + return m_it; + } + + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return m_it == begin_value; + } + + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return m_it == end_value; + } + + friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it == rhs.m_it; + } + + friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it < rhs.m_it; + } + + primitive_iterator_t operator+(difference_type n) noexcept + { + auto result = *this; + result += n; + return result; + } + + friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it - rhs.m_it; + } + + primitive_iterator_t& operator++() noexcept + { + ++m_it; + return *this; + } + + primitive_iterator_t const operator++(int) noexcept + { + auto result = *this; + ++m_it; + return result; + } + + primitive_iterator_t& operator--() noexcept + { + --m_it; + return *this; + } + + primitive_iterator_t const operator--(int) noexcept + { + auto result = *this; + --m_it; + return result; + } + + primitive_iterator_t& operator+=(difference_type n) noexcept + { + m_it += n; + return *this; + } + + primitive_iterator_t& operator-=(difference_type n) noexcept + { + m_it -= n; + return *this; + } +}; +} // namespace detail +} // namespace nlohmann + + +namespace nlohmann +{ +namespace detail +{ +/*! +@brief an iterator value + +@note This structure could easily be a union, but MSVC currently does not allow +unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. +*/ +template struct internal_iterator +{ + /// iterator for JSON objects + typename BasicJsonType::object_t::iterator object_iterator {}; + /// iterator for JSON arrays + typename BasicJsonType::array_t::iterator array_iterator {}; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator {}; +}; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next +#include // conditional, is_const, remove_const + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +// forward declare, to be able to friend it later on +template class iteration_proxy; +template class iteration_proxy_value; + +/*! +@brief a template for a bidirectional iterator for the @ref basic_json class +This class implements a both iterators (iterator and const_iterator) for the +@ref basic_json class. +@note An iterator is called *initialized* when a pointer to a JSON value has + been set (e.g., by a constructor or a copy assignment). If the iterator is + default-constructed, it is *uninitialized* and most methods are undefined. + **The library uses assertions to detect calls on uninitialized iterators.** +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +@since version 1.0.0, simplified in version 2.0.9, change to bidirectional + iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) +*/ +template +class iter_impl +{ + /// allow basic_json to access private members + friend iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; + friend BasicJsonType; + friend iteration_proxy; + friend iteration_proxy_value; + + using object_t = typename BasicJsonType::object_t; + using array_t = typename BasicJsonType::array_t; + // make sure BasicJsonType is basic_json or const basic_json + static_assert(is_basic_json::type>::value, + "iter_impl only accepts (const) basic_json"); + + public: + + /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. + /// The C++ Standard has never required user-defined iterators to derive from std::iterator. + /// A user-defined iterator should provide publicly accessible typedefs named + /// iterator_category, value_type, difference_type, pointer, and reference. + /// Note that value_type is required to be non-const, even for constant iterators. + using iterator_category = std::bidirectional_iterator_tag; + + /// the type of the values when the iterator is dereferenced + using value_type = typename BasicJsonType::value_type; + /// a type to represent differences between iterators + using difference_type = typename BasicJsonType::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename std::conditional::value, + typename BasicJsonType::const_pointer, + typename BasicJsonType::pointer>::type; + /// defines a reference to the type iterated over (value_type) + using reference = + typename std::conditional::value, + typename BasicJsonType::const_reference, + typename BasicJsonType::reference>::type; + + /// default constructor + iter_impl() = default; + + /*! + @brief constructor for a given JSON instance + @param[in] object pointer to a JSON object for this iterator + @pre object != nullptr + @post The iterator is initialized; i.e. `m_object != nullptr`. + */ + explicit iter_impl(pointer object) noexcept : m_object(object) + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } + + case value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } + + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } + } + + /*! + @note The conventional copy constructor and copy assignment are implicitly + defined. Combined with the following converting constructor and + assignment, they support: (1) copy from iterator to iterator, (2) + copy from const iterator to const iterator, and (3) conversion from + iterator to const iterator. However conversion from const iterator + to iterator is not defined. + */ + + /*! + @brief const copy constructor + @param[in] other const iterator to copy from + @note This copy constructor had to be defined explicitly to circumvent a bug + occurring on msvc v19.0 compiler (VS 2015) debug build. For more + information refer to: https://github.com/nlohmann/json/issues/1608 + */ + iter_impl(const iter_impl& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /*! + @brief converting assignment + @param[in] other const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl& other) noexcept + { + m_object = other.m_object; + m_it = other.m_it; + return *this; + } + + /*! + @brief converting constructor + @param[in] other non-const iterator to copy from + @note It is not checked whether @a other is initialized. + */ + iter_impl(const iter_impl::type>& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /*! + @brief converting assignment + @param[in] other non-const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl::type>& other) noexcept + { + m_object = other.m_object; + m_it = other.m_it; + return *this; + } + + private: + /*! + @brief set the iterator to the first value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_begin() noexcept + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->begin(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->begin(); + break; + } + + case value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } + + /*! + @brief set the iterator past the last value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_end() noexcept + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->end(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->end(); + break; + } + + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + + public: + /*! + @brief return a reference to the value pointed to by the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator*() const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); + return m_it.object_iterator->second; + } + + case value_t::array: + { + JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); + return *m_it.array_iterator; + } + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief dereference the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + pointer operator->() const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case value_t::array: + { + JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); + return &*m_it.array_iterator; + } + + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) + { + return m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief post-increment (it++) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator++(int) + { + auto result = *this; + ++(*this); + return result; + } + + /*! + @brief pre-increment (++it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator++() + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, 1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, 1); + break; + } + + default: + { + ++m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief post-decrement (it--) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator--(int) + { + auto result = *this; + --(*this); + return result; + } + + /*! + @brief pre-decrement (--it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator--() + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, -1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, -1); + break; + } + + default: + { + --m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief comparison: equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator==(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } + + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + return (m_it.object_iterator == other.m_it.object_iterator); + + case value_t::array: + return (m_it.array_iterator == other.m_it.array_iterator); + + default: + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: not equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator!=(const iter_impl& other) const + { + return !operator==(other); + } + + /*! + @brief comparison: smaller + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } + + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators")); + + case value_t::array: + return (m_it.array_iterator < other.m_it.array_iterator); + + default: + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: less than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<=(const iter_impl& other) const + { + return !other.operator < (*this); + } + + /*! + @brief comparison: greater than + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>(const iter_impl& other) const + { + return !operator<=(other); + } + + /*! + @brief comparison: greater than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>=(const iter_impl& other) const + { + return !operator<(other); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator+=(difference_type i) + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + + case value_t::array: + { + std::advance(m_it.array_iterator, i); + break; + } + + default: + { + m_it.primitive_iterator += i; + break; + } + } + + return *this; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator-=(difference_type i) + { + return operator+=(-i); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } + + /*! + @brief addition of distance and iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + friend iter_impl operator+(difference_type i, const iter_impl& it) + { + auto result = it; + result += i; + return result; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } + + /*! + @brief return difference + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + difference_type operator-(const iter_impl& other) const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + + case value_t::array: + return m_it.array_iterator - other.m_it.array_iterator; + + default: + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + + /*! + @brief access to successor + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator[](difference_type n) const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); + + case value_t::array: + return *std::next(m_it.array_iterator, n); + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n)) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief return the key of an object iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + const typename object_t::key_type& key() const + { + JSON_ASSERT(m_object != nullptr); + + if (JSON_HEDLEY_LIKELY(m_object->is_object())) + { + return m_it.object_iterator->first; + } + + JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators")); + } + + /*! + @brief return the value of an iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference value() const + { + return operator*(); + } + + private: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator::type> m_it {}; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // ptrdiff_t +#include // reverse_iterator +#include // declval + +namespace nlohmann +{ +namespace detail +{ +////////////////////// +// reverse_iterator // +////////////////////// + +/*! +@brief a template for a reverse iterator class + +@tparam Base the base iterator type to reverse. Valid types are @ref +iterator (to create @ref reverse_iterator) and @ref const_iterator (to +create @ref const_reverse_iterator). + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + +@since version 1.0.0 +*/ +template +class json_reverse_iterator : public std::reverse_iterator +{ + public: + using difference_type = std::ptrdiff_t; + /// shortcut to the reverse iterator adapter + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; + + /// create reverse iterator from iterator + explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept + : base_iterator(it) {} + + /// create reverse iterator from base class + explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} + + /// post-increment (it++) + json_reverse_iterator const operator++(int) + { + return static_cast(base_iterator::operator++(1)); + } + + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + return static_cast(base_iterator::operator++()); + } + + /// post-decrement (it--) + json_reverse_iterator const operator--(int) + { + return static_cast(base_iterator::operator--(1)); + } + + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + return static_cast(base_iterator::operator--()); + } + + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + return static_cast(base_iterator::operator+=(i)); + } + + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + return static_cast(base_iterator::operator+(i)); + } + + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + return static_cast(base_iterator::operator-(i)); + } + + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return base_iterator(*this) - base_iterator(other); + } + + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + + /// return the key of an object iterator + auto key() const -> decltype(std::declval().key()) + { + auto it = --this->base(); + return it.key(); + } + + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // all_of +#include // isdigit +#include // max +#include // accumulate +#include // string +#include // move +#include // vector + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +template +class json_pointer +{ + // allow basic_json to access private members + NLOHMANN_BASIC_JSON_TPL_DECLARATION + friend class basic_json; + + public: + /*! + @brief create JSON pointer + + Create a JSON pointer according to the syntax described in + [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). + + @param[in] s string representing the JSON pointer; if omitted, the empty + string is assumed which references the whole JSON value + + @throw parse_error.107 if the given JSON pointer @a s is nonempty and does + not begin with a slash (`/`); see example below + + @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is + not followed by `0` (representing `~`) or `1` (representing `/`); see + example below + + @liveexample{The example shows the construction several valid JSON pointers + as well as the exceptional behavior.,json_pointer} + + @since version 2.0.0 + */ + explicit json_pointer(const std::string& s = "") + : reference_tokens(split(s)) + {} + + /*! + @brief return a string representation of the JSON pointer + + @invariant For each JSON pointer `ptr`, it holds: + @code {.cpp} + ptr == json_pointer(ptr.to_string()); + @endcode + + @return a string representation of the JSON pointer + + @liveexample{The example shows the result of `to_string`.,json_pointer__to_string} + + @since version 2.0.0 + */ + std::string to_string() const + { + return std::accumulate(reference_tokens.begin(), reference_tokens.end(), + std::string{}, + [](const std::string & a, const std::string & b) + { + return a + "/" + escape(b); + }); + } + + /// @copydoc to_string() + operator std::string() const + { + return to_string(); + } + + /*! + @brief append another JSON pointer at the end of this JSON pointer + + @param[in] ptr JSON pointer to append + @return JSON pointer with @a ptr appended + + @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add} + + @complexity Linear in the length of @a ptr. + + @sa @ref operator/=(std::string) to append a reference token + @sa @ref operator/=(std::size_t) to append an array index + @sa @ref operator/(const json_pointer&, const json_pointer&) for a binary operator + + @since version 3.6.0 + */ + json_pointer& operator/=(const json_pointer& ptr) + { + reference_tokens.insert(reference_tokens.end(), + ptr.reference_tokens.begin(), + ptr.reference_tokens.end()); + return *this; + } + + /*! + @brief append an unescaped reference token at the end of this JSON pointer + + @param[in] token reference token to append + @return JSON pointer with @a token appended without escaping @a token + + @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add} + + @complexity Amortized constant. + + @sa @ref operator/=(const json_pointer&) to append a JSON pointer + @sa @ref operator/=(std::size_t) to append an array index + @sa @ref operator/(const json_pointer&, std::size_t) for a binary operator + + @since version 3.6.0 + */ + json_pointer& operator/=(std::string token) + { + push_back(std::move(token)); + return *this; + } + + /*! + @brief append an array index at the end of this JSON pointer + + @param[in] array_idx array index to append + @return JSON pointer with @a array_idx appended + + @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add} + + @complexity Amortized constant. + + @sa @ref operator/=(const json_pointer&) to append a JSON pointer + @sa @ref operator/=(std::string) to append a reference token + @sa @ref operator/(const json_pointer&, std::string) for a binary operator + + @since version 3.6.0 + */ + json_pointer& operator/=(std::size_t array_idx) + { + return *this /= std::to_string(array_idx); + } + + /*! + @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer + + @param[in] lhs JSON pointer + @param[in] rhs JSON pointer + @return a new JSON pointer with @a rhs appended to @a lhs + + @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary} + + @complexity Linear in the length of @a lhs and @a rhs. + + @sa @ref operator/=(const json_pointer&) to append a JSON pointer + + @since version 3.6.0 + */ + friend json_pointer operator/(const json_pointer& lhs, + const json_pointer& rhs) + { + return json_pointer(lhs) /= rhs; + } + + /*! + @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer + + @param[in] ptr JSON pointer + @param[in] token reference token + @return a new JSON pointer with unescaped @a token appended to @a ptr + + @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary} + + @complexity Linear in the length of @a ptr. + + @sa @ref operator/=(std::string) to append a reference token + + @since version 3.6.0 + */ + friend json_pointer operator/(const json_pointer& ptr, std::string token) + { + return json_pointer(ptr) /= std::move(token); + } + + /*! + @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer + + @param[in] ptr JSON pointer + @param[in] array_idx array index + @return a new JSON pointer with @a array_idx appended to @a ptr + + @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary} + + @complexity Linear in the length of @a ptr. + + @sa @ref operator/=(std::size_t) to append an array index + + @since version 3.6.0 + */ + friend json_pointer operator/(const json_pointer& ptr, std::size_t array_idx) + { + return json_pointer(ptr) /= array_idx; + } + + /*! + @brief returns the parent of this JSON pointer + + @return parent of this JSON pointer; in case this JSON pointer is the root, + the root itself is returned + + @complexity Linear in the length of the JSON pointer. + + @liveexample{The example shows the result of `parent_pointer` for different + JSON Pointers.,json_pointer__parent_pointer} + + @since version 3.6.0 + */ + json_pointer parent_pointer() const + { + if (empty()) + { + return *this; + } + + json_pointer res = *this; + res.pop_back(); + return res; + } + + /*! + @brief remove last reference token + + @pre not `empty()` + + @liveexample{The example shows the usage of `pop_back`.,json_pointer__pop_back} + + @complexity Constant. + + @throw out_of_range.405 if JSON pointer has no parent + + @since version 3.6.0 + */ + void pop_back() + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); + } + + reference_tokens.pop_back(); + } + + /*! + @brief return last reference token + + @pre not `empty()` + @return last reference token + + @liveexample{The example shows the usage of `back`.,json_pointer__back} + + @complexity Constant. + + @throw out_of_range.405 if JSON pointer has no parent + + @since version 3.6.0 + */ + const std::string& back() const + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); + } + + return reference_tokens.back(); + } + + /*! + @brief append an unescaped token at the end of the reference pointer + + @param[in] token token to add + + @complexity Amortized constant. + + @liveexample{The example shows the result of `push_back` for different + JSON Pointers.,json_pointer__push_back} + + @since version 3.6.0 + */ + void push_back(const std::string& token) + { + reference_tokens.push_back(token); + } + + /// @copydoc push_back(const std::string&) + void push_back(std::string&& token) + { + reference_tokens.push_back(std::move(token)); + } + + /*! + @brief return whether pointer points to the root document + + @return true iff the JSON pointer points to the root document + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example shows the result of `empty` for different JSON + Pointers.,json_pointer__empty} + + @since version 3.6.0 + */ + bool empty() const noexcept + { + return reference_tokens.empty(); + } + + private: + /*! + @param[in] s reference token to be converted into an array index + + @return integer representation of @a s + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index begins not with a digit + @throw out_of_range.404 if string @a s could not be converted to an integer + @throw out_of_range.410 if an array index exceeds size_type + */ + static typename BasicJsonType::size_type array_index(const std::string& s) + { + using size_type = typename BasicJsonType::size_type; + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + s + + "' must not begin with '0'")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9'))) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number")); + } + + std::size_t processed_chars = 0; + unsigned long long res = 0; + JSON_TRY + { + res = std::stoull(s, &processed_chars); + } + JSON_CATCH(std::out_of_range&) + { + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); + } + + // check if the string was completely read + if (JSON_HEDLEY_UNLIKELY(processed_chars != s.size())) + { + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); + } + + // only triggered on special platforms (like 32bit), see also + // https://github.com/nlohmann/json/pull/2203 + if (res >= static_cast((std::numeric_limits::max)())) + { + JSON_THROW(detail::out_of_range::create(410, "array index " + s + " exceeds size_type")); // LCOV_EXCL_LINE + } + + return static_cast(res); + } + + json_pointer top() const + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); + } + + json_pointer result = *this; + result.reference_tokens = {reference_tokens[0]}; + return result; + } + + /*! + @brief create and return a reference to the pointed to value + + @complexity Linear in the number of reference tokens. + + @throw parse_error.109 if array index is not a number + @throw type_error.313 if value cannot be unflattened + */ + BasicJsonType& get_and_create(BasicJsonType& j) const + { + auto result = &j; + + // in case no reference tokens exist, return a reference to the JSON value + // j which will be overwritten by a primitive value + for (const auto& reference_token : reference_tokens) + { + switch (result->type()) + { + case detail::value_t::null: + { + if (reference_token == "0") + { + // start a new array if reference token is 0 + result = &result->operator[](0); + } + else + { + // start a new object otherwise + result = &result->operator[](reference_token); + } + break; + } + + case detail::value_t::object: + { + // create an entry in the object + result = &result->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + // create an entry in the array + result = &result->operator[](array_index(reference_token)); + break; + } + + /* + The following code is only reached if there exists a reference + token _and_ the current value is primitive. In this case, we have + an error situation, because primitive values may only occur as + single value; that is, with an empty list of reference tokens. + */ + default: + JSON_THROW(detail::type_error::create(313, "invalid value to unflatten")); + } + } + + return *result; + } + + /*! + @brief return a reference to the pointed to value + + @note This version does not throw if a value is not present, but tries to + create nested values instead. For instance, calling this function + with pointer `"/this/that"` on a null value is equivalent to calling + `operator[]("this").operator[]("that")` on that value, effectively + changing the null value to an object. + + @param[in] ptr a JSON value + + @return reference to the JSON value pointed to by the JSON pointer + + @complexity Linear in the length of the JSON pointer. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + BasicJsonType& get_unchecked(BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + // convert null values to arrays or objects before continuing + if (ptr->is_null()) + { + // check if reference token is a number + const bool nums = + std::all_of(reference_token.begin(), reference_token.end(), + [](const unsigned char x) + { + return std::isdigit(x); + }); + + // change value to array for numbers or "-" or to object otherwise + *ptr = (nums || reference_token == "-") + ? detail::value_t::array + : detail::value_t::object; + } + + switch (ptr->type()) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (reference_token == "-") + { + // explicitly treat "-" as index beyond the end + ptr = &ptr->operator[](ptr->m_value.array->size()); + } + else + { + // convert array index to number; unchecked access + ptr = &ptr->operator[](array_index(reference_token)); + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + BasicJsonType& get_checked(BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // note: at performs range check + ptr = &ptr->at(array_index(reference_token)); + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @brief return a const reference to the pointed to value + + @param[in] ptr a JSON value + + @return const reference to the JSON value pointed to by the JSON + pointer + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" cannot be used for const access + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // use unchecked array access + ptr = &ptr->operator[](array_index(reference_token)); + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + const BasicJsonType& get_checked(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // note: at performs range check + ptr = &ptr->at(array_index(reference_token)); + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + */ + bool contains(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + if (!ptr->contains(reference_token)) + { + // we did not find the key in the object + return false; + } + + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + return false; + } + if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9"))) + { + // invalid char + return false; + } + if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1)) + { + if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9'))) + { + // first char should be between '1' and '9' + return false; + } + for (std::size_t i = 1; i < reference_token.size(); i++) + { + if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9'))) + { + // other char should be between '0' and '9' + return false; + } + } + } + + const auto idx = array_index(reference_token); + if (idx >= ptr->size()) + { + // index out of range + return false; + } + + ptr = &ptr->operator[](idx); + break; + } + + default: + { + // we do not expect primitive values if there is still a + // reference token to process + return false; + } + } + } + + // no reference token left means we found a primitive value + return true; + } + + /*! + @brief split the string input to reference tokens + + @note This function is only called by the json_pointer constructor. + All exceptions below are documented there. + + @throw parse_error.107 if the pointer is not empty or begins with '/' + @throw parse_error.108 if character '~' is not followed by '0' or '1' + */ + static std::vector split(const std::string& reference_string) + { + std::vector result; + + // special case: empty reference string -> no reference tokens + if (reference_string.empty()) + { + return result; + } + + // check if nonempty reference string begins with slash + if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) + { + JSON_THROW(detail::parse_error::create(107, 1, + "JSON pointer must be empty or begin with '/' - was: '" + + reference_string + "'")); + } + + // extract the reference tokens: + // - slash: position of the last read slash (or end of string) + // - start: position after the previous slash + for ( + // search for the first slash after the first character + std::size_t slash = reference_string.find_first_of('/', 1), + // set the beginning of the first reference token + start = 1; + // we can stop if start == 0 (if slash == std::string::npos) + start != 0; + // set the beginning of the next reference token + // (will eventually be 0 if slash == std::string::npos) + start = (slash == std::string::npos) ? 0 : slash + 1, + // find next slash + slash = reference_string.find_first_of('/', start)) + { + // use the text between the beginning of the reference token + // (start) and the last slash (slash). + auto reference_token = reference_string.substr(start, slash - start); + + // check reference tokens are properly escaped + for (std::size_t pos = reference_token.find_first_of('~'); + pos != std::string::npos; + pos = reference_token.find_first_of('~', pos + 1)) + { + JSON_ASSERT(reference_token[pos] == '~'); + + // ~ must be followed by 0 or 1 + if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 || + (reference_token[pos + 1] != '0' && + reference_token[pos + 1] != '1'))) + { + JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'")); + } + } + + // finally, store the reference token + unescape(reference_token); + result.push_back(reference_token); + } + + return result; + } + + /*! + @brief replace all occurrences of a substring by another string + + @param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t + @param[in] f the substring to replace with @a t + @param[in] t the string to replace @a f + + @pre The search string @a f must not be empty. **This precondition is + enforced with an assertion.** + + @since version 2.0.0 + */ + static void replace_substring(std::string& s, const std::string& f, + const std::string& t) + { + JSON_ASSERT(!f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != std::string::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} + } + + /// escape "~" to "~0" and "/" to "~1" + static std::string escape(std::string s) + { + replace_substring(s, "~", "~0"); + replace_substring(s, "/", "~1"); + return s; + } + + /// unescape "~1" to tilde and "~0" to slash (order is important!) + static void unescape(std::string& s) + { + replace_substring(s, "~1", "/"); + replace_substring(s, "~0", "~"); + } + + /*! + @param[in] reference_string the reference string to the current value + @param[in] value the value to consider + @param[in,out] result the result object to insert values to + + @note Empty objects or arrays are flattened to `null`. + */ + static void flatten(const std::string& reference_string, + const BasicJsonType& value, + BasicJsonType& result) + { + switch (value.type()) + { + case detail::value_t::array: + { + if (value.m_value.array->empty()) + { + // flatten empty array as null + result[reference_string] = nullptr; + } + else + { + // iterate array and use index as reference string + for (std::size_t i = 0; i < value.m_value.array->size(); ++i) + { + flatten(reference_string + "/" + std::to_string(i), + value.m_value.array->operator[](i), result); + } + } + break; + } + + case detail::value_t::object: + { + if (value.m_value.object->empty()) + { + // flatten empty object as null + result[reference_string] = nullptr; + } + else + { + // iterate object and use keys as reference string + for (const auto& element : *value.m_value.object) + { + flatten(reference_string + "/" + escape(element.first), element.second, result); + } + } + break; + } + + default: + { + // add primitive value with its reference string + result[reference_string] = value; + break; + } + } + } + + /*! + @param[in] value flattened JSON + + @return unflattened JSON + + @throw parse_error.109 if array index is not a number + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + @throw type_error.313 if value cannot be unflattened + */ + static BasicJsonType + unflatten(const BasicJsonType& value) + { + if (JSON_HEDLEY_UNLIKELY(!value.is_object())) + { + JSON_THROW(detail::type_error::create(314, "only objects can be unflattened")); + } + + BasicJsonType result; + + // iterate the JSON object values + for (const auto& element : *value.m_value.object) + { + if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) + { + JSON_THROW(detail::type_error::create(315, "values in object must be primitive")); + } + + // assign value to reference pointed to by JSON pointer; Note that if + // the JSON pointer is "" (i.e., points to the whole value), function + // get_and_create returns a reference to result itself. An assignment + // will then create a primitive value. + json_pointer(element.first).get_and_create(result) = element.second; + } + + return result; + } + + /*! + @brief compares two JSON pointers for equality + + @param[in] lhs JSON pointer to compare + @param[in] rhs JSON pointer to compare + @return whether @a lhs is equal to @a rhs + + @complexity Linear in the length of the JSON pointer + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + */ + friend bool operator==(json_pointer const& lhs, + json_pointer const& rhs) noexcept + { + return lhs.reference_tokens == rhs.reference_tokens; + } + + /*! + @brief compares two JSON pointers for inequality + + @param[in] lhs JSON pointer to compare + @param[in] rhs JSON pointer to compare + @return whether @a lhs is not equal @a rhs + + @complexity Linear in the length of the JSON pointer + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + */ + friend bool operator!=(json_pointer const& lhs, + json_pointer const& rhs) noexcept + { + return !(lhs == rhs); + } + + /// the reference tokens + std::vector reference_tokens; +}; +} // namespace nlohmann + +// #include + + +#include +#include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +class json_ref +{ + public: + using value_type = BasicJsonType; + + json_ref(value_type&& value) + : owned_value(std::move(value)) + , value_ref(&owned_value) + , is_rvalue(true) + {} + + json_ref(const value_type& value) + : value_ref(const_cast(&value)) + , is_rvalue(false) + {} + + json_ref(std::initializer_list init) + : owned_value(init) + , value_ref(&owned_value) + , is_rvalue(true) + {} + + template < + class... Args, + enable_if_t::value, int> = 0 > + json_ref(Args && ... args) + : owned_value(std::forward(args)...) + , value_ref(&owned_value) + , is_rvalue(true) + {} + + // class should be movable only + json_ref(json_ref&&) = default; + json_ref(const json_ref&) = delete; + json_ref& operator=(const json_ref&) = delete; + json_ref& operator=(json_ref&&) = delete; + ~json_ref() = default; + + value_type moved_or_copied() const + { + if (is_rvalue) + { + return std::move(*value_ref); + } + return *value_ref; + } + + value_type const& operator*() const + { + return *static_cast(value_ref); + } + + value_type const* operator->() const + { + return static_cast(value_ref); + } + + private: + mutable value_type owned_value = nullptr; + value_type* value_ref = nullptr; + const bool is_rvalue = true; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + +// #include + + +#include // reverse +#include // array +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // numeric_limits +#include // string +#include // isnan, isinf + +// #include + +// #include + +// #include + + +#include // copy +#include // size_t +#include // streamsize +#include // back_inserter +#include // shared_ptr, make_shared +#include // basic_ostream +#include // basic_string +#include // vector +// #include + + +namespace nlohmann +{ +namespace detail +{ +/// abstract output adapter interface +template struct output_adapter_protocol +{ + virtual void write_character(CharType c) = 0; + virtual void write_characters(const CharType* s, std::size_t length) = 0; + virtual ~output_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +template +using output_adapter_t = std::shared_ptr>; + +/// output adapter for byte vectors +template +class output_vector_adapter : public output_adapter_protocol +{ + public: + explicit output_vector_adapter(std::vector& vec) noexcept + : v(vec) + {} + + void write_character(CharType c) override + { + v.push_back(c); + } + + JSON_HEDLEY_NON_NULL(2) + void write_characters(const CharType* s, std::size_t length) override + { + std::copy(s, s + length, std::back_inserter(v)); + } + + private: + std::vector& v; +}; + +/// output adapter for output streams +template +class output_stream_adapter : public output_adapter_protocol +{ + public: + explicit output_stream_adapter(std::basic_ostream& s) noexcept + : stream(s) + {} + + void write_character(CharType c) override + { + stream.put(c); + } + + JSON_HEDLEY_NON_NULL(2) + void write_characters(const CharType* s, std::size_t length) override + { + stream.write(s, static_cast(length)); + } + + private: + std::basic_ostream& stream; +}; + +/// output adapter for basic_string +template> +class output_string_adapter : public output_adapter_protocol +{ + public: + explicit output_string_adapter(StringType& s) noexcept + : str(s) + {} + + void write_character(CharType c) override + { + str.push_back(c); + } + + JSON_HEDLEY_NON_NULL(2) + void write_characters(const CharType* s, std::size_t length) override + { + str.append(s, length); + } + + private: + StringType& str; +}; + +template> +class output_adapter +{ + public: + output_adapter(std::vector& vec) + : oa(std::make_shared>(vec)) {} + + output_adapter(std::basic_ostream& s) + : oa(std::make_shared>(s)) {} + + output_adapter(StringType& s) + : oa(std::make_shared>(s)) {} + + operator output_adapter_t() + { + return oa; + } + + private: + output_adapter_t oa = nullptr; +}; +} // namespace detail +} // namespace nlohmann + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary writer // +/////////////////// + +/*! +@brief serialization to CBOR and MessagePack values +*/ +template +class binary_writer +{ + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using number_float_t = typename BasicJsonType::number_float_t; + + public: + /*! + @brief create a binary writer + + @param[in] adapter output adapter to write to + */ + explicit binary_writer(output_adapter_t adapter) : oa(adapter) + { + JSON_ASSERT(oa); + } + + /*! + @param[in] j JSON value to serialize + @pre j.type() == value_t::object + */ + void write_bson(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::object: + { + write_bson_object(*j.m_value.object); + break; + } + + default: + { + JSON_THROW(type_error::create(317, "to serialize to BSON, top-level type must be object, but is " + std::string(j.type_name()))); + } + } + } + + /*! + @param[in] j JSON value to serialize + */ + void write_cbor(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: + { + oa->write_character(to_char_type(0xF6)); + break; + } + + case value_t::boolean: + { + oa->write_character(j.m_value.boolean + ? to_char_type(0xF5) + : to_char_type(0xF4)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // CBOR does not differentiate between positive signed + // integers and unsigned integers. Therefore, we used the + // code from the value_t::number_unsigned case here. + if (j.m_value.number_integer <= 0x17) + { + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x18)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x19)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x1A)); + write_number(static_cast(j.m_value.number_integer)); + } + else + { + oa->write_character(to_char_type(0x1B)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + // The conversions below encode the sign in the first + // byte, and the value is converted to a positive number. + const auto positive_number = -1 - j.m_value.number_integer; + if (j.m_value.number_integer >= -24) + { + write_number(static_cast(0x20 + positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x38)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x39)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x3A)); + write_number(static_cast(positive_number)); + } + else + { + oa->write_character(to_char_type(0x3B)); + write_number(static_cast(positive_number)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned <= 0x17) + { + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x18)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x19)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x1A)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else + { + oa->write_character(to_char_type(0x1B)); + write_number(static_cast(j.m_value.number_unsigned)); + } + break; + } + + case value_t::number_float: + { + if (std::isnan(j.m_value.number_float)) + { + // NaN is 0xf97e00 in CBOR + oa->write_character(to_char_type(0xF9)); + oa->write_character(to_char_type(0x7E)); + oa->write_character(to_char_type(0x00)); + } + else if (std::isinf(j.m_value.number_float)) + { + // Infinity is 0xf97c00, -Infinity is 0xf9fc00 + oa->write_character(to_char_type(0xf9)); + oa->write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC)); + oa->write_character(to_char_type(0x00)); + } + else + { + write_compact_float(j.m_value.number_float, detail::input_format_t::cbor); + } + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 0x17) + { + write_number(static_cast(0x60 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x78)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x79)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x7A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x7B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 0x17) + { + write_number(static_cast(0x80 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x98)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x99)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x9A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x9B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_cbor(el); + } + break; + } + + case value_t::binary: + { + if (j.m_value.binary->has_subtype()) + { + write_number(static_cast(0xd8)); + write_number(j.m_value.binary->subtype()); + } + + // step 1: write control byte and the binary array size + const auto N = j.m_value.binary->size(); + if (N <= 0x17) + { + write_number(static_cast(0x40 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x58)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x59)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x5A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x5B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + oa->write_characters( + reinterpret_cast(j.m_value.binary->data()), + N); + + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 0x17) + { + write_number(static_cast(0xA0 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xB8)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xB9)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xBA)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xBB)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_cbor(el.first); + write_cbor(el.second); + } + break; + } + + default: + break; + } + } + + /*! + @param[in] j JSON value to serialize + */ + void write_msgpack(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: // nil + { + oa->write_character(to_char_type(0xC0)); + break; + } + + case value_t::boolean: // true and false + { + oa->write_character(j.m_value.boolean + ? to_char_type(0xC3) + : to_char_type(0xC2)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // MessagePack does not differentiate between positive + // signed integers and unsigned integers. Therefore, we used + // the code from the value_t::number_unsigned case here. + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(to_char_type(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(to_char_type(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(to_char_type(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(to_char_type(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + if (j.m_value.number_integer >= -32) + { + // negative fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 8 + oa->write_character(to_char_type(0xD0)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 16 + oa->write_character(to_char_type(0xD1)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 32 + oa->write_character(to_char_type(0xD2)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 64 + oa->write_character(to_char_type(0xD3)); + write_number(static_cast(j.m_value.number_integer)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(to_char_type(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(to_char_type(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(to_char_type(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(to_char_type(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + break; + } + + case value_t::number_float: + { + write_compact_float(j.m_value.number_float, detail::input_format_t::msgpack); + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 31) + { + // fixstr + write_number(static_cast(0xA0 | N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 8 + oa->write_character(to_char_type(0xD9)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 16 + oa->write_character(to_char_type(0xDA)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 32 + oa->write_character(to_char_type(0xDB)); + write_number(static_cast(N)); + } + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 15) + { + // fixarray + write_number(static_cast(0x90 | N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // array 16 + oa->write_character(to_char_type(0xDC)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // array 32 + oa->write_character(to_char_type(0xDD)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_msgpack(el); + } + break; + } + + case value_t::binary: + { + // step 0: determine if the binary type has a set subtype to + // determine whether or not to use the ext or fixext types + const bool use_ext = j.m_value.binary->has_subtype(); + + // step 1: write control byte and the byte string length + const auto N = j.m_value.binary->size(); + if (N <= (std::numeric_limits::max)()) + { + std::uint8_t output_type{}; + bool fixed = true; + if (use_ext) + { + switch (N) + { + case 1: + output_type = 0xD4; // fixext 1 + break; + case 2: + output_type = 0xD5; // fixext 2 + break; + case 4: + output_type = 0xD6; // fixext 4 + break; + case 8: + output_type = 0xD7; // fixext 8 + break; + case 16: + output_type = 0xD8; // fixext 16 + break; + default: + output_type = 0xC7; // ext 8 + fixed = false; + break; + } + + } + else + { + output_type = 0xC4; // bin 8 + fixed = false; + } + + oa->write_character(to_char_type(output_type)); + if (!fixed) + { + write_number(static_cast(N)); + } + } + else if (N <= (std::numeric_limits::max)()) + { + std::uint8_t output_type = use_ext + ? 0xC8 // ext 16 + : 0xC5; // bin 16 + + oa->write_character(to_char_type(output_type)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + std::uint8_t output_type = use_ext + ? 0xC9 // ext 32 + : 0xC6; // bin 32 + + oa->write_character(to_char_type(output_type)); + write_number(static_cast(N)); + } + + // step 1.5: if this is an ext type, write the subtype + if (use_ext) + { + write_number(static_cast(j.m_value.binary->subtype())); + } + + // step 2: write the byte string + oa->write_characters( + reinterpret_cast(j.m_value.binary->data()), + N); + + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 15) + { + // fixmap + write_number(static_cast(0x80 | (N & 0xF))); + } + else if (N <= (std::numeric_limits::max)()) + { + // map 16 + oa->write_character(to_char_type(0xDE)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // map 32 + oa->write_character(to_char_type(0xDF)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_msgpack(el.first); + write_msgpack(el.second); + } + break; + } + + default: + break; + } + } + + /*! + @param[in] j JSON value to serialize + @param[in] use_count whether to use '#' prefixes (optimized format) + @param[in] use_type whether to use '$' prefixes (optimized format) + @param[in] add_prefix whether prefixes need to be used for this value + */ + void write_ubjson(const BasicJsonType& j, const bool use_count, + const bool use_type, const bool add_prefix = true) + { + switch (j.type()) + { + case value_t::null: + { + if (add_prefix) + { + oa->write_character(to_char_type('Z')); + } + break; + } + + case value_t::boolean: + { + if (add_prefix) + { + oa->write_character(j.m_value.boolean + ? to_char_type('T') + : to_char_type('F')); + } + break; + } + + case value_t::number_integer: + { + write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix); + break; + } + + case value_t::number_unsigned: + { + write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix); + break; + } + + case value_t::number_float: + { + write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix); + break; + } + + case value_t::string: + { + if (add_prefix) + { + oa->write_character(to_char_type('S')); + } + write_number_with_ubjson_prefix(j.m_value.string->size(), true); + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + if (add_prefix) + { + oa->write_character(to_char_type('[')); + } + + bool prefix_required = true; + if (use_type && !j.m_value.array->empty()) + { + JSON_ASSERT(use_count); + const CharType first_prefix = ubjson_prefix(j.front()); + const bool same_prefix = std::all_of(j.begin() + 1, j.end(), + [this, first_prefix](const BasicJsonType & v) + { + return ubjson_prefix(v) == first_prefix; + }); + + if (same_prefix) + { + prefix_required = false; + oa->write_character(to_char_type('$')); + oa->write_character(first_prefix); + } + } + + if (use_count) + { + oa->write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_value.array->size(), true); + } + + for (const auto& el : *j.m_value.array) + { + write_ubjson(el, use_count, use_type, prefix_required); + } + + if (!use_count) + { + oa->write_character(to_char_type(']')); + } + + break; + } + + case value_t::binary: + { + if (add_prefix) + { + oa->write_character(to_char_type('[')); + } + + if (use_type && !j.m_value.binary->empty()) + { + JSON_ASSERT(use_count); + oa->write_character(to_char_type('$')); + oa->write_character('U'); + } + + if (use_count) + { + oa->write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_value.binary->size(), true); + } + + if (use_type) + { + oa->write_characters( + reinterpret_cast(j.m_value.binary->data()), + j.m_value.binary->size()); + } + else + { + for (size_t i = 0; i < j.m_value.binary->size(); ++i) + { + oa->write_character(to_char_type('U')); + oa->write_character(j.m_value.binary->data()[i]); + } + } + + if (!use_count) + { + oa->write_character(to_char_type(']')); + } + + break; + } + + case value_t::object: + { + if (add_prefix) + { + oa->write_character(to_char_type('{')); + } + + bool prefix_required = true; + if (use_type && !j.m_value.object->empty()) + { + JSON_ASSERT(use_count); + const CharType first_prefix = ubjson_prefix(j.front()); + const bool same_prefix = std::all_of(j.begin(), j.end(), + [this, first_prefix](const BasicJsonType & v) + { + return ubjson_prefix(v) == first_prefix; + }); + + if (same_prefix) + { + prefix_required = false; + oa->write_character(to_char_type('$')); + oa->write_character(first_prefix); + } + } + + if (use_count) + { + oa->write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_value.object->size(), true); + } + + for (const auto& el : *j.m_value.object) + { + write_number_with_ubjson_prefix(el.first.size(), true); + oa->write_characters( + reinterpret_cast(el.first.c_str()), + el.first.size()); + write_ubjson(el.second, use_count, use_type, prefix_required); + } + + if (!use_count) + { + oa->write_character(to_char_type('}')); + } + + break; + } + + default: + break; + } + } + + private: + ////////// + // BSON // + ////////// + + /*! + @return The size of a BSON document entry header, including the id marker + and the entry name size (and its null-terminator). + */ + static std::size_t calc_bson_entry_header_size(const string_t& name) + { + const auto it = name.find(static_cast(0)); + if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos)) + { + JSON_THROW(out_of_range::create(409, + "BSON key cannot contain code point U+0000 (at byte " + std::to_string(it) + ")")); + } + + return /*id*/ 1ul + name.size() + /*zero-terminator*/1u; + } + + /*! + @brief Writes the given @a element_type and @a name to the output adapter + */ + void write_bson_entry_header(const string_t& name, + const std::uint8_t element_type) + { + oa->write_character(to_char_type(element_type)); // boolean + oa->write_characters( + reinterpret_cast(name.c_str()), + name.size() + 1u); + } + + /*! + @brief Writes a BSON element with key @a name and boolean value @a value + */ + void write_bson_boolean(const string_t& name, + const bool value) + { + write_bson_entry_header(name, 0x08); + oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00)); + } + + /*! + @brief Writes a BSON element with key @a name and double value @a value + */ + void write_bson_double(const string_t& name, + const double value) + { + write_bson_entry_header(name, 0x01); + write_number(value); + } + + /*! + @return The size of the BSON-encoded string in @a value + */ + static std::size_t calc_bson_string_size(const string_t& value) + { + return sizeof(std::int32_t) + value.size() + 1ul; + } + + /*! + @brief Writes a BSON element with key @a name and string value @a value + */ + void write_bson_string(const string_t& name, + const string_t& value) + { + write_bson_entry_header(name, 0x02); + + write_number(static_cast(value.size() + 1ul)); + oa->write_characters( + reinterpret_cast(value.c_str()), + value.size() + 1); + } + + /*! + @brief Writes a BSON element with key @a name and null value + */ + void write_bson_null(const string_t& name) + { + write_bson_entry_header(name, 0x0A); + } + + /*! + @return The size of the BSON-encoded integer @a value + */ + static std::size_t calc_bson_integer_size(const std::int64_t value) + { + return (std::numeric_limits::min)() <= value && value <= (std::numeric_limits::max)() + ? sizeof(std::int32_t) + : sizeof(std::int64_t); + } + + /*! + @brief Writes a BSON element with key @a name and integer @a value + */ + void write_bson_integer(const string_t& name, + const std::int64_t value) + { + if ((std::numeric_limits::min)() <= value && value <= (std::numeric_limits::max)()) + { + write_bson_entry_header(name, 0x10); // int32 + write_number(static_cast(value)); + } + else + { + write_bson_entry_header(name, 0x12); // int64 + write_number(static_cast(value)); + } + } + + /*! + @return The size of the BSON-encoded unsigned integer in @a j + */ + static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept + { + return (value <= static_cast((std::numeric_limits::max)())) + ? sizeof(std::int32_t) + : sizeof(std::int64_t); + } + + /*! + @brief Writes a BSON element with key @a name and unsigned @a value + */ + void write_bson_unsigned(const string_t& name, + const std::uint64_t value) + { + if (value <= static_cast((std::numeric_limits::max)())) + { + write_bson_entry_header(name, 0x10 /* int32 */); + write_number(static_cast(value)); + } + else if (value <= static_cast((std::numeric_limits::max)())) + { + write_bson_entry_header(name, 0x12 /* int64 */); + write_number(static_cast(value)); + } + else + { + JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(value) + " cannot be represented by BSON as it does not fit int64")); + } + } + + /*! + @brief Writes a BSON element with key @a name and object @a value + */ + void write_bson_object_entry(const string_t& name, + const typename BasicJsonType::object_t& value) + { + write_bson_entry_header(name, 0x03); // object + write_bson_object(value); + } + + /*! + @return The size of the BSON-encoded array @a value + */ + static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value) + { + std::size_t array_index = 0ul; + + const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), std::size_t(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el) + { + return result + calc_bson_element_size(std::to_string(array_index++), el); + }); + + return sizeof(std::int32_t) + embedded_document_size + 1ul; + } + + /*! + @return The size of the BSON-encoded binary array @a value + */ + static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value) + { + return sizeof(std::int32_t) + value.size() + 1ul; + } + + /*! + @brief Writes a BSON element with key @a name and array @a value + */ + void write_bson_array(const string_t& name, + const typename BasicJsonType::array_t& value) + { + write_bson_entry_header(name, 0x04); // array + write_number(static_cast(calc_bson_array_size(value))); + + std::size_t array_index = 0ul; + + for (const auto& el : value) + { + write_bson_element(std::to_string(array_index++), el); + } + + oa->write_character(to_char_type(0x00)); + } + + /*! + @brief Writes a BSON element with key @a name and binary value @a value + */ + void write_bson_binary(const string_t& name, + const binary_t& value) + { + write_bson_entry_header(name, 0x05); + + write_number(static_cast(value.size())); + write_number(value.has_subtype() ? value.subtype() : std::uint8_t(0x00)); + + oa->write_characters(reinterpret_cast(value.data()), value.size()); + } + + /*! + @brief Calculates the size necessary to serialize the JSON value @a j with its @a name + @return The calculated size for the BSON document entry for @a j with the given @a name. + */ + static std::size_t calc_bson_element_size(const string_t& name, + const BasicJsonType& j) + { + const auto header_size = calc_bson_entry_header_size(name); + switch (j.type()) + { + case value_t::object: + return header_size + calc_bson_object_size(*j.m_value.object); + + case value_t::array: + return header_size + calc_bson_array_size(*j.m_value.array); + + case value_t::binary: + return header_size + calc_bson_binary_size(*j.m_value.binary); + + case value_t::boolean: + return header_size + 1ul; + + case value_t::number_float: + return header_size + 8ul; + + case value_t::number_integer: + return header_size + calc_bson_integer_size(j.m_value.number_integer); + + case value_t::number_unsigned: + return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned); + + case value_t::string: + return header_size + calc_bson_string_size(*j.m_value.string); + + case value_t::null: + return header_size + 0ul; + + // LCOV_EXCL_START + default: + JSON_ASSERT(false); + return 0ul; + // LCOV_EXCL_STOP + } + } + + /*! + @brief Serializes the JSON value @a j to BSON and associates it with the + key @a name. + @param name The name to associate with the JSON entity @a j within the + current BSON document + @return The size of the BSON entry + */ + void write_bson_element(const string_t& name, + const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::object: + return write_bson_object_entry(name, *j.m_value.object); + + case value_t::array: + return write_bson_array(name, *j.m_value.array); + + case value_t::binary: + return write_bson_binary(name, *j.m_value.binary); + + case value_t::boolean: + return write_bson_boolean(name, j.m_value.boolean); + + case value_t::number_float: + return write_bson_double(name, j.m_value.number_float); + + case value_t::number_integer: + return write_bson_integer(name, j.m_value.number_integer); + + case value_t::number_unsigned: + return write_bson_unsigned(name, j.m_value.number_unsigned); + + case value_t::string: + return write_bson_string(name, *j.m_value.string); + + case value_t::null: + return write_bson_null(name); + + // LCOV_EXCL_START + default: + JSON_ASSERT(false); + return; + // LCOV_EXCL_STOP + } + } + + /*! + @brief Calculates the size of the BSON serialization of the given + JSON-object @a j. + @param[in] j JSON value to serialize + @pre j.type() == value_t::object + */ + static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value) + { + std::size_t document_size = std::accumulate(value.begin(), value.end(), std::size_t(0), + [](size_t result, const typename BasicJsonType::object_t::value_type & el) + { + return result += calc_bson_element_size(el.first, el.second); + }); + + return sizeof(std::int32_t) + document_size + 1ul; + } + + /*! + @param[in] j JSON value to serialize + @pre j.type() == value_t::object + */ + void write_bson_object(const typename BasicJsonType::object_t& value) + { + write_number(static_cast(calc_bson_object_size(value))); + + for (const auto& el : value) + { + write_bson_element(el.first, el.second); + } + + oa->write_character(to_char_type(0x00)); + } + + ////////// + // CBOR // + ////////// + + static constexpr CharType get_cbor_float_prefix(float /*unused*/) + { + return to_char_type(0xFA); // Single-Precision Float + } + + static constexpr CharType get_cbor_float_prefix(double /*unused*/) + { + return to_char_type(0xFB); // Double-Precision Float + } + + ///////////// + // MsgPack // + ///////////// + + static constexpr CharType get_msgpack_float_prefix(float /*unused*/) + { + return to_char_type(0xCA); // float 32 + } + + static constexpr CharType get_msgpack_float_prefix(double /*unused*/) + { + return to_char_type(0xCB); // float 64 + } + + //////////// + // UBJSON // + //////////// + + // UBJSON: write number (floating point) + template::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if (add_prefix) + { + oa->write_character(get_ubjson_float_prefix(n)); + } + write_number(n); + } + + // UBJSON: write number (unsigned integer) + template::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('i')); // int8 + } + write_number(static_cast(n)); + } + else if (n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('U')); // uint8 + } + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('I')); // int16 + } + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('l')); // int32 + } + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('L')); // int64 + } + write_number(static_cast(n)); + } + else + { + if (add_prefix) + { + oa->write_character(to_char_type('H')); // high-precision number + } + + const auto number = BasicJsonType(n).dump(); + write_number_with_ubjson_prefix(number.size(), true); + for (std::size_t i = 0; i < number.size(); ++i) + { + oa->write_character(to_char_type(static_cast(number[i]))); + } + } + } + + // UBJSON: write number (signed integer) + template < typename NumberType, typename std::enable_if < + std::is_signed::value&& + !std::is_floating_point::value, int >::type = 0 > + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('i')); // int8 + } + write_number(static_cast(n)); + } + else if (static_cast((std::numeric_limits::min)()) <= n && n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('U')); // uint8 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('I')); // int16 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('l')); // int32 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('L')); // int64 + } + write_number(static_cast(n)); + } + // LCOV_EXCL_START + else + { + if (add_prefix) + { + oa->write_character(to_char_type('H')); // high-precision number + } + + const auto number = BasicJsonType(n).dump(); + write_number_with_ubjson_prefix(number.size(), true); + for (std::size_t i = 0; i < number.size(); ++i) + { + oa->write_character(to_char_type(static_cast(number[i]))); + } + } + // LCOV_EXCL_STOP + } + + /*! + @brief determine the type prefix of container values + */ + CharType ubjson_prefix(const BasicJsonType& j) const noexcept + { + switch (j.type()) + { + case value_t::null: + return 'Z'; + + case value_t::boolean: + return j.m_value.boolean ? 'T' : 'F'; + + case value_t::number_integer: + { + if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'i'; + } + if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'U'; + } + if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'I'; + } + if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'l'; + } + if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'L'; + } + // anything else is treated as high-precision number + return 'H'; // LCOV_EXCL_LINE + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'i'; + } + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'U'; + } + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'I'; + } + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'l'; + } + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'L'; + } + // anything else is treated as high-precision number + return 'H'; // LCOV_EXCL_LINE + } + + case value_t::number_float: + return get_ubjson_float_prefix(j.m_value.number_float); + + case value_t::string: + return 'S'; + + case value_t::array: // fallthrough + case value_t::binary: + return '['; + + case value_t::object: + return '{'; + + default: // discarded values + return 'N'; + } + } + + static constexpr CharType get_ubjson_float_prefix(float /*unused*/) + { + return 'd'; // float 32 + } + + static constexpr CharType get_ubjson_float_prefix(double /*unused*/) + { + return 'D'; // float 64 + } + + /////////////////////// + // Utility functions // + /////////////////////// + + /* + @brief write a number to output input + @param[in] n number of type @a NumberType + @tparam NumberType the type of the number + @tparam OutputIsLittleEndian Set to true if output data is + required to be little endian + + @note This function needs to respect the system's endianess, because bytes + in CBOR, MessagePack, and UBJSON are stored in network order (big + endian) and therefore need reordering on little endian systems. + */ + template + void write_number(const NumberType n) + { + // step 1: write number to array of length NumberType + std::array vec; + std::memcpy(vec.data(), &n, sizeof(NumberType)); + + // step 2: write array to output (with possible reordering) + if (is_little_endian != OutputIsLittleEndian) + { + // reverse byte order prior to conversion if necessary + std::reverse(vec.begin(), vec.end()); + } + + oa->write_characters(vec.data(), sizeof(NumberType)); + } + + void write_compact_float(const number_float_t n, detail::input_format_t format) + { + if (static_cast(n) >= static_cast(std::numeric_limits::lowest()) && + static_cast(n) <= static_cast((std::numeric_limits::max)()) && + static_cast(static_cast(n)) == static_cast(n)) + { + oa->write_character(format == detail::input_format_t::cbor + ? get_cbor_float_prefix(static_cast(n)) + : get_msgpack_float_prefix(static_cast(n))); + write_number(static_cast(n)); + } + else + { + oa->write_character(format == detail::input_format_t::cbor + ? get_cbor_float_prefix(n) + : get_msgpack_float_prefix(n)); + write_number(n); + } + } + + public: + // The following to_char_type functions are implement the conversion + // between uint8_t and CharType. In case CharType is not unsigned, + // such a conversion is required to allow values greater than 128. + // See for a discussion. + template < typename C = CharType, + enable_if_t < std::is_signed::value && std::is_signed::value > * = nullptr > + static constexpr CharType to_char_type(std::uint8_t x) noexcept + { + return *reinterpret_cast(&x); + } + + template < typename C = CharType, + enable_if_t < std::is_signed::value && std::is_unsigned::value > * = nullptr > + static CharType to_char_type(std::uint8_t x) noexcept + { + static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t"); + static_assert(std::is_trivial::value, "CharType must be trivial"); + CharType result; + std::memcpy(&result, &x, sizeof(x)); + return result; + } + + template::value>* = nullptr> + static constexpr CharType to_char_type(std::uint8_t x) noexcept + { + return x; + } + + template < typename InputCharType, typename C = CharType, + enable_if_t < + std::is_signed::value && + std::is_signed::value && + std::is_same::type>::value + > * = nullptr > + static constexpr CharType to_char_type(InputCharType x) noexcept + { + return x; + } + + private: + /// whether we can assume little endianess + const bool is_little_endian = little_endianess(); + + /// the output + output_adapter_t oa = nullptr; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // reverse, remove, fill, find, none_of +#include // array +#include // localeconv, lconv +#include // labs, isfinite, isnan, signbit +#include // size_t, ptrdiff_t +#include // uint8_t +#include // snprintf +#include // numeric_limits +#include // string, char_traits +#include // is_same +#include // move + +// #include + + +#include // array +#include // signbit, isfinite +#include // intN_t, uintN_t +#include // memcpy, memmove +#include // numeric_limits +#include // conditional + +// #include + + +namespace nlohmann +{ +namespace detail +{ + +/*! +@brief implements the Grisu2 algorithm for binary to decimal floating-point +conversion. + +This implementation is a slightly modified version of the reference +implementation which may be obtained from +http://florian.loitsch.com/publications (bench.tar.gz). + +The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch. + +For a detailed description of the algorithm see: + +[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with + Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming + Language Design and Implementation, PLDI 2010 +[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately", + Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language + Design and Implementation, PLDI 1996 +*/ +namespace dtoa_impl +{ + +template +Target reinterpret_bits(const Source source) +{ + static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); + + Target target; + std::memcpy(&target, &source, sizeof(Source)); + return target; +} + +struct diyfp // f * 2^e +{ + static constexpr int kPrecision = 64; // = q + + std::uint64_t f = 0; + int e = 0; + + constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {} + + /*! + @brief returns x - y + @pre x.e == y.e and x.f >= y.f + */ + static diyfp sub(const diyfp& x, const diyfp& y) noexcept + { + JSON_ASSERT(x.e == y.e); + JSON_ASSERT(x.f >= y.f); + + return {x.f - y.f, x.e}; + } + + /*! + @brief returns x * y + @note The result is rounded. (Only the upper q bits are returned.) + */ + static diyfp mul(const diyfp& x, const diyfp& y) noexcept + { + static_assert(kPrecision == 64, "internal error"); + + // Computes: + // f = round((x.f * y.f) / 2^q) + // e = x.e + y.e + q + + // Emulate the 64-bit * 64-bit multiplication: + // + // p = u * v + // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi) + // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi ) + // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 ) + // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 ) + // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3) + // = (p0_lo ) + 2^32 (Q ) + 2^64 (H ) + // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H ) + // + // (Since Q might be larger than 2^32 - 1) + // + // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H) + // + // (Q_hi + H does not overflow a 64-bit int) + // + // = p_lo + 2^64 p_hi + + const std::uint64_t u_lo = x.f & 0xFFFFFFFFu; + const std::uint64_t u_hi = x.f >> 32u; + const std::uint64_t v_lo = y.f & 0xFFFFFFFFu; + const std::uint64_t v_hi = y.f >> 32u; + + const std::uint64_t p0 = u_lo * v_lo; + const std::uint64_t p1 = u_lo * v_hi; + const std::uint64_t p2 = u_hi * v_lo; + const std::uint64_t p3 = u_hi * v_hi; + + const std::uint64_t p0_hi = p0 >> 32u; + const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu; + const std::uint64_t p1_hi = p1 >> 32u; + const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu; + const std::uint64_t p2_hi = p2 >> 32u; + + std::uint64_t Q = p0_hi + p1_lo + p2_lo; + + // The full product might now be computed as + // + // p_hi = p3 + p2_hi + p1_hi + (Q >> 32) + // p_lo = p0_lo + (Q << 32) + // + // But in this particular case here, the full p_lo is not required. + // Effectively we only need to add the highest bit in p_lo to p_hi (and + // Q_hi + 1 does not overflow). + + Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up + + const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u); + + return {h, x.e + y.e + 64}; + } + + /*! + @brief normalize x such that the significand is >= 2^(q-1) + @pre x.f != 0 + */ + static diyfp normalize(diyfp x) noexcept + { + JSON_ASSERT(x.f != 0); + + while ((x.f >> 63u) == 0) + { + x.f <<= 1u; + x.e--; + } + + return x; + } + + /*! + @brief normalize x such that the result has the exponent E + @pre e >= x.e and the upper e - x.e bits of x.f must be zero. + */ + static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept + { + const int delta = x.e - target_exponent; + + JSON_ASSERT(delta >= 0); + JSON_ASSERT(((x.f << delta) >> delta) == x.f); + + return {x.f << delta, target_exponent}; + } +}; + +struct boundaries +{ + diyfp w; + diyfp minus; + diyfp plus; +}; + +/*! +Compute the (normalized) diyfp representing the input number 'value' and its +boundaries. + +@pre value must be finite and positive +*/ +template +boundaries compute_boundaries(FloatType value) +{ + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); + + // Convert the IEEE representation into a diyfp. + // + // If v is denormal: + // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) + // If v is normalized: + // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) + + static_assert(std::numeric_limits::is_iec559, + "internal error: dtoa_short requires an IEEE-754 floating-point implementation"); + + constexpr int kPrecision = std::numeric_limits::digits; // = p (includes the hidden bit) + constexpr int kBias = std::numeric_limits::max_exponent - 1 + (kPrecision - 1); + constexpr int kMinExp = 1 - kBias; + constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1) + + using bits_type = typename std::conditional::type; + + const std::uint64_t bits = reinterpret_bits(value); + const std::uint64_t E = bits >> (kPrecision - 1); + const std::uint64_t F = bits & (kHiddenBit - 1); + + const bool is_denormal = E == 0; + const diyfp v = is_denormal + ? diyfp(F, kMinExp) + : diyfp(F + kHiddenBit, static_cast(E) - kBias); + + // Compute the boundaries m- and m+ of the floating-point value + // v = f * 2^e. + // + // Determine v- and v+, the floating-point predecessor and successor if v, + // respectively. + // + // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) + // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) + // + // v+ = v + 2^e + // + // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ + // between m- and m+ round to v, regardless of how the input rounding + // algorithm breaks ties. + // + // ---+-------------+-------------+-------------+-------------+--- (A) + // v- m- v m+ v+ + // + // -----------------+------+------+-------------+-------------+--- (B) + // v- m- v m+ v+ + + const bool lower_boundary_is_closer = F == 0 && E > 1; + const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); + const diyfp m_minus = lower_boundary_is_closer + ? diyfp(4 * v.f - 1, v.e - 2) // (B) + : diyfp(2 * v.f - 1, v.e - 1); // (A) + + // Determine the normalized w+ = m+. + const diyfp w_plus = diyfp::normalize(m_plus); + + // Determine w- = m- such that e_(w-) = e_(w+). + const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e); + + return {diyfp::normalize(v), w_minus, w_plus}; +} + +// Given normalized diyfp w, Grisu needs to find a (normalized) cached +// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies +// within a certain range [alpha, gamma] (Definition 3.2 from [1]) +// +// alpha <= e = e_c + e_w + q <= gamma +// +// or +// +// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q +// <= f_c * f_w * 2^gamma +// +// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies +// +// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma +// +// or +// +// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma) +// +// The choice of (alpha,gamma) determines the size of the table and the form of +// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well +// in practice: +// +// The idea is to cut the number c * w = f * 2^e into two parts, which can be +// processed independently: An integral part p1, and a fractional part p2: +// +// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e +// = (f div 2^-e) + (f mod 2^-e) * 2^e +// = p1 + p2 * 2^e +// +// The conversion of p1 into decimal form requires a series of divisions and +// modulos by (a power of) 10. These operations are faster for 32-bit than for +// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be +// achieved by choosing +// +// -e >= 32 or e <= -32 := gamma +// +// In order to convert the fractional part +// +// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ... +// +// into decimal form, the fraction is repeatedly multiplied by 10 and the digits +// d[-i] are extracted in order: +// +// (10 * p2) div 2^-e = d[-1] +// (10 * p2) mod 2^-e = d[-2] / 10^1 + ... +// +// The multiplication by 10 must not overflow. It is sufficient to choose +// +// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64. +// +// Since p2 = f mod 2^-e < 2^-e, +// +// -e <= 60 or e >= -60 := alpha + +constexpr int kAlpha = -60; +constexpr int kGamma = -32; + +struct cached_power // c = f * 2^e ~= 10^k +{ + std::uint64_t f; + int e; + int k; +}; + +/*! +For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached +power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c +satisfies (Definition 3.2 from [1]) + + alpha <= e_c + e + q <= gamma. +*/ +inline cached_power get_cached_power_for_binary_exponent(int e) +{ + // Now + // + // alpha <= e_c + e + q <= gamma (1) + // ==> f_c * 2^alpha <= c * 2^e * 2^q + // + // and since the c's are normalized, 2^(q-1) <= f_c, + // + // ==> 2^(q - 1 + alpha) <= c * 2^(e + q) + // ==> 2^(alpha - e - 1) <= c + // + // If c were an exact power of ten, i.e. c = 10^k, one may determine k as + // + // k = ceil( log_10( 2^(alpha - e - 1) ) ) + // = ceil( (alpha - e - 1) * log_10(2) ) + // + // From the paper: + // "In theory the result of the procedure could be wrong since c is rounded, + // and the computation itself is approximated [...]. In practice, however, + // this simple function is sufficient." + // + // For IEEE double precision floating-point numbers converted into + // normalized diyfp's w = f * 2^e, with q = 64, + // + // e >= -1022 (min IEEE exponent) + // -52 (p - 1) + // -52 (p - 1, possibly normalize denormal IEEE numbers) + // -11 (normalize the diyfp) + // = -1137 + // + // and + // + // e <= +1023 (max IEEE exponent) + // -52 (p - 1) + // -11 (normalize the diyfp) + // = 960 + // + // This binary exponent range [-1137,960] results in a decimal exponent + // range [-307,324]. One does not need to store a cached power for each + // k in this range. For each such k it suffices to find a cached power + // such that the exponent of the product lies in [alpha,gamma]. + // This implies that the difference of the decimal exponents of adjacent + // table entries must be less than or equal to + // + // floor( (gamma - alpha) * log_10(2) ) = 8. + // + // (A smaller distance gamma-alpha would require a larger table.) + + // NB: + // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. + + constexpr int kCachedPowersMinDecExp = -300; + constexpr int kCachedPowersDecStep = 8; + + static constexpr std::array kCachedPowers = + { + { + { 0xAB70FE17C79AC6CA, -1060, -300 }, + { 0xFF77B1FCBEBCDC4F, -1034, -292 }, + { 0xBE5691EF416BD60C, -1007, -284 }, + { 0x8DD01FAD907FFC3C, -980, -276 }, + { 0xD3515C2831559A83, -954, -268 }, + { 0x9D71AC8FADA6C9B5, -927, -260 }, + { 0xEA9C227723EE8BCB, -901, -252 }, + { 0xAECC49914078536D, -874, -244 }, + { 0x823C12795DB6CE57, -847, -236 }, + { 0xC21094364DFB5637, -821, -228 }, + { 0x9096EA6F3848984F, -794, -220 }, + { 0xD77485CB25823AC7, -768, -212 }, + { 0xA086CFCD97BF97F4, -741, -204 }, + { 0xEF340A98172AACE5, -715, -196 }, + { 0xB23867FB2A35B28E, -688, -188 }, + { 0x84C8D4DFD2C63F3B, -661, -180 }, + { 0xC5DD44271AD3CDBA, -635, -172 }, + { 0x936B9FCEBB25C996, -608, -164 }, + { 0xDBAC6C247D62A584, -582, -156 }, + { 0xA3AB66580D5FDAF6, -555, -148 }, + { 0xF3E2F893DEC3F126, -529, -140 }, + { 0xB5B5ADA8AAFF80B8, -502, -132 }, + { 0x87625F056C7C4A8B, -475, -124 }, + { 0xC9BCFF6034C13053, -449, -116 }, + { 0x964E858C91BA2655, -422, -108 }, + { 0xDFF9772470297EBD, -396, -100 }, + { 0xA6DFBD9FB8E5B88F, -369, -92 }, + { 0xF8A95FCF88747D94, -343, -84 }, + { 0xB94470938FA89BCF, -316, -76 }, + { 0x8A08F0F8BF0F156B, -289, -68 }, + { 0xCDB02555653131B6, -263, -60 }, + { 0x993FE2C6D07B7FAC, -236, -52 }, + { 0xE45C10C42A2B3B06, -210, -44 }, + { 0xAA242499697392D3, -183, -36 }, + { 0xFD87B5F28300CA0E, -157, -28 }, + { 0xBCE5086492111AEB, -130, -20 }, + { 0x8CBCCC096F5088CC, -103, -12 }, + { 0xD1B71758E219652C, -77, -4 }, + { 0x9C40000000000000, -50, 4 }, + { 0xE8D4A51000000000, -24, 12 }, + { 0xAD78EBC5AC620000, 3, 20 }, + { 0x813F3978F8940984, 30, 28 }, + { 0xC097CE7BC90715B3, 56, 36 }, + { 0x8F7E32CE7BEA5C70, 83, 44 }, + { 0xD5D238A4ABE98068, 109, 52 }, + { 0x9F4F2726179A2245, 136, 60 }, + { 0xED63A231D4C4FB27, 162, 68 }, + { 0xB0DE65388CC8ADA8, 189, 76 }, + { 0x83C7088E1AAB65DB, 216, 84 }, + { 0xC45D1DF942711D9A, 242, 92 }, + { 0x924D692CA61BE758, 269, 100 }, + { 0xDA01EE641A708DEA, 295, 108 }, + { 0xA26DA3999AEF774A, 322, 116 }, + { 0xF209787BB47D6B85, 348, 124 }, + { 0xB454E4A179DD1877, 375, 132 }, + { 0x865B86925B9BC5C2, 402, 140 }, + { 0xC83553C5C8965D3D, 428, 148 }, + { 0x952AB45CFA97A0B3, 455, 156 }, + { 0xDE469FBD99A05FE3, 481, 164 }, + { 0xA59BC234DB398C25, 508, 172 }, + { 0xF6C69A72A3989F5C, 534, 180 }, + { 0xB7DCBF5354E9BECE, 561, 188 }, + { 0x88FCF317F22241E2, 588, 196 }, + { 0xCC20CE9BD35C78A5, 614, 204 }, + { 0x98165AF37B2153DF, 641, 212 }, + { 0xE2A0B5DC971F303A, 667, 220 }, + { 0xA8D9D1535CE3B396, 694, 228 }, + { 0xFB9B7CD9A4A7443C, 720, 236 }, + { 0xBB764C4CA7A44410, 747, 244 }, + { 0x8BAB8EEFB6409C1A, 774, 252 }, + { 0xD01FEF10A657842C, 800, 260 }, + { 0x9B10A4E5E9913129, 827, 268 }, + { 0xE7109BFBA19C0C9D, 853, 276 }, + { 0xAC2820D9623BF429, 880, 284 }, + { 0x80444B5E7AA7CF85, 907, 292 }, + { 0xBF21E44003ACDD2D, 933, 300 }, + { 0x8E679C2F5E44FF8F, 960, 308 }, + { 0xD433179D9C8CB841, 986, 316 }, + { 0x9E19DB92B4E31BA9, 1013, 324 }, + } + }; + + // This computation gives exactly the same results for k as + // k = ceil((kAlpha - e - 1) * 0.30102999566398114) + // for |e| <= 1500, but doesn't require floating-point operations. + // NB: log_10(2) ~= 78913 / 2^18 + JSON_ASSERT(e >= -1500); + JSON_ASSERT(e <= 1500); + const int f = kAlpha - e - 1; + const int k = (f * 78913) / (1 << 18) + static_cast(f > 0); + + const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; + JSON_ASSERT(index >= 0); + JSON_ASSERT(static_cast(index) < kCachedPowers.size()); + + const cached_power cached = kCachedPowers[static_cast(index)]; + JSON_ASSERT(kAlpha <= cached.e + e + 64); + JSON_ASSERT(kGamma >= cached.e + e + 64); + + return cached; +} + +/*! +For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. +For n == 0, returns 1 and sets pow10 := 1. +*/ +inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10) +{ + // LCOV_EXCL_START + if (n >= 1000000000) + { + pow10 = 1000000000; + return 10; + } + // LCOV_EXCL_STOP + else if (n >= 100000000) + { + pow10 = 100000000; + return 9; + } + else if (n >= 10000000) + { + pow10 = 10000000; + return 8; + } + else if (n >= 1000000) + { + pow10 = 1000000; + return 7; + } + else if (n >= 100000) + { + pow10 = 100000; + return 6; + } + else if (n >= 10000) + { + pow10 = 10000; + return 5; + } + else if (n >= 1000) + { + pow10 = 1000; + return 4; + } + else if (n >= 100) + { + pow10 = 100; + return 3; + } + else if (n >= 10) + { + pow10 = 10; + return 2; + } + else + { + pow10 = 1; + return 1; + } +} + +inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, + std::uint64_t rest, std::uint64_t ten_k) +{ + JSON_ASSERT(len >= 1); + JSON_ASSERT(dist <= delta); + JSON_ASSERT(rest <= delta); + JSON_ASSERT(ten_k > 0); + + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // ten_k + // <------> + // <---- rest ----> + // --------------[------------------+----+--------------]-------------- + // w V + // = buf * 10^k + // + // ten_k represents a unit-in-the-last-place in the decimal representation + // stored in buf. + // Decrement buf by ten_k while this takes buf closer to w. + + // The tests are written in this order to avoid overflow in unsigned + // integer arithmetic. + + while (rest < dist + && delta - rest >= ten_k + && (rest + ten_k < dist || dist - rest > rest + ten_k - dist)) + { + JSON_ASSERT(buf[len - 1] != '0'); + buf[len - 1]--; + rest += ten_k; + } +} + +/*! +Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. +M- and M+ must be normalized and share the same exponent -60 <= e <= -32. +*/ +inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, + diyfp M_minus, diyfp w, diyfp M_plus) +{ + static_assert(kAlpha >= -60, "internal error"); + static_assert(kGamma <= -32, "internal error"); + + // Generates the digits (and the exponent) of a decimal floating-point + // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's + // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma. + // + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // Grisu2 generates the digits of M+ from left to right and stops as soon as + // V is in [M-,M+]. + + JSON_ASSERT(M_plus.e >= kAlpha); + JSON_ASSERT(M_plus.e <= kGamma); + + std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) + std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) + + // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): + // + // M+ = f * 2^e + // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e + // = ((p1 ) * 2^-e + (p2 )) * 2^e + // = p1 + p2 * 2^e + + const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e); + + auto p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) + std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e + + // 1) + // + // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] + + JSON_ASSERT(p1 > 0); + + std::uint32_t pow10; + const int k = find_largest_pow10(p1, pow10); + + // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) + // + // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1)) + // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1)) + // + // M+ = p1 + p2 * 2^e + // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e + // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e + // = d[k-1] * 10^(k-1) + ( rest) * 2^e + // + // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0) + // + // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0] + // + // but stop as soon as + // + // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e + + int n = k; + while (n > 0) + { + // Invariants: + // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) + // pow10 = 10^(n-1) <= p1 < 10^n + // + const std::uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) + const std::uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) + // + // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e + // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) + // + JSON_ASSERT(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) + // + p1 = r; + n--; + // + // M+ = buffer * 10^n + (p1 + p2 * 2^e) + // pow10 = 10^n + // + + // Now check if enough digits have been generated. + // Compute + // + // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e + // + // Note: + // Since rest and delta share the same exponent e, it suffices to + // compare the significands. + const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2; + if (rest <= delta) + { + // V = buffer * 10^n, with M- <= V <= M+. + + decimal_exponent += n; + + // We may now just stop. But instead look if the buffer could be + // decremented to bring V closer to w. + // + // pow10 = 10^n is now 1 ulp in the decimal representation V. + // The rounding procedure works with diyfp's with an implicit + // exponent of e. + // + // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e + // + const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e; + grisu2_round(buffer, length, dist, delta, rest, ten_n); + + return; + } + + pow10 /= 10; + // + // pow10 = 10^(n-1) <= p1 < 10^n + // Invariants restored. + } + + // 2) + // + // The digits of the integral part have been generated: + // + // M+ = d[k-1]...d[1]d[0] + p2 * 2^e + // = buffer + p2 * 2^e + // + // Now generate the digits of the fractional part p2 * 2^e. + // + // Note: + // No decimal point is generated: the exponent is adjusted instead. + // + // p2 actually represents the fraction + // + // p2 * 2^e + // = p2 / 2^-e + // = d[-1] / 10^1 + d[-2] / 10^2 + ... + // + // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...) + // + // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m + // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...) + // + // using + // + // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e) + // = ( d) * 2^-e + ( r) + // + // or + // 10^m * p2 * 2^e = d + r * 2^e + // + // i.e. + // + // M+ = buffer + p2 * 2^e + // = buffer + 10^-m * (d + r * 2^e) + // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e + // + // and stop as soon as 10^-m * r * 2^e <= delta * 2^e + + JSON_ASSERT(p2 > delta); + + int m = 0; + for (;;) + { + // Invariant: + // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e + // = buffer * 10^-m + 10^-m * (p2 ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e + // + JSON_ASSERT(p2 <= (std::numeric_limits::max)() / 10); + p2 *= 10; + const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e + const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e + // + // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) + // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + JSON_ASSERT(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + p2 = r; + m++; + // + // M+ = buffer * 10^-m + 10^-m * p2 * 2^e + // Invariant restored. + + // Check if enough digits have been generated. + // + // 10^-m * p2 * 2^e <= delta * 2^e + // p2 * 2^e <= 10^m * delta * 2^e + // p2 <= 10^m * delta + delta *= 10; + dist *= 10; + if (p2 <= delta) + { + break; + } + } + + // V = buffer * 10^-m, with M- <= V <= M+. + + decimal_exponent -= m; + + // 1 ulp in the decimal representation is now 10^-m. + // Since delta and dist are now scaled by 10^m, we need to do the + // same with ulp in order to keep the units in sync. + // + // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e + // + const std::uint64_t ten_m = one.f; + grisu2_round(buffer, length, dist, delta, p2, ten_m); + + // By construction this algorithm generates the shortest possible decimal + // number (Loitsch, Theorem 6.2) which rounds back to w. + // For an input number of precision p, at least + // + // N = 1 + ceil(p * log_10(2)) + // + // decimal digits are sufficient to identify all binary floating-point + // numbers (Matula, "In-and-Out conversions"). + // This implies that the algorithm does not produce more than N decimal + // digits. + // + // N = 17 for p = 53 (IEEE double precision) + // N = 9 for p = 24 (IEEE single precision) +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +JSON_HEDLEY_NON_NULL(1) +inline void grisu2(char* buf, int& len, int& decimal_exponent, + diyfp m_minus, diyfp v, diyfp m_plus) +{ + JSON_ASSERT(m_plus.e == m_minus.e); + JSON_ASSERT(m_plus.e == v.e); + + // --------(-----------------------+-----------------------)-------- (A) + // m- v m+ + // + // --------------------(-----------+-----------------------)-------- (B) + // m- v m+ + // + // First scale v (and m- and m+) such that the exponent is in the range + // [alpha, gamma]. + + const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); + + const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k + + // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] + const diyfp w = diyfp::mul(v, c_minus_k); + const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); + const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); + + // ----(---+---)---------------(---+---)---------------(---+---)---- + // w- w w+ + // = c*m- = c*v = c*m+ + // + // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and + // w+ are now off by a small amount. + // In fact: + // + // w - v * 10^k < 1 ulp + // + // To account for this inaccuracy, add resp. subtract 1 ulp. + // + // --------+---[---------------(---+---)---------------]---+-------- + // w- M- w M+ w+ + // + // Now any number in [M-, M+] (bounds included) will round to w when input, + // regardless of how the input rounding algorithm breaks ties. + // + // And digit_gen generates the shortest possible such number in [M-, M+]. + // Note that this does not mean that Grisu2 always generates the shortest + // possible number in the interval (m-, m+). + const diyfp M_minus(w_minus.f + 1, w_minus.e); + const diyfp M_plus (w_plus.f - 1, w_plus.e ); + + decimal_exponent = -cached.k; // = -(-k) = k + + grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +template +JSON_HEDLEY_NON_NULL(1) +void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) +{ + static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, + "internal error: not enough precision"); + + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); + + // If the neighbors (and boundaries) of 'value' are always computed for double-precision + // numbers, all float's can be recovered using strtod (and strtof). However, the resulting + // decimal representations are not exactly "short". + // + // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars) + // says "value is converted to a string as if by std::sprintf in the default ("C") locale" + // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars' + // does. + // On the other hand, the documentation for 'std::to_chars' requires that "parsing the + // representation using the corresponding std::from_chars function recovers value exactly". That + // indicates that single precision floating-point numbers should be recovered using + // 'std::strtof'. + // + // NB: If the neighbors are computed for single-precision numbers, there is a single float + // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision + // value is off by 1 ulp. +#if 0 + const boundaries w = compute_boundaries(static_cast(value)); +#else + const boundaries w = compute_boundaries(value); +#endif + + grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus); +} + +/*! +@brief appends a decimal representation of e to buf +@return a pointer to the element following the exponent. +@pre -1000 < e < 1000 +*/ +JSON_HEDLEY_NON_NULL(1) +JSON_HEDLEY_RETURNS_NON_NULL +inline char* append_exponent(char* buf, int e) +{ + JSON_ASSERT(e > -1000); + JSON_ASSERT(e < 1000); + + if (e < 0) + { + e = -e; + *buf++ = '-'; + } + else + { + *buf++ = '+'; + } + + auto k = static_cast(e); + if (k < 10) + { + // Always print at least two digits in the exponent. + // This is for compatibility with printf("%g"). + *buf++ = '0'; + *buf++ = static_cast('0' + k); + } + else if (k < 100) + { + *buf++ = static_cast('0' + k / 10); + k %= 10; + *buf++ = static_cast('0' + k); + } + else + { + *buf++ = static_cast('0' + k / 100); + k %= 100; + *buf++ = static_cast('0' + k / 10); + k %= 10; + *buf++ = static_cast('0' + k); + } + + return buf; +} + +/*! +@brief prettify v = buf * 10^decimal_exponent + +If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point +notation. Otherwise it will be printed in exponential notation. + +@pre min_exp < 0 +@pre max_exp > 0 +*/ +JSON_HEDLEY_NON_NULL(1) +JSON_HEDLEY_RETURNS_NON_NULL +inline char* format_buffer(char* buf, int len, int decimal_exponent, + int min_exp, int max_exp) +{ + JSON_ASSERT(min_exp < 0); + JSON_ASSERT(max_exp > 0); + + const int k = len; + const int n = len + decimal_exponent; + + // v = buf * 10^(n-k) + // k is the length of the buffer (number of decimal digits) + // n is the position of the decimal point relative to the start of the buffer. + + if (k <= n && n <= max_exp) + { + // digits[000] + // len <= max_exp + 2 + + std::memset(buf + k, '0', static_cast(n) - static_cast(k)); + // Make it look like a floating-point number (#362, #378) + buf[n + 0] = '.'; + buf[n + 1] = '0'; + return buf + (static_cast(n) + 2); + } + + if (0 < n && n <= max_exp) + { + // dig.its + // len <= max_digits10 + 1 + + JSON_ASSERT(k > n); + + std::memmove(buf + (static_cast(n) + 1), buf + n, static_cast(k) - static_cast(n)); + buf[n] = '.'; + return buf + (static_cast(k) + 1U); + } + + if (min_exp < n && n <= 0) + { + // 0.[000]digits + // len <= 2 + (-min_exp - 1) + max_digits10 + + std::memmove(buf + (2 + static_cast(-n)), buf, static_cast(k)); + buf[0] = '0'; + buf[1] = '.'; + std::memset(buf + 2, '0', static_cast(-n)); + return buf + (2U + static_cast(-n) + static_cast(k)); + } + + if (k == 1) + { + // dE+123 + // len <= 1 + 5 + + buf += 1; + } + else + { + // d.igitsE+123 + // len <= max_digits10 + 1 + 5 + + std::memmove(buf + 2, buf + 1, static_cast(k) - 1); + buf[1] = '.'; + buf += 1 + static_cast(k); + } + + *buf++ = 'e'; + return append_exponent(buf, n - 1); +} + +} // namespace dtoa_impl + +/*! +@brief generates a decimal representation of the floating-point number value in [first, last). + +The format of the resulting decimal representation is similar to printf's %g +format. Returns an iterator pointing past-the-end of the decimal representation. + +@note The input number must be finite, i.e. NaN's and Inf's are not supported. +@note The buffer must be large enough. +@note The result is NOT null-terminated. +*/ +template +JSON_HEDLEY_NON_NULL(1, 2) +JSON_HEDLEY_RETURNS_NON_NULL +char* to_chars(char* first, const char* last, FloatType value) +{ + static_cast(last); // maybe unused - fix warning + JSON_ASSERT(std::isfinite(value)); + + // Use signbit(value) instead of (value < 0) since signbit works for -0. + if (std::signbit(value)) + { + value = -value; + *first++ = '-'; + } + + if (value == 0) // +-0 + { + *first++ = '0'; + // Make it look like a floating-point number (#362, #378) + *first++ = '.'; + *first++ = '0'; + return first; + } + + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10); + + // Compute v = buffer * 10^decimal_exponent. + // The decimal digits are stored in the buffer, which needs to be interpreted + // as an unsigned decimal integer. + // len is the length of the buffer, i.e. the number of decimal digits. + int len = 0; + int decimal_exponent = 0; + dtoa_impl::grisu2(first, len, decimal_exponent, value); + + JSON_ASSERT(len <= std::numeric_limits::max_digits10); + + // Format the buffer like printf("%.*g", prec, value) + constexpr int kMinExp = -4; + // Use digits10 here to increase compatibility with version 2. + constexpr int kMaxExp = std::numeric_limits::digits10; + + JSON_ASSERT(last - first >= kMaxExp + 2); + JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10 + 6); + + return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); +} + +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// serialization // +/////////////////// + +/// how to treat decoding errors +enum class error_handler_t +{ + strict, ///< throw a type_error exception in case of invalid UTF-8 + replace, ///< replace invalid UTF-8 sequences with U+FFFD + ignore ///< ignore invalid UTF-8 sequences +}; + +template +class serializer +{ + using string_t = typename BasicJsonType::string_t; + using number_float_t = typename BasicJsonType::number_float_t; + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using binary_char_t = typename BasicJsonType::binary_t::value_type; + static constexpr std::uint8_t UTF8_ACCEPT = 0; + static constexpr std::uint8_t UTF8_REJECT = 1; + + public: + /*! + @param[in] s output stream to serialize to + @param[in] ichar indentation character to use + @param[in] error_handler_ how to react on decoding errors + */ + serializer(output_adapter_t s, const char ichar, + error_handler_t error_handler_ = error_handler_t::strict) + : o(std::move(s)) + , loc(std::localeconv()) + , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->thousands_sep))) + , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->decimal_point))) + , indent_char(ichar) + , indent_string(512, indent_char) + , error_handler(error_handler_) + {} + + // delete because of pointer members + serializer(const serializer&) = delete; + serializer& operator=(const serializer&) = delete; + serializer(serializer&&) = delete; + serializer& operator=(serializer&&) = delete; + ~serializer() = default; + + /*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is + called recursively. + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + - binary values are serialized as objects containing the subtype and the + byte array + + @param[in] val value to serialize + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ + void dump(const BasicJsonType& val, + const bool pretty_print, + const bool ensure_ascii, + const unsigned int indent_step, + const unsigned int current_indent = 0) + { + switch (val.m_type) + { + case value_t::object: + { + if (val.m_value.object->empty()) + { + o->write_characters("{}", 2); + return; + } + + if (pretty_print) + { + o->write_characters("{\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + JSON_ASSERT(i != val.m_value.object->cend()); + JSON_ASSERT(std::next(i) == val.m_value.object->cend()); + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); + } + else + { + o->write_character('{'); + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + JSON_ASSERT(i != val.m_value.object->cend()); + JSON_ASSERT(std::next(i) == val.m_value.object->cend()); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + + o->write_character('}'); + } + + return; + } + + case value_t::array: + { + if (val.m_value.array->empty()) + { + o->write_characters("[]", 2); + return; + } + + if (pretty_print) + { + o->write_characters("[\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + dump(*i, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + JSON_ASSERT(!val.m_value.array->empty()); + o->write_characters(indent_string.c_str(), new_indent); + dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character(']'); + } + else + { + o->write_character('['); + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + dump(*i, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + JSON_ASSERT(!val.m_value.array->empty()); + dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); + + o->write_character(']'); + } + + return; + } + + case value_t::string: + { + o->write_character('\"'); + dump_escaped(*val.m_value.string, ensure_ascii); + o->write_character('\"'); + return; + } + + case value_t::binary: + { + if (pretty_print) + { + o->write_characters("{\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + o->write_characters(indent_string.c_str(), new_indent); + + o->write_characters("\"bytes\": [", 10); + + if (!val.m_value.binary->empty()) + { + for (auto i = val.m_value.binary->cbegin(); + i != val.m_value.binary->cend() - 1; ++i) + { + dump_integer(*i); + o->write_characters(", ", 2); + } + dump_integer(val.m_value.binary->back()); + } + + o->write_characters("],\n", 3); + o->write_characters(indent_string.c_str(), new_indent); + + o->write_characters("\"subtype\": ", 11); + if (val.m_value.binary->has_subtype()) + { + dump_integer(val.m_value.binary->subtype()); + } + else + { + o->write_characters("null", 4); + } + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); + } + else + { + o->write_characters("{\"bytes\":[", 10); + + if (!val.m_value.binary->empty()) + { + for (auto i = val.m_value.binary->cbegin(); + i != val.m_value.binary->cend() - 1; ++i) + { + dump_integer(*i); + o->write_character(','); + } + dump_integer(val.m_value.binary->back()); + } + + o->write_characters("],\"subtype\":", 12); + if (val.m_value.binary->has_subtype()) + { + dump_integer(val.m_value.binary->subtype()); + o->write_character('}'); + } + else + { + o->write_characters("null}", 5); + } + } + return; + } + + case value_t::boolean: + { + if (val.m_value.boolean) + { + o->write_characters("true", 4); + } + else + { + o->write_characters("false", 5); + } + return; + } + + case value_t::number_integer: + { + dump_integer(val.m_value.number_integer); + return; + } + + case value_t::number_unsigned: + { + dump_integer(val.m_value.number_unsigned); + return; + } + + case value_t::number_float: + { + dump_float(val.m_value.number_float); + return; + } + + case value_t::discarded: + { + o->write_characters("", 11); + return; + } + + case value_t::null: + { + o->write_characters("null", 4); + return; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + } + + private: + /*! + @brief dump escaped string + + Escape a string by replacing certain special characters by a sequence of an + escape character (backslash) and another character and other control + characters by a sequence of "\u" followed by a four-digit hex + representation. The escaped string is written to output stream @a o. + + @param[in] s the string to escape + @param[in] ensure_ascii whether to escape non-ASCII characters with + \uXXXX sequences + + @complexity Linear in the length of string @a s. + */ + void dump_escaped(const string_t& s, const bool ensure_ascii) + { + std::uint32_t codepoint; + std::uint8_t state = UTF8_ACCEPT; + std::size_t bytes = 0; // number of bytes written to string_buffer + + // number of bytes written at the point of the last valid byte + std::size_t bytes_after_last_accept = 0; + std::size_t undumped_chars = 0; + + for (std::size_t i = 0; i < s.size(); ++i) + { + const auto byte = static_cast(s[i]); + + switch (decode(state, codepoint, byte)) + { + case UTF8_ACCEPT: // decode found a new code point + { + switch (codepoint) + { + case 0x08: // backspace + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'b'; + break; + } + + case 0x09: // horizontal tab + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 't'; + break; + } + + case 0x0A: // newline + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'n'; + break; + } + + case 0x0C: // formfeed + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'f'; + break; + } + + case 0x0D: // carriage return + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'r'; + break; + } + + case 0x22: // quotation mark + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = '\"'; + break; + } + + case 0x5C: // reverse solidus + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = '\\'; + break; + } + + default: + { + // escape control characters (0x00..0x1F) or, if + // ensure_ascii parameter is used, non-ASCII characters + if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F))) + { + if (codepoint <= 0xFFFF) + { + (std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", + static_cast(codepoint)); + bytes += 6; + } + else + { + (std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", + static_cast(0xD7C0u + (codepoint >> 10u)), + static_cast(0xDC00u + (codepoint & 0x3FFu))); + bytes += 12; + } + } + else + { + // copy byte to buffer (all previous bytes + // been copied have in default case above) + string_buffer[bytes++] = s[i]; + } + break; + } + } + + // write buffer and reset index; there must be 13 bytes + // left, as this is the maximal number of bytes to be + // written ("\uxxxx\uxxxx\0") for one code point + if (string_buffer.size() - bytes < 13) + { + o->write_characters(string_buffer.data(), bytes); + bytes = 0; + } + + // remember the byte position of this accept + bytes_after_last_accept = bytes; + undumped_chars = 0; + break; + } + + case UTF8_REJECT: // decode found invalid UTF-8 byte + { + switch (error_handler) + { + case error_handler_t::strict: + { + std::string sn(3, '\0'); + (std::snprintf)(&sn[0], sn.size(), "%.2X", byte); + JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn)); + } + + case error_handler_t::ignore: + case error_handler_t::replace: + { + // in case we saw this character the first time, we + // would like to read it again, because the byte + // may be OK for itself, but just not OK for the + // previous sequence + if (undumped_chars > 0) + { + --i; + } + + // reset length buffer to the last accepted index; + // thus removing/ignoring the invalid characters + bytes = bytes_after_last_accept; + + if (error_handler == error_handler_t::replace) + { + // add a replacement character + if (ensure_ascii) + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'u'; + string_buffer[bytes++] = 'f'; + string_buffer[bytes++] = 'f'; + string_buffer[bytes++] = 'f'; + string_buffer[bytes++] = 'd'; + } + else + { + string_buffer[bytes++] = detail::binary_writer::to_char_type('\xEF'); + string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBF'); + string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBD'); + } + + // write buffer and reset index; there must be 13 bytes + // left, as this is the maximal number of bytes to be + // written ("\uxxxx\uxxxx\0") for one code point + if (string_buffer.size() - bytes < 13) + { + o->write_characters(string_buffer.data(), bytes); + bytes = 0; + } + + bytes_after_last_accept = bytes; + } + + undumped_chars = 0; + + // continue processing the string + state = UTF8_ACCEPT; + break; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + break; + } + + default: // decode found yet incomplete multi-byte code point + { + if (!ensure_ascii) + { + // code point will not be escaped - copy byte to buffer + string_buffer[bytes++] = s[i]; + } + ++undumped_chars; + break; + } + } + } + + // we finished processing the string + if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT)) + { + // write buffer + if (bytes > 0) + { + o->write_characters(string_buffer.data(), bytes); + } + } + else + { + // we finish reading, but do not accept: string was incomplete + switch (error_handler) + { + case error_handler_t::strict: + { + std::string sn(3, '\0'); + (std::snprintf)(&sn[0], sn.size(), "%.2X", static_cast(s.back())); + JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn)); + } + + case error_handler_t::ignore: + { + // write all accepted bytes + o->write_characters(string_buffer.data(), bytes_after_last_accept); + break; + } + + case error_handler_t::replace: + { + // write all accepted bytes + o->write_characters(string_buffer.data(), bytes_after_last_accept); + // add a replacement character + if (ensure_ascii) + { + o->write_characters("\\ufffd", 6); + } + else + { + o->write_characters("\xEF\xBF\xBD", 3); + } + break; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + } + } + + /*! + @brief count digits + + Count the number of decimal (base 10) digits for an input unsigned integer. + + @param[in] x unsigned integer number to count its digits + @return number of decimal digits + */ + inline unsigned int count_digits(number_unsigned_t x) noexcept + { + unsigned int n_digits = 1; + for (;;) + { + if (x < 10) + { + return n_digits; + } + if (x < 100) + { + return n_digits + 1; + } + if (x < 1000) + { + return n_digits + 2; + } + if (x < 10000) + { + return n_digits + 3; + } + x = x / 10000u; + n_digits += 4; + } + } + + /*! + @brief dump an integer + + Dump a given integer to output stream @a o. Works internally with + @a number_buffer. + + @param[in] x integer number (signed or unsigned) to dump + @tparam NumberType either @a number_integer_t or @a number_unsigned_t + */ + template < typename NumberType, detail::enable_if_t < + std::is_same::value || + std::is_same::value || + std::is_same::value, + int > = 0 > + void dump_integer(NumberType x) + { + static constexpr std::array, 100> digits_to_99 + { + { + {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}}, + {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}}, + {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}}, + {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}}, + {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}}, + {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}}, + {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}}, + {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}}, + {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}}, + {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}}, + } + }; + + // special case for "0" + if (x == 0) + { + o->write_character('0'); + return; + } + + // use a pointer to fill the buffer + auto buffer_ptr = number_buffer.begin(); + + const bool is_negative = std::is_same::value && !(x >= 0); // see issue #755 + number_unsigned_t abs_value; + + unsigned int n_chars; + + if (is_negative) + { + *buffer_ptr = '-'; + abs_value = remove_sign(static_cast(x)); + + // account one more byte for the minus sign + n_chars = 1 + count_digits(abs_value); + } + else + { + abs_value = static_cast(x); + n_chars = count_digits(abs_value); + } + + // spare 1 byte for '\0' + JSON_ASSERT(n_chars < number_buffer.size() - 1); + + // jump to the end to generate the string from backward + // so we later avoid reversing the result + buffer_ptr += n_chars; + + // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu + // See: https://www.youtube.com/watch?v=o4-CwDo2zpg + while (abs_value >= 100) + { + const auto digits_index = static_cast((abs_value % 100)); + abs_value /= 100; + *(--buffer_ptr) = digits_to_99[digits_index][1]; + *(--buffer_ptr) = digits_to_99[digits_index][0]; + } + + if (abs_value >= 10) + { + const auto digits_index = static_cast(abs_value); + *(--buffer_ptr) = digits_to_99[digits_index][1]; + *(--buffer_ptr) = digits_to_99[digits_index][0]; + } + else + { + *(--buffer_ptr) = static_cast('0' + abs_value); + } + + o->write_characters(number_buffer.data(), n_chars); + } + + /*! + @brief dump a floating-point number + + Dump a given floating-point number to output stream @a o. Works internally + with @a number_buffer. + + @param[in] x floating-point number to dump + */ + void dump_float(number_float_t x) + { + // NaN / inf + if (!std::isfinite(x)) + { + o->write_characters("null", 4); + return; + } + + // If number_float_t is an IEEE-754 single or double precision number, + // use the Grisu2 algorithm to produce short numbers which are + // guaranteed to round-trip, using strtof and strtod, resp. + // + // NB: The test below works if == . + static constexpr bool is_ieee_single_or_double + = (std::numeric_limits::is_iec559 && std::numeric_limits::digits == 24 && std::numeric_limits::max_exponent == 128) || + (std::numeric_limits::is_iec559 && std::numeric_limits::digits == 53 && std::numeric_limits::max_exponent == 1024); + + dump_float(x, std::integral_constant()); + } + + void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/) + { + char* begin = number_buffer.data(); + char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x); + + o->write_characters(begin, static_cast(end - begin)); + } + + void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) + { + // get number of digits for a float -> text -> float round-trip + static constexpr auto d = std::numeric_limits::max_digits10; + + // the actual conversion + std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x); + + // negative value indicates an error + JSON_ASSERT(len > 0); + // check if buffer was large enough + JSON_ASSERT(static_cast(len) < number_buffer.size()); + + // erase thousands separator + if (thousands_sep != '\0') + { + const auto end = std::remove(number_buffer.begin(), + number_buffer.begin() + len, thousands_sep); + std::fill(end, number_buffer.end(), '\0'); + JSON_ASSERT((end - number_buffer.begin()) <= len); + len = (end - number_buffer.begin()); + } + + // convert decimal point to '.' + if (decimal_point != '\0' && decimal_point != '.') + { + const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); + if (dec_pos != number_buffer.end()) + { + *dec_pos = '.'; + } + } + + o->write_characters(number_buffer.data(), static_cast(len)); + + // determine if need to append ".0" + const bool value_is_int_like = + std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, + [](char c) + { + return c == '.' || c == 'e'; + }); + + if (value_is_int_like) + { + o->write_characters(".0", 2); + } + } + + /*! + @brief check whether a string is UTF-8 encoded + + The function checks each byte of a string whether it is UTF-8 encoded. The + result of the check is stored in the @a state parameter. The function must + be called initially with state 0 (accept). State 1 means the string must + be rejected, because the current byte is not allowed. If the string is + completely processed, but the state is non-zero, the string ended + prematurely; that is, the last byte indicated more bytes should have + followed. + + @param[in,out] state the state of the decoding + @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT) + @param[in] byte next byte to decode + @return new state + + @note The function has been edited: a std::array is used. + + @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann + @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + */ + static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept + { + static const std::array utf8d = + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF + 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF + 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF + 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF + 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 + 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 + 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 + 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 + } + }; + + const std::uint8_t type = utf8d[byte]; + + codep = (state != UTF8_ACCEPT) + ? (byte & 0x3fu) | (codep << 6u) + : (0xFFu >> type) & (byte); + + std::size_t index = 256u + static_cast(state) * 16u + static_cast(type); + JSON_ASSERT(index < 400); + state = utf8d[index]; + return state; + } + + /* + * Overload to make the compiler happy while it is instantiating + * dump_integer for number_unsigned_t. + * Must never be called. + */ + number_unsigned_t remove_sign(number_unsigned_t x) + { + JSON_ASSERT(false); // LCOV_EXCL_LINE + return x; // LCOV_EXCL_LINE + } + + /* + * Helper function for dump_integer + * + * This function takes a negative signed integer and returns its absolute + * value as unsigned integer. The plus/minus shuffling is necessary as we can + * not directly remove the sign of an arbitrary signed integer as the + * absolute values of INT_MIN and INT_MAX are usually not the same. See + * #1708 for details. + */ + inline number_unsigned_t remove_sign(number_integer_t x) noexcept + { + JSON_ASSERT(x < 0 && x < (std::numeric_limits::max)()); + return static_cast(-(x + 1)) + 1; + } + + private: + /// the output of the serializer + output_adapter_t o = nullptr; + + /// a (hopefully) large enough character buffer + std::array number_buffer{{}}; + + /// the locale + const std::lconv* loc = nullptr; + /// the locale's thousand separator character + const char thousands_sep = '\0'; + /// the locale's decimal point character + const char decimal_point = '\0'; + + /// string buffer + std::array string_buffer{{}}; + + /// the indentation character + const char indent_char; + /// the indentation string + string_t indent_string; + + /// error_handler how to react on decoding errors + const error_handler_t error_handler; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + + +#include // less +#include // allocator +#include // pair +#include // vector + +namespace nlohmann +{ + +/// ordered_map: a minimal map-like container that preserves insertion order +/// for use within nlohmann::basic_json +template , + class Allocator = std::allocator>> + struct ordered_map : std::vector, Allocator> +{ + using key_type = Key; + using mapped_type = T; + using Container = std::vector, Allocator>; + using typename Container::iterator; + using typename Container::const_iterator; + using typename Container::size_type; + using typename Container::value_type; + + // Explicit constructors instead of `using Container::Container` + // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) + ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {} + template + ordered_map(It first, It last, const Allocator& alloc = Allocator()) + : Container{first, last, alloc} {} + ordered_map(std::initializer_list init, const Allocator& alloc = Allocator() ) + : Container{init, alloc} {} + + std::pair emplace(const key_type& key, T&& t) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return {it, false}; + } + } + Container::emplace_back(key, t); + return {--this->end(), true}; + } + + T& operator[](const Key& key) + { + return emplace(key, T{}).first->second; + } + + const T& operator[](const Key& key) const + { + return at(key); + } + + T& at(const Key& key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return it->second; + } + } + + throw std::out_of_range("key not found"); + } + + const T& at(const Key& key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return it->second; + } + } + + throw std::out_of_range("key not found"); + } + + size_type erase(const Key& key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + // Since we cannot move const Keys, re-construct them in place + for (auto next = it; ++next != this->end(); ++it) + { + it->~value_type(); // Destroy but keep allocation + new (&*it) value_type{std::move(*next)}; + } + Container::pop_back(); + return 1; + } + } + return 0; + } + + iterator erase(iterator pos) + { + auto it = pos; + + // Since we cannot move const Keys, re-construct them in place + for (auto next = it; ++next != this->end(); ++it) + { + it->~value_type(); // Destroy but keep allocation + new (&*it) value_type{std::move(*next)}; + } + Container::pop_back(); + return pos; + } + + size_type count(const Key& key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return 1; + } + } + return 0; + } + + iterator find(const Key& key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return it; + } + } + return Container::end(); + } + + const_iterator find(const Key& key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return it; + } + } + return Container::end(); + } + + std::pair insert( value_type&& value ) + { + return emplace(value.first, std::move(value.second)); + } + + std::pair insert( const value_type& value ) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == value.first) + { + return {it, false}; + } + } + Container::push_back(value); + return {--this->end(), true}; + } +}; + +} // namespace nlohmann + + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ + +/*! +@brief a class to store JSON values + +@tparam ObjectType type for JSON objects (`std::map` by default; will be used +in @ref object_t) +@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used +in @ref array_t) +@tparam StringType type for JSON strings and object keys (`std::string` by +default; will be used in @ref string_t) +@tparam BooleanType type for JSON booleans (`bool` by default; will be used +in @ref boolean_t) +@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by +default; will be used in @ref number_integer_t) +@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c +`uint64_t` by default; will be used in @ref number_unsigned_t) +@tparam NumberFloatType type for JSON floating-point numbers (`double` by +default; will be used in @ref number_float_t) +@tparam BinaryType type for packed binary data for compatibility with binary +serialization formats (`std::vector` by default; will be used in +@ref binary_t) +@tparam AllocatorType type of the allocator to use (`std::allocator` by +default) +@tparam JSONSerializer the serializer to resolve internal calls to `to_json()` +and `from_json()` (@ref adl_serializer by default) + +@requirement The class satisfies the following concept requirements: +- Basic + - [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible): + JSON values can be default constructed. The result will be a JSON null + value. + - [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible): + A JSON value can be constructed from an rvalue argument. + - [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible): + A JSON value can be copy-constructed from an lvalue expression. + - [MoveAssignable](https://en.cppreference.com/w/cpp/named_req/MoveAssignable): + A JSON value van be assigned from an rvalue argument. + - [CopyAssignable](https://en.cppreference.com/w/cpp/named_req/CopyAssignable): + A JSON value can be copy-assigned from an lvalue expression. + - [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible): + JSON values can be destructed. +- Layout + - [StandardLayoutType](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType): + JSON values have + [standard layout](https://en.cppreference.com/w/cpp/language/data_members#Standard_layout): + All non-static data members are private and standard layout types, the + class has no virtual functions or (virtual) base classes. +- Library-wide + - [EqualityComparable](https://en.cppreference.com/w/cpp/named_req/EqualityComparable): + JSON values can be compared with `==`, see @ref + operator==(const_reference,const_reference). + - [LessThanComparable](https://en.cppreference.com/w/cpp/named_req/LessThanComparable): + JSON values can be compared with `<`, see @ref + operator<(const_reference,const_reference). + - [Swappable](https://en.cppreference.com/w/cpp/named_req/Swappable): + Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of + other compatible types, using unqualified function call @ref swap(). + - [NullablePointer](https://en.cppreference.com/w/cpp/named_req/NullablePointer): + JSON values can be compared against `std::nullptr_t` objects which are used + to model the `null` value. +- Container + - [Container](https://en.cppreference.com/w/cpp/named_req/Container): + JSON values can be used like STL containers and provide iterator access. + - [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer); + JSON values can be used like STL containers and provide reverse iterator + access. + +@invariant The member variables @a m_value and @a m_type have the following +relationship: +- If `m_type == value_t::object`, then `m_value.object != nullptr`. +- If `m_type == value_t::array`, then `m_value.array != nullptr`. +- If `m_type == value_t::string`, then `m_value.string != nullptr`. +The invariants are checked by member function assert_invariant(). + +@internal +@note ObjectType trick from https://stackoverflow.com/a/9860911 +@endinternal + +@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange +Format](http://rfc7159.net/rfc7159) + +@since version 1.0.0 + +@nosubgrouping +*/ +NLOHMANN_BASIC_JSON_TPL_DECLARATION +class basic_json +{ + private: + template friend struct detail::external_constructor; + friend ::nlohmann::json_pointer; + + template + friend class ::nlohmann::detail::parser; + friend ::nlohmann::detail::serializer; + template + friend class ::nlohmann::detail::iter_impl; + template + friend class ::nlohmann::detail::binary_writer; + template + friend class ::nlohmann::detail::binary_reader; + template + friend class ::nlohmann::detail::json_sax_dom_parser; + template + friend class ::nlohmann::detail::json_sax_dom_callback_parser; + + /// workaround type for MSVC + using basic_json_t = NLOHMANN_BASIC_JSON_TPL; + + // convenience aliases for types residing in namespace detail; + using lexer = ::nlohmann::detail::lexer_base; + + template + static ::nlohmann::detail::parser parser( + InputAdapterType adapter, + detail::parser_callback_tcb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false + ) + { + return ::nlohmann::detail::parser(std::move(adapter), + std::move(cb), allow_exceptions, ignore_comments); + } + + using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; + template + using internal_iterator = ::nlohmann::detail::internal_iterator; + template + using iter_impl = ::nlohmann::detail::iter_impl; + template + using iteration_proxy = ::nlohmann::detail::iteration_proxy; + template using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator; + + template + using output_adapter_t = ::nlohmann::detail::output_adapter_t; + + template + using binary_reader = ::nlohmann::detail::binary_reader; + template using binary_writer = ::nlohmann::detail::binary_writer; + + using serializer = ::nlohmann::detail::serializer; + + public: + using value_t = detail::value_t; + /// JSON Pointer, see @ref nlohmann::json_pointer + using json_pointer = ::nlohmann::json_pointer; + template + using json_serializer = JSONSerializer; + /// how to treat decoding errors + using error_handler_t = detail::error_handler_t; + /// how to treat CBOR tags + using cbor_tag_handler_t = detail::cbor_tag_handler_t; + /// helper type for initializer lists of basic_json values + using initializer_list_t = std::initializer_list>; + + using input_format_t = detail::input_format_t; + /// SAX interface type, see @ref nlohmann::json_sax + using json_sax_t = json_sax; + + //////////////// + // exceptions // + //////////////// + + /// @name exceptions + /// Classes to implement user-defined exceptions. + /// @{ + + /// @copydoc detail::exception + using exception = detail::exception; + /// @copydoc detail::parse_error + using parse_error = detail::parse_error; + /// @copydoc detail::invalid_iterator + using invalid_iterator = detail::invalid_iterator; + /// @copydoc detail::type_error + using type_error = detail::type_error; + /// @copydoc detail::out_of_range + using out_of_range = detail::out_of_range; + /// @copydoc detail::other_error + using other_error = detail::other_error; + + /// @} + + + ///////////////////// + // container types // + ///////////////////// + + /// @name container types + /// The canonic container types to use @ref basic_json like any other STL + /// container. + /// @{ + + /// the type of elements in a basic_json container + using value_type = basic_json; + + /// the type of an element reference + using reference = value_type&; + /// the type of an element const reference + using const_reference = const value_type&; + + /// a type to represent differences between iterators + using difference_type = std::ptrdiff_t; + /// a type to represent container sizes + using size_type = std::size_t; + + /// the allocator type + using allocator_type = AllocatorType; + + /// the type of an element pointer + using pointer = typename std::allocator_traits::pointer; + /// the type of an element const pointer + using const_pointer = typename std::allocator_traits::const_pointer; + + /// an iterator for a basic_json container + using iterator = iter_impl; + /// a const iterator for a basic_json container + using const_iterator = iter_impl; + /// a reverse iterator for a basic_json container + using reverse_iterator = json_reverse_iterator; + /// a const reverse iterator for a basic_json container + using const_reverse_iterator = json_reverse_iterator; + + /// @} + + + /*! + @brief returns the allocator associated with the container + */ + static allocator_type get_allocator() + { + return allocator_type(); + } + + /*! + @brief returns version information on the library + + This function returns a JSON object with information about the library, + including the version number and information on the platform and compiler. + + @return JSON object holding version information + key | description + ----------- | --------------- + `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). + `copyright` | The copyright line for the library as string. + `name` | The name of the library as string. + `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. + `url` | The URL of the project as string. + `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). + + @liveexample{The following code shows an example output of the `meta()` + function.,meta} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @complexity Constant. + + @since 2.1.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json meta() + { + basic_json result; + + result["copyright"] = "(C) 2013-2020 Niels Lohmann"; + result["name"] = "JSON for Modern C++"; + result["url"] = "https://github.com/nlohmann/json"; + result["version"]["string"] = + std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + "." + + std::to_string(NLOHMANN_JSON_VERSION_MINOR) + "." + + std::to_string(NLOHMANN_JSON_VERSION_PATCH); + result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR; + result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR; + result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH; + +#ifdef _WIN32 + result["platform"] = "win32"; +#elif defined __linux__ + result["platform"] = "linux"; +#elif defined __APPLE__ + result["platform"] = "apple"; +#elif defined __unix__ + result["platform"] = "unix"; +#else + result["platform"] = "unknown"; +#endif + +#if defined(__ICC) || defined(__INTEL_COMPILER) + result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; +#elif defined(__clang__) + result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; +#elif defined(__GNUC__) || defined(__GNUG__) + result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; +#elif defined(__HP_cc) || defined(__HP_aCC) + result["compiler"] = "hp" +#elif defined(__IBMCPP__) + result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; +#elif defined(_MSC_VER) + result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; +#elif defined(__PGI) + result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; +#elif defined(__SUNPRO_CC) + result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; +#else + result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; +#endif + +#ifdef __cplusplus + result["compiler"]["c++"] = std::to_string(__cplusplus); +#else + result["compiler"]["c++"] = "unknown"; +#endif + return result; + } + + + /////////////////////////// + // JSON value data types // + /////////////////////////// + + /// @name JSON value data types + /// The data types to store a JSON value. These types are derived from + /// the template arguments passed to class @ref basic_json. + /// @{ + +#if defined(JSON_HAS_CPP_14) + // Use transparent comparator if possible, combined with perfect forwarding + // on find() and count() calls prevents unnecessary string construction. + using object_comparator_t = std::less<>; +#else + using object_comparator_t = std::less; +#endif + + /*! + @brief a type for an object + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: + > An object is an unordered collection of zero or more name/value pairs, + > where a name is a string and a value is a string, number, boolean, null, + > object, or array. + + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). + The comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) + + #### Default type + + With the default values for @a ObjectType (`std::map`), @a StringType + (`std::string`), and @a AllocatorType (`std::allocator`), the default + value for @a object_t is: + + @code {.cpp} + std::map< + std::string, // key_type + basic_json, // value_type + std::less, // key_compare + std::allocator> // allocator_type + > + @endcode + + #### Behavior + + The choice of @a object_t influences the behavior of the JSON class. With + the default type, objects have the following behavior: + + - When all names are unique, objects will be interoperable in the sense + that all software implementations receiving that object will agree on + the name-value mappings. + - When the names within an object are not unique, it is unspecified which + one of the values for a given key will be chosen. For instance, + `{"key": 2, "key": 1}` could be equal to either `{"key": 1}` or + `{"key": 2}`. + - Internally, name/value pairs are stored in lexicographical order of the + names. Objects will also be serialized (see @ref dump) in this order. + For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored + and serialized as `{"a": 2, "b": 1}`. + - When comparing objects, the order of the name/value pairs is irrelevant. + This makes objects interoperable in the sense that they will not be + affected by these differences. For instance, `{"b": 1, "a": 2}` and + `{"a": 2, "b": 1}` will be treated as equal. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the object's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON object. + + #### Storage + + Objects are stored as pointers in a @ref basic_json type. That is, for any + access to object values, a pointer of type `object_t*` must be + dereferenced. + + @sa @ref array_t -- type for an array value + + @since version 1.0.0 + + @note The order name/value pairs are added to the object is *not* + preserved by the library. Therefore, iterating an object may return + name/value pairs in a different order than they were originally stored. In + fact, keys will be traversed in alphabetical order as `std::map` with + `std::less` is used by default. Please note this behavior conforms to [RFC + 7159](http://rfc7159.net/rfc7159), because any order implements the + specified "unordered" nature of JSON objects. + */ + using object_t = ObjectType>>; + + /*! + @brief a type for an array + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: + > An array is an ordered sequence of zero or more values. + + To store objects in C++, a type is defined by the template parameters + explained below. + + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) + + #### Default type + + With the default values for @a ArrayType (`std::vector`) and @a + AllocatorType (`std::allocator`), the default value for @a array_t is: + + @code {.cpp} + std::vector< + basic_json, // value_type + std::allocator // allocator_type + > + @endcode + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the array's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON array. + + #### Storage + + Arrays are stored as pointers in a @ref basic_json type. That is, for any + access to array values, a pointer of type `array_t*` must be dereferenced. + + @sa @ref object_t -- type for an object value + + @since version 1.0.0 + */ + using array_t = ArrayType>; + + /*! + @brief a type for a string + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: + > A string is a sequence of zero or more Unicode characters. + + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into + byte-sized characters during deserialization. + + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. + + #### Default type + + With the default values for @a StringType (`std::string`), the default + value for @a string_t is: + + @code {.cpp} + std::string + @endcode + + #### Encoding + + Strings are stored in UTF-8 encoding. Therefore, functions like + `std::string::size()` or `std::string::length()` return the number of + bytes in the string rather than the number of characters or glyphs. + + #### String comparison + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > Software implementations are typically required to test names of object + > members for equality. Implementations that transform the textual + > representation into sequences of Unicode code units and then perform the + > comparison numerically, code unit by code unit, are interoperable in the + > sense that implementations will agree in all cases on equality or + > inequality of two strings. For example, implementations that compare + > strings with escaped characters unconverted may incorrectly find that + > `"a\\b"` and `"a\u005Cb"` are not equal. + + This implementation is interoperable as it does compare strings code unit + by code unit. + + #### Storage + + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be + dereferenced. + + @since version 1.0.0 + */ + using string_t = StringType; + + /*! + @brief a type for a boolean + + [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a + type which differentiates the two literals `true` and `false`. + + To store objects in C++, a type is defined by the template parameter @a + BooleanType which chooses the type to use. + + #### Default type + + With the default values for @a BooleanType (`bool`), the default value for + @a boolean_t is: + + @code {.cpp} + bool + @endcode + + #### Storage + + Boolean values are stored directly inside a @ref basic_json type. + + @since version 1.0.0 + */ + using boolean_t = BooleanType; + + /*! + @brief a type for a number (integer) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store integer numbers in C++, a type is defined by the template + parameter @a NumberIntegerType which chooses the type to use. + + #### Default type + + With the default values for @a NumberIntegerType (`int64_t`), the default + value for @a number_integer_t is: + + @code {.cpp} + int64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `9223372036854775807` (INT64_MAX) and the minimal integer number + that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers + that are out of range will yield over/underflow when used in a + constructor. During deserialization, too large or small integer numbers + will be automatically be stored as @ref number_unsigned_t or @ref + number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange of the exactly supported range [INT64_MIN, + INT64_MAX], this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_integer_t = NumberIntegerType; + + /*! + @brief a type for a number (unsigned) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store unsigned integer numbers in C++, a type is defined by the + template parameter @a NumberUnsignedType which chooses the type to use. + + #### Default type + + With the default values for @a NumberUnsignedType (`uint64_t`), the + default value for @a number_unsigned_t is: + + @code {.cpp} + uint64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer + number that can be stored is `0`. Integer numbers that are out of range + will yield over/underflow when used in a constructor. During + deserialization, too large or small integer numbers will be automatically + be stored as @ref number_integer_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], + this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + @sa @ref number_integer_t -- type for number values (integer) + + @since version 2.0.0 + */ + using number_unsigned_t = NumberUnsignedType; + + /*! + @brief a type for a number (floating-point) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store floating-point numbers in C++, a type is defined by the template + parameter @a NumberFloatType which chooses the type to use. + + #### Default type + + With the default values for @a NumberFloatType (`double`), the default + value for @a number_float_t is: + + @code {.cpp} + double + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in floating-point literals will be ignored. Internally, + the value will be stored as decimal number. For instance, the C++ + floating-point literal `01.2` will be serialized to `1.2`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > This specification allows implementations to set limits on the range and + > precision of numbers accepted. Since software that implements IEEE + > 754-2008 binary64 (double precision) numbers is generally available and + > widely used, good interoperability can be achieved by implementations + > that expect no more precision or range than these provide, in the sense + > that implementations will approximate JSON numbers within the expected + > precision. + + This implementation does exactly follow this approach, as it uses double + precision floating-point numbers. Note values smaller than + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` + will be stored as NaN internally and be serialized to `null`. + + #### Storage + + Floating-point number values are stored directly inside a @ref basic_json + type. + + @sa @ref number_integer_t -- type for number values (integer) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_float_t = NumberFloatType; + + /*! + @brief a type for a packed binary type + + This type is a type designed to carry binary data that appears in various + serialized formats, such as CBOR's Major Type 2, MessagePack's bin, and + BSON's generic binary subtype. This type is NOT a part of standard JSON and + exists solely for compatibility with these binary types. As such, it is + simply defined as an ordered sequence of zero or more byte values. + + Additionally, as an implementation detail, the subtype of the binary data is + carried around as a `std::uint8_t`, which is compatible with both of the + binary data formats that use binary subtyping, (though the specific + numbering is incompatible with each other, and it is up to the user to + translate between them). + + [CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type + as: + > Major type 2: a byte string. The string's length in bytes is represented + > following the rules for positive integers (major type 0). + + [MessagePack's documentation on the bin type + family](https://github.com/msgpack/msgpack/blob/master/spec.md#bin-format-family) + describes this type as: + > Bin format family stores an byte array in 2, 3, or 5 bytes of extra bytes + > in addition to the size of the byte array. + + [BSON's specifications](http://bsonspec.org/spec.html) describe several + binary types; however, this type is intended to represent the generic binary + type which has the description: + > Generic binary subtype - This is the most commonly used binary subtype and + > should be the 'default' for drivers and tools. + + None of these impose any limitations on the internal representation other + than the basic unit of storage be some type of array whose parts are + decomposable into bytes. + + The default representation of this binary format is a + `std::vector`, which is a very common way to represent a byte + array in modern C++. + + #### Default type + + The default values for @a BinaryType is `std::vector` + + #### Storage + + Binary Arrays are stored as pointers in a @ref basic_json type. That is, + for any access to array values, a pointer of the type `binary_t*` must be + dereferenced. + + #### Notes on subtypes + + - CBOR + - Binary values are represented as byte strings. No subtypes are + supported and will be ignored when CBOR is written. + - MessagePack + - If a subtype is given and the binary array contains exactly 1, 2, 4, 8, + or 16 elements, the fixext family (fixext1, fixext2, fixext4, fixext8) + is used. For other sizes, the ext family (ext8, ext16, ext32) is used. + The subtype is then added as singed 8-bit integer. + - If no subtype is given, the bin family (bin8, bin16, bin32) is used. + - BSON + - If a subtype is given, it is used and added as unsigned 8-bit integer. + - If no subtype is given, the generic binary subtype 0x00 is used. + + @sa @ref binary -- create a binary array + + @since version 3.8.0 + */ + using binary_t = nlohmann::byte_container_with_subtype; + /// @} + + private: + + /// helper for exception-safe object creation + template + JSON_HEDLEY_RETURNS_NON_NULL + static T* create(Args&& ... args) + { + AllocatorType alloc; + using AllocatorTraits = std::allocator_traits>; + + auto deleter = [&](T * object) + { + AllocatorTraits::deallocate(alloc, object, 1); + }; + std::unique_ptr object(AllocatorTraits::allocate(alloc, 1), deleter); + AllocatorTraits::construct(alloc, object.get(), std::forward(args)...); + JSON_ASSERT(object != nullptr); + return object.release(); + } + + //////////////////////// + // JSON value storage // + //////////////////////// + + /*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. This + union combines the different storage types for the JSON value types + defined in @ref value_t. + + JSON type | value_t type | used type + --------- | --------------- | ------------------------ + object | object | pointer to @ref object_t + array | array | pointer to @ref array_t + string | string | pointer to @ref string_t + boolean | boolean | @ref boolean_t + number | number_integer | @ref number_integer_t + number | number_unsigned | @ref number_unsigned_t + number | number_float | @ref number_float_t + binary | binary | pointer to @ref binary_t + null | null | *no value is stored* + + @note Variable-length types (objects, arrays, and strings) are stored as + pointers. The size of the union should not exceed 64 bits if the default + value types are used. + + @since version 1.0.0 + */ + union json_value + { + /// object (stored with pointer to save storage) + object_t* object; + /// array (stored with pointer to save storage) + array_t* array; + /// string (stored with pointer to save storage) + string_t* string; + /// binary (stored with pointer to save storage) + binary_t* binary; + /// boolean + boolean_t boolean; + /// number (integer) + number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; + /// number (floating-point) + number_float_t number_float; + + /// default constructor (for null values) + json_value() = default; + /// constructor for booleans + json_value(boolean_t v) noexcept : boolean(v) {} + /// constructor for numbers (integer) + json_value(number_integer_t v) noexcept : number_integer(v) {} + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} + /// constructor for numbers (floating-point) + json_value(number_float_t v) noexcept : number_float(v) {} + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) + { + case value_t::object: + { + object = create(); + break; + } + + case value_t::array: + { + array = create(); + break; + } + + case value_t::string: + { + string = create(""); + break; + } + + case value_t::binary: + { + binary = create(); + break; + } + + case value_t::boolean: + { + boolean = boolean_t(false); + break; + } + + case value_t::number_integer: + { + number_integer = number_integer_t(0); + break; + } + + case value_t::number_unsigned: + { + number_unsigned = number_unsigned_t(0); + break; + } + + case value_t::number_float: + { + number_float = number_float_t(0.0); + break; + } + + case value_t::null: + { + object = nullptr; // silence warning, see #821 + break; + } + + default: + { + object = nullptr; // silence warning, see #821 + if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) + { + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.9.1")); // LCOV_EXCL_LINE + } + break; + } + } + } + + /// constructor for strings + json_value(const string_t& value) + { + string = create(value); + } + + /// constructor for rvalue strings + json_value(string_t&& value) + { + string = create(std::move(value)); + } + + /// constructor for objects + json_value(const object_t& value) + { + object = create(value); + } + + /// constructor for rvalue objects + json_value(object_t&& value) + { + object = create(std::move(value)); + } + + /// constructor for arrays + json_value(const array_t& value) + { + array = create(value); + } + + /// constructor for rvalue arrays + json_value(array_t&& value) + { + array = create(std::move(value)); + } + + /// constructor for binary arrays + json_value(const typename binary_t::container_type& value) + { + binary = create(value); + } + + /// constructor for rvalue binary arrays + json_value(typename binary_t::container_type&& value) + { + binary = create(std::move(value)); + } + + /// constructor for binary arrays (internal type) + json_value(const binary_t& value) + { + binary = create(value); + } + + /// constructor for rvalue binary arrays (internal type) + json_value(binary_t&& value) + { + binary = create(std::move(value)); + } + + void destroy(value_t t) noexcept + { + // flatten the current json_value to a heap-allocated stack + std::vector stack; + + // move the top-level items to stack + if (t == value_t::array) + { + stack.reserve(array->size()); + std::move(array->begin(), array->end(), std::back_inserter(stack)); + } + else if (t == value_t::object) + { + stack.reserve(object->size()); + for (auto&& it : *object) + { + stack.push_back(std::move(it.second)); + } + } + + while (!stack.empty()) + { + // move the last item to local variable to be processed + basic_json current_item(std::move(stack.back())); + stack.pop_back(); + + // if current_item is array/object, move + // its children to the stack to be processed later + if (current_item.is_array()) + { + std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(), + std::back_inserter(stack)); + + current_item.m_value.array->clear(); + } + else if (current_item.is_object()) + { + for (auto&& it : *current_item.m_value.object) + { + stack.push_back(std::move(it.second)); + } + + current_item.m_value.object->clear(); + } + + // it's now safe that current_item get destructed + // since it doesn't have any children + } + + switch (t) + { + case value_t::object: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, object); + std::allocator_traits::deallocate(alloc, object, 1); + break; + } + + case value_t::array: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, array); + std::allocator_traits::deallocate(alloc, array, 1); + break; + } + + case value_t::string: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, string); + std::allocator_traits::deallocate(alloc, string, 1); + break; + } + + case value_t::binary: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, binary); + std::allocator_traits::deallocate(alloc, binary, 1); + break; + } + + default: + { + break; + } + } + } + }; + + /*! + @brief checks the class invariants + + This function asserts the class invariants. It needs to be called at the + end of every constructor to make sure that created objects respect the + invariant. Furthermore, it has to be called each time the type of a JSON + value is changed, because the invariant expresses a relationship between + @a m_type and @a m_value. + */ + void assert_invariant() const noexcept + { + JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr); + JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr); + JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr); + JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr); + } + + public: + ////////////////////////// + // JSON parser callback // + ////////////////////////// + + /*! + @brief parser event types + + The parser callback distinguishes the following events: + - `object_start`: the parser read `{` and started to process a JSON object + - `key`: the parser read a key of a value in an object + - `object_end`: the parser read `}` and finished processing a JSON object + - `array_start`: the parser read `[` and started to process a JSON array + - `array_end`: the parser read `]` and finished processing a JSON array + - `value`: the parser finished reading a JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + @sa @ref parser_callback_t for more information and examples + */ + using parse_event_t = detail::parse_event_t; + + /*! + @brief per-element parser callback type + + With a parser callback function, the result of parsing a JSON text can be + influenced. When passed to @ref parse, it is called on certain events + (passed as @ref parse_event_t via parameter @a event) with a set recursion + depth @a depth and context JSON value @a parsed. The return value of the + callback function is a boolean indicating whether the element that emitted + the callback shall be kept or not. + + We distinguish six scenarios (determined by the event type) in which the + callback function can be called. The following table describes the values + of the parameters @a depth, @a event, and @a parsed. + + parameter @a event | description | parameter @a depth | parameter @a parsed + ------------------ | ----------- | ------------------ | ------------------- + parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded + parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key + parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object + parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded + parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array + parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: + + - Discarded values in structured types are skipped. That is, the parser + will behave as if the discarded value was never read. + - In case a value outside a structured type is skipped, it is replaced + with `null`. This case happens if the top-level element is skipped. + + @param[in] depth the depth of the recursion during parsing + + @param[in] event an event of type parse_event_t indicating the context in + the callback function has been called + + @param[in,out] parsed the current intermediate parse result; note that + writing to this value has no effect for parse_event_t::key events + + @return Whether the JSON value which called the function during parsing + should be kept (`true`) or not (`false`). In the latter case, it is either + skipped completely or replaced by an empty discarded object. + + @sa @ref parse for examples + + @since version 1.0.0 + */ + using parser_callback_t = detail::parser_callback_t; + + ////////////////// + // constructors // + ////////////////// + + /// @name constructors and destructors + /// Constructors of class @ref basic_json, copy/move constructor, copy + /// assignment, static functions creating objects, and the destructor. + /// @{ + + /*! + @brief create an empty value with a given type + + Create an empty JSON value with a given type. The value will be default + initialized with an empty value which depends on the type: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + binary | empty array + + @param[in] v the type of the value to create + + @complexity Constant. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows the constructor for different @ref + value_t values,basic_json__value_t} + + @sa @ref clear() -- restores the postcondition of this constructor + + @since version 1.0.0 + */ + basic_json(const value_t v) + : m_type(v), m_value(v) + { + assert_invariant(); + } + + /*! + @brief create a null object + + Create a `null` JSON value. It either takes a null pointer as parameter + (explicitly creating `null`) or no parameter (implicitly creating `null`). + The passed null pointer itself is not read -- it is only used to choose + the right constructor. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @liveexample{The following code shows the constructor with and without a + null pointer parameter.,basic_json__nullptr_t} + + @since version 1.0.0 + */ + basic_json(std::nullptr_t = nullptr) noexcept + : basic_json(value_t::null) + { + assert_invariant(); + } + + /*! + @brief create a JSON value + + This is a "catch all" constructor for all compatible JSON types; that is, + types for which a `to_json()` method exists. The constructor forwards the + parameter @a val to that method (to `json_serializer::to_json` method + with `U = uncvref_t`, to be exact). + + Template type @a CompatibleType includes, but is not limited to, the + following types: + - **arrays**: @ref array_t and all kinds of compatible containers such as + `std::vector`, `std::deque`, `std::list`, `std::forward_list`, + `std::array`, `std::valarray`, `std::set`, `std::unordered_set`, + `std::multiset`, and `std::unordered_multiset` with a `value_type` from + which a @ref basic_json value can be constructed. + - **objects**: @ref object_t and all kinds of compatible associative + containers such as `std::map`, `std::unordered_map`, `std::multimap`, + and `std::unordered_multimap` with a `key_type` compatible to + @ref string_t and a `value_type` from which a @ref basic_json value can + be constructed. + - **strings**: @ref string_t, string literals, and all compatible string + containers can be used. + - **numbers**: @ref number_integer_t, @ref number_unsigned_t, + @ref number_float_t, and all convertible number types such as `int`, + `size_t`, `int64_t`, `float` or `double` can be used. + - **boolean**: @ref boolean_t / `bool` can be used. + - **binary**: @ref binary_t / `std::vector` may be used, + unfortunately because string literals cannot be distinguished from binary + character arrays by the C++ type system, all types compatible with `const + char*` will be directed to the string constructor instead. This is both + for backwards compatibility, and due to the fact that a binary type is not + a standard JSON type. + + See the examples below. + + @tparam CompatibleType a type such that: + - @a CompatibleType is not derived from `std::istream`, + - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move + constructors), + - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments) + - @a CompatibleType is not a @ref basic_json nested type (e.g., + @ref json_pointer, @ref iterator, etc ...) + - @ref @ref json_serializer has a + `to_json(basic_json_t&, CompatibleType&&)` method + + @tparam U = `uncvref_t` + + @param[in] val the value to be forwarded to the respective constructor + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @liveexample{The following code shows the constructor with several + compatible types.,basic_json__CompatibleType} + + @since version 2.1.0 + */ + template < typename CompatibleType, + typename U = detail::uncvref_t, + detail::enable_if_t < + !detail::is_basic_json::value && detail::is_compatible_type::value, int > = 0 > + basic_json(CompatibleType && val) noexcept(noexcept( + JSONSerializer::to_json(std::declval(), + std::forward(val)))) + { + JSONSerializer::to_json(*this, std::forward(val)); + assert_invariant(); + } + + /*! + @brief create a JSON value from an existing one + + This is a constructor for existing @ref basic_json types. + It does not hijack copy/move constructors, since the parameter has different + template arguments than the current ones. + + The constructor tries to convert the internal @ref m_value of the parameter. + + @tparam BasicJsonType a type such that: + - @a BasicJsonType is a @ref basic_json type. + - @a BasicJsonType has different template arguments than @ref basic_json_t. + + @param[in] val the @ref basic_json value to be converted. + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @since version 3.2.0 + */ + template < typename BasicJsonType, + detail::enable_if_t < + detail::is_basic_json::value&& !std::is_same::value, int > = 0 > + basic_json(const BasicJsonType& val) + { + using other_boolean_t = typename BasicJsonType::boolean_t; + using other_number_float_t = typename BasicJsonType::number_float_t; + using other_number_integer_t = typename BasicJsonType::number_integer_t; + using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using other_string_t = typename BasicJsonType::string_t; + using other_object_t = typename BasicJsonType::object_t; + using other_array_t = typename BasicJsonType::array_t; + using other_binary_t = typename BasicJsonType::binary_t; + + switch (val.type()) + { + case value_t::boolean: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_float: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_integer: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_unsigned: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::string: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::object: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::array: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::binary: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::null: + *this = nullptr; + break; + case value_t::discarded: + m_type = value_t::discarded; + break; + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + assert_invariant(); + } + + /*! + @brief create a container (array or object) from an initializer list + + Creates a JSON value of type array or object from the passed initializer + list @a init. In case @a type_deduction is `true` (default), the type of + the JSON value to be created is deducted from the initializer list @a init + according to the following rules: + + 1. If the list is empty, an empty JSON object value `{}` is created. + 2. If the list consists of pairs whose first element is a string, a JSON + object value is created where the first elements of the pairs are + treated as keys and the second elements are as values. + 3. In all other cases, an array is created. + + The rules aim to create the best fit between a C++ initializer list and + JSON values. The rationale is as follows: + + 1. The empty initializer list is written as `{}` which is exactly an empty + JSON object. + 2. C++ has no way of describing mapped types other than to list a list of + pairs. As JSON requires that keys must be of type string, rule 2 is the + weakest constraint one can pose on initializer lists to interpret them + as an object. + 3. In all other cases, the initializer list could not be interpreted as + JSON object type, so interpreting it as JSON array type is safe. + + With the rules described above, the following JSON values cannot be + expressed by an initializer list: + + - the empty array (`[]`): use @ref array(initializer_list_t) + with an empty initializer list in this case + - arrays whose elements satisfy rule 2: use @ref + array(initializer_list_t) with the same initializer list + in this case + + @note When used without parentheses around an empty initializer list, @ref + basic_json() is called instead of this function, yielding the JSON null + value. + + @param[in] init initializer list with JSON values + + @param[in] type_deduction internal parameter; when set to `true`, the type + of the JSON value is deducted from the initializer list @a init; when set + to `false`, the type provided via @a manual_type is forced. This mode is + used by the functions @ref array(initializer_list_t) and + @ref object(initializer_list_t). + + @param[in] manual_type internal parameter; when @a type_deduction is set + to `false`, the created JSON value will use the provided type (only @ref + value_t::array and @ref value_t::object are valid); when @a type_deduction + is set to `true`, this parameter has no effect + + @throw type_error.301 if @a type_deduction is `false`, @a manual_type is + `value_t::object`, but @a init contains an element which is not a pair + whose first element is a string. In this case, the constructor could not + create an object. If @a type_deduction would have be `true`, an array + would have been created. See @ref object(initializer_list_t) + for an example. + + @complexity Linear in the size of the initializer list @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows how JSON values are created from + initializer lists.,basic_json__list_init_t} + + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + basic_json(initializer_list_t init, + bool type_deduction = true, + value_t manual_type = value_t::array) + { + // check if each element is an array with two elements whose first + // element is a string + bool is_an_object = std::all_of(init.begin(), init.end(), + [](const detail::json_ref& element_ref) + { + return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[0].is_string(); + }); + + // adjust type if type deduction is not wanted + if (!type_deduction) + { + // if array is wanted, do not create an object though possible + if (manual_type == value_t::array) + { + is_an_object = false; + } + + // if object is wanted but impossible, throw an exception + if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object)) + { + JSON_THROW(type_error::create(301, "cannot create object from initializer list")); + } + } + + if (is_an_object) + { + // the initializer list is a list of pairs -> create object + m_type = value_t::object; + m_value = value_t::object; + + std::for_each(init.begin(), init.end(), [this](const detail::json_ref& element_ref) + { + auto element = element_ref.moved_or_copied(); + m_value.object->emplace( + std::move(*((*element.m_value.array)[0].m_value.string)), + std::move((*element.m_value.array)[1])); + }); + } + else + { + // the initializer list describes an array -> create array + m_type = value_t::array; + m_value.array = create(init.begin(), init.end()); + } + + assert_invariant(); + } + + /*! + @brief explicitly create a binary array (without subtype) + + Creates a JSON binary array value from a given binary container. Binary + values are part of various binary formats, such as CBOR, MessagePack, and + BSON. This constructor is used to create a value for serialization to those + formats. + + @note Note, this function exists because of the difficulty in correctly + specifying the correct template overload in the standard value ctor, as both + JSON arrays and JSON binary arrays are backed with some form of a + `std::vector`. Because JSON binary arrays are a non-standard extension it + was decided that it would be best to prevent automatic initialization of a + binary array type, for backwards compatibility and so it does not happen on + accident. + + @param[in] init container containing bytes to use as binary type + + @return JSON binary array value + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @since version 3.8.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(const typename binary_t::container_type& init) + { + auto res = basic_json(); + res.m_type = value_t::binary; + res.m_value = init; + return res; + } + + /*! + @brief explicitly create a binary array (with subtype) + + Creates a JSON binary array value from a given binary container. Binary + values are part of various binary formats, such as CBOR, MessagePack, and + BSON. This constructor is used to create a value for serialization to those + formats. + + @note Note, this function exists because of the difficulty in correctly + specifying the correct template overload in the standard value ctor, as both + JSON arrays and JSON binary arrays are backed with some form of a + `std::vector`. Because JSON binary arrays are a non-standard extension it + was decided that it would be best to prevent automatic initialization of a + binary array type, for backwards compatibility and so it does not happen on + accident. + + @param[in] init container containing bytes to use as binary type + @param[in] subtype subtype to use in MessagePack and BSON + + @return JSON binary array value + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @since version 3.8.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(const typename binary_t::container_type& init, std::uint8_t subtype) + { + auto res = basic_json(); + res.m_type = value_t::binary; + res.m_value = binary_t(init, subtype); + return res; + } + + /// @copydoc binary(const typename binary_t::container_type&) + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(typename binary_t::container_type&& init) + { + auto res = basic_json(); + res.m_type = value_t::binary; + res.m_value = std::move(init); + return res; + } + + /// @copydoc binary(const typename binary_t::container_type&, std::uint8_t) + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(typename binary_t::container_type&& init, std::uint8_t subtype) + { + auto res = basic_json(); + res.m_type = value_t::binary; + res.m_value = binary_t(std::move(init), subtype); + return res; + } + + /*! + @brief explicitly create an array from an initializer list + + Creates a JSON array value from a given initializer list. That is, given a + list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the + initializer list is empty, the empty array `[]` is created. + + @note This function is only needed to express two edge cases that cannot + be realized with the initializer list constructor (@ref + basic_json(initializer_list_t, bool, value_t)). These cases + are: + 1. creating an array whose elements are all pairs whose first element is a + string -- in this case, the initializer list constructor would create an + object, taking the first elements as keys + 2. creating an empty array -- passing the empty initializer list to the + initializer list constructor yields an empty object + + @param[in] init initializer list with JSON values to create an array from + (optional) + + @return JSON array value + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `array` + function.,array} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json array(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::array); + } + + /*! + @brief explicitly create an object from an initializer list + + Creates a JSON object value from a given initializer list. The initializer + lists elements must be pairs, and their first elements must be strings. If + the initializer list is empty, the empty object `{}` is created. + + @note This function is only added for symmetry reasons. In contrast to the + related function @ref array(initializer_list_t), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor @ref basic_json(initializer_list_t, bool, value_t). + + @param[in] init initializer list to create an object from (optional) + + @return JSON object value + + @throw type_error.301 if @a init is not a list of pairs whose first + elements are strings. In this case, no object can be created. When such a + value is passed to @ref basic_json(initializer_list_t, bool, value_t), + an array would have been created from the passed initializer list @a init. + See example below. + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `object` + function.,object} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + + @since version 1.0.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json object(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::object); + } + + /*! + @brief construct an array with count copies of given value + + Constructs a JSON array value by creating @a cnt copies of a passed value. + In case @a cnt is `0`, an empty array is created. + + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy + + @post `std::distance(begin(),end()) == cnt` holds. + + @complexity Linear in @a cnt. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows examples for the @ref + basic_json(size_type\, const basic_json&) + constructor.,basic_json__size_type_basic_json} + + @since version 1.0.0 + */ + basic_json(size_type cnt, const basic_json& val) + : m_type(value_t::array) + { + m_value.array = create(cnt, val); + assert_invariant(); + } + + /*! + @brief construct a JSON container given an iterator range + + Constructs the JSON value with the contents of the range `[first, last)`. + The semantics depends on the different types a JSON value can have: + - In case of a null type, invalid_iterator.206 is thrown. + - In case of other primitive types (number, boolean, or string), @a first + must be `begin()` and @a last must be `end()`. In this case, the value is + copied. Otherwise, invalid_iterator.204 is thrown. + - In case of structured types (array, object), the constructor behaves as + similar versions for `std::vector` or `std::map`; that is, a JSON array + or object is constructed from the values in the range. + + @tparam InputIT an input iterator type (@ref iterator or @ref + const_iterator) + + @param[in] first begin of the range to copy from (included) + @param[in] last end of the range to copy from (excluded) + + @pre Iterators @a first and @a last must be initialized. **This + precondition is enforced with an assertion (see warning).** If + assertions are switched off, a violation of this precondition yields + undefined behavior. + + @pre Range `[first, last)` is valid. Usually, this precondition cannot be + checked efficiently. Only certain edge cases are detected; see the + description of the exceptions below. A violation of this precondition + yields undefined behavior. + + @warning A precondition is enforced with a runtime assertion that will + result in calling `std::abort` if this precondition is not met. + Assertions can be disabled by defining `NDEBUG` at compile time. + See https://en.cppreference.com/w/cpp/error/assert for more + information. + + @throw invalid_iterator.201 if iterators @a first and @a last are not + compatible (i.e., do not belong to the same JSON value). In this case, + the range `[first, last)` is undefined. + @throw invalid_iterator.204 if iterators @a first and @a last belong to a + primitive type (number, boolean, or string), but @a first does not point + to the first element any more. In this case, the range `[first, last)` is + undefined. See example code below. + @throw invalid_iterator.206 if iterators @a first and @a last belong to a + null value. In this case, the range `[first, last)` is undefined. + + @complexity Linear in distance between @a first and @a last. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows several ways to create JSON values by + specifying a subrange with iterators.,basic_json__InputIt_InputIt} + + @since version 1.0.0 + */ + template < class InputIT, typename std::enable_if < + std::is_same::value || + std::is_same::value, int >::type = 0 > + basic_json(InputIT first, InputIT last) + { + JSON_ASSERT(first.m_object != nullptr); + JSON_ASSERT(last.m_object != nullptr); + + // make sure iterator fits the current value + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(201, "iterators are not compatible")); + } + + // copy type from first iterator + m_type = first.m_object->m_type; + + // check if iterator range is complete for primitive values + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin() + || !last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); + } + break; + } + + default: + break; + } + + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = first.m_object->m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = first.m_object->m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value.number_float = first.m_object->m_value.number_float; + break; + } + + case value_t::boolean: + { + m_value.boolean = first.m_object->m_value.boolean; + break; + } + + case value_t::string: + { + m_value = *first.m_object->m_value.string; + break; + } + + case value_t::object: + { + m_value.object = create(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + m_value.array = create(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + case value_t::binary: + { + m_value = *first.m_object->m_value.binary; + break; + } + + default: + JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + + std::string(first.m_object->type_name()))); + } + + assert_invariant(); + } + + + /////////////////////////////////////// + // other constructors and destructor // + /////////////////////////////////////// + + template, + std::is_same>::value, int> = 0 > + basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {} + + /*! + @brief copy constructor + + Creates a copy of a given JSON value. + + @param[in] other the JSON value to copy + + @post `*this == other` + + @complexity Linear in the size of @a other. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is linear. + - As postcondition, it holds: `other == basic_json(other)`. + + @liveexample{The following code shows an example for the copy + constructor.,basic_json__basic_json} + + @since version 1.0.0 + */ + basic_json(const basic_json& other) + : m_type(other.m_type) + { + // check of passed value is valid + other.assert_invariant(); + + switch (m_type) + { + case value_t::object: + { + m_value = *other.m_value.object; + break; + } + + case value_t::array: + { + m_value = *other.m_value.array; + break; + } + + case value_t::string: + { + m_value = *other.m_value.string; + break; + } + + case value_t::boolean: + { + m_value = other.m_value.boolean; + break; + } + + case value_t::number_integer: + { + m_value = other.m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value = other.m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value = other.m_value.number_float; + break; + } + + case value_t::binary: + { + m_value = *other.m_value.binary; + break; + } + + default: + break; + } + + assert_invariant(); + } + + /*! + @brief move constructor + + Move constructor. Constructs a JSON value with the contents of the given + value @a other using move semantics. It "steals" the resources from @a + other and leaves it as JSON null value. + + @param[in,out] other value to move to this object + + @post `*this` has the same value as @a other before the call. + @post @a other is a JSON null value. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @requirement This function helps `basic_json` satisfying the + [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible) + requirements. + + @liveexample{The code below shows the move constructor explicitly called + via std::move.,basic_json__moveconstructor} + + @since version 1.0.0 + */ + basic_json(basic_json&& other) noexcept + : m_type(std::move(other.m_type)), + m_value(std::move(other.m_value)) + { + // check that passed value is valid + other.assert_invariant(); + + // invalidate payload + other.m_type = value_t::null; + other.m_value = {}; + + assert_invariant(); + } + + /*! + @brief copy assignment + + Copy assignment operator. Copies a JSON value via the "copy and swap" + strategy: It is expressed in terms of the copy constructor, destructor, + and the `swap()` member function. + + @param[in] other value to copy from + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is linear. + + @liveexample{The code below shows and example for the copy assignment. It + creates a copy of value `a` which is then swapped with `b`. Finally\, the + copy of `a` (which is the null value after the swap) is + destroyed.,basic_json__copyassignment} + + @since version 1.0.0 + */ + basic_json& operator=(basic_json other) noexcept ( + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value + ) + { + // check that passed value is valid + other.assert_invariant(); + + using std::swap; + swap(m_type, other.m_type); + swap(m_value, other.m_value); + + assert_invariant(); + return *this; + } + + /*! + @brief destructor + + Destroys the JSON value and frees all allocated memory. + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is linear. + - All stored elements are destroyed and all memory is freed. + + @since version 1.0.0 + */ + ~basic_json() noexcept + { + assert_invariant(); + m_value.destroy(m_type); + } + + /// @} + + public: + /////////////////////// + // object inspection // + /////////////////////// + + /// @name object inspection + /// Functions to inspect the type of a JSON value. + /// @{ + + /*! + @brief serialization + + Serialization function for JSON values. The function tries to mimic + Python's `json.dumps()` function, and currently supports its @a indent + and @a ensure_ascii parameters. + + @param[in] indent If indent is nonnegative, then array elements and object + members will be pretty-printed with that indent level. An indent level of + `0` will only insert newlines. `-1` (the default) selects the most compact + representation. + @param[in] indent_char The character to use for indentation if @a indent is + greater than `0`. The default is ` ` (space). + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. + @param[in] error_handler how to react on decoding errors; there are three + possible values: `strict` (throws and exception in case a decoding error + occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD), + and `ignore` (ignore invalid UTF-8 sequences during serialization; all + bytes are copied to the output unchanged). + + @return string containing the serialization of the JSON value + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded and @a error_handler is set to strict + + @note Binary values are serialized as object containing two keys: + - "bytes": an array of bytes as integers + - "subtype": the subtype as integer or "null" if the binary has no subtype + + @complexity Linear. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @liveexample{The following example shows the effect of different @a indent\, + @a indent_char\, and @a ensure_ascii parameters to the result of the + serialization.,dump} + + @see https://docs.python.org/2/library/json.html#json.dump + + @since version 1.0.0; indentation character @a indent_char, option + @a ensure_ascii and exceptions added in version 3.0.0; error + handlers added in version 3.4.0; serialization of binary values added + in version 3.8.0. + */ + string_t dump(const int indent = -1, + const char indent_char = ' ', + const bool ensure_ascii = false, + const error_handler_t error_handler = error_handler_t::strict) const + { + string_t result; + serializer s(detail::output_adapter(result), indent_char, error_handler); + + if (indent >= 0) + { + s.dump(*this, true, ensure_ascii, static_cast(indent)); + } + else + { + s.dump(*this, false, ensure_ascii, 0); + } + + return result; + } + + /*! + @brief return the type of the JSON value (explicit) + + Return the type of the JSON value as a value from the @ref value_t + enumeration. + + @return the type of the JSON value + Value type | return value + ------------------------- | ------------------------- + null | value_t::null + boolean | value_t::boolean + string | value_t::string + number (integer) | value_t::number_integer + number (unsigned integer) | value_t::number_unsigned + number (floating-point) | value_t::number_float + object | value_t::object + array | value_t::array + binary | value_t::binary + discarded | value_t::discarded + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `type()` for all JSON + types.,type} + + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ + constexpr value_t type() const noexcept + { + return m_type; + } + + /*! + @brief return whether type is primitive + + This function returns true if and only if the JSON type is primitive + (string, number, boolean, or null). + + @return `true` if type is primitive (string, number, boolean, or null), + `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_primitive()` for all JSON + types.,is_primitive} + + @sa @ref is_structured() -- returns whether JSON value is structured + @sa @ref is_null() -- returns whether JSON value is `null` + @sa @ref is_string() -- returns whether JSON value is a string + @sa @ref is_boolean() -- returns whether JSON value is a boolean + @sa @ref is_number() -- returns whether JSON value is a number + @sa @ref is_binary() -- returns whether JSON value is a binary array + + @since version 1.0.0 + */ + constexpr bool is_primitive() const noexcept + { + return is_null() || is_string() || is_boolean() || is_number() || is_binary(); + } + + /*! + @brief return whether type is structured + + This function returns true if and only if the JSON type is structured + (array or object). + + @return `true` if type is structured (array or object), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_structured()` for all JSON + types.,is_structured} + + @sa @ref is_primitive() -- returns whether value is primitive + @sa @ref is_array() -- returns whether value is an array + @sa @ref is_object() -- returns whether value is an object + + @since version 1.0.0 + */ + constexpr bool is_structured() const noexcept + { + return is_array() || is_object(); + } + + /*! + @brief return whether value is null + + This function returns true if and only if the JSON value is null. + + @return `true` if type is null, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_null()` for all JSON + types.,is_null} + + @since version 1.0.0 + */ + constexpr bool is_null() const noexcept + { + return m_type == value_t::null; + } + + /*! + @brief return whether value is a boolean + + This function returns true if and only if the JSON value is a boolean. + + @return `true` if type is boolean, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_boolean()` for all JSON + types.,is_boolean} + + @since version 1.0.0 + */ + constexpr bool is_boolean() const noexcept + { + return m_type == value_t::boolean; + } + + /*! + @brief return whether value is a number + + This function returns true if and only if the JSON value is a number. This + includes both integer (signed and unsigned) and floating-point values. + + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number()` for all JSON + types.,is_number} + + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number() const noexcept + { + return is_number_integer() || is_number_float(); + } + + /*! + @brief return whether value is an integer number + + This function returns true if and only if the JSON value is a signed or + unsigned integer number. This excludes floating-point values. + + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_integer()` for all + JSON types.,is_number_integer} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number_integer() const noexcept + { + return m_type == value_t::number_integer || m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is an unsigned integer number + + This function returns true if and only if the JSON value is an unsigned + integer number. This excludes floating-point and signed integer values. + + @return `true` if type is an unsigned integer number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_unsigned()` for all + JSON types.,is_number_unsigned} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 2.0.0 + */ + constexpr bool is_number_unsigned() const noexcept + { + return m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is a floating-point number + + This function returns true if and only if the JSON value is a + floating-point number. This excludes signed and unsigned integer values. + + @return `true` if type is a floating-point number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_float()` for all + JSON types.,is_number_float} + + @sa @ref is_number() -- check if value is number + @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + + @since version 1.0.0 + */ + constexpr bool is_number_float() const noexcept + { + return m_type == value_t::number_float; + } + + /*! + @brief return whether value is an object + + This function returns true if and only if the JSON value is an object. + + @return `true` if type is object, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_object()` for all JSON + types.,is_object} + + @since version 1.0.0 + */ + constexpr bool is_object() const noexcept + { + return m_type == value_t::object; + } + + /*! + @brief return whether value is an array + + This function returns true if and only if the JSON value is an array. + + @return `true` if type is array, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_array()` for all JSON + types.,is_array} + + @since version 1.0.0 + */ + constexpr bool is_array() const noexcept + { + return m_type == value_t::array; + } + + /*! + @brief return whether value is a string + + This function returns true if and only if the JSON value is a string. + + @return `true` if type is string, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_string()` for all JSON + types.,is_string} + + @since version 1.0.0 + */ + constexpr bool is_string() const noexcept + { + return m_type == value_t::string; + } + + /*! + @brief return whether value is a binary array + + This function returns true if and only if the JSON value is a binary array. + + @return `true` if type is binary array, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_binary()` for all JSON + types.,is_binary} + + @since version 3.8.0 + */ + constexpr bool is_binary() const noexcept + { + return m_type == value_t::binary; + } + + /*! + @brief return whether value is discarded + + This function returns true if and only if the JSON value was discarded + during parsing with a callback function (see @ref parser_callback_t). + + @note This function will always be `false` for JSON values after parsing. + That is, discarded values can only occur during parsing, but will be + removed when inside a structured value or replaced by null in other cases. + + @return `true` if type is discarded, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_discarded()` for all JSON + types.,is_discarded} + + @since version 1.0.0 + */ + constexpr bool is_discarded() const noexcept + { + return m_type == value_t::discarded; + } + + /*! + @brief return the type of the JSON value (implicit) + + Implicitly return the type of the JSON value as a value from the @ref + value_t enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies the @ref value_t operator for + all JSON types.,operator__value_t} + + @sa @ref type() -- return the type of the JSON value (explicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ + constexpr operator value_t() const noexcept + { + return m_type; + } + + /// @} + + private: + ////////////////// + // value access // + ////////////////// + + /// get a boolean (explicit) + boolean_t get_impl(boolean_t* /*unused*/) const + { + if (JSON_HEDLEY_LIKELY(is_boolean())) + { + return m_value.boolean; + } + + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name()))); + } + + /// get a pointer to the value (object) + object_t* get_impl_ptr(object_t* /*unused*/) noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (object) + constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (array) + array_t* get_impl_ptr(array_t* /*unused*/) noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (array) + constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (string) + string_t* get_impl_ptr(string_t* /*unused*/) noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (string) + constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (boolean) + boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (boolean) + constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (integer number) + number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (integer number) + constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (unsigned number) + number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (unsigned number) + constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (floating-point number) + number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /// get a pointer to the value (floating-point number) + constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /// get a pointer to the value (binary) + binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept + { + return is_binary() ? m_value.binary : nullptr; + } + + /// get a pointer to the value (binary) + constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept + { + return is_binary() ? m_value.binary : nullptr; + } + + /*! + @brief helper function to implement get_ref() + + This function helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw type_error.303 if ReferenceType does not match underlying value + type of the current JSON + */ + template + static ReferenceType get_ref_impl(ThisType& obj) + { + // delegate the call to get_ptr<>() + auto ptr = obj.template get_ptr::type>(); + + if (JSON_HEDLEY_LIKELY(ptr != nullptr)) + { + return *ptr; + } + + JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name()))); + } + + public: + /// @name value access + /// Direct access to the stored value of a JSON value. + /// @{ + + /*! + @brief get special-case overload + + This overloads avoids a lot of template boilerplate, it can be seen as the + identity method + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this + + @complexity Constant. + + @since version 2.1.0 + */ + template::type, basic_json_t>::value, + int> = 0> + basic_json get() const + { + return *this; + } + + /*! + @brief get special-case overload + + This overloads converts the current @ref basic_json in a different + @ref basic_json type + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this, converted into @tparam BasicJsonType + + @complexity Depending on the implementation of the called `from_json()` + method. + + @since version 3.2.0 + */ + template < typename BasicJsonType, detail::enable_if_t < + !std::is_same::value&& + detail::is_basic_json::value, int > = 0 > + BasicJsonType get() const + { + return *this; + } + + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value + which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) + and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and + - @ref json_serializer does not have a `from_json()` method of + the form `ValueType from_json(const basic_json&)` + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get__ValueType_const} + + @since version 2.1.0 + */ + template < typename ValueTypeCV, typename ValueType = detail::uncvref_t, + detail::enable_if_t < + !detail::is_basic_json::value && + detail::has_from_json::value && + !detail::has_non_default_from_json::value, + int > = 0 > + ValueType get() const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), std::declval()))) + { + // we cannot static_assert on ValueTypeCV being non-const, because + // there is support for get(), which is why we + // still need the uncvref + static_assert(!std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + static_assert(std::is_default_constructible::value, + "types must be DefaultConstructible when used with get()"); + + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + } + + /*! + @brief get a value (explicit); special case + + Explicit type conversion between the JSON value and a compatible value + which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) + and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + return JSONSerializer::from_json(*this); + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json and + - @ref json_serializer has a `from_json()` method of the form + `ValueType from_json(const basic_json&)` + + @note If @ref json_serializer has both overloads of + `from_json()`, this one is chosen. + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @since version 2.1.0 + */ + template < typename ValueTypeCV, typename ValueType = detail::uncvref_t, + detail::enable_if_t < !std::is_same::value && + detail::has_non_default_from_json::value, + int > = 0 > + ValueType get() const noexcept(noexcept( + JSONSerializer::from_json(std::declval()))) + { + static_assert(!std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + return JSONSerializer::from_json(*this); + } + + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value. + The value is filled into the input parameter by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + ValueType v; + JSONSerializer::from_json(*this, v); + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and + + @tparam ValueType the input parameter type. + + @return the input parameter, allowing chaining calls. + + @throw what @ref json_serializer `from_json()` method throws + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get_to} + + @since version 3.3.0 + */ + template < typename ValueType, + detail::enable_if_t < + !detail::is_basic_json::value&& + detail::has_from_json::value, + int > = 0 > + ValueType & get_to(ValueType& v) const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), v))) + { + JSONSerializer::from_json(*this, v); + return v; + } + + // specialization to allow to call get_to with a basic_json value + // see https://github.com/nlohmann/json/issues/2175 + template::value, + int> = 0> + ValueType & get_to(ValueType& v) const + { + v = *this; + return v; + } + + template < + typename T, std::size_t N, + typename Array = T (&)[N], + detail::enable_if_t < + detail::has_from_json::value, int > = 0 > + Array get_to(T (&v)[N]) const + noexcept(noexcept(JSONSerializer::from_json( + std::declval(), v))) + { + JSONSerializer::from_json(*this, v); + return v; + } + + + /*! + @brief get a pointer value (implicit) + + Implicit pointer access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the pointee of the result yields an undefined + state. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. Enforced by a static + assertion. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get_ptr} + + @since version 1.0.0 + */ + template::value, int>::type = 0> + auto get_ptr() noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) + { + // delegate the call to get_impl_ptr<>() + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (implicit) + @copydoc get_ptr() + */ + template < typename PointerType, typename std::enable_if < + std::is_pointer::value&& + std::is_const::type>::value, int >::type = 0 > + constexpr auto get_ptr() const noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) + { + // delegate the call to get_impl_ptr<>() const + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template::value, int>::type = 0> + auto get() noexcept -> decltype(std::declval().template get_ptr()) + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template::value, int>::type = 0> + constexpr auto get() const noexcept -> decltype(std::declval().template get_ptr()) + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a reference value (implicit) + + Implicit reference access to the internally stored JSON value. No copies + are made. + + @warning Writing data to the referee of the result yields an undefined + state. + + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. Enforced by static assertion. + + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + type_error.303 otherwise + + @throw type_error.303 in case passed type @a ReferenceType is incompatible + with the stored JSON value; see example below + + @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.1.0 + */ + template::value, int>::type = 0> + ReferenceType get_ref() + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a reference value (implicit) + @copydoc get_ref() + */ + template < typename ReferenceType, typename std::enable_if < + std::is_reference::value&& + std::is_const::type>::value, int >::type = 0 > + ReferenceType get_ref() const + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a value (implicit) + + Implicit type conversion between the JSON value and a compatible value. + The call is realized by calling @ref get() const. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays. The character type of @ref string_t + as well as an initializer list of this type is excluded to avoid + ambiguities as these types implicitly convert to `std::string`. + + @return copy of the JSON value, converted to type @a ValueType + + @throw type_error.302 in case passed type @a ValueType is incompatible + to the JSON value type (e.g., the JSON value is of type boolean, but a + string is requested); see example below + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0.0 + */ + template < typename ValueType, typename std::enable_if < + !std::is_pointer::value&& + !std::is_same>::value&& + !std::is_same::value&& + !detail::is_basic_json::value + && !std::is_same>::value +#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914)) + && !std::is_same::value +#endif + && detail::is_detected::value + , int >::type = 0 > + JSON_EXPLICIT operator ValueType() const + { + // delegate the call to get<>() const + return get(); + } + + /*! + @return reference to the binary value + + @throw type_error.302 if the value is not binary + + @sa @ref is_binary() to check if the value is binary + + @since version 3.8.0 + */ + binary_t& get_binary() + { + if (!is_binary()) + { + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()))); + } + + return *get_ptr(); + } + + /// @copydoc get_binary() + const binary_t& get_binary() const + { + if (!is_binary()) + { + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()))); + } + + return *get_ptr(); + } + + /// @} + + + //////////////////// + // element access // + //////////////////// + + /// @name element access + /// Access to the JSON value. + /// @{ + + /*! + @brief access specified array element with bounds checking + + Returns a reference to the element at specified location @a idx, with + bounds checking. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__size_type} + */ + reference at(size_type idx) + { + // at only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified array element with bounds checking + + Returns a const reference to the element at specified location @a idx, + with bounds checking. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__size_type_const} + */ + const_reference at(size_type idx) const + { + // at only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a reference to the element at with specified key @a key, with + bounds checking. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__object_t_key_type} + */ + reference at(const typename object_t::key_type& key) + { + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a const reference to the element at with specified key @a key, + with bounds checking. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__object_t_key_type_const} + */ + const_reference at(const typename object_t::key_type& key) const + { + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified array element + + Returns a reference to the element at specified location @a idx. + + @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), + then the array is silently filled up with `null` values to make `idx` a + valid reference to the last stored element. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array or null; in that + cases, using the [] operator with an index makes no sense. + + @complexity Constant if @a idx is in the range of the array. Otherwise + linear in `idx - size()`. + + @liveexample{The example below shows how array elements can be read and + written using `[]` operator. Note the addition of `null` + values.,operatorarray__size_type} + + @since version 1.0.0 + */ + reference operator[](size_type idx) + { + // implicitly convert null value to an empty array + if (is_null()) + { + m_type = value_t::array; + m_value.array = create(); + assert_invariant(); + } + + // operator[] only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + // fill up array with null values if given idx is outside range + if (idx >= m_value.array->size()) + { + m_value.array->insert(m_value.array->end(), + idx - m_value.array->size() + 1, + basic_json()); + } + + return m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); + } + + /*! + @brief access specified array element + + Returns a const reference to the element at specified location @a idx. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array; in that case, + using the [] operator with an index makes no sense. + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + the `[]` operator.,operatorarray__size_type_const} + + @since version 1.0.0 + */ + const_reference operator[](size_type idx) const + { + // const operator[] only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + return m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + reference operator[](const typename object_t::key_type& key) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + // operator[] only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + return m_value.object->operator[](key); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + const_reference operator[](const typename object_t::key_type& key) const + { + // const operator[] only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + JSON_HEDLEY_NON_NULL(2) + reference operator[](T* key) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + return m_value.object->operator[](key); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + JSON_HEDLEY_NON_NULL(2) + const_reference operator[](T* key) const + { + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); + } + + /*! + @brief access specified object element with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(key); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. + + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. + + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.302 if @a default_value does not match the type of the + value at @a key + @throw type_error.306 if the JSON value is not an object; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + + @since version 1.0.0 + */ + // using std::is_convertible in a std::enable_if will fail when using explicit conversions + template < class ValueType, typename std::enable_if < + detail::is_getable::value + && !std::is_same::value, int >::type = 0 > + ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const + { + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return it->template get(); + } + + return default_value; + } + + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const typename object_t::key_type&, const ValueType&) const + */ + string_t value(const typename object_t::key_type& key, const char* default_value) const + { + return value(key, string_t(default_value)); + } + + /*! + @brief access specified object element via JSON Pointer with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(ptr); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const json_pointer&), this function does not throw + if the given key @a key was not found. + + @param[in] ptr a JSON pointer to the element to access + @param[in] default_value the value to return if @a ptr found no value + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.302 if @a default_value does not match the type of the + value at @a ptr + @throw type_error.306 if the JSON value is not an object; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value_ptr} + + @sa @ref operator[](const json_pointer&) for unchecked access by reference + + @since version 2.0.2 + */ + template::value, int>::type = 0> + ValueType value(const json_pointer& ptr, const ValueType& default_value) const + { + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + // if pointer resolves a value, return it or use default value + JSON_TRY + { + return ptr.get_checked(this).template get(); + } + JSON_INTERNAL_CATCH (out_of_range&) + { + return default_value; + } + } + + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const json_pointer&, ValueType) const + */ + JSON_HEDLEY_NON_NULL(3) + string_t value(const json_pointer& ptr, const char* default_value) const + { + return value(ptr, string_t(default_value)); + } + + /*! + @brief access the first element + + Returns a reference to the first element in the container. For a JSON + container `c`, the expression `c.front()` is equivalent to `*c.begin()`. + + @return In case of a structured type (array or object), a reference to the + first element is returned. In case of number, string, boolean, or binary + values, a reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on `null` value + + @liveexample{The following code shows an example for `front()`.,front} + + @sa @ref back() -- access the last element + + @since version 1.0.0 + */ + reference front() + { + return *begin(); + } + + /*! + @copydoc basic_json::front() + */ + const_reference front() const + { + return *cbegin(); + } + + /*! + @brief access the last element + + Returns a reference to the last element in the container. For a JSON + container `c`, the expression `c.back()` is equivalent to + @code {.cpp} + auto tmp = c.end(); + --tmp; + return *tmp; + @endcode + + @return In case of a structured type (array or object), a reference to the + last element is returned. In case of number, string, boolean, or binary + values, a reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on a `null` value. See example + below. + + @liveexample{The following code shows an example for `back()`.,back} + + @sa @ref front() -- access the first element + + @since version 1.0.0 + */ + reference back() + { + auto tmp = end(); + --tmp; + return *tmp; + } + + /*! + @copydoc basic_json::back() + */ + const_reference back() const + { + auto tmp = cend(); + --tmp; + return *tmp; + } + + /*! + @brief remove element given an iterator + + Removes the element specified by iterator @a pos. The iterator @a pos must + be valid and dereferenceable. Thus the `end()` iterator (which is valid, + but is not dereferenceable) cannot be used as a value for @a pos. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] pos iterator to the element to remove + @return Iterator following the last removed element. If the iterator @a + pos refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.202 if called on an iterator which does not belong + to the current JSON value; example: `"iterator does not fit current + value"` + @throw invalid_iterator.205 if called on a primitive type with invalid + iterator (i.e., any iterator which is not `begin()`); example: `"iterator + out of range"` + + @complexity The complexity depends on the type: + - objects: amortized constant + - arrays: linear in distance between @a pos and the end of the container + - strings and binary: linear in the length of the member + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType} + + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template < class IteratorType, typename std::enable_if < + std::is_same::value || + std::is_same::value, int >::type + = 0 > + IteratorType erase(IteratorType pos) + { + // make sure iterator fits the current value + if (JSON_HEDLEY_UNLIKELY(this != pos.m_object)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + case value_t::binary: + { + if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin())) + { + JSON_THROW(invalid_iterator::create(205, "iterator out of range")); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); + m_value.string = nullptr; + } + else if (is_binary()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.binary); + std::allocator_traits::deallocate(alloc, m_value.binary, 1); + m_value.binary = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); + break; + } + + default: + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + return result; + } + + /*! + @brief remove elements given an iterator range + + Removes the element specified by the range `[first; last)`. The iterator + @a first does not need to be dereferenceable if `first == last`: erasing + an empty range is a no-op. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] first iterator to the beginning of the range to remove + @param[in] last iterator past the end of the range to remove + @return Iterator following the last removed element. If the iterator @a + second refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.203 if called on iterators which does not belong + to the current JSON value; example: `"iterators do not fit current value"` + @throw invalid_iterator.204 if called on a primitive type with invalid + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` + + @complexity The complexity depends on the type: + - objects: `log(size()) + std::distance(first, last)` + - arrays: linear in the distance between @a first and @a last, plus linear + in the distance between @a last and end of the container + - strings and binary: linear in the length of the member + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType_IteratorType} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template < class IteratorType, typename std::enable_if < + std::is_same::value || + std::is_same::value, int >::type + = 0 > + IteratorType erase(IteratorType first, IteratorType last) + { + // make sure iterator fits the current value + if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object)) + { + JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value")); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + case value_t::binary: + { + if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin() + || !last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); + m_value.string = nullptr; + } + else if (is_binary()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.binary); + std::allocator_traits::deallocate(alloc, m_value.binary, 1); + m_value.binary = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + default: + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + return result; + } + + /*! + @brief remove element from a JSON object given a key + + Removes elements from a JSON object with the key value @a key. + + @param[in] key value of the elements to remove + + @return Number of elements removed. If @a ObjectType is the default + `std::map` type, the return value will always be `0` (@a key was not + found) or `1` (@a key was found). + + @post References and iterators to the erased elements are invalidated. + Other references and iterators are not affected. + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + + @complexity `log(size()) + count(key)` + + @liveexample{The example shows the effect of `erase()`.,erase__key_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + size_type erase(const typename object_t::key_type& key) + { + // this erase only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + return m_value.object->erase(key); + } + + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + /*! + @brief remove element from a JSON array given an index + + Removes element from a JSON array at the index @a idx. + + @param[in] idx index of the element to remove + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 + is out of range"` + + @complexity Linear in distance between @a idx and the end of the container. + + @liveexample{The example shows the effect of `erase()`.,erase__size_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + + @since version 1.0.0 + */ + void erase(const size_type idx) + { + // this erase only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + if (JSON_HEDLEY_UNLIKELY(idx >= size())) + { + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + + m_value.array->erase(m_value.array->begin() + static_cast(idx)); + } + else + { + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + } + + /// @} + + + //////////// + // lookup // + //////////// + + /// @name lookup + /// @{ + + /*! + @brief find an element in a JSON object + + Finds an element in a JSON object with key equivalent to @a key. If the + element is not found or the JSON value is not an object, end() is + returned. + + @note This method always returns @ref end() when executed on a JSON type + that is not an object. + + @param[in] key key value of the element to search for. + + @return Iterator to an element with key equivalent to @a key. If no such + element is found or the JSON value is not an object, past-the-end (see + @ref end()) iterator is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `find()` is used.,find__key_type} + + @sa @ref contains(KeyT&&) const -- checks whether a key exists + + @since version 1.0.0 + */ + template + iterator find(KeyT&& key) + { + auto result = end(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } + + /*! + @brief find an element in a JSON object + @copydoc find(KeyT&&) + */ + template + const_iterator find(KeyT&& key) const + { + auto result = cend(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } + + /*! + @brief returns the number of occurrences of a key in a JSON object + + Returns the number of elements with key @a key. If ObjectType is the + default `std::map` type, the return value will always be `0` (@a key was + not found) or `1` (@a key was found). + + @note This method always returns `0` when executed on a JSON type that is + not an object. + + @param[in] key key value of the element to count + + @return Number of elements with key @a key. If the JSON value is not an + object, the return value will be `0`. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `count()` is used.,count} + + @since version 1.0.0 + */ + template + size_type count(KeyT&& key) const + { + // return 0 for all nonobject types + return is_object() ? m_value.object->count(std::forward(key)) : 0; + } + + /*! + @brief check the existence of an element in a JSON object + + Check whether an element exists in a JSON object with key equivalent to + @a key. If the element is not found or the JSON value is not an object, + false is returned. + + @note This method always returns false when executed on a JSON type + that is not an object. + + @param[in] key key value to check its existence. + + @return true if an element with specified @a key exists. If no such + element with such key is found or the JSON value is not an object, + false is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The following code shows an example for `contains()`.,contains} + + @sa @ref find(KeyT&&) -- returns an iterator to an object element + @sa @ref contains(const json_pointer&) const -- checks the existence for a JSON pointer + + @since version 3.6.0 + */ + template < typename KeyT, typename std::enable_if < + !std::is_same::type, json_pointer>::value, int >::type = 0 > + bool contains(KeyT && key) const + { + return is_object() && m_value.object->find(std::forward(key)) != m_value.object->end(); + } + + /*! + @brief check the existence of an element in a JSON object given a JSON pointer + + Check whether the given JSON pointer @a ptr can be resolved in the current + JSON value. + + @note This method can be executed on any JSON value type. + + @param[in] ptr JSON pointer to check its existence. + + @return true if the JSON pointer can be resolved to a stored value, false + otherwise. + + @post If `j.contains(ptr)` returns true, it is safe to call `j[ptr]`. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The following code shows an example for `contains()`.,contains_json_pointer} + + @sa @ref contains(KeyT &&) const -- checks the existence of a key + + @since version 3.7.0 + */ + bool contains(const json_pointer& ptr) const + { + return ptr.contains(this); + } + + /// @} + + + /////////////// + // iterators // + /////////////// + + /// @name iterators + /// @{ + + /*! + @brief returns an iterator to the first element + + Returns an iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `begin()`.,begin} + + @sa @ref cbegin() -- returns a const iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + iterator begin() noexcept + { + iterator result(this); + result.set_begin(); + return result; + } + + /*! + @copydoc basic_json::cbegin() + */ + const_iterator begin() const noexcept + { + return cbegin(); + } + + /*! + @brief returns a const iterator to the first element + + Returns a const iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).begin()`. + + @liveexample{The following code shows an example for `cbegin()`.,cbegin} + + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + const_iterator cbegin() const noexcept + { + const_iterator result(this); + result.set_begin(); + return result; + } + + /*! + @brief returns an iterator to one past the last element + + Returns an iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `end()`.,end} + + @sa @ref cend() -- returns a const iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + iterator end() noexcept + { + iterator result(this); + result.set_end(); + return result; + } + + /*! + @copydoc basic_json::cend() + */ + const_iterator end() const noexcept + { + return cend(); + } + + /*! + @brief returns a const iterator to one past the last element + + Returns a const iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).end()`. + + @liveexample{The following code shows an example for `cend()`.,cend} + + @sa @ref end() -- returns an iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + const_iterator cend() const noexcept + { + const_iterator result(this); + result.set_end(); + return result; + } + + /*! + @brief returns an iterator to the reverse-beginning + + Returns an iterator to the reverse-beginning; that is, the last element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(end())`. + + @liveexample{The following code shows an example for `rbegin()`.,rbegin} + + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + reverse_iterator rbegin() noexcept + { + return reverse_iterator(end()); + } + + /*! + @copydoc basic_json::crbegin() + */ + const_reverse_iterator rbegin() const noexcept + { + return crbegin(); + } + + /*! + @brief returns an iterator to the reverse-end + + Returns an iterator to the reverse-end; that is, one before the first + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(begin())`. + + @liveexample{The following code shows an example for `rend()`.,rend} + + @sa @ref crend() -- returns a const reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + reverse_iterator rend() noexcept + { + return reverse_iterator(begin()); + } + + /*! + @copydoc basic_json::crend() + */ + const_reverse_iterator rend() const noexcept + { + return crend(); + } + + /*! + @brief returns a const reverse iterator to the last element + + Returns a const iterator to the reverse-beginning; that is, the last + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rbegin()`. + + @liveexample{The following code shows an example for `crbegin()`.,crbegin} + + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(cend()); + } + + /*! + @brief returns a const reverse iterator to one before the first + + Returns a const reverse iterator to the reverse-end; that is, one before + the first element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rend()`. + + @liveexample{The following code shows an example for `crend()`.,crend} + + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(cbegin()); + } + + public: + /*! + @brief wrapper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without iterator_wrapper: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without iterator proxy: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with iterator proxy: + + @code{cpp} + for (auto it : json::iterator_wrapper(j_object)) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). + + @param[in] ref reference to a JSON value + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the wrapper is used,iterator_wrapper} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @note The name of this function is not yet final and may change in the + future. + + @deprecated This stream operator is deprecated and will be removed in + future 4.0.0 of the library. Please use @ref items() instead; + that is, replace `json::iterator_wrapper(j)` with `j.items()`. + */ + JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) + static iteration_proxy iterator_wrapper(reference ref) noexcept + { + return ref.items(); + } + + /*! + @copydoc iterator_wrapper(reference) + */ + JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) + static iteration_proxy iterator_wrapper(const_reference ref) noexcept + { + return ref.items(); + } + + /*! + @brief helper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without `items()` function: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without `items()` function: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with `items()` function: + + @code{cpp} + for (auto& el : j_object.items()) + { + std::cout << "key: " << el.key() << ", value:" << el.value() << '\n'; + } + @endcode + + The `items()` function also allows to use + [structured bindings](https://en.cppreference.com/w/cpp/language/structured_binding) + (C++17): + + @code{cpp} + for (auto& [key, val] : j_object.items()) + { + std::cout << "key: " << key << ", value:" << val << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). For primitive types (e.g., numbers), + `key()` returns an empty string. + + @warning Using `items()` on temporary objects is dangerous. Make sure the + object's lifetime exeeds the iteration. See + for more + information. + + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the function is used.,items} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 3.1.0, structured bindings support since 3.5.0. + */ + iteration_proxy items() noexcept + { + return iteration_proxy(*this); + } + + /*! + @copydoc items() + */ + iteration_proxy items() const noexcept + { + return iteration_proxy(*this); + } + + /// @} + + + ////////////// + // capacity // + ////////////// + + /// @name capacity + /// @{ + + /*! + @brief checks whether the container is empty. + + Checks if a JSON value has no elements (i.e. whether its @ref size is `0`). + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `true` + boolean | `false` + string | `false` + number | `false` + binary | `false` + object | result of function `object_t::empty()` + array | result of function `array_t::empty()` + + @liveexample{The following code uses `empty()` to check if a JSON + object contains any elements.,empty} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `empty()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return whether a string stored as JSON value + is empty - it returns whether the JSON container itself is empty which is + false in the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + - Has the semantics of `begin() == end()`. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + bool empty() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return true; + } + + case value_t::array: + { + // delegate call to array_t::empty() + return m_value.array->empty(); + } + + case value_t::object: + { + // delegate call to object_t::empty() + return m_value.object->empty(); + } + + default: + { + // all other types are nonempty + return false; + } + } + } + + /*! + @brief returns the number of elements + + Returns the number of elements in a JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` + boolean | `1` + string | `1` + number | `1` + binary | `1` + object | result of function object_t::size() + array | result of function array_t::size() + + @liveexample{The following code calls `size()` on the different value + types.,size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their size() functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return the length of a string stored as JSON + value - it returns the number of elements in the JSON value which is 1 in + the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + - Has the semantics of `std::distance(begin(), end())`. + + @sa @ref empty() -- checks whether the container is empty + @sa @ref max_size() -- returns the maximal number of elements + + @since version 1.0.0 + */ + size_type size() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return 0; + } + + case value_t::array: + { + // delegate call to array_t::size() + return m_value.array->size(); + } + + case value_t::object: + { + // delegate call to object_t::size() + return m_value.object->size(); + } + + default: + { + // all other types have size 1 + return 1; + } + } + } + + /*! + @brief returns the maximum possible number of elements + + Returns the maximum number of elements a JSON value is able to hold due to + system or library implementation limitations, i.e. `std::distance(begin(), + end())` for the JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` (same as `size()`) + boolean | `1` (same as `size()`) + string | `1` (same as `size()`) + number | `1` (same as `size()`) + binary | `1` (same as `size()`) + object | result of function `object_t::max_size()` + array | result of function `array_t::max_size()` + + @liveexample{The following code calls `max_size()` on the different value + types. Note the output is implementation specific.,max_size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `max_size()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + - Has the semantics of returning `b.size()` where `b` is the largest + possible JSON value. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + size_type max_size() const noexcept + { + switch (m_type) + { + case value_t::array: + { + // delegate call to array_t::max_size() + return m_value.array->max_size(); + } + + case value_t::object: + { + // delegate call to object_t::max_size() + return m_value.object->max_size(); + } + + default: + { + // all other types have max_size() == size() + return size(); + } + } + } + + /// @} + + + /////////////// + // modifiers // + /////////////// + + /// @name modifiers + /// @{ + + /*! + @brief clears the contents + + Clears the content of a JSON value and resets it to the default value as + if @ref basic_json(value_t) would have been called with the current value + type from @ref type(): + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + binary | An empty byte vector + object | `{}` + array | `[]` + + @post Has the same effect as calling + @code {.cpp} + *this = basic_json(type()); + @endcode + + @liveexample{The example below shows the effect of `clear()` to different + JSON types.,clear} + + @complexity Linear in the size of the JSON value. + + @iterators All iterators, pointers and references related to this container + are invalidated. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @sa @ref basic_json(value_t) -- constructor that creates an object with the + same value than calling `clear()` + + @since version 1.0.0 + */ + void clear() noexcept + { + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = 0; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = 0; + break; + } + + case value_t::number_float: + { + m_value.number_float = 0.0; + break; + } + + case value_t::boolean: + { + m_value.boolean = false; + break; + } + + case value_t::string: + { + m_value.string->clear(); + break; + } + + case value_t::binary: + { + m_value.binary->clear(); + break; + } + + case value_t::array: + { + m_value.array->clear(); + break; + } + + case value_t::object: + { + m_value.object->clear(); + break; + } + + default: + break; + } + } + + /*! + @brief add an object to an array + + Appends the given element @a val to the end of the JSON value. If the + function is called on a JSON null value, an empty array is created before + appending @a val. + + @param[in] val the value to add to the JSON array + + @throw type_error.308 when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON array. Note how the `null` value was silently + converted to a JSON array.,push_back} + + @since version 1.0.0 + */ + void push_back(basic_json&& val) + { + // push_back only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (move semantics) + m_value.array->push_back(std::move(val)); + // if val is moved from, basic_json move constructor marks it null so we do not call the destructor + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(basic_json&& val) + { + push_back(std::move(val)); + return *this; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + void push_back(const basic_json& val) + { + // push_back only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array + m_value.array->push_back(val); + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(const basic_json& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + Inserts the given element @a val to the JSON object. If the function is + called on a JSON null value, an empty object is created before inserting + @a val. + + @param[in] val the value to add to the JSON object + + @throw type_error.308 when called on a type other than JSON object or + null; example: `"cannot use push_back() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON object. Note how the `null` value was silently + converted to a JSON object.,push_back__object_t__value} + + @since version 1.0.0 + */ + void push_back(const typename object_t::value_type& val) + { + // push_back only works for null objects or objects + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to array + m_value.object->insert(val); + } + + /*! + @brief add an object to an object + @copydoc push_back(const typename object_t::value_type&) + */ + reference operator+=(const typename object_t::value_type& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + This function allows to use `push_back` with an initializer list. In case + + 1. the current value is an object, + 2. the initializer list @a init contains only two elements, and + 3. the first element of @a init is a string, + + @a init is converted into an object element and added using + @ref push_back(const typename object_t::value_type&). Otherwise, @a init + is converted to a JSON value and added using @ref push_back(basic_json&&). + + @param[in] init an initializer list + + @complexity Linear in the size of the initializer list @a init. + + @note This function is required to resolve an ambiguous overload error, + because pairs like `{"key", "value"}` can be both interpreted as + `object_t::value_type` or `std::initializer_list`, see + https://github.com/nlohmann/json/issues/235 for more information. + + @liveexample{The example shows how initializer lists are treated as + objects when possible.,push_back__initializer_list} + */ + void push_back(initializer_list_t init) + { + if (is_object() && init.size() == 2 && (*init.begin())->is_string()) + { + basic_json&& key = init.begin()->moved_or_copied(); + push_back(typename object_t::value_type( + std::move(key.get_ref()), (init.begin() + 1)->moved_or_copied())); + } + else + { + push_back(basic_json(init)); + } + } + + /*! + @brief add an object to an object + @copydoc push_back(initializer_list_t) + */ + reference operator+=(initializer_list_t init) + { + push_back(init); + return *this; + } + + /*! + @brief add an object to an array + + Creates a JSON value from the passed parameters @a args to the end of the + JSON value. If the function is called on a JSON null value, an empty array + is created before appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @return reference to the inserted element + + @throw type_error.311 when called on a type other than JSON array or + null; example: `"cannot use emplace_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` can be used to add + elements to a JSON array. Note how the `null` value was silently converted + to a JSON array.,emplace_back} + + @since version 2.0.8, returns reference since 3.7.0 + */ + template + reference emplace_back(Args&& ... args) + { + // emplace_back only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) + { + JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (perfect forwarding) +#ifdef JSON_HAS_CPP_17 + return m_value.array->emplace_back(std::forward(args)...); +#else + m_value.array->emplace_back(std::forward(args)...); + return m_value.array->back(); +#endif + } + + /*! + @brief add an object to an object if key does not exist + + Inserts a new element into a JSON object constructed in-place with the + given @a args if there is no element with the key in the container. If the + function is called on a JSON null value, an empty object is created before + appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @return a pair consisting of an iterator to the inserted element, or the + already-existing element if no insertion happened, and a bool + denoting whether the insertion took place. + + @throw type_error.311 when called on a type other than JSON object or + null; example: `"cannot use emplace() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `emplace()` can be used to add elements + to a JSON object. Note how the `null` value was silently converted to a + JSON object. Further note how no value is added if there was already one + value stored with the same key.,emplace} + + @since version 2.0.8 + */ + template + std::pair emplace(Args&& ... args) + { + // emplace only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) + { + JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()))); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to array (perfect forwarding) + auto res = m_value.object->emplace(std::forward(args)...); + // create result iterator and set iterator to the result of emplace + auto it = begin(); + it.m_it.object_iterator = res.first; + + // return pair of iterator and boolean + return {it, res.second}; + } + + /// Helper for insertion of an iterator + /// @note: This uses std::distance to support GCC 4.8, + /// see https://github.com/nlohmann/json/pull/1257 + template + iterator insert_iterator(const_iterator pos, Args&& ... args) + { + iterator result(this); + JSON_ASSERT(m_value.array != nullptr); + + auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator); + m_value.array->insert(pos.m_it.array_iterator, std::forward(args)...); + result.m_it.array_iterator = m_value.array->begin() + insert_pos; + + // This could have been written as: + // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + // but the return value of insert is missing in GCC 4.8, so it is written this way instead. + + return result; + } + + /*! + @brief inserts element + + Inserts element @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] val element to insert + @return iterator pointing to the inserted @a val. + + @throw type_error.309 if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Constant plus linear in the distance between @a pos and end of + the container. + + @liveexample{The example shows how `insert()` is used.,insert} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const basic_json& val) + { + // insert only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + return insert_iterator(pos, val); + } + + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + /*! + @brief inserts element + @copydoc insert(const_iterator, const basic_json&) + */ + iterator insert(const_iterator pos, basic_json&& val) + { + return insert(pos, val); + } + + /*! + @brief inserts elements + + Inserts @a cnt copies of @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert + @return iterator pointing to the first element inserted, or @a pos if + `cnt==0` + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Linear in @a cnt plus linear in the distance between @a pos + and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__count} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) + { + // insert only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + return insert_iterator(pos, cnt, val); + } + + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)` before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + @throw invalid_iterator.211 if @a first or @a last are iterators into + container for which insert is called; example: `"passed iterators may not + belong to container"` + + @return iterator pointing to the first element inserted, or @a pos if + `first==last` + + @complexity Linear in `std::distance(first, last)` plus linear in the + distance between @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__range} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const_iterator first, const_iterator last) + { + // insert only works for arrays + if (JSON_HEDLEY_UNLIKELY(!is_array())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // check if range iterators belong to the same JSON object + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + if (JSON_HEDLEY_UNLIKELY(first.m_object == this)) + { + JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container")); + } + + // insert to array and return iterator + return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); + } + + /*! + @brief inserts elements + + Inserts elements from initializer list @a ilist before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] ilist initializer list to insert the values from + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @return iterator pointing to the first element inserted, or @a pos if + `ilist` is empty + + @complexity Linear in `ilist.size()` plus linear in the distance between + @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__ilist} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, initializer_list_t ilist) + { + // insert only works for arrays + if (JSON_HEDLEY_UNLIKELY(!is_array())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + return insert_iterator(pos, ilist.begin(), ilist.end()); + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)`. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than objects; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number + of elements to insert. + + @liveexample{The example shows how `insert()` is used.,insert__range_object} + + @since version 3.0.0 + */ + void insert(const_iterator first, const_iterator last) + { + // insert only works for objects + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if range iterators belong to the same JSON object + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + // passed iterators must belong to objects + if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); + } + + m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); + } + + /*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from JSON object @a j and overwrites existing keys. + + @param[in] j JSON object to read values from + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ + void update(const_reference j) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); + } + if (JSON_HEDLEY_UNLIKELY(!j.is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()))); + } + + for (auto it = j.cbegin(); it != j.cend(); ++it) + { + m_value.object->operator[](it.key()) = it.value(); + } + } + + /*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from from range `[first, last)` and overwrites existing + keys. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used__range.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ + void update(const_iterator first, const_iterator last) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); + } + + // check if range iterators belong to the same JSON object + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + // passed iterators must belong to objects + if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object() + || !last.m_object->is_object())) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); + } + + for (auto it = first; it != last; ++it) + { + m_value.object->operator[](it.key()) = it.value(); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of the JSON value with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + void swap(reference other) noexcept ( + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_type, other.m_type); + std::swap(m_value, other.m_value); + assert_invariant(); + } + + /*! + @brief exchanges the values + + Exchanges the contents of the JSON value from @a left with those of @a right. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. implemented as a friend function callable via ADL. + + @param[in,out] left JSON value to exchange the contents with + @param[in,out] right JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + friend void swap(reference left, reference right) noexcept ( + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value + ) + { + left.swap(right); + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON array with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other array to exchange the contents with + + @throw type_error.310 when JSON value is not an array; example: `"cannot + use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how arrays can be swapped with + `swap()`.,swap__array_t} + + @since version 1.0.0 + */ + void swap(array_t& other) + { + // swap only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + std::swap(*(m_value.array), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON object with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other object to exchange the contents with + + @throw type_error.310 when JSON value is not an object; example: + `"cannot use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how objects can be swapped with + `swap()`.,swap__object_t} + + @since version 1.0.0 + */ + void swap(object_t& other) + { + // swap only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + std::swap(*(m_value.object), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other string to exchange the contents with + + @throw type_error.310 when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__string_t} + + @since version 1.0.0 + */ + void swap(string_t& other) + { + // swap only works for strings + if (JSON_HEDLEY_LIKELY(is_string())) + { + std::swap(*(m_value.string), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other binary to exchange the contents with + + @throw type_error.310 when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__binary_t} + + @since version 3.8.0 + */ + void swap(binary_t& other) + { + // swap only works for strings + if (JSON_HEDLEY_LIKELY(is_binary())) + { + std::swap(*(m_value.binary), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /// @copydoc swap(binary_t) + void swap(typename binary_t::container_type& other) + { + // swap only works for strings + if (JSON_HEDLEY_LIKELY(is_binary())) + { + std::swap(*(m_value.binary), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /// @} + + public: + ////////////////////////////////////////// + // lexicographical comparison operators // + ////////////////////////////////////////// + + /// @name lexicographical comparison operators + /// @{ + + /*! + @brief comparison: equal + + Compares two JSON values for equality according to the following rules: + - Two JSON values are equal if (1) they are from the same type and (2) + their stored values are the same according to their respective + `operator==`. + - Integer and floating-point numbers are automatically converted before + comparison. Note that two NaN values are always treated as unequal. + - Two JSON null values are equal. + + @note Floating-point inside JSON values numbers are compared with + `json::number_float_t::operator==` which is `double::operator==` by + default. To compare floating-point while respecting an epsilon, an alternative + [comparison function](https://github.com/mariokonrad/marnav/blob/master/include/marnav/math/floatingpoint.hpp#L34-#L39) + could be used, for instance + @code {.cpp} + template::value, T>::type> + inline bool is_same(T a, T b, T epsilon = std::numeric_limits::epsilon()) noexcept + { + return std::abs(a - b) <= epsilon; + } + @endcode + Or you can self-defined operator equal function like this: + @code {.cpp} + bool my_equal(const_reference lhs, const_reference rhs) { + const auto lhs_type lhs.type(); + const auto rhs_type rhs.type(); + if (lhs_type == rhs_type) { + switch(lhs_type) + // self_defined case + case value_t::number_float: + return std::abs(lhs - rhs) <= std::numeric_limits::epsilon(); + // other cases remain the same with the original + ... + } + ... + } + @endcode + + @note NaN values never compare equal to themselves or to other NaN values. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are equal + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__equal} + + @since version 1.0.0 + */ + friend bool operator==(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + return *lhs.m_value.array == *rhs.m_value.array; + + case value_t::object: + return *lhs.m_value.object == *rhs.m_value.object; + + case value_t::null: + return true; + + case value_t::string: + return *lhs.m_value.string == *rhs.m_value.string; + + case value_t::boolean: + return lhs.m_value.boolean == rhs.m_value.boolean; + + case value_t::number_integer: + return lhs.m_value.number_integer == rhs.m_value.number_integer; + + case value_t::number_unsigned: + return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; + + case value_t::number_float: + return lhs.m_value.number_float == rhs.m_value.number_float; + + case value_t::binary: + return *lhs.m_value.binary == *rhs.m_value.binary; + + default: + return false; + } + } + else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; + } + else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); + } + + return false; + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept + { + return lhs == basic_json(rhs); + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) == rhs; + } + + /*! + @brief comparison: not equal + + Compares two JSON values for inequality by calculating `not (lhs == rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are not equal + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__notequal} + + @since version 1.0.0 + */ + friend bool operator!=(const_reference lhs, const_reference rhs) noexcept + { + return !(lhs == rhs); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept + { + return lhs != basic_json(rhs); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) != rhs; + } + + /*! + @brief comparison: less than + + Compares whether one JSON value @a lhs is less than another JSON value @a + rhs according to the following rules: + - If @a lhs and @a rhs have the same type, the values are compared using + the default `<` operator. + - Integer and floating-point numbers are automatically converted before + comparison + - In case @a lhs and @a rhs have different types, the values are ignored + and the order of the types is considered, see + @ref operator<(const value_t, const value_t). + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__less} + + @since version 1.0.0 + */ + friend bool operator<(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + // note parentheses are necessary, see + // https://github.com/nlohmann/json/issues/1530 + return (*lhs.m_value.array) < (*rhs.m_value.array); + + case value_t::object: + return (*lhs.m_value.object) < (*rhs.m_value.object); + + case value_t::null: + return false; + + case value_t::string: + return (*lhs.m_value.string) < (*rhs.m_value.string); + + case value_t::boolean: + return (lhs.m_value.boolean) < (rhs.m_value.boolean); + + case value_t::number_integer: + return (lhs.m_value.number_integer) < (rhs.m_value.number_integer); + + case value_t::number_unsigned: + return (lhs.m_value.number_unsigned) < (rhs.m_value.number_unsigned); + + case value_t::number_float: + return (lhs.m_value.number_float) < (rhs.m_value.number_float); + + case value_t::binary: + return (*lhs.m_value.binary) < (*rhs.m_value.binary); + + default: + return false; + } + } + else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; + } + + // We only reach this line if we cannot compare values. In that case, + // we compare types. Note we have to call the operator explicitly, + // because MSVC has problems otherwise. + return operator<(lhs_type, rhs_type); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept + { + return lhs < basic_json(rhs); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) < rhs; + } + + /*! + @brief comparison: less than or equal + + Compares whether one JSON value @a lhs is less than or equal to another + JSON value by calculating `not (rhs < lhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greater} + + @since version 1.0.0 + */ + friend bool operator<=(const_reference lhs, const_reference rhs) noexcept + { + return !(rhs < lhs); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept + { + return lhs <= basic_json(rhs); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) <= rhs; + } + + /*! + @brief comparison: greater than + + Compares whether one JSON value @a lhs is greater than another + JSON value by calculating `not (lhs <= rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__lessequal} + + @since version 1.0.0 + */ + friend bool operator>(const_reference lhs, const_reference rhs) noexcept + { + return !(lhs <= rhs); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept + { + return lhs > basic_json(rhs); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) > rhs; + } + + /*! + @brief comparison: greater than or equal + + Compares whether one JSON value @a lhs is greater than or equal to another + JSON value by calculating `not (lhs < rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greaterequal} + + @since version 1.0.0 + */ + friend bool operator>=(const_reference lhs, const_reference rhs) noexcept + { + return !(lhs < rhs); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept + { + return lhs >= basic_json(rhs); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) >= rhs; + } + + /// @} + + /////////////////// + // serialization // + /////////////////// + + /// @name serialization + /// @{ + + /*! + @brief serialize to stream + + Serialize the given JSON value @a j to the output stream @a o. The JSON + value will be serialized using the @ref dump member function. + + - The indentation of the output can be controlled with the member variable + `width` of the output stream @a o. For instance, using the manipulator + `std::setw(4)` on @a o sets the indentation level to `4` and the + serialization result is the same as calling `dump(4)`. + + - The indentation character can be controlled with the member variable + `fill` of the output stream @a o. For instance, the manipulator + `std::setfill('\\t')` sets indentation to use a tab character rather than + the default space character. + + @param[in,out] o stream to serialize to + @param[in] j JSON value to serialize + + @return the stream @a o + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + + @complexity Linear. + + @liveexample{The example below shows the serialization with different + parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0.0; indentation character added in version 3.0.0 + */ + friend std::ostream& operator<<(std::ostream& o, const basic_json& j) + { + // read width member and use it as indentation parameter if nonzero + const bool pretty_print = o.width() > 0; + const auto indentation = pretty_print ? o.width() : 0; + + // reset width to 0 for subsequent calls to this stream + o.width(0); + + // do the actual serialization + serializer s(detail::output_adapter(o), o.fill()); + s.dump(j, pretty_print, false, static_cast(indentation)); + return o; + } + + /*! + @brief serialize to stream + @deprecated This stream operator is deprecated and will be removed in + future 4.0.0 of the library. Please use + @ref operator<<(std::ostream&, const basic_json&) + instead; that is, replace calls like `j >> o;` with `o << j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ + JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&)) + friend std::ostream& operator>>(const basic_json& j, std::ostream& o) + { + return o << j; + } + + /// @} + + + ///////////////////// + // deserialization // + ///////////////////// + + /// @name deserialization + /// @{ + + /*! + @brief deserialize from a compatible input + + @tparam InputType A compatible input, for instance + - an std::istream object + - a FILE pointer + - a C-style array of characters + - a pointer to a null-terminated string of single byte characters + - an object obj for which begin(obj) and end(obj) produces a valid pair of + iterators. + + @param[in] i input to read from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + @param[in] ignore_comments whether comments should be ignored and treated + like whitespace (true) or yield a parse error (true); (optional, false by + default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb or reading from the input @a i has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an array.,parse__array__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__string__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__istream__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function reading + from a contiguous container.,parse__contiguouscontainer__parser_callback_t} + + @since version 2.0.3 (contiguous containers); version 3.9.0 allowed to + ignore comments. + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json parse(InputType&& i, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false) + { + basic_json result; + parser(detail::input_adapter(std::forward(i)), cb, allow_exceptions, ignore_comments).parse(true, result); + return result; + } + + /*! + @brief deserialize from a pair of character iterators + + The value_type of the iterator must be a integral type with size of 1, 2 or + 4 bytes, which will be interpreted respectively as UTF-8, UTF-16 and UTF-32. + + @param[in] first iterator to start of character range + @param[in] last iterator to end of character range + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + @param[in] ignore_comments whether comments should be ignored and treated + like whitespace (true) or yield a parse error (true); (optional, false by + default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json parse(IteratorType first, + IteratorType last, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false) + { + basic_json result; + parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result); + return result; + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) + static basic_json parse(detail::span_input_adapter&& i, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false) + { + basic_json result; + parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result); + return result; + } + + /*! + @brief check if the input is valid JSON + + Unlike the @ref parse(InputType&&, const parser_callback_t,const bool) + function, this function neither throws an exception in case of invalid JSON + input (i.e., a parse error) nor creates diagnostic information. + + @tparam InputType A compatible input, for instance + - an std::istream object + - a FILE pointer + - a C-style array of characters + - a pointer to a null-terminated string of single byte characters + - an object obj for which begin(obj) and end(obj) produces a valid pair of + iterators. + + @param[in] i input to read from + @param[in] ignore_comments whether comments should be ignored and treated + like whitespace (true) or yield a parse error (true); (optional, false by + default) + + @return Whether the input read from @a i is valid JSON. + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `accept()` function reading + from a string.,accept__string} + */ + template + static bool accept(InputType&& i, + const bool ignore_comments = false) + { + return parser(detail::input_adapter(std::forward(i)), nullptr, false, ignore_comments).accept(true); + } + + template + static bool accept(IteratorType first, IteratorType last, + const bool ignore_comments = false) + { + return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) + static bool accept(detail::span_input_adapter&& i, + const bool ignore_comments = false) + { + return parser(i.get(), nullptr, false, ignore_comments).accept(true); + } + + /*! + @brief generate SAX events + + The SAX event lister must follow the interface of @ref json_sax. + + This function reads from a compatible input. Examples are: + - an std::istream object + - a FILE pointer + - a C-style array of characters + - a pointer to a null-terminated string of single byte characters + - an object obj for which begin(obj) and end(obj) produces a valid pair of + iterators. + + @param[in] i input to read from + @param[in,out] sax SAX event listener + @param[in] format the format to parse (JSON, CBOR, MessagePack, or UBJSON) + @param[in] strict whether the input has to be consumed completely + @param[in] ignore_comments whether comments should be ignored and treated + like whitespace (true) or yield a parse error (true); (optional, false by + default); only applies to the JSON file format. + + @return return value of the last processed SAX event + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the SAX consumer @a sax has + a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `sax_parse()` function + reading from string and processing the events with a user-defined SAX + event consumer.,sax_parse} + + @since version 3.2.0 + */ + template + JSON_HEDLEY_NON_NULL(2) + static bool sax_parse(InputType&& i, SAX* sax, + input_format_t format = input_format_t::json, + const bool strict = true, + const bool ignore_comments = false) + { + auto ia = detail::input_adapter(std::forward(i)); + return format == input_format_t::json + ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); + } + + template + JSON_HEDLEY_NON_NULL(3) + static bool sax_parse(IteratorType first, IteratorType last, SAX* sax, + input_format_t format = input_format_t::json, + const bool strict = true, + const bool ignore_comments = false) + { + auto ia = detail::input_adapter(std::move(first), std::move(last)); + return format == input_format_t::json + ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); + } + + template + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...)) + JSON_HEDLEY_NON_NULL(2) + static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, + input_format_t format = input_format_t::json, + const bool strict = true, + const bool ignore_comments = false) + { + auto ia = i.get(); + return format == input_format_t::json + ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); + } + + /*! + @brief deserialize from stream + @deprecated This stream operator is deprecated and will be removed in + version 4.0.0 of the library. Please use + @ref operator>>(std::istream&, basic_json&) + instead; that is, replace calls like `j << i;` with `i >> j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ + JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&)) + friend std::istream& operator<<(basic_json& j, std::istream& i) + { + return operator>>(i, j); + } + + /*! + @brief deserialize from stream + + Deserializes an input stream to a JSON value. + + @param[in,out] i input stream to read a serialized JSON value from + @param[in,out] j JSON value to write the deserialized input to + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below shows how a JSON value is constructed by + reading a serialization from a stream.,operator_deserialize} + + @sa parse(std::istream&, const parser_callback_t) for a variant with a + parser callback function to filter values while parsing + + @since version 1.0.0 + */ + friend std::istream& operator>>(std::istream& i, basic_json& j) + { + parser(detail::input_adapter(i)).parse(false, j); + return i; + } + + /// @} + + /////////////////////////// + // convenience functions // + /////////////////////////// + + /*! + @brief return the type as string + + Returns the type name as string to be used in error messages - usually to + indicate that a function was called on a wrong JSON type. + + @return a string representation of a the @a m_type member: + Value type | return value + ----------- | ------------- + null | `"null"` + boolean | `"boolean"` + string | `"string"` + number | `"number"` (for all number types) + object | `"object"` + array | `"array"` + binary | `"binary"` + discarded | `"discarded"` + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Constant. + + @liveexample{The following code exemplifies `type_name()` for all JSON + types.,type_name} + + @sa @ref type() -- return the type of the JSON value + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + + @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept` + since 3.0.0 + */ + JSON_HEDLEY_RETURNS_NON_NULL + const char* type_name() const noexcept + { + { + switch (m_type) + { + case value_t::null: + return "null"; + case value_t::object: + return "object"; + case value_t::array: + return "array"; + case value_t::string: + return "string"; + case value_t::boolean: + return "boolean"; + case value_t::binary: + return "binary"; + case value_t::discarded: + return "discarded"; + default: + return "number"; + } + } + } + + + private: + ////////////////////// + // member variables // + ////////////////////// + + /// the type of the current element + value_t m_type = value_t::null; + + /// the value of the current element + json_value m_value = {}; + + ////////////////////////////////////////// + // binary serialization/deserialization // + ////////////////////////////////////////// + + /// @name binary serialization/deserialization support + /// @{ + + public: + /*! + @brief create a CBOR serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the CBOR (Concise + Binary Object Representation) serialization format. CBOR is a binary + serialization format which aims to be more compact than JSON itself, yet + more efficient to parse. + + The library uses the following mapping from JSON values types to + CBOR types according to the CBOR specification (RFC 7049): + + JSON value type | value/range | CBOR type | first byte + --------------- | ------------------------------------------ | ---------------------------------- | --------------- + null | `null` | Null | 0xF6 + boolean | `true` | True | 0xF5 + boolean | `false` | False | 0xF4 + number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B + number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A + number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 + number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 + number_integer | -24..-1 | Negative integer | 0x20..0x37 + number_integer | 0..23 | Integer | 0x00..0x17 + number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_unsigned | 0..23 | Integer | 0x00..0x17 + number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_float | *any value representable by a float* | Single-Precision Float | 0xFA + number_float | *any value NOT representable by a float* | Double-Precision Float | 0xFB + string | *length*: 0..23 | UTF-8 string | 0x60..0x77 + string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 + string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 + string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A + string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B + array | *size*: 0..23 | array | 0x80..0x97 + array | *size*: 23..255 | array (1 byte follow) | 0x98 + array | *size*: 256..65535 | array (2 bytes follow) | 0x99 + array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9A + array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B + object | *size*: 0..23 | map | 0xA0..0xB7 + object | *size*: 23..255 | map (1 byte follow) | 0xB8 + object | *size*: 256..65535 | map (2 bytes follow) | 0xB9 + object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA + object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB + binary | *size*: 0..23 | byte string | 0x40..0x57 + binary | *size*: 23..255 | byte string (1 byte follow) | 0x58 + binary | *size*: 256..65535 | byte string (2 bytes follow) | 0x59 + binary | *size*: 65536..4294967295 | byte string (4 bytes follow) | 0x5A + binary | *size*: 4294967296..18446744073709551615 | byte string (8 bytes follow) | 0x5B + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a CBOR value. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The following CBOR types are not used in the conversion: + - UTF-8 strings terminated by "break" (0x7F) + - arrays terminated by "break" (0x9F) + - maps terminated by "break" (0xBF) + - byte strings terminated by "break" (0x5F) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + - half-precision floats (0xF9) + - break (0xFF) + + @param[in] j JSON value to serialize + @return CBOR serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in CBOR format.,to_cbor} + + @sa http://cbor.io + @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the + analogous deserialization + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9; compact representation of floating-point numbers + since version 3.8.0 + */ + static std::vector to_cbor(const basic_json& j) + { + std::vector result; + to_cbor(j, result); + return result; + } + + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + /*! + @brief create a MessagePack serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the MessagePack + serialization format. MessagePack is a binary serialization format which + aims to be more compact than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + MessagePack types according to the MessagePack specification: + + JSON value type | value/range | MessagePack type | first byte + --------------- | --------------------------------- | ---------------- | ---------- + null | `null` | nil | 0xC0 + boolean | `true` | true | 0xC3 + boolean | `false` | false | 0xC2 + number_integer | -9223372036854775808..-2147483649 | int64 | 0xD3 + number_integer | -2147483648..-32769 | int32 | 0xD2 + number_integer | -32768..-129 | int16 | 0xD1 + number_integer | -128..-33 | int8 | 0xD0 + number_integer | -32..-1 | negative fixint | 0xE0..0xFF + number_integer | 0..127 | positive fixint | 0x00..0x7F + number_integer | 128..255 | uint 8 | 0xCC + number_integer | 256..65535 | uint 16 | 0xCD + number_integer | 65536..4294967295 | uint 32 | 0xCE + number_integer | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_unsigned | 0..127 | positive fixint | 0x00..0x7F + number_unsigned | 128..255 | uint 8 | 0xCC + number_unsigned | 256..65535 | uint 16 | 0xCD + number_unsigned | 65536..4294967295 | uint 32 | 0xCE + number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_float | *any value representable by a float* | float 32 | 0xCA + number_float | *any value NOT representable by a float* | float 64 | 0xCB + string | *length*: 0..31 | fixstr | 0xA0..0xBF + string | *length*: 32..255 | str 8 | 0xD9 + string | *length*: 256..65535 | str 16 | 0xDA + string | *length*: 65536..4294967295 | str 32 | 0xDB + array | *size*: 0..15 | fixarray | 0x90..0x9F + array | *size*: 16..65535 | array 16 | 0xDC + array | *size*: 65536..4294967295 | array 32 | 0xDD + object | *size*: 0..15 | fix map | 0x80..0x8F + object | *size*: 16..65535 | map 16 | 0xDE + object | *size*: 65536..4294967295 | map 32 | 0xDF + binary | *size*: 0..255 | bin 8 | 0xC4 + binary | *size*: 256..65535 | bin 16 | 0xC5 + binary | *size*: 65536..4294967295 | bin 32 | 0xC6 + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a MessagePack value. + + @note The following values can **not** be converted to a MessagePack value: + - strings with more than 4294967295 bytes + - byte strings with more than 4294967295 bytes + - arrays with more than 4294967295 elements + - objects with more than 4294967295 elements + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in MessagePack format.,to_msgpack} + + @sa http://msgpack.org + @sa @ref from_msgpack for the analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9 + */ + static std::vector to_msgpack(const basic_json& j) + { + std::vector result; + to_msgpack(j, result); + return result; + } + + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + /*! + @brief create a UBJSON serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the UBJSON + (Universal Binary JSON) serialization format. UBJSON aims to be more compact + than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + UBJSON types according to the UBJSON specification: + + JSON value type | value/range | UBJSON type | marker + --------------- | --------------------------------- | ----------- | ------ + null | `null` | null | `Z` + boolean | `true` | true | `T` + boolean | `false` | false | `F` + number_integer | -9223372036854775808..-2147483649 | int64 | `L` + number_integer | -2147483648..-32769 | int32 | `l` + number_integer | -32768..-129 | int16 | `I` + number_integer | -128..127 | int8 | `i` + number_integer | 128..255 | uint8 | `U` + number_integer | 256..32767 | int16 | `I` + number_integer | 32768..2147483647 | int32 | `l` + number_integer | 2147483648..9223372036854775807 | int64 | `L` + number_unsigned | 0..127 | int8 | `i` + number_unsigned | 128..255 | uint8 | `U` + number_unsigned | 256..32767 | int16 | `I` + number_unsigned | 32768..2147483647 | int32 | `l` + number_unsigned | 2147483648..9223372036854775807 | int64 | `L` + number_unsigned | 2147483649..18446744073709551615 | high-precision | `H` + number_float | *any value* | float64 | `D` + string | *with shortest length indicator* | string | `S` + array | *see notes on optimized format* | array | `[` + object | *see notes on optimized format* | map | `{` + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a UBJSON value. + + @note The following values can **not** be converted to a UBJSON value: + - strings with more than 9223372036854775807 bytes (theoretical) + + @note The following markers are not used in the conversion: + - `Z`: no-op values are not created. + - `C`: single-byte strings are serialized with `S` markers. + + @note Any UBJSON output created @ref to_ubjson can be successfully parsed + by @ref from_ubjson. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The optimized formats for containers are supported: Parameter + @a use_size adds size information to the beginning of a container and + removes the closing marker. Parameter @a use_type further checks + whether all elements of a container have the same type and adds the + type marker to the beginning of the container. The @a use_type + parameter must only be used together with @a use_size = true. Note + that @a use_size = true alone may result in larger representations - + the benefit of this parameter is that the receiving side is + immediately informed on the number of elements of the container. + + @note If the JSON data contains the binary type, the value stored is a list + of integers, as suggested by the UBJSON documentation. In particular, + this means that serialization and the deserialization of a JSON + containing binary values into UBJSON and back will result in a + different JSON object. + + @param[in] j JSON value to serialize + @param[in] use_size whether to add size annotations to container types + @param[in] use_type whether to add type annotations to container types + (must be combined with @a use_size = true) + @return UBJSON serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in UBJSON format.,to_ubjson} + + @sa http://ubjson.org + @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the + analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + + @since version 3.1.0 + */ + static std::vector to_ubjson(const basic_json& j, + const bool use_size = false, + const bool use_type = false) + { + std::vector result; + to_ubjson(j, result, use_size, use_type); + return result; + } + + static void to_ubjson(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false) + { + binary_writer(o).write_ubjson(j, use_size, use_type); + } + + static void to_ubjson(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false) + { + binary_writer(o).write_ubjson(j, use_size, use_type); + } + + + /*! + @brief Serializes the given JSON object `j` to BSON and returns a vector + containing the corresponding BSON-representation. + + BSON (Binary JSON) is a binary format in which zero or more ordered key/value pairs are + stored as a single entity (a so-called document). + + The library uses the following mapping from JSON values types to BSON types: + + JSON value type | value/range | BSON type | marker + --------------- | --------------------------------- | ----------- | ------ + null | `null` | null | 0x0A + boolean | `true`, `false` | boolean | 0x08 + number_integer | -9223372036854775808..-2147483649 | int64 | 0x12 + number_integer | -2147483648..2147483647 | int32 | 0x10 + number_integer | 2147483648..9223372036854775807 | int64 | 0x12 + number_unsigned | 0..2147483647 | int32 | 0x10 + number_unsigned | 2147483648..9223372036854775807 | int64 | 0x12 + number_unsigned | 9223372036854775808..18446744073709551615| -- | -- + number_float | *any value* | double | 0x01 + string | *any value* | string | 0x02 + array | *any value* | document | 0x04 + object | *any value* | document | 0x03 + binary | *any value* | binary | 0x05 + + @warning The mapping is **incomplete**, since only JSON-objects (and things + contained therein) can be serialized to BSON. + Also, integers larger than 9223372036854775807 cannot be serialized to BSON, + and the keys may not contain U+0000, since they are serialized a + zero-terminated c-strings. + + @throw out_of_range.407 if `j.is_number_unsigned() && j.get() > 9223372036854775807` + @throw out_of_range.409 if a key in `j` contains a NULL (U+0000) + @throw type_error.317 if `!j.is_object()` + + @pre The input `j` is required to be an object: `j.is_object() == true`. + + @note Any BSON output created via @ref to_bson can be successfully parsed + by @ref from_bson. + + @param[in] j JSON value to serialize + @return BSON serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in BSON format.,to_bson} + + @sa http://bsonspec.org/spec.html + @sa @ref from_bson(detail::input_adapter&&, const bool strict) for the + analogous deserialization + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + @sa @ref to_cbor(const basic_json&) for the related CBOR format + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + */ + static std::vector to_bson(const basic_json& j) + { + std::vector result; + to_bson(j, result); + return result; + } + + /*! + @brief Serializes the given JSON object `j` to BSON and forwards the + corresponding BSON-representation to the given output_adapter `o`. + @param j The JSON object to convert to BSON. + @param o The output adapter that receives the binary BSON representation. + @pre The input `j` shall be an object: `j.is_object() == true` + @sa @ref to_bson(const basic_json&) + */ + static void to_bson(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_bson(j); + } + + /*! + @copydoc to_bson(const basic_json&, detail::output_adapter) + */ + static void to_bson(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_bson(j); + } + + + /*! + @brief create a JSON value from an input in CBOR format + + Deserializes a given input @a i to a JSON value using the CBOR (Concise + Binary Object Representation) serialization format. + + The library maps CBOR types to JSON value types as follows: + + CBOR type | JSON value type | first byte + ---------------------- | --------------- | ---------- + Integer | number_unsigned | 0x00..0x17 + Unsigned integer | number_unsigned | 0x18 + Unsigned integer | number_unsigned | 0x19 + Unsigned integer | number_unsigned | 0x1A + Unsigned integer | number_unsigned | 0x1B + Negative integer | number_integer | 0x20..0x37 + Negative integer | number_integer | 0x38 + Negative integer | number_integer | 0x39 + Negative integer | number_integer | 0x3A + Negative integer | number_integer | 0x3B + Byte string | binary | 0x40..0x57 + Byte string | binary | 0x58 + Byte string | binary | 0x59 + Byte string | binary | 0x5A + Byte string | binary | 0x5B + UTF-8 string | string | 0x60..0x77 + UTF-8 string | string | 0x78 + UTF-8 string | string | 0x79 + UTF-8 string | string | 0x7A + UTF-8 string | string | 0x7B + UTF-8 string | string | 0x7F + array | array | 0x80..0x97 + array | array | 0x98 + array | array | 0x99 + array | array | 0x9A + array | array | 0x9B + array | array | 0x9F + map | object | 0xA0..0xB7 + map | object | 0xB8 + map | object | 0xB9 + map | object | 0xBA + map | object | 0xBB + map | object | 0xBF + False | `false` | 0xF4 + True | `true` | 0xF5 + Null | `null` | 0xF6 + Half-Precision Float | number_float | 0xF9 + Single-Precision Float | number_float | 0xFA + Double-Precision Float | number_float | 0xFB + + @warning The mapping is **incomplete** in the sense that not all CBOR + types can be converted to a JSON value. The following CBOR types + are not supported and will yield parse errors (parse_error.112): + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + + @warning CBOR allows map keys of any type, whereas JSON only allows + strings as keys in object values. Therefore, CBOR maps with keys + other than UTF-8 strings are rejected (parse_error.113). + + @note Any CBOR output created @ref to_cbor can be successfully parsed by + @ref from_cbor. + + @param[in] i an input in CBOR format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + @param[in] tag_handler how to treat CBOR tags (optional, error by default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from CBOR were + used in the given input @a v or if the input is not valid CBOR + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in CBOR + format to a JSON value.,from_cbor} + + @sa http://cbor.io + @sa @ref to_cbor(const basic_json&) for the analogous serialization + @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for the + related MessagePack format + @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0; added @a allow_exceptions parameter + since 3.2.0; added @a tag_handler parameter since 3.9.0. + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_cbor(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::forward(i)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); + return res ? result : basic_json(value_t::discarded); + } + + /*! + @copydoc from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_cbor(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); + return res ? result : basic_json(value_t::discarded); + } + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) + static basic_json from_cbor(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler); + } + + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) + static basic_json from_cbor(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); + return res ? result : basic_json(value_t::discarded); + } + + /*! + @brief create a JSON value from an input in MessagePack format + + Deserializes a given input @a i to a JSON value using the MessagePack + serialization format. + + The library maps MessagePack types to JSON value types as follows: + + MessagePack type | JSON value type | first byte + ---------------- | --------------- | ---------- + positive fixint | number_unsigned | 0x00..0x7F + fixmap | object | 0x80..0x8F + fixarray | array | 0x90..0x9F + fixstr | string | 0xA0..0xBF + nil | `null` | 0xC0 + false | `false` | 0xC2 + true | `true` | 0xC3 + float 32 | number_float | 0xCA + float 64 | number_float | 0xCB + uint 8 | number_unsigned | 0xCC + uint 16 | number_unsigned | 0xCD + uint 32 | number_unsigned | 0xCE + uint 64 | number_unsigned | 0xCF + int 8 | number_integer | 0xD0 + int 16 | number_integer | 0xD1 + int 32 | number_integer | 0xD2 + int 64 | number_integer | 0xD3 + str 8 | string | 0xD9 + str 16 | string | 0xDA + str 32 | string | 0xDB + array 16 | array | 0xDC + array 32 | array | 0xDD + map 16 | object | 0xDE + map 32 | object | 0xDF + bin 8 | binary | 0xC4 + bin 16 | binary | 0xC5 + bin 32 | binary | 0xC6 + ext 8 | binary | 0xC7 + ext 16 | binary | 0xC8 + ext 32 | binary | 0xC9 + fixext 1 | binary | 0xD4 + fixext 2 | binary | 0xD5 + fixext 4 | binary | 0xD6 + fixext 8 | binary | 0xD7 + fixext 16 | binary | 0xD8 + negative fixint | number_integer | 0xE0-0xFF + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @param[in] i an input in MessagePack format convertible to an input + adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from MessagePack were + used in the given input @a i or if the input is not valid MessagePack + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + MessagePack format to a JSON value.,from_msgpack} + + @sa http://msgpack.org + @sa @ref to_msgpack(const basic_json&) for the analogous serialization + @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the + related CBOR format + @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for + the related UBJSON format + @sa @ref from_bson(detail::input_adapter&&, const bool, const bool) for + the related BSON format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0; added @a allow_exceptions parameter + since 3.2.0 + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_msgpack(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::forward(i)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + /*! + @copydoc from_msgpack(detail::input_adapter&&, const bool, const bool) + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_msgpack(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) + static basic_json from_msgpack(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_msgpack(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) + static basic_json from_msgpack(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + + /*! + @brief create a JSON value from an input in UBJSON format + + Deserializes a given input @a i to a JSON value using the UBJSON (Universal + Binary JSON) serialization format. + + The library maps UBJSON types to JSON value types as follows: + + UBJSON type | JSON value type | marker + ----------- | --------------------------------------- | ------ + no-op | *no value, next value is read* | `N` + null | `null` | `Z` + false | `false` | `F` + true | `true` | `T` + float32 | number_float | `d` + float64 | number_float | `D` + uint8 | number_unsigned | `U` + int8 | number_integer | `i` + int16 | number_integer | `I` + int32 | number_integer | `l` + int64 | number_integer | `L` + high-precision number | number_integer, number_unsigned, or number_float - depends on number string | 'H' + string | string | `S` + char | string | `C` + array | array (optimized values are supported) | `[` + object | object (optimized values are supported) | `{` + + @note The mapping is **complete** in the sense that any UBJSON value can + be converted to a JSON value. + + @param[in] i an input in UBJSON format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if a parse error occurs + @throw parse_error.113 if a string could not be parsed successfully + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + UBJSON format to a JSON value.,from_ubjson} + + @sa http://ubjson.org + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + analogous serialization + @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the + related CBOR format + @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for + the related MessagePack format + @sa @ref from_bson(detail::input_adapter&&, const bool, const bool) for + the related BSON format + + @since version 3.1.0; added @a allow_exceptions parameter since 3.2.0 + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_ubjson(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::forward(i)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + /*! + @copydoc from_ubjson(detail::input_adapter&&, const bool, const bool) + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_ubjson(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) + static basic_json from_ubjson(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_ubjson(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) + static basic_json from_ubjson(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + + /*! + @brief Create a JSON value from an input in BSON format + + Deserializes a given input @a i to a JSON value using the BSON (Binary JSON) + serialization format. + + The library maps BSON record types to JSON value types as follows: + + BSON type | BSON marker byte | JSON value type + --------------- | ---------------- | --------------------------- + double | 0x01 | number_float + string | 0x02 | string + document | 0x03 | object + array | 0x04 | array + binary | 0x05 | still unsupported + undefined | 0x06 | still unsupported + ObjectId | 0x07 | still unsupported + boolean | 0x08 | boolean + UTC Date-Time | 0x09 | still unsupported + null | 0x0A | null + Regular Expr. | 0x0B | still unsupported + DB Pointer | 0x0C | still unsupported + JavaScript Code | 0x0D | still unsupported + Symbol | 0x0E | still unsupported + JavaScript Code | 0x0F | still unsupported + int32 | 0x10 | number_integer + Timestamp | 0x11 | still unsupported + 128-bit decimal float | 0x13 | still unsupported + Max Key | 0x7F | still unsupported + Min Key | 0xFF | still unsupported + + @warning The mapping is **incomplete**. The unsupported mappings + are indicated in the table above. + + @param[in] i an input in BSON format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.114 if an unsupported BSON record type is encountered + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + BSON format to a JSON value.,from_bson} + + @sa http://bsonspec.org/spec.html + @sa @ref to_bson(const basic_json&) for the analogous serialization + @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the + related CBOR format + @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for + the related MessagePack format + @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the + related UBJSON format + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_bson(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::forward(i)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + /*! + @copydoc from_bson(detail::input_adapter&&, const bool, const bool) + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_bson(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) + static basic_json from_bson(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_bson(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) + static basic_json from_bson(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + /// @} + + ////////////////////////// + // JSON Pointer support // + ////////////////////////// + + /// @name JSON Pointer functions + /// @{ + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. Similar to @ref operator[](const typename + object_t::key_type&), `null` values are created in arrays and objects if + necessary. + + In particular: + - If the JSON pointer points to an object key that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. + - If the JSON pointer points to an array index that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. All indices between the current maximum and the given + index are also filled with `null`. + - The special value `-` is treated as a synonym for the index past the + end. + + @param[in] ptr a JSON pointer + + @return reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer} + + @since version 2.0.0 + */ + reference operator[](const json_pointer& ptr) + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. The function does not change the JSON + value; no `null` values are created. In particular, the special value + `-` yields an exception. + + @param[in] ptr JSON pointer to the desired element + + @return const reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} + + @since version 2.0.0 + */ + const_reference operator[](const json_pointer& ptr) const + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a reference to the element at with specified JSON pointer @a ptr, + with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer} + */ + reference at(const json_pointer& ptr) + { + return ptr.get_checked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a const reference to the element at with specified JSON pointer @a + ptr, with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer_const} + */ + const_reference at(const json_pointer& ptr) const + { + return ptr.get_checked(this); + } + + /*! + @brief return flattened JSON value + + The function creates a JSON object whose keys are JSON pointers (see [RFC + 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all + primitive. The original JSON value can be restored using the @ref + unflatten() function. + + @return an object that maps JSON pointers to primitive values + + @note Empty objects and arrays are flattened to `null` and will not be + reconstructed correctly by the @ref unflatten() function. + + @complexity Linear in the size the JSON value. + + @liveexample{The following code shows how a JSON object is flattened to an + object whose keys consist of JSON pointers.,flatten} + + @sa @ref unflatten() for the reverse function + + @since version 2.0.0 + */ + basic_json flatten() const + { + basic_json result(value_t::object); + json_pointer::flatten("", *this, result); + return result; + } + + /*! + @brief unflatten a previously flattened JSON value + + The function restores the arbitrary nesting of a JSON value that has been + flattened before using the @ref flatten() function. The JSON value must + meet certain constraints: + 1. The value must be an object. + 2. The keys must be JSON pointers (see + [RFC 6901](https://tools.ietf.org/html/rfc6901)) + 3. The mapped values must be primitive JSON types. + + @return the original JSON from a flattened version + + @note Empty objects and arrays are flattened by @ref flatten() to `null` + values and can not unflattened to their original type. Apart from + this example, for a JSON value `j`, the following is always true: + `j == j.flatten().unflatten()`. + + @complexity Linear in the size the JSON value. + + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + + @liveexample{The following code shows how a flattened JSON object is + unflattened into the original nested JSON object.,unflatten} + + @sa @ref flatten() for the reverse function + + @since version 2.0.0 + */ + basic_json unflatten() const + { + return json_pointer::unflatten(*this); + } + + /// @} + + ////////////////////////// + // JSON Patch functions // + ////////////////////////// + + /// @name JSON Patch functions + /// @{ + + /*! + @brief applies a JSON patch + + [JSON Patch](http://jsonpatch.com) defines a JSON document structure for + expressing a sequence of operations to apply to a JSON) document. With + this function, a JSON Patch is applied to the current JSON value by + executing all operations from the patch. + + @param[in] json_patch JSON patch document + @return patched document + + @note The application of a patch is atomic: Either all operations succeed + and the patched document is returned or an exception is thrown. In + any case, the original value is not changed: the patch is applied + to a copy of the value. + + @throw parse_error.104 if the JSON patch does not consist of an array of + objects + + @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory + attributes are missing); example: `"operation add must have member path"` + + @throw out_of_range.401 if an array index is out of range. + + @throw out_of_range.403 if a JSON pointer inside the patch could not be + resolved successfully in the current JSON value; example: `"key baz not + found"` + + @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", + "move") + + @throw other_error.501 if "test" operation was unsuccessful + + @complexity Linear in the size of the JSON value and the length of the + JSON patch. As usually only a fraction of the JSON value is affected by + the patch, the complexity can usually be neglected. + + @liveexample{The following code shows how a JSON patch is applied to a + value.,patch} + + @sa @ref diff -- create a JSON patch by comparing two JSON values + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) + + @since version 2.0.0 + */ + basic_json patch(const basic_json& json_patch) const + { + // make a working copy to apply the patch to + basic_json result = *this; + + // the valid JSON Patch operations + enum class patch_operations {add, remove, replace, move, copy, test, invalid}; + + const auto get_op = [](const std::string & op) + { + if (op == "add") + { + return patch_operations::add; + } + if (op == "remove") + { + return patch_operations::remove; + } + if (op == "replace") + { + return patch_operations::replace; + } + if (op == "move") + { + return patch_operations::move; + } + if (op == "copy") + { + return patch_operations::copy; + } + if (op == "test") + { + return patch_operations::test; + } + + return patch_operations::invalid; + }; + + // wrapper for "add" operation; add value at ptr + const auto operation_add = [&result](json_pointer & ptr, basic_json val) + { + // adding to the root of the target document means replacing it + if (ptr.empty()) + { + result = val; + return; + } + + // make sure the top element of the pointer exists + json_pointer top_pointer = ptr.top(); + if (top_pointer != ptr) + { + result.at(top_pointer); + } + + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.back(); + ptr.pop_back(); + basic_json& parent = result[ptr]; + + switch (parent.m_type) + { + case value_t::null: + case value_t::object: + { + // use operator[] to add value + parent[last_path] = val; + break; + } + + case value_t::array: + { + if (last_path == "-") + { + // special case: append to back + parent.push_back(val); + } + else + { + const auto idx = json_pointer::array_index(last_path); + if (JSON_HEDLEY_UNLIKELY(idx > parent.size())) + { + // avoid undefined behavior + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + + // default case: insert add offset + parent.insert(parent.begin() + static_cast(idx), val); + } + break; + } + + // if there exists a parent it cannot be primitive + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + }; + + // wrapper for "remove" operation; remove value at ptr + const auto operation_remove = [&result](json_pointer & ptr) + { + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.back(); + ptr.pop_back(); + basic_json& parent = result.at(ptr); + + // remove child + if (parent.is_object()) + { + // perform range check + auto it = parent.find(last_path); + if (JSON_HEDLEY_LIKELY(it != parent.end())) + { + parent.erase(it); + } + else + { + JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found")); + } + } + else if (parent.is_array()) + { + // note erase performs range check + parent.erase(json_pointer::array_index(last_path)); + } + }; + + // type check: top level value must be an array + if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); + } + + // iterate and apply the operations + for (const auto& val : json_patch) + { + // wrapper to get a value for an operation + const auto get_value = [&val](const std::string & op, + const std::string & member, + bool string_type) -> basic_json & + { + // find value + auto it = val.m_value.object->find(member); + + // context-sensitive error message + const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; + + // check if desired value is present + if (JSON_HEDLEY_UNLIKELY(it == val.m_value.object->end())) + { + JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'")); + } + + // check if result is of type string + if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string())) + { + JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'")); + } + + // no error: return value + return it->second; + }; + + // type check: every element of the array must be an object + if (JSON_HEDLEY_UNLIKELY(!val.is_object())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); + } + + // collect mandatory members + const auto op = get_value("op", "op", true).template get(); + const auto path = get_value(op, "path", true).template get(); + json_pointer ptr(path); + + switch (get_op(op)) + { + case patch_operations::add: + { + operation_add(ptr, get_value("add", "value", false)); + break; + } + + case patch_operations::remove: + { + operation_remove(ptr); + break; + } + + case patch_operations::replace: + { + // the "path" location must exist - use at() + result.at(ptr) = get_value("replace", "value", false); + break; + } + + case patch_operations::move: + { + const auto from_path = get_value("move", "from", true).template get(); + json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The move operation is functionally identical to a + // "remove" operation on the "from" location, followed + // immediately by an "add" operation at the target + // location with the value that was just removed. + operation_remove(from_ptr); + operation_add(ptr, v); + break; + } + + case patch_operations::copy: + { + const auto from_path = get_value("copy", "from", true).template get(); + const json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The copy is functionally identical to an "add" + // operation at the target location using the value + // specified in the "from" member. + operation_add(ptr, v); + break; + } + + case patch_operations::test: + { + bool success = false; + JSON_TRY + { + // check if "value" matches the one at "path" + // the "path" location must exist - use at() + success = (result.at(ptr) == get_value("test", "value", false)); + } + JSON_INTERNAL_CATCH (out_of_range&) + { + // ignore out of range errors: success remains false + } + + // throw an exception if test fails + if (JSON_HEDLEY_UNLIKELY(!success)) + { + JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump())); + } + + break; + } + + default: + { + // op must be "add", "remove", "replace", "move", "copy", or + // "test" + JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid")); + } + } + } + + return result; + } + + /*! + @brief creates a diff as a JSON patch + + Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can + be changed into the value @a target by calling @ref patch function. + + @invariant For two JSON values @a source and @a target, the following code + yields always `true`: + @code {.cpp} + source.patch(diff(source, target)) == target; + @endcode + + @note Currently, only `remove`, `add`, and `replace` operations are + generated. + + @param[in] source JSON value to compare from + @param[in] target JSON value to compare against + @param[in] path helper value to create JSON pointers + + @return a JSON patch to convert the @a source to @a target + + @complexity Linear in the lengths of @a source and @a target. + + @liveexample{The following code shows how a JSON patch is created as a + diff for two JSON values.,diff} + + @sa @ref patch -- apply a JSON patch + @sa @ref merge_patch -- apply a JSON Merge Patch + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + + @since version 2.0.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json diff(const basic_json& source, const basic_json& target, + const std::string& path = "") + { + // the patch + basic_json result(value_t::array); + + // if the values are the same, return empty patch + if (source == target) + { + return result; + } + + if (source.type() != target.type()) + { + // different types: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + return result; + } + + switch (source.type()) + { + case value_t::array: + { + // first pass: traverse common elements + std::size_t i = 0; + while (i < source.size() && i < target.size()) + { + // recursive call to compare array values at index i + auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + ++i; + } + + // i now reached the end of at least one array + // in a second pass, traverse the remaining elements + + // remove my remaining elements + const auto end_index = static_cast(result.size()); + while (i < source.size()) + { + // add operations in reverse order to avoid invalid + // indices + result.insert(result.begin() + end_index, object( + { + {"op", "remove"}, + {"path", path + "/" + std::to_string(i)} + })); + ++i; + } + + // add other remaining elements + while (i < target.size()) + { + result.push_back( + { + {"op", "add"}, + {"path", path + "/-"}, + {"value", target[i]} + }); + ++i; + } + + break; + } + + case value_t::object: + { + // first pass: traverse this object's elements + for (auto it = source.cbegin(); it != source.cend(); ++it) + { + // escape the key name to be used in a JSON patch + const auto key = json_pointer::escape(it.key()); + + if (target.find(it.key()) != target.end()) + { + // recursive call to compare object values at key it + auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + } + else + { + // found a key that is not in o -> remove it + result.push_back(object( + { + {"op", "remove"}, {"path", path + "/" + key} + })); + } + } + + // second pass: traverse other object's elements + for (auto it = target.cbegin(); it != target.cend(); ++it) + { + if (source.find(it.key()) == source.end()) + { + // found a key that is not in this -> add it + const auto key = json_pointer::escape(it.key()); + result.push_back( + { + {"op", "add"}, {"path", path + "/" + key}, + {"value", it.value()} + }); + } + } + + break; + } + + default: + { + // both primitive type: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + break; + } + } + + return result; + } + + /// @} + + //////////////////////////////// + // JSON Merge Patch functions // + //////////////////////////////// + + /// @name JSON Merge Patch functions + /// @{ + + /*! + @brief applies a JSON Merge Patch + + The merge patch format is primarily intended for use with the HTTP PATCH + method as a means of describing a set of modifications to a target + resource's content. This function applies a merge patch to the current + JSON value. + + The function implements the following algorithm from Section 2 of + [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396): + + ``` + define MergePatch(Target, Patch): + if Patch is an Object: + if Target is not an Object: + Target = {} // Ignore the contents and set it to an empty Object + for each Name/Value pair in Patch: + if Value is null: + if Name exists in Target: + remove the Name/Value pair from Target + else: + Target[Name] = MergePatch(Target[Name], Value) + return Target + else: + return Patch + ``` + + Thereby, `Target` is the current object; that is, the patch is applied to + the current value. + + @param[in] apply_patch the patch to apply + + @complexity Linear in the lengths of @a patch. + + @liveexample{The following code shows how a JSON Merge Patch is applied to + a JSON document.,merge_patch} + + @sa @ref patch -- apply a JSON patch + @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396) + + @since version 3.0.0 + */ + void merge_patch(const basic_json& apply_patch) + { + if (apply_patch.is_object()) + { + if (!is_object()) + { + *this = object(); + } + for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it) + { + if (it.value().is_null()) + { + erase(it.key()); + } + else + { + operator[](it.key()).merge_patch(it.value()); + } + } + } + else + { + *this = apply_patch; + } + } + + /// @} +}; + +/*! +@brief user-defined to_string function for JSON values + +This function implements a user-defined to_string for JSON objects. + +@param[in] j a JSON object +@return a std::string object +*/ + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j) +{ + return j.dump(); +} +} // namespace nlohmann + +/////////////////////// +// nonmember support // +/////////////////////// + +// specialization of std::swap, and std::hash +namespace std +{ + +/// hash value for JSON objects +template<> +struct hash +{ + /*! + @brief return a hash value for a JSON object + + @since version 1.0.0 + */ + std::size_t operator()(const nlohmann::json& j) const + { + return nlohmann::detail::hash(j); + } +}; + +/// specialization for std::less +/// @note: do not remove the space after '<', +/// see https://github.com/nlohmann/json/pull/679 +template<> +struct less<::nlohmann::detail::value_t> +{ + /*! + @brief compare two value_t enum values + @since version 3.0.0 + */ + bool operator()(nlohmann::detail::value_t lhs, + nlohmann::detail::value_t rhs) const noexcept + { + return nlohmann::detail::operator<(lhs, rhs); + } +}; + +// C++20 prohibit function specialization in the std namespace. +#ifndef JSON_HAS_CPP_20 + +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template<> +inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcept( + is_nothrow_move_constructible::value&& + is_nothrow_move_assignable::value + ) +{ + j1.swap(j2); +} + +#endif + +} // namespace std + +/*! +@brief user-defined string literal for JSON values + +This operator implements a user-defined string literal for JSON objects. It +can be used by adding `"_json"` to a string literal and returns a JSON object +if no parse error occurred. + +@param[in] s a string representation of a JSON object +@param[in] n the length of string @a s +@return a JSON object + +@since version 1.0.0 +*/ +JSON_HEDLEY_NON_NULL(1) +inline nlohmann::json operator "" _json(const char* s, std::size_t n) +{ + return nlohmann::json::parse(s, s + n); +} + +/*! +@brief user-defined string literal for JSON pointer + +This operator implements a user-defined string literal for JSON Pointers. It +can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer +object if no parse error occurred. + +@param[in] s a string representation of a JSON Pointer +@param[in] n the length of string @a s +@return a JSON pointer object + +@since version 2.0.0 +*/ +JSON_HEDLEY_NON_NULL(1) +inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) +{ + return nlohmann::json::json_pointer(std::string(s, n)); +} + +// #include + + +// restore GCC/clang diagnostic settings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic pop +#endif +#if defined(__clang__) + #pragma GCC diagnostic pop +#endif + +// clean up +#undef JSON_ASSERT +#undef JSON_INTERNAL_CATCH +#undef JSON_CATCH +#undef JSON_THROW +#undef JSON_TRY +#undef JSON_HAS_CPP_14 +#undef JSON_HAS_CPP_17 +#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION +#undef NLOHMANN_BASIC_JSON_TPL +#undef JSON_EXPLICIT + +// #include +#undef JSON_HEDLEY_ALWAYS_INLINE +#undef JSON_HEDLEY_ARM_VERSION +#undef JSON_HEDLEY_ARM_VERSION_CHECK +#undef JSON_HEDLEY_ARRAY_PARAM +#undef JSON_HEDLEY_ASSUME +#undef JSON_HEDLEY_BEGIN_C_DECLS +#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#undef JSON_HEDLEY_CLANG_HAS_FEATURE +#undef JSON_HEDLEY_CLANG_HAS_WARNING +#undef JSON_HEDLEY_COMPCERT_VERSION +#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#undef JSON_HEDLEY_CONCAT +#undef JSON_HEDLEY_CONCAT3 +#undef JSON_HEDLEY_CONCAT3_EX +#undef JSON_HEDLEY_CONCAT_EX +#undef JSON_HEDLEY_CONST +#undef JSON_HEDLEY_CONSTEXPR +#undef JSON_HEDLEY_CONST_CAST +#undef JSON_HEDLEY_CPP_CAST +#undef JSON_HEDLEY_CRAY_VERSION +#undef JSON_HEDLEY_CRAY_VERSION_CHECK +#undef JSON_HEDLEY_C_DECL +#undef JSON_HEDLEY_DEPRECATED +#undef JSON_HEDLEY_DEPRECATED_FOR +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#undef JSON_HEDLEY_DIAGNOSTIC_POP +#undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#undef JSON_HEDLEY_DMC_VERSION +#undef JSON_HEDLEY_DMC_VERSION_CHECK +#undef JSON_HEDLEY_EMPTY_BASES +#undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#undef JSON_HEDLEY_END_C_DECLS +#undef JSON_HEDLEY_FLAGS +#undef JSON_HEDLEY_FLAGS_CAST +#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#undef JSON_HEDLEY_GCC_HAS_BUILTIN +#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_GCC_HAS_EXTENSION +#undef JSON_HEDLEY_GCC_HAS_FEATURE +#undef JSON_HEDLEY_GCC_HAS_WARNING +#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#undef JSON_HEDLEY_GCC_VERSION +#undef JSON_HEDLEY_GCC_VERSION_CHECK +#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#undef JSON_HEDLEY_GNUC_HAS_FEATURE +#undef JSON_HEDLEY_GNUC_HAS_WARNING +#undef JSON_HEDLEY_GNUC_VERSION +#undef JSON_HEDLEY_GNUC_VERSION_CHECK +#undef JSON_HEDLEY_HAS_ATTRIBUTE +#undef JSON_HEDLEY_HAS_BUILTIN +#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_HAS_EXTENSION +#undef JSON_HEDLEY_HAS_FEATURE +#undef JSON_HEDLEY_HAS_WARNING +#undef JSON_HEDLEY_IAR_VERSION +#undef JSON_HEDLEY_IAR_VERSION_CHECK +#undef JSON_HEDLEY_IBM_VERSION +#undef JSON_HEDLEY_IBM_VERSION_CHECK +#undef JSON_HEDLEY_IMPORT +#undef JSON_HEDLEY_INLINE +#undef JSON_HEDLEY_INTEL_VERSION +#undef JSON_HEDLEY_INTEL_VERSION_CHECK +#undef JSON_HEDLEY_IS_CONSTANT +#undef JSON_HEDLEY_IS_CONSTEXPR_ +#undef JSON_HEDLEY_LIKELY +#undef JSON_HEDLEY_MALLOC +#undef JSON_HEDLEY_MESSAGE +#undef JSON_HEDLEY_MSVC_VERSION +#undef JSON_HEDLEY_MSVC_VERSION_CHECK +#undef JSON_HEDLEY_NEVER_INLINE +#undef JSON_HEDLEY_NON_NULL +#undef JSON_HEDLEY_NO_ESCAPE +#undef JSON_HEDLEY_NO_RETURN +#undef JSON_HEDLEY_NO_THROW +#undef JSON_HEDLEY_NULL +#undef JSON_HEDLEY_PELLES_VERSION +#undef JSON_HEDLEY_PELLES_VERSION_CHECK +#undef JSON_HEDLEY_PGI_VERSION +#undef JSON_HEDLEY_PGI_VERSION_CHECK +#undef JSON_HEDLEY_PREDICT +#undef JSON_HEDLEY_PRINTF_FORMAT +#undef JSON_HEDLEY_PRIVATE +#undef JSON_HEDLEY_PUBLIC +#undef JSON_HEDLEY_PURE +#undef JSON_HEDLEY_REINTERPRET_CAST +#undef JSON_HEDLEY_REQUIRE +#undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#undef JSON_HEDLEY_REQUIRE_MSG +#undef JSON_HEDLEY_RESTRICT +#undef JSON_HEDLEY_RETURNS_NON_NULL +#undef JSON_HEDLEY_SENTINEL +#undef JSON_HEDLEY_STATIC_ASSERT +#undef JSON_HEDLEY_STATIC_CAST +#undef JSON_HEDLEY_STRINGIFY +#undef JSON_HEDLEY_STRINGIFY_EX +#undef JSON_HEDLEY_SUNPRO_VERSION +#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#undef JSON_HEDLEY_TINYC_VERSION +#undef JSON_HEDLEY_TINYC_VERSION_CHECK +#undef JSON_HEDLEY_TI_ARMCL_VERSION +#undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL2000_VERSION +#undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL430_VERSION +#undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL6X_VERSION +#undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL7X_VERSION +#undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#undef JSON_HEDLEY_TI_CLPRU_VERSION +#undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#undef JSON_HEDLEY_TI_VERSION +#undef JSON_HEDLEY_TI_VERSION_CHECK +#undef JSON_HEDLEY_UNAVAILABLE +#undef JSON_HEDLEY_UNLIKELY +#undef JSON_HEDLEY_UNPREDICTABLE +#undef JSON_HEDLEY_UNREACHABLE +#undef JSON_HEDLEY_UNREACHABLE_RETURN +#undef JSON_HEDLEY_VERSION +#undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#undef JSON_HEDLEY_VERSION_DECODE_MINOR +#undef JSON_HEDLEY_VERSION_DECODE_REVISION +#undef JSON_HEDLEY_VERSION_ENCODE +#undef JSON_HEDLEY_WARNING +#undef JSON_HEDLEY_WARN_UNUSED_RESULT +#undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#undef JSON_HEDLEY_FALL_THROUGH + + + +#endif // INCLUDE_NLOHMANN_JSON_HPP_ diff --git a/old-code/v5_hal/firmware/include/api.h b/old-code/v5_hal/firmware/include/api.h new file mode 100644 index 00000000..70af8173 --- /dev/null +++ b/old-code/v5_hal/firmware/include/api.h @@ -0,0 +1,76 @@ +/** + * \file api.h + * + * PROS API header provides high-level user functionality + * + * Contains declarations for use by typical VEX programmers using PROS. + * + * 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. + * 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/. + */ + +#ifndef _PROS_API_H_ +#define _PROS_API_H_ + +#ifdef __cplusplus +#include +#include +#include +#include +#include +#include +#include +#include +#else /* (not) __cplusplus */ +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* __cplusplus */ + +#define PROS_VERSION_MAJOR 3 +#define PROS_VERSION_MINOR 3 +#define PROS_VERSION_PATCH 1 +#define PROS_VERSION_STRING "3.3.1" + +#define PROS_ERR (INT32_MAX) +#define PROS_ERR_F (INFINITY) + +#include "pros/adi.h" +#include "pros/colors.h" +#include "pros/distance.h" +#include "pros/ext_adi.h" +#include "pros/imu.h" +#include "pros/llemu.h" +#include "pros/misc.h" +#include "pros/motors.h" +#include "pros/optical.h" +#include "pros/rtos.h" +#include "pros/rotation.h" +#include "pros/vision.h" + +#ifdef __cplusplus +#include "pros/adi.hpp" +#include "pros/distance.hpp" +#include "pros/imu.hpp" +#include "pros/llemu.hpp" +#include "pros/misc.hpp" +#include "pros/motors.hpp" +#include "pros/optical.hpp" +#include "pros/rotation.hpp" +#include "pros/rtos.hpp" +#include "pros/vision.hpp" +#endif + +#endif // _PROS_API_H_ diff --git a/old-code/v5_hal/firmware/include/auton/Auton.h b/old-code/v5_hal/firmware/include/auton/Auton.h new file mode 100644 index 00000000..55c2bbb5 --- /dev/null +++ b/old-code/v5_hal/firmware/include/auton/Auton.h @@ -0,0 +1,97 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "util/Timer.h" + +using namespace std; + +class AutonAction { +public: + enum actionStatus { + CONTINUE, + END + }; + + virtual void ActionInit() {} + + virtual void ActionEnd() {} + + virtual actionStatus Action() = 0; + + virtual ~AutonAction() {} +}; + +class AutonNode { +public: + AutonNode(double timeout, AutonAction* action1 = nullptr, AutonAction* action2 = nullptr, AutonAction* action3 = nullptr); + void AddNext(AutonNode* childNode); + void AddAction(AutonAction* leaf); + void AddCondition(function startCondition); + bool Complete(); + void Reset(); + void SetTimeout(double timeout); + void Act(bool lastNodeDone); + ~AutonNode(); +private: + vector m_children; + vector m_actions; + bool m_startConditonGiven = false; + bool m_actionsInitialized = false; + function m_startCondition; + double m_timeout; + Timer m_timer; +}; + +class Auton { +public: + Auton(string name, bool defaultAuton = false); + + inline Auton* GetInstance() { + return this; + } + + inline bool GetDefault() { + return m_defaultAuton; + } + + string GetName(); + void AutonPeriodic(); + void AutonInit(); + bool Complete(); + void Reset(); + virtual ~Auton(); +protected: + void AddFirstNode(AutonNode* firstNode); + virtual void AddNodes() = 0; +private: + string m_name; + bool m_defaultAuton = false; + vector m_firstNode; +}; + +class WaitAction : public AutonAction { +public: + WaitAction(double duration); + void ActionInit(); + actionStatus Action(); +private: + Timer m_timer; + double m_duration; +}; + +class PrintAction : public AutonAction { +public: + PrintAction(string toPrint); + void ActionInit(); + actionStatus Action(); + +private: + string m_toPrint; +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/auton/AutonSequence.h b/old-code/v5_hal/firmware/include/auton/AutonSequence.h new file mode 100644 index 00000000..ab6d7c93 --- /dev/null +++ b/old-code/v5_hal/firmware/include/auton/AutonSequence.h @@ -0,0 +1,26 @@ +#pragma once + +#include "Auton.h" + +class AutonSequence { +public: + struct AutonSequenceList{ + AutonNode* headNode; + AutonNode* tailNode; + }; + + AutonSequence(AutonNode* initialNode); + + void AddNext(AutonNode* source, AutonNode* node); + + void AddAction(AutonAction* action); + + void SetTailNode(AutonNode* tail); + + AutonSequenceList GetSequence(); + + ~AutonSequence(); + +private: + AutonSequenceList m_auton_sequence; +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/auton/auton_actions/DriveStraightAction.h b/old-code/v5_hal/firmware/include/auton/auton_actions/DriveStraightAction.h new file mode 100644 index 00000000..40038974 --- /dev/null +++ b/old-code/v5_hal/firmware/include/auton/auton_actions/DriveStraightAction.h @@ -0,0 +1,27 @@ +#pragma once + +#include "api.h" +#include "auton/Auton.h" +#include "nodes/subsystems/drivetrain_nodes/IDriveNode.h" + +class DriveStraightAction : public AutonAction { +private: + IDriveNode* m_drive_node; + Timer m_timer; + double m_distance; + double m_max_velocity; + double m_max_accel; + int m_actual_left_distance; + int m_actual_right_distance; + double m_lastSpeed; + double m_lastTime; + double m_feedForward; + +public: + DriveStraightAction(IDriveNode* drive_node, double distance, double max_velocity, + double max_accel); + + void ActionInit(); + actionStatus Action(); + void ActionEnd(); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/auton/auton_actions/DriveToPoseAction.h b/old-code/v5_hal/firmware/include/auton/auton_actions/DriveToPoseAction.h new file mode 100644 index 00000000..75c5e243 --- /dev/null +++ b/old-code/v5_hal/firmware/include/auton/auton_actions/DriveToPoseAction.h @@ -0,0 +1,29 @@ +#pragma once + +#include "api.h" +#include "auton/Auton.h" +#include "nodes/subsystems/drivetrain_nodes/IDriveNode.h" +#include "nodes/odometry_nodes/OdometryNode.h" +#include "nodes/sensor_nodes/InertialSensorNode.h" +#include "pursuit/holonomic_pursuit/HolonomicPosePursuit.h" +#include "math/Pose.h" + +#include + +class DriveToPoseAction : public AutonAction { +private: + IDriveNode* m_drive_node; + OdometryNode* m_odom_node; + HolonomicPosePursuit m_holonomic_pose_pursuit; + Timer m_timer; + Pose m_end_pose; + +public: + DriveToPoseAction(IDriveNode* drive_node, OdometryNode* odom_node, Pose end_pose); + + void ActionInit(); + + actionStatus Action(); + + void ActionEnd(); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/auton/auton_actions/FollowPathAction.h b/old-code/v5_hal/firmware/include/auton/auton_actions/FollowPathAction.h new file mode 100644 index 00000000..a9fdc366 --- /dev/null +++ b/old-code/v5_hal/firmware/include/auton/auton_actions/FollowPathAction.h @@ -0,0 +1,28 @@ +#pragma once + +#include "api.h" +#include "auton/Auton.h" +#include "nodes/subsystems/drivetrain_nodes/IDriveNode.h" +#include "nodes/odometry_nodes/OdometryNode.h" +#include "pursuit/holonomic_pursuit/HolonomicPursuit.h" +#include "math/Pose.h" +#include "util/Logger.h" + +class FollowPathAction : public AutonAction { +private: + IDriveNode* m_drive_node; + OdometryNode* m_odom_node; + HolonomicPursuit m_holonomic_pursuit; + Path m_path; + bool m_reset_pose; + Timer m_timer; + +public: + FollowPathAction(IDriveNode* drive_node, OdometryNode* odom_node, Path path, bool reset_pose=false); + + void ActionInit(); + + actionStatus Action(); + + void ActionEnd(); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/auton/auton_actions/ProfiledTurnAction.h b/old-code/v5_hal/firmware/include/auton/auton_actions/ProfiledTurnAction.h new file mode 100644 index 00000000..6281a931 --- /dev/null +++ b/old-code/v5_hal/firmware/include/auton/auton_actions/ProfiledTurnAction.h @@ -0,0 +1,30 @@ +#pragma once + +#include "api.h" +#include "auton/Auton.h" +#include "nodes/subsystems/drivetrain_nodes/IDriveNode.h" +#include "nodes/sensor_nodes/InertialSensorNode.h" +#include "eigen/Eigen/Dense" + +#include + +class ProfiledTurnAction : public AutonAction { +private: + IDriveNode* m_drive_node; + Timer m_timer; + Eigen::Rotation2Dd m_angle; + double m_max_velocity; + double m_max_accel; + double m_lastSpeed; + double m_lastTime; + double m_feedForward; + InertialSensorNode* m_imu; + +public: + ProfiledTurnAction(IDriveNode* drive_node, InertialSensorNode* imu, Eigen::Rotation2Dd angle, double max_velocity, + double max_accel); + + void ActionInit(); + actionStatus Action(); + void ActionEnd(); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/auton/auton_actions/TurnToAngleAction.h b/old-code/v5_hal/firmware/include/auton/auton_actions/TurnToAngleAction.h new file mode 100644 index 00000000..ffa1d67e --- /dev/null +++ b/old-code/v5_hal/firmware/include/auton/auton_actions/TurnToAngleAction.h @@ -0,0 +1,30 @@ +#pragma once + +#include "api.h" +#include "auton/Auton.h" +#include "util/PID.h" +#include "util/Timer.h" +#include "util/Constants.h" +#include "nodes/subsystems/drivetrain_nodes/IDriveNode.h" +#include "nodes/subsystems/drivetrain_nodes/TankDriveNode.h" +#include "nodes/sensor_nodes/InertialSensorNode.h" +#include "eigen/Eigen/Dense" + +class TurnToAngleAction : public AutonAction { +private: + IDriveNode* m_drive_node; + InertialSensorNode* m_inertial_sensor; + Eigen::Rotation2Dd m_target_angle; + Timer m_turn_timer; + PID m_turning_pid; + +public: + TurnToAngleAction(IDriveNode* drive_node, InertialSensorNode* inertial_sensor, + Eigen::Rotation2Dd target_angle); + + void ActionInit(); + + actionStatus Action(); + + void ActionEnd(); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/auton/auton_routines/TestPathAuton.h b/old-code/v5_hal/firmware/include/auton/auton_routines/TestPathAuton.h new file mode 100644 index 00000000..1e7d0095 --- /dev/null +++ b/old-code/v5_hal/firmware/include/auton/auton_routines/TestPathAuton.h @@ -0,0 +1,21 @@ +#include "auton/Auton.h" +#include "nodes/subsystems/drivetrain_nodes/IDriveNode.h" +#include "nodes/odometry_nodes/OdometryNode.h" +#include "auton/auton_actions/TurnToAngleAction.h" +#include "auton/auton_actions/FollowPathAction.h" +#include "pathing/PathManager.h" +#include "pathing/Path.h" +#include "eigen/Eigen/Dense" + +class TestPathAuton : public Auton { +public: + TestPathAuton(IDriveNode* drive_node, OdometryNode* odom_node); + + void AddNodes(); + +private: + IDriveNode* m_drive_node; + OdometryNode* m_odom_node; + AutonNode* m_path_node; + PathManager* m_path_manager; +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/auton/auton_routines/TestPoseAuton.h b/old-code/v5_hal/firmware/include/auton/auton_routines/TestPoseAuton.h new file mode 100644 index 00000000..c79b720e --- /dev/null +++ b/old-code/v5_hal/firmware/include/auton/auton_routines/TestPoseAuton.h @@ -0,0 +1,17 @@ +#include "auton/Auton.h" +#include "nodes/subsystems/drivetrain_nodes/IDriveNode.h" +#include "nodes/odometry_nodes/OdometryNode.h" +#include "auton/auton_actions/DriveToPoseAction.h" +#include "eigen/Eigen/Dense" + +class TestPoseAuton : public Auton { +public: + TestPoseAuton(IDriveNode* drive_node, OdometryNode* odom_node); + + void AddNodes(); + +private: + IDriveNode* m_drive_node; + OdometryNode* m_odom_node; + AutonNode* m_pose_node; +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/auton/auton_routines/TestTurnAuton.h b/old-code/v5_hal/firmware/include/auton/auton_routines/TestTurnAuton.h new file mode 100644 index 00000000..dcb9c572 --- /dev/null +++ b/old-code/v5_hal/firmware/include/auton/auton_routines/TestTurnAuton.h @@ -0,0 +1,18 @@ +#include "auton/Auton.h" +#include "nodes/subsystems/drivetrain_nodes/IDriveNode.h" +#include "nodes/sensor_nodes/InertialSensorNode.h" +#include "auton/auton_actions/TurnToAngleAction.h" +#include "util/Constants.h" +#include "eigen/Eigen/Dense" + +class TestTurnAuton : public Auton { +public: + TestTurnAuton(IDriveNode* drive_node, InertialSensorNode* inertial_sensor_node); + + void AddNodes(); + +private: + IDriveNode* m_drive_node; + InertialSensorNode* m_inertial_sensor_node; + AutonNode* m_turn_node; +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/display/README.md b/old-code/v5_hal/firmware/include/display/README.md new file mode 100644 index 00000000..afdfdeb5 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/README.md @@ -0,0 +1,71 @@ +# Littlev Graphics Libraray + +![LittlevGL cover](http://www.gl.littlev.hu/home/main_cover_small.png) + +LittlevGL provides everything you need to create a Graphical User Interface (GUI) on embedded systems with easy-to-use graphical elements, beautiful visual effects and low memory footprint. + +Homepage: https://littlevgl.com + +### Table Of Content +* [Key features](#key-features) +* [Porting](#porting) +* [Project set-up](#project-set-up) +* [PC simulator](#pc-simulator) +* [Screenshots](#screenshots) +* [Contributing](#contributing) +* [Donate](#donate) + +## Key features +* Powerful building blocks buttons, charts, lists, sliders, images etc +* Advanced graphics with animations, anti-aliasing, opacity, smooth scrolling +* Various input devices touch pad, mouse, keyboard, encoder, buttons etc +* Multi language support with UTF-8 decoding +* Fully customizable graphical elements +* Hardware independent to use with any microcontroller or display +* Scalable to operate with few memory (50 kB Flash, 10 kB RAM) +* OS, External memory and GPU supported but not required +* Single frame buffer operation even with advances graphical effects +* Written in C for maximal compatibility +* Simulator to develop on PC without embedded hardware +* Tutorials, examples, themes for rapid development +* Documentation and API references online + +## Porting +In the most sime case you need 4 things: +1. Call `lv_tick_inc(1)` in every millisecods in a Timer or Task +2. Register a function which can **copy a pixel array** to an area of the screen +3. Register a function which can **read an input device**. (E.g. touch pad) +4. Call `lv_task_handler()` periodically in every few milliseconds +For more information visit https://littlevgl.com/porting + +## Project set-up +1. **Clone** or [Download](https://littlevgl.com/download) the lvgl repository: `git clone https://github.com/littlevgl/lvgl.git` +2. **Create project** with your preferred IDE and add the *lvgl* folder +3. Copy **lvgl/lv_conf_templ.h** as **lv_conf.h** next to the *lvgl* folder +4. In the lv_conf.h delete the first `#if 0` and its `#endif`. Let the default configurations at first. +5. In your *main.c*: #include "lvgl/lvgl.h" +6. In your *main function*: + * lvgl_init(); + * tick, display and input device initialization (see above) +7. To **test** create a label: `lv_obj_t * label = lv_label_create(lv_scr_act(), NULL);` +8. In the main *while(1)* call `lv_task_handler();` and make a few milliseconds delay (e.g. `my_delay_ms(5);`) +9. Compile the code and load it to your embedded hardware + +## PC Simulator +If you don't have got an embedded hardware you can test the graphics library in a PC simulator. The simulator uses [SDL2](https://www.libsdl.org/) to emulate a display on your monitor and a touch pad with your mouse. + +There is a pre-configured PC project for **Eclipse CDT** in this repository: https://github.com/littlevgl/pc_simulator + +## Screenshots +![TFT material](http://www.gl.littlev.hu/github_res/tft_material.png) +![TFT zen](http://www.gl.littlev.hu/github_res/tft_zen.png) +![TFT alien](http://www.gl.littlev.hu/github_res/tft_alien.png) +![TFT night](http://www.gl.littlev.hu/github_res/tft_night.png) + +## Contributing +See [CONTRIBUTING.md](https://github.com/littlevgl/lvgl/blob/master/docs/CONTRIBUTING.md) + +## Donate +If you are pleased with the graphics library, found it useful or be happy with the support you got, please help its further development: + +[![Donate](https://littlevgl.com/donate_dir/donate_btn.png)](https://littlevgl.com/donate) diff --git a/old-code/v5_hal/firmware/include/display/licence.txt b/old-code/v5_hal/firmware/include/display/licence.txt new file mode 100644 index 00000000..beaef1d2 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/licence.txt @@ -0,0 +1,8 @@ +MIT licence +Copyright (c) 2016 Gábor Kiss-Vámosi + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/old-code/v5_hal/firmware/include/display/lv_conf.h b/old-code/v5_hal/firmware/include/display/lv_conf.h new file mode 100644 index 00000000..0b1a1626 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_conf.h @@ -0,0 +1,341 @@ +/** + * @file lv_conf.h + * + */ + +#ifndef LV_CONF_H +#define LV_CONF_H + +/*---------------- + * Dynamic memory + *----------------*/ + +/* Memory size which will be used by the library + * to store the graphical objects and other data */ +#define LV_MEM_CUSTOM \ + 1 /*1: use custom malloc/free, 0: use the built-in \ + lv_mem_alloc/lv_mem_free*/ +#if LV_MEM_CUSTOM == 0 +#define LV_MEM_SIZE \ + (32U * 1024U) /*Size memory used by `lv_mem_alloc` in bytes (>= 2kB)*/ +#define LV_MEM_ATTR /*Complier prefix for big array declaration*/ +#define LV_MEM_AUTO_DEFRAG 1 /*Automatically defrag on free*/ +#else /*LV_MEM_CUSTOM*/ +#define LV_MEM_CUSTOM_INCLUDE \ + "kapi.h" /*Header for the dynamic memory function*/ +#define LV_MEM_CUSTOM_ALLOC kmalloc /*Wrapper to malloc*/ +#define LV_MEM_CUSTOM_FREE kfree /*Wrapper to free*/ +#endif /*LV_MEM_CUSTOM*/ +#define LV_ENABLE_GC 0 + +/*=================== + Graphical settings + *===================*/ + +/* Horizontal and vertical resolution of the library.*/ +#define LV_HOR_RES (480) +#define LV_VER_RES (240) +#define LV_DPI 126 + +/* Size of VDB (Virtual Display Buffer: the internal graphics buffer). + * Required for buffered drawing, opacity and anti-aliasing + * VDB makes the double buffering, you don't need to deal with it! + * Typical size: ~1/10 screen */ +#define LV_VDB_SIZE \ + (LV_VER_RES * \ + LV_HOR_RES) /*Size of VDB in pixel count (1/10 screen size is good for \ + first)*/ +#define LV_VDB_ADR \ + 0 /*Place VDB to a specific address (e.g. in external RAM) (0: allocate \ + automatically into RAM)*/ + +/* Use two Virtual Display buffers (VDB) parallelize rendering and flushing + * (optional) + * The flushing should use DMA to write the frame buffer in the background*/ +#define LV_VDB_DOUBLE 0 /*1: Enable the use of 2 VDBs*/ +#define LV_VDB2_ADR \ + 0 /*Place VDB2 to a specific address (e.g. in external RAM) (0: allocate \ + automatically into RAM)*/ + +/* Enable anti-aliasing (lines, and radiuses will be smoothed) */ +#define LV_ANTIALIAS 1 /*1: Enable anti-aliasing*/ + +/*Screen refresh settings*/ +#define LV_REFR_PERIOD 40 /*Screen refresh period in milliseconds*/ +#define LV_INV_FIFO_SIZE 32 /*The average count of objects on a screen */ + +/*================= + Misc. setting + *=================*/ + +/*Input device settings*/ +#define LV_INDEV_READ_PERIOD 50 /*Input device read period in milliseconds*/ +#define LV_INDEV_POINT_MARKER \ + 0 /*Mark the pressed points (required: USE_LV_REAL_DRAW = 1)*/ +#define LV_INDEV_DRAG_LIMIT 10 /*Drag threshold in pixels */ +#define LV_INDEV_DRAG_THROW \ + 20 /*Drag throw slow-down in [%]. Greater value means faster slow-down */ +#define LV_INDEV_LONG_PRESS_TIME 400 /*Long press time in milliseconds*/ +#define LV_INDEV_LONG_PRESS_REP_TIME \ + 100 /*Repeated trigger period in long press [ms] */ + +/*Color settings*/ +#define LV_COLOR_DEPTH 32 /*Color depth: 1/8/16/24*/ +#define LV_COLOR_TRANSP \ + LV_COLOR_LIME /*Images pixels with this color will not be drawn (with chroma \ + keying)*/ + +/*Text settings*/ +#define LV_TXT_UTF8 1 /*Enable UTF-8 coded Unicode character usage */ +#define LV_TXT_BREAK_CHARS " ,.;:-_" /*Can break texts on these chars*/ +#define LV_TXT_LINE_BREAK_LONG_LEN 12 +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 + +/*Graphics feature usage*/ +#define USE_LV_ANIMATION 1 /*1: Enable all animations*/ +#define USE_LV_SHADOW 1 /*1: Enable shadows*/ +#define USE_LV_GROUP 1 /*1: Enable object groups (for keyboards)*/ +#define USE_LV_GPU 0 /*1: Enable GPU interface*/ +#define USE_LV_REAL_DRAW \ + 1 /*1: Enable function which draw directly to the frame buffer instead of \ + VDB (required if LV_VDB_SIZE = 0)*/ +#define USE_LV_FILESYSTEM 1 /*1: Enable file system (required by images*/ +#define USE_LV_MULTI_LANG 1 + +/*Compiler attributes*/ +#define LV_ATTRIBUTE_TICK_INC /* Define a custom attribute to tick increment \ + function */ +#define LV_ATTRIBUTE_TASK_HANDLER +#define LV_ATTRIBUTE_MEM_ALIGN +#define LV_COMPILER_VLA_SUPPORTED 1 +#define LV_COMPILER_NON_CONST_INIT_SUPPORTED 1 + +#define USE_LV_LOG 0 +/*================ + * THEME USAGE + *================*/ +#define LV_THEME_LIVE_UPDATE 1 +#define USE_LV_THEME_TEMPL 0 /*Just for test*/ +#define USE_LV_THEME_DEFAULT 0 /*Built mainly from the built-in styles. Consumes very few RAM*/ +#define USE_LV_THEME_ALIEN 1 /*Dark futuristic theme*/ +#define USE_LV_THEME_NIGHT 1 /*Dark elegant theme*/ +#define USE_LV_THEME_MONO 1 /*Mono color theme for monochrome displays*/ +#define USE_LV_THEME_MATERIAL 1 /*Flat theme with bold colors and light shadows*/ +#define USE_LV_THEME_ZEN 1 /*Peaceful, mainly light theme */ + +/*================== + * FONT USAGE + *===================*/ + +/* More info about fonts: https://littlevgl.com/basics#fonts + * To enable a built-in font use 1,2,4 or 8 values + * which will determine the bit-per-pixel */ +#define LV_FONT_DEFAULT \ + &lv_font_dejavu_20 /*Always set a default font from the built-in fonts*/ + +#define USE_LV_FONT_DEJAVU_10 4 +#define USE_LV_FONT_DEJAVU_10_LATIN_SUP 4 +#define USE_LV_FONT_DEJAVU_10_CYRILLIC 4 +#define USE_LV_FONT_SYMBOL_10 4 + +#define USE_LV_FONT_DEJAVU_20 4 +#define USE_LV_FONT_DEJAVU_20_LATIN_SUP 4 +#define USE_LV_FONT_DEJAVU_20_CYRILLIC 4 +#define USE_LV_FONT_SYMBOL_20 4 + +#define USE_LV_FONT_DEJAVU_30 0 +#define USE_LV_FONT_DEJAVU_30_LATIN_SUP 0 +#define USE_LV_FONT_DEJAVU_30_CYRILLIC 0 +#define USE_LV_FONT_SYMBOL_30 0 + +#define USE_LV_FONT_DEJAVU_40 0 +#define USE_LV_FONT_DEJAVU_40_LATIN_SUP 0 +#define USE_LV_FONT_DEJAVU_40_CYRILLIC 0 +#define USE_LV_FONT_SYMBOL_40 0 + +/* PROS adds the mono variant of DejaVu sans */ +#define USE_PROS_FONT_DEJAVU_MONO_10 4 +#define USE_PROS_FONT_DEJAVU_MONO_10_LATIN_SUP 4 + +#define USE_PROS_FONT_DEJAVU_MONO_20 4 +#define USE_PROS_FONT_DEJAVU_MONO_LATIN_SUP_20 4 + +#define USE_PROS_FONT_DEJAVU_MONO_30 0 +#define USE_PROS_FONT_DEJAVU_MONO_30_LATIN_SUP 0 + +#define USE_PROS_FONT_DEJAVU_MONO_40 0 +#define USE_PROS_FONT_DEJAVU_MONO_40_LATIN_SUP 0 + +/*=================== + * LV_OBJ SETTINGS + *==================*/ +#define LV_OBJ_FREE_NUM_TYPE \ + uint32_t /*Type of free number attribute (comment out disable free number)*/ +#define LV_OBJ_FREE_PTR 1 /*Enable the free pointer attribute*/ + +/*================== + * LV OBJ X USAGE + *================*/ +/* + * Documentation of the object types: https://littlevgl.com/object-types + */ + +/***************** + * Simple object + *****************/ + +/*Label (dependencies: -*/ +#define USE_LV_LABEL 1 +#if USE_LV_LABEL != 0 +#define LV_LABEL_SCROLL_SPEED \ + 25 /*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_SCROLL/ROLL' \ + mode*/ +#endif + +/*Image (dependencies: lv_label*/ +#define USE_LV_IMG 1 +#if USE_LV_IMG != 0 +# define LV_IMG_CF_INDEXED 1 +# define LV_IMG_CF_ALPHA 1 +#endif + +/*Line (dependencies: -*/ +#define USE_LV_LINE 1 +#define USE_LV_ARC 1 + +/******************* + * Container objects + *******************/ + +/*Container (dependencies: -*/ +#define USE_LV_CONT 1 + +/*Page (dependencies: lv_cont)*/ +#define USE_LV_PAGE 1 + +/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/ +#define USE_LV_WIN 1 + +/*Tab (dependencies: lv_page, lv_btnm)*/ +#define USE_LV_TABVIEW 1 +#if USE_LV_TABVIEW != 0 +#define LV_TABVIEW_ANIM_TIME \ + 300 /*Time of slide animation [ms] (0: no animation)*/ +#endif +#define USE_LV_TILEVIEW 1 +#if USE_LV_TILEVIEW +# define LV_TILEVIEW_ANIM_TIME 300 +#endif + + +/************************* + * Data visualizer objects + *************************/ + +/*Bar (dependencies: -)*/ +#define USE_LV_BAR 1 + +/*Line meter (dependencies: *;)*/ +#define USE_LV_LMETER 1 + +/*Gauge (dependencies:bar, lmeter)*/ +#define USE_LV_GAUGE 1 + +/*Chart (dependencies: -)*/ +#define USE_LV_CHART 1 + +#define USE_LV_TABLE 1 +#if USE_LV_TABLE +# define LV_TABLE_COL_MAX 12 +#endif + +/*LED (dependencies: -)*/ +#define USE_LV_LED 1 + +/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ +#define USE_LV_MBOX 1 + +/*Text area (dependencies: lv_label, lv_page)*/ +#define USE_LV_TA 1 +#if USE_LV_TA != 0 +#define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/ +#define LV_TA_PWD_SHOW_TIME 1500 /*ms*/ +#endif + +#define USE_LV_SPINBOX 1 +#define USE_LV_CALENDAR 1 + +#define USE_PRELOAD 1 +#if USE_LV_PRELOAD != 0 +# define LV_PRELOAD_DEF_ARC_LENGTH 60 +# define LV_PRELOAD_DEF_SPIN_TIME 1000 +# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC +#endif + +#define USE_LV_CANVAS 1 +/************************* + * User input objects + *************************/ + +/*Button (dependencies: lv_cont*/ +#define USE_LV_BTN 1 +#if USE_LV_BTN != 0 +# define LV_BTN_INK_EFFECT 1 +#endif + +#define USE_LV_IMGBTN 1 +#if USE_LV_IMGBTN +# define LV_IMGBTN_TILED 0 +#endif + +/*Button matrix (dependencies: -)*/ +#define USE_LV_BTNM 1 + +/*Keyboard (dependencies: lv_btnm)*/ +#define USE_LV_KB 1 + +/*Check box (dependencies: lv_btn, lv_label)*/ +#define USE_LV_CB 1 + +/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons + * ))*/ +#define USE_LV_LIST 1 +#if USE_LV_LIST != 0 +#define LV_LIST_FOCUS_TIME \ + 100 /*Default animation time of focusing to a list element [ms] (0: no \ + animation) */ +#endif + +/*Drop down list (dependencies: lv_page, lv_label)*/ +#define USE_LV_DDLIST 1 +#if USE_LV_DDLIST != 0 +#define LV_DDLIST_ANIM_TIME \ + 200 /*Open and close default animation time [ms] (0: no animation)*/ +#endif + +/*Roller (dependencies: lv_ddlist)*/ +#define USE_LV_ROLLER 1 +#if USE_LV_ROLLER != 0 +#define LV_ROLLER_ANIM_TIME \ + 200 /*Focus animation time [ms] (0: no \ + animation)*/ +#endif + +/*Slider (dependencies: lv_bar)*/ +#define USE_LV_SLIDER 1 + +/*Switch (dependencies: lv_slider)*/ +#define USE_LV_SW 1 + +#if LV_INDEV_DRAG_THROW <= 0 +#warning "LV_INDEV_DRAG_THROW must be greater than 0" +#undef LV_INDEV_DRAG_THROW +#define LV_INDEV_DRAG_THROW 1 +#endif + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +# define _CRT_SECURE_NO_WARNINGS +#endif +#include "display/lv_conf_checker.h" +#endif /*LV_CONF_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_conf_checker.h b/old-code/v5_hal/firmware/include/display/lv_conf_checker.h new file mode 100644 index 00000000..3a8ead51 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_conf_checker.h @@ -0,0 +1,664 @@ +/** + * GENERATED FILE, DO NOT EDIT IT! + * @file lv_conf_checker.h + * Make sure all the defines of lv_conf.h have a default value +**/ + +#ifndef LV_CONF_CHECKER_H +#define LV_CONF_CHECKER_H +/*=================== + Dynamic memory + *===================*/ + +/* Memory size which will be used by the library + * to store the graphical objects and other data */ +#ifndef LV_MEM_CUSTOM +#define LV_MEM_CUSTOM 0 /*1: use custom malloc/free, 0: use the built-in lv_mem_alloc/lv_mem_free*/ +#endif +#if LV_MEM_CUSTOM == 0 +#ifndef LV_MEM_SIZE +# define LV_MEM_SIZE (64U * 1024U) /*Size memory used by `lv_mem_alloc` in bytes (>= 2kB)*/ +#endif +#ifndef LV_MEM_ATTR +# define LV_MEM_ATTR /*Complier prefix for big array declaration*/ +#endif +#ifndef LV_MEM_ADR +# define LV_MEM_ADR 0 /*Set an address for memory pool instead of allocation it as an array. Can be in external SRAM too.*/ +#endif +#ifndef LV_MEM_AUTO_DEFRAG +# define LV_MEM_AUTO_DEFRAG 1 /*Automatically defrag on free*/ +#endif +#else /*LV_MEM_CUSTOM*/ +#ifndef LV_MEM_CUSTOM_INCLUDE +# define LV_MEM_CUSTOM_INCLUDE /*Header for the dynamic memory function*/ +#endif +#ifndef LV_MEM_CUSTOM_ALLOC +# define LV_MEM_CUSTOM_ALLOC malloc /*Wrapper to malloc*/ +#endif +#ifndef LV_MEM_CUSTOM_FREE +# define LV_MEM_CUSTOM_FREE free /*Wrapper to free*/ +#endif +#endif /*LV_MEM_CUSTOM*/ + +/* Garbage Collector settings + * Used if lvgl is binded to higher language and the memory is managed by that language */ +#ifndef LV_ENABLE_GC +#define LV_ENABLE_GC 0 +#endif +#if LV_ENABLE_GC != 0 +#ifndef LV_MEM_CUSTOM_REALLOC +# define LV_MEM_CUSTOM_REALLOC your_realloc /*Wrapper to realloc*/ +#endif +#ifndef LV_MEM_CUSTOM_GET_SIZE +# define LV_MEM_CUSTOM_GET_SIZE your_mem_get_size /*Wrapper to lv_mem_get_size*/ +#endif +#ifndef LV_GC_INCLUDE +# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/ +#endif +#endif /* LV_ENABLE_GC */ + +/*=================== + Graphical settings + *===================*/ + +/* Horizontal and vertical resolution of the library.*/ +#ifndef LV_HOR_RES +#define LV_HOR_RES (480) +#endif +#ifndef LV_VER_RES +#define LV_VER_RES (320) +#endif + +/* Dot Per Inch: used to initialize default sizes. E.g. a button with width = LV_DPI / 2 -> half inch wide + * (Not so important, you can adjust it to modify default sizes and spaces)*/ +#ifndef LV_DPI +#define LV_DPI 100 +#endif + +/* Enable anti-aliasing (lines, and radiuses will be smoothed) */ +#ifndef LV_ANTIALIAS +#define LV_ANTIALIAS 1 /*1: Enable anti-aliasing*/ +#endif + +/*Screen refresh period in milliseconds*/ +#ifndef LV_REFR_PERIOD +#define LV_REFR_PERIOD 30 +#endif + +/*----------------- + * VDB settings + *----------------*/ + +/* VDB (Virtual Display Buffer) is an internal graphics buffer. + * The GUI will be drawn into this buffer first and then + * the buffer will be passed to your `disp_drv.disp_flush` function to + * copy it to your frame buffer. + * VDB is required for: buffered drawing, opacity, anti-aliasing and shadows + * Learn more: https://docs.littlevgl.com/#Drawing*/ + +/* Size of the VDB in pixels. Typical size: ~1/10 screen. Must be >= LV_HOR_RES + * Setting it to 0 will disable VDB and `disp_drv.disp_fill` and `disp_drv.disp_map` functions + * will be called to draw to the frame buffer directly*/ +#ifndef LV_VDB_SIZE +#define LV_VDB_SIZE ((LV_VER_RES * LV_HOR_RES) / 10) +#endif + + /* Bit-per-pixel of VDB. Useful for monochrome or non-standard color format displays. + * Special formats are handled with `disp_drv.vdb_wr`)*/ +#ifndef LV_VDB_PX_BPP +#define LV_VDB_PX_BPP LV_COLOR_SIZE /*LV_COLOR_SIZE comes from LV_COLOR_DEPTH below to set 8, 16 or 32 bit pixel size automatically */ +#endif + + /* Place VDB to a specific address (e.g. in external RAM) + * 0: allocate automatically into RAM + * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/ +#ifndef LV_VDB_ADR +#define LV_VDB_ADR 0 +#endif + +/* Use two Virtual Display buffers (VDB) to parallelize rendering and flushing + * The flushing should use DMA to write the frame buffer in the background */ +#ifndef LV_VDB_DOUBLE +#define LV_VDB_DOUBLE 0 +#endif + +/* Place VDB2 to a specific address (e.g. in external RAM) + * 0: allocate automatically into RAM + * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/ +#ifndef LV_VDB2_ADR +#define LV_VDB2_ADR 0 +#endif + +/* Using true double buffering in `disp_drv.disp_flush` you will always get the image of the whole screen. + * Your only task is to set the rendered image (`color_p` parameter) as frame buffer address or send it to your display. + * The best if you do in the blank period of you display to avoid tearing effect. + * Requires: + * - LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES + * - LV_VDB_DOUBLE = 1 + */ +#ifndef LV_VDB_TRUE_DOUBLE_BUFFERED +#define LV_VDB_TRUE_DOUBLE_BUFFERED 0 +#endif + +/*================= + Misc. setting + *=================*/ + +/*Input device settings*/ +#ifndef LV_INDEV_READ_PERIOD +#define LV_INDEV_READ_PERIOD 50 /*Input device read period in milliseconds*/ +#endif +#ifndef LV_INDEV_POINT_MARKER +#define LV_INDEV_POINT_MARKER 0 /*Mark the pressed points (required: USE_LV_REAL_DRAW = 1)*/ +#endif +#ifndef LV_INDEV_DRAG_LIMIT +#define LV_INDEV_DRAG_LIMIT 10 /*Drag threshold in pixels */ +#endif +#ifndef LV_INDEV_DRAG_THROW +#define LV_INDEV_DRAG_THROW 20 /*Drag throw slow-down in [%] (must be > 0). Greater value means faster slow-down */ +#endif +#ifndef LV_INDEV_LONG_PRESS_TIME +#define LV_INDEV_LONG_PRESS_TIME 400 /*Long press time in milliseconds*/ +#endif +#ifndef LV_INDEV_LONG_PRESS_REP_TIME +#define LV_INDEV_LONG_PRESS_REP_TIME 100 /*Repeated trigger period in long press [ms] */ +#endif + +/*Color settings*/ +#ifndef LV_COLOR_DEPTH +#define LV_COLOR_DEPTH 16 /*Color depth: 1/8/16/32*/ +#endif +#ifndef LV_COLOR_16_SWAP +#define LV_COLOR_16_SWAP 0 /*Swap the 2 bytes of RGB565 color. Useful if the display has a 8 bit interface (e.g. SPI)*/ +#endif +#ifndef LV_COLOR_SCREEN_TRANSP +#define LV_COLOR_SCREEN_TRANSP 0 /*1: Enable screen transparency. Useful for OSD or other overlapping GUIs. Requires ARGB8888 colors*/ +#endif +#ifndef LV_COLOR_TRANSP +#define LV_COLOR_TRANSP LV_COLOR_LIME /*Images pixels with this color will not be drawn (with chroma keying)*/ +#endif + +/*Text settings*/ +#ifndef LV_TXT_UTF8 +#define LV_TXT_UTF8 1 /*Enable UTF-8 coded Unicode character usage */ +#endif +#ifndef LV_TXT_BREAK_CHARS +#define LV_TXT_BREAK_CHARS " ,.;:-_" /*Can break texts on these chars*/ +#endif +#ifndef LV_TXT_LINE_BREAK_LONG_LEN +#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever "prettiest" */ +#endif +#ifndef LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */ +#endif +#ifndef LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 /* Minimum number of characters of a word to put on a line after a break */ +#endif + +/*Feature usage*/ +#ifndef USE_LV_ANIMATION +#define USE_LV_ANIMATION 1 /*1: Enable all animations*/ +#endif +#ifndef USE_LV_SHADOW +#define USE_LV_SHADOW 1 /*1: Enable shadows*/ +#endif +#ifndef USE_LV_GROUP +#define USE_LV_GROUP 1 /*1: Enable object groups (for keyboards)*/ +#endif +#ifndef USE_LV_GPU +#define USE_LV_GPU 1 /*1: Enable GPU interface*/ +#endif +#ifndef USE_LV_REAL_DRAW +#define USE_LV_REAL_DRAW 1 /*1: Enable function which draw directly to the frame buffer instead of VDB (required if LV_VDB_SIZE = 0)*/ +#endif +#ifndef USE_LV_FILESYSTEM +#define USE_LV_FILESYSTEM 1 /*1: Enable file system (might be required for images*/ +#endif +#ifndef USE_LV_MULTI_LANG +#define USE_LV_MULTI_LANG 0 /* Number of languages for labels to store (0: to disable this feature)*/ +#endif + +/*Compiler settings*/ +#ifndef LV_ATTRIBUTE_TICK_INC +#define LV_ATTRIBUTE_TICK_INC /* Define a custom attribute to `lv_tick_inc` function */ +#endif +#ifndef LV_ATTRIBUTE_TASK_HANDLER +#define LV_ATTRIBUTE_TASK_HANDLER /* Define a custom attribute to `lv_task_handler` function */ +#endif +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN /* With size optimization (-Os) the compiler might not align data to 4 or 8 byte boundary. This alignment will be explicitly applied where needed.*/ +#endif +#ifndef LV_COMPILER_VLA_SUPPORTED +#define LV_COMPILER_VLA_SUPPORTED 1 /* 1: Variable length array is supported*/ +#endif +#ifndef LV_COMPILER_NON_CONST_INIT_SUPPORTED +#define LV_COMPILER_NON_CONST_INIT_SUPPORTED 1 /* 1: Initialization with non constant values are supported */ +#endif + +/*HAL settings*/ +#ifndef LV_TICK_CUSTOM +#define LV_TICK_CUSTOM 0 /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */ +#endif +#if LV_TICK_CUSTOM == 1 +#ifndef LV_TICK_CUSTOM_INCLUDE +#define LV_TICK_CUSTOM_INCLUDE "something.h" /*Header for the sys time function*/ +#endif +#ifndef LV_TICK_CUSTOM_SYS_TIME_EXPR +#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current systime in ms*/ +#endif +#endif /*LV_TICK_CUSTOM*/ + + +/*Log settings*/ +#ifndef USE_LV_LOG +#define USE_LV_LOG 1 /*Enable/disable the log module*/ +#endif +#if USE_LV_LOG +/* How important log should be added: + * LV_LOG_LEVEL_TRACE A lot of logs to give detailed information + * LV_LOG_LEVEL_INFO Log important events + * LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't caused problem + * LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail + */ +#ifndef LV_LOG_LEVEL +# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN +#endif +/* 1: Print the log with 'printf'; 0: user need to register a callback*/ + +#ifndef LV_LOG_PRINTF +# define LV_LOG_PRINTF 0 +#endif +#endif /*USE_LV_LOG*/ + +/*================ + * THEME USAGE + *================*/ +#ifndef LV_THEME_LIVE_UPDATE +#define LV_THEME_LIVE_UPDATE 1 /*1: Allow theme switching at run time. Uses 8..10 kB of RAM*/ +#endif + +#ifndef USE_LV_THEME_TEMPL +#define USE_LV_THEME_TEMPL 0 /*Just for test*/ +#endif +#ifndef USE_LV_THEME_DEFAULT +#define USE_LV_THEME_DEFAULT 1 /*Built mainly from the built-in styles. Consumes very few RAM*/ +#endif +#ifndef USE_LV_THEME_ALIEN +#define USE_LV_THEME_ALIEN 1 /*Dark futuristic theme*/ +#endif +#ifndef USE_LV_THEME_NIGHT +#define USE_LV_THEME_NIGHT 1 /*Dark elegant theme*/ +#endif +#ifndef USE_LV_THEME_MONO +#define USE_LV_THEME_MONO 1 /*Mono color theme for monochrome displays*/ +#endif +#ifndef USE_LV_THEME_MATERIAL +#define USE_LV_THEME_MATERIAL 1 /*Flat theme with bold colors and light shadows*/ +#endif +#ifndef USE_LV_THEME_ZEN +#define USE_LV_THEME_ZEN 1 /*Peaceful, mainly light theme */ +#endif +#ifndef USE_LV_THEME_NEMO +#define USE_LV_THEME_NEMO 1 /*Water-like theme based on the movie "Finding Nemo"*/ +#endif + +/*================== + * FONT USAGE + *===================*/ + +/* More info about fonts: https://docs.littlevgl.com/#Fonts + * To enable a built-in font use 1,2,4 or 8 values + * which will determine the bit-per-pixel. Higher value means smoother fonts */ +#ifndef USE_LV_FONT_DEJAVU_10 +#define USE_LV_FONT_DEJAVU_10 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_10_LATIN_SUP +#define USE_LV_FONT_DEJAVU_10_LATIN_SUP 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_10_CYRILLIC +#define USE_LV_FONT_DEJAVU_10_CYRILLIC 4 +#endif +#ifndef USE_LV_FONT_SYMBOL_10 +#define USE_LV_FONT_SYMBOL_10 4 +#endif + +#ifndef USE_LV_FONT_DEJAVU_20 +#define USE_LV_FONT_DEJAVU_20 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_20_LATIN_SUP +#define USE_LV_FONT_DEJAVU_20_LATIN_SUP 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_20_CYRILLIC +#define USE_LV_FONT_DEJAVU_20_CYRILLIC 4 +#endif +#ifndef USE_LV_FONT_SYMBOL_20 +#define USE_LV_FONT_SYMBOL_20 4 +#endif + +#ifndef USE_LV_FONT_DEJAVU_30 +#define USE_LV_FONT_DEJAVU_30 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_30_LATIN_SUP +#define USE_LV_FONT_DEJAVU_30_LATIN_SUP 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_30_CYRILLIC +#define USE_LV_FONT_DEJAVU_30_CYRILLIC 4 +#endif +#ifndef USE_LV_FONT_SYMBOL_30 +#define USE_LV_FONT_SYMBOL_30 4 +#endif + +#ifndef USE_LV_FONT_DEJAVU_40 +#define USE_LV_FONT_DEJAVU_40 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_40_LATIN_SUP +#define USE_LV_FONT_DEJAVU_40_LATIN_SUP 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_40_CYRILLIC +#define USE_LV_FONT_DEJAVU_40_CYRILLIC 4 +#endif +#ifndef USE_LV_FONT_SYMBOL_40 +#define USE_LV_FONT_SYMBOL_40 4 +#endif + +#ifndef USE_LV_FONT_MONOSPACE_8 +#define USE_LV_FONT_MONOSPACE_8 1 +#endif + +/* Optionally declare your custom fonts here. + * You can use these fonts as default font too + * and they will be available globally. E.g. + * #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) \ + * LV_FONT_DECLARE(my_font_2) \ + */ +#ifndef LV_FONT_CUSTOM_DECLARE +#define LV_FONT_CUSTOM_DECLARE +#endif + + +#ifndef LV_FONT_DEFAULT +#define LV_FONT_DEFAULT &lv_font_dejavu_20 /*Always set a default font from the built-in fonts*/ +#endif + +/*=================== + * LV_OBJ SETTINGS + *==================*/ +#ifndef LV_OBJ_FREE_NUM_TYPE +#define LV_OBJ_FREE_NUM_TYPE uint32_t /*Type of free number attribute (comment out disable free number)*/ +#endif +#ifndef LV_OBJ_FREE_PTR +#define LV_OBJ_FREE_PTR 1 /*Enable the free pointer attribute*/ +#endif +#ifndef LV_OBJ_REALIGN +#define LV_OBJ_REALIGN 1 /*Enable `lv_obj_realaign()` based on `lv_obj_align()` parameters*/ +#endif + +/*================== + * LV OBJ X USAGE + *================*/ +/* + * Documentation of the object types: https://docs.littlevgl.com/#Object-types + */ + +/***************** + * Simple object + *****************/ + +/*Label (dependencies: -*/ +#ifndef USE_LV_LABEL +#define USE_LV_LABEL 1 +#endif +#if USE_LV_LABEL != 0 +#ifndef LV_LABEL_SCROLL_SPEED +# define LV_LABEL_SCROLL_SPEED 25 /*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_SCROLL/ROLL' mode*/ +#endif +#endif + +/*Image (dependencies: lv_label*/ +#ifndef USE_LV_IMG +#define USE_LV_IMG 1 +#endif +#if USE_LV_IMG != 0 +#ifndef LV_IMG_CF_INDEXED +# define LV_IMG_CF_INDEXED 1 /*Enable indexed (palette) images*/ +#endif +#ifndef LV_IMG_CF_ALPHA +# define LV_IMG_CF_ALPHA 1 /*Enable alpha indexed images*/ +#endif +#endif + +/*Line (dependencies: -*/ +#ifndef USE_LV_LINE +#define USE_LV_LINE 1 +#endif + +/*Arc (dependencies: -)*/ +#ifndef USE_LV_ARC +#define USE_LV_ARC 1 +#endif + +/******************* + * Container objects + *******************/ + +/*Container (dependencies: -*/ +#ifndef USE_LV_CONT +#define USE_LV_CONT 1 +#endif + +/*Page (dependencies: lv_cont)*/ +#ifndef USE_LV_PAGE +#define USE_LV_PAGE 1 +#endif + +/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/ +#ifndef USE_LV_WIN +#define USE_LV_WIN 1 +#endif + +/*Tab (dependencies: lv_page, lv_btnm)*/ +#ifndef USE_LV_TABVIEW +#define USE_LV_TABVIEW 1 +#endif +# if USE_LV_TABVIEW != 0 +#ifndef LV_TABVIEW_ANIM_TIME +# define LV_TABVIEW_ANIM_TIME 300 /*Time of slide animation [ms] (0: no animation)*/ +#endif +#endif + +/*Tileview (dependencies: lv_page) */ +#ifndef USE_LV_TILEVIEW +#define USE_LV_TILEVIEW 1 +#endif +#if USE_LV_TILEVIEW +#ifndef LV_TILEVIEW_ANIM_TIME +# define LV_TILEVIEW_ANIM_TIME 300 /*Time of slide animation [ms] (0: no animation)*/ +#endif +#endif + +/************************* + * Data visualizer objects + *************************/ + +/*Bar (dependencies: -)*/ +#ifndef USE_LV_BAR +#define USE_LV_BAR 1 +#endif + +/*Line meter (dependencies: *;)*/ +#ifndef USE_LV_LMETER +#define USE_LV_LMETER 1 +#endif + +/*Gauge (dependencies:lv_bar, lv_lmeter)*/ +#ifndef USE_LV_GAUGE +#define USE_LV_GAUGE 1 +#endif + +/*Chart (dependencies: -)*/ +#ifndef USE_LV_CHART +#define USE_LV_CHART 1 +#endif + +/*Table (dependencies: lv_label)*/ +#ifndef USE_LV_TABLE +#define USE_LV_TABLE 1 +#endif +#if USE_LV_TABLE +#ifndef LV_TABLE_COL_MAX +# define LV_TABLE_COL_MAX 12 +#endif +#endif + +/*LED (dependencies: -)*/ +#ifndef USE_LV_LED +#define USE_LV_LED 1 +#endif + +/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ +#ifndef USE_LV_MBOX +#define USE_LV_MBOX 1 +#endif + +/*Text area (dependencies: lv_label, lv_page)*/ +#ifndef USE_LV_TA +#define USE_LV_TA 1 +#endif +#if USE_LV_TA != 0 +#ifndef LV_TA_CURSOR_BLINK_TIME +# define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/ +#endif +#ifndef LV_TA_PWD_SHOW_TIME +# define LV_TA_PWD_SHOW_TIME 1500 /*ms*/ +#endif +#endif + +/*Spinbox (dependencies: lv_ta)*/ +#ifndef USE_LV_SPINBOX +#define USE_LV_SPINBOX 1 +#endif + +/*Calendar (dependencies: -)*/ +#ifndef USE_LV_CALENDAR +#define USE_LV_CALENDAR 1 +#endif + +/*Preload (dependencies: lv_arc)*/ +#ifndef USE_LV_PRELOAD +#define USE_LV_PRELOAD 1 +#endif +#if USE_LV_PRELOAD != 0 +#ifndef LV_PRELOAD_DEF_ARC_LENGTH +# define LV_PRELOAD_DEF_ARC_LENGTH 60 /*[deg]*/ +#endif +#ifndef LV_PRELOAD_DEF_SPIN_TIME +# define LV_PRELOAD_DEF_SPIN_TIME 1000 /*[ms]*/ +#endif +#ifndef LV_PRELOAD_DEF_ANIM +# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC +#endif +#endif + +/*Canvas (dependencies: lv_img)*/ +#ifndef USE_LV_CANVAS +#define USE_LV_CANVAS 1 +#endif +/************************* + * User input objects + *************************/ + +/*Button (dependencies: lv_cont*/ +#ifndef USE_LV_BTN +#define USE_LV_BTN 1 +#endif +#if USE_LV_BTN != 0 +#ifndef LV_BTN_INK_EFFECT +# define LV_BTN_INK_EFFECT 1 /*Enable button-state animations - draw a circle on click (dependencies: USE_LV_ANIMATION)*/ +#endif +#endif + +/*Image Button (dependencies: lv_btn*/ +#ifndef USE_LV_IMGBTN +#define USE_LV_IMGBTN 1 +#endif +#if USE_LV_IMGBTN +#ifndef LV_IMGBTN_TILED +# define LV_IMGBTN_TILED 0 /*1: The imgbtn requires left, mid and right parts and the width can be set freely*/ +#endif +#endif + +/*Button matrix (dependencies: -)*/ +#ifndef USE_LV_BTNM +#define USE_LV_BTNM 1 +#endif + +/*Keyboard (dependencies: lv_btnm)*/ +#ifndef USE_LV_KB +#define USE_LV_KB 1 +#endif + +/*Check box (dependencies: lv_btn, lv_label)*/ +#ifndef USE_LV_CB +#define USE_LV_CB 1 +#endif + +/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/ +#ifndef USE_LV_LIST +#define USE_LV_LIST 1 +#endif +#if USE_LV_LIST != 0 +#ifndef LV_LIST_FOCUS_TIME +# define LV_LIST_FOCUS_TIME 100 /*Default animation time of focusing to a list element [ms] (0: no animation) */ +#endif +#endif + +/*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/ +#ifndef USE_LV_DDLIST +#define USE_LV_DDLIST 1 +#endif +#if USE_LV_DDLIST != 0 +#ifndef LV_DDLIST_ANIM_TIME +# define LV_DDLIST_ANIM_TIME 200 /*Open and close default animation time [ms] (0: no animation)*/ +#endif +#endif + +/*Roller (dependencies: lv_ddlist)*/ +#ifndef USE_LV_ROLLER +#define USE_LV_ROLLER 1 +#endif +#if USE_LV_ROLLER != 0 +#ifndef LV_ROLLER_ANIM_TIME +# define LV_ROLLER_ANIM_TIME 200 /*Focus animation time [ms] (0: no animation)*/ +#endif +#endif + +/*Slider (dependencies: lv_bar)*/ +#ifndef USE_LV_SLIDER +#define USE_LV_SLIDER 1 +#endif + +/*Switch (dependencies: lv_slider)*/ +#ifndef USE_LV_SW +#define USE_LV_SW 1 +#endif + +/************************* + * Non-user section + *************************/ + +#if LV_INDEV_DRAG_THROW <= 0 +#warning "LV_INDEV_DRAG_THROW must be greater than 0" +#undef LV_INDEV_DRAG_THROW +#ifndef LV_INDEV_DRAG_THROW +#define LV_INDEV_DRAG_THROW 1 +#endif +#endif + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) /* Disable warnings for Visual Studio*/ +#ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS +#endif +#endif + + +#endif /*LV_CONF_CHECKER_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_core/lv_core.mk b/old-code/v5_hal/firmware/include/display/lv_core/lv_core.mk new file mode 100644 index 00000000..9992e3fe --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_core/lv_core.mk @@ -0,0 +1,12 @@ +CSRCS += lv_group.c +CSRCS += lv_indev.c +CSRCS += lv_obj.c +CSRCS += lv_refr.c +CSRCS += lv_style.c +CSRCS += lv_vdb.c +CSRCS += lv_lang.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_core +VPATH += :$(LVGL_DIR)/lvgl/lv_core + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_core" diff --git a/old-code/v5_hal/firmware/include/display/lv_core/lv_group.h b/old-code/v5_hal/firmware/include/display/lv_core/lv_group.h new file mode 100644 index 00000000..4fb6043b --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_core/lv_group.h @@ -0,0 +1,247 @@ +/** + * @file lv_group.h + * + */ + +#ifndef LV_GROUP_H +#define LV_GROUP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include "lv_obj.h" + +/********************* + * DEFINES + *********************/ +/*Predefined keys to control the focused object via lv_group_send(group, c)*/ +/*For compatibility in signal function define the keys regardless to LV_GROUP*/ +#define LV_GROUP_KEY_UP 17 /*0x11*/ +#define LV_GROUP_KEY_DOWN 18 /*0x12*/ +#define LV_GROUP_KEY_RIGHT 19 /*0x13*/ +#define LV_GROUP_KEY_LEFT 20 /*0x14*/ +#define LV_GROUP_KEY_ESC 27 /*0x1B*/ +#define LV_GROUP_KEY_DEL 127 /*0x7F*/ +#define LV_GROUP_KEY_BACKSPACE 8 /*0x08*/ +#define LV_GROUP_KEY_ENTER 10 /*0x0A, '\n'*/ +#define LV_GROUP_KEY_NEXT 9 /*0x09, '\t'*/ +#define LV_GROUP_KEY_PREV 11 /*0x0B, '*/ + +#if USE_LV_GROUP != 0 +/********************** + * TYPEDEFS + **********************/ +struct _lv_group_t; + +typedef void (*lv_group_style_mod_func_t)(lv_style_t *); +typedef void (*lv_group_focus_cb_t)(struct _lv_group_t *); + +typedef struct _lv_group_t +{ + lv_ll_t obj_ll; /*Linked list to store the objects in the group */ + lv_obj_t ** obj_focus; /*The object in focus*/ + lv_group_style_mod_func_t style_mod; /*A function which modifies the style of the focused object*/ + lv_group_style_mod_func_t style_mod_edit;/*A function which modifies the style of the focused object*/ + lv_group_focus_cb_t focus_cb; /*A function to call when a new object is focused (optional)*/ + lv_style_t style_tmp; /*Stores the modified style of the focused object */ + uint8_t frozen :1; /*1: can't focus to new object*/ + uint8_t editing :1; /*1: Edit mode, 0: Navigate mode*/ + uint8_t click_focus :1; /*1: If an object in a group is clicked by an indev then it will be focused */ + uint8_t refocus_policy :1; /*1: Focus prev if focused on deletion. 0: Focus prev if focused on deletion.*/ + uint8_t wrap :1; /*1: Focus next/prev can wrap at end of list. 0: Focus next/prev stops at end of list.*/ +} lv_group_t; + +typedef enum _lv_group_refocus_policy_t { + LV_GROUP_REFOCUS_POLICY_NEXT = 0, + LV_GROUP_REFOCUS_POLICY_PREV = 1 +} lv_group_refocus_policy_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a new object group + * @return pointer to the new object group + */ +lv_group_t * lv_group_create(void); + +/** + * Delete a group object + * @param group pointer to a group + */ +void lv_group_del(lv_group_t * group); + +/** + * Add an object to a group + * @param group pointer to a group + * @param obj pointer to an object to add + */ +void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj); + +/** + * Remove an object from its group + * @param obj pointer to an object to remove + */ +void lv_group_remove_obj(lv_obj_t * obj); + +/** + * Focus on an object (defocus the current) + * @param obj pointer to an object to focus on + */ +void lv_group_focus_obj(lv_obj_t * obj); + +/** + * Focus the next object in a group (defocus the current) + * @param group pointer to a group + */ +void lv_group_focus_next(lv_group_t * group); + +/** + * Focus the previous object in a group (defocus the current) + * @param group pointer to a group + */ +void lv_group_focus_prev(lv_group_t * group); + +/** + * Do not let to change the focus from the current object + * @param group pointer to a group + * @param en true: freeze, false: release freezing (normal mode) + */ +void lv_group_focus_freeze(lv_group_t * group, bool en); + +/** + * Send a control character to the focuses object of a group + * @param group pointer to a group + * @param c a character (use LV_GROUP_KEY_.. to navigate) + * @return result of focused object in group. + */ +lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c); + +/** + * Set a function for a group which will modify the object's style if it is in focus + * @param group pointer to a group + * @param style_mod_func the style modifier function pointer + */ +void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func); + +/** + * Set a function for a group which will modify the object's style if it is in focus in edit mode + * @param group pointer to a group + * @param style_mod_func the style modifier function pointer + */ +void lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func); + +/** + * Set a function for a group which will be called when a new object is focused + * @param group pointer to a group + * @param focus_cb the call back function or NULL if unused + */ +void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb); + +/** + * Set whether the next or previous item in a group is focused if the currently focussed obj is deleted. + * @param group pointer to a group + * @param new refocus policy enum + */ +void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy); + +/** + * Manually set the current mode (edit or navigate). + * @param group pointer to group + * @param edit: true: edit mode; false: navigate mode + */ +void lv_group_set_editing(lv_group_t * group, bool edit); + +/** + * Set the `click_focus` attribute. If enabled then the object will be focused then it is clicked. + * @param group pointer to group + * @param en: true: enable `click_focus` + */ +void lv_group_set_click_focus(lv_group_t * group, bool en); + +/** + * Set whether focus next/prev will allow wrapping from first->last or last->first object. + * @param group pointer to group + * @param en: true: wrapping enabled; false: wrapping disabled + */ +void lv_group_set_wrap(lv_group_t * group, bool en); + +/** + * Modify a style with the set 'style_mod' function. The input style remains unchanged. + * @param group pointer to group + * @param style pointer to a style to modify + * @return a copy of the input style but modified with the 'style_mod' function + */ +lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style); + +/** + * Get the focused object or NULL if there isn't one + * @param group pointer to a group + * @return pointer to the focused object + */ +lv_obj_t * lv_group_get_focused(const lv_group_t * group); + +/** + * Get a the style modifier function of a group + * @param group pointer to a group + * @return pointer to the style modifier function + */ +lv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group); + +/** + * Get a the style modifier function of a group in edit mode + * @param group pointer to a group + * @return pointer to the style modifier function + */ +lv_group_style_mod_func_t lv_group_get_style_mod_edit_cb(const lv_group_t * group); + +/** + * Get the focus callback function of a group + * @param group pointer to a group + * @return the call back function or NULL if not set + */ +lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group); + +/** + * Get the current mode (edit or navigate). + * @param group pointer to group + * @return true: edit mode; false: navigate mode + */ +bool lv_group_get_editing(const lv_group_t * group); + +/** + * Get the `click_focus` attribute. + * @param group pointer to group + * @return true: `click_focus` is enabled; false: disabled + */ +bool lv_group_get_click_focus(const lv_group_t * group); + +/** + * Get whether focus next/prev will allow wrapping from first->last or last->first object. + * @param group pointer to group + * @param en: true: wrapping enabled; false: wrapping disabled + */ +bool lv_group_get_wrap(lv_group_t * group); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_GROUP != 0*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GROUP_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_core/lv_indev.h b/old-code/v5_hal/firmware/include/display/lv_core/lv_indev.h new file mode 100644 index 00000000..b066246b --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_core/lv_indev.h @@ -0,0 +1,157 @@ +/** + * @file lv_indev_proc.h + * + */ + +#ifndef LV_INDEV_H +#define LV_INDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" +#include "display/lv_hal/lv_hal_indev.h" +#include "display/lv_core/lv_group.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the display input device subsystem + */ +void lv_indev_init(void); + +/** + * Get the currently processed input device. Can be used in action functions too. + * @return pointer to the currently processed input device or NULL if no input device processing right now + */ +lv_indev_t * lv_indev_get_act(void); + + +/** + * Get the type of an input device + * @param indev pointer to an input device + * @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`) + */ +lv_hal_indev_type_t lv_indev_get_type(const lv_indev_t * indev); + +/** + * Reset one or all input devices + * @param indev pointer to an input device to reset or NULL to reset all of them + */ +void lv_indev_reset(lv_indev_t * indev); + +/** + * Reset the long press state of an input device + * @param indev_proc pointer to an input device + */ +void lv_indev_reset_lpr(lv_indev_t * indev); + +/** + * Enable input devices device by type + * @param type Input device type + * @param enable true: enable this type; false: disable this type + */ +void lv_indev_enable(lv_hal_indev_type_t type, bool enable); + +/** + * Set a cursor for a pointer input device (for LV_INPUT_TYPE_POINTER and LV_INPUT_TYPE_BUTTON) + * @param indev pointer to an input device + * @param cur_obj pointer to an object to be used as cursor + */ +void lv_indev_set_cursor(lv_indev_t *indev, lv_obj_t *cur_obj); + +#if USE_LV_GROUP +/** + * Set a destination group for a keypad input device (for LV_INDEV_TYPE_KEYPAD) + * @param indev pointer to an input device + * @param group point to a group + */ +void lv_indev_set_group(lv_indev_t *indev, lv_group_t *group); +#endif + +/** + * Set the an array of points for LV_INDEV_TYPE_BUTTON. + * These points will be assigned to the buttons to press a specific point on the screen + * @param indev pointer to an input device + * @param group point to a group + */ +void lv_indev_set_button_points(lv_indev_t *indev, const lv_point_t *points); + +/** + * Set feedback callback for indev. + * @param indev pointer to an input device + * @param feedback feedback callback + */ +void lv_indev_set_feedback(lv_indev_t *indev, lv_indev_feedback_t feedback); + +/** + * Get the last point of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @param point pointer to a point to store the result + */ +void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point); + +/** + * Get the last key of an input device (for LV_INDEV_TYPE_KEYPAD) + * @param indev pointer to an input device + * @return the last pressed key (0 on error) + */ +uint32_t lv_indev_get_key(const lv_indev_t * indev); + +/** + * Check if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @return true: drag is in progress + */ +bool lv_indev_is_dragging(const lv_indev_t * indev); + +/** + * Get the vector of dragging of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @param point pointer to a point to store the vector + */ +void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point); +/** + * Get elapsed time since last press + * @param indev pointer to an input device (NULL to get the overall smallest inactivity) + * @return Elapsed ticks (milliseconds) since last press + */ +uint32_t lv_indev_get_inactive_time(const lv_indev_t * indev); + +/** + * Get feedback callback for indev. + * @param indev pointer to an input device + * @return feedback callback + */ +lv_indev_feedback_t lv_indev_get_feedback(const lv_indev_t *indev); + +/** + * Do nothing until the next release + * @param indev pointer to an input device + */ +void lv_indev_wait_release(lv_indev_t * indev); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_INDEV_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_core/lv_lang.h b/old-code/v5_hal/firmware/include/display/lv_core/lv_lang.h new file mode 100644 index 00000000..efbdd0a8 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_core/lv_lang.h @@ -0,0 +1,74 @@ +/** + * @file lv_lang.h + * + */ + +#ifndef LV_LANG_H +#define LV_LANG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_MULTI_LANG + +#include + +/********************* + * DEFINES + *********************/ +#define LV_LANG_TXT_ID_NONE 0xFFFF /*Used to not assign any text IDs for a multi-language object.*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Change the language + * @param lang_id the id of the + */ +void lv_lang_set(uint8_t lang_id); + +/** + * Set a function to get the texts of the set languages from a `txt_id` + * @param fp a function pointer to get the texts + */ +void lv_lang_set_text_func(const void * (*fp)(uint16_t)); + +/** + * Use the function set by `lv_lang_set_text_func` to get the `txt_id` text in the set language + * @param txt_id an ID of the text to get + * @return the `txt_id` txt on the set language + */ +const void * lv_lang_get_text(uint16_t txt_id); + +/** + * Return with ID of the currently selected language + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +uint8_t lv_lang_act(void); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_MULTI_LANG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LANG_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_core/lv_obj.h b/old-code/v5_hal/firmware/include/display/lv_core/lv_obj.h new file mode 100644 index 00000000..02378a51 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_core/lv_obj.h @@ -0,0 +1,841 @@ +/** + * @file lv_obj.h + * + */ + +#ifndef LV_OBJ_H +#define LV_OBJ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include +#include "lv_style.h" +#include "display/lv_misc/lv_area.h" +#include "display/lv_misc/lv_mem.h" +#include "display/lv_misc/lv_ll.h" +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_log.h" + +/********************* + * DEFINES + *********************/ + +/*Error check of lv_conf.h*/ +#if LV_HOR_RES == 0 || LV_VER_RES == 0 +#error "LittlevGL: LV_HOR_RES and LV_VER_RES must be greater than 0" +#endif + +#if LV_ANTIALIAS > 1 +#error "LittlevGL: LV_ANTIALIAS can be only 0 or 1" +#endif + +#if LV_VDB_SIZE == 0 && LV_ANTIALIAS != 0 +#error "LittlevGL: If LV_VDB_SIZE == 0 the anti-aliasing must be disabled" +#endif + +#if LV_VDB_SIZE > 0 && LV_VDB_SIZE < LV_HOR_RES +#error "LittlevGL: Small Virtual Display Buffer (lv_conf.h: LV_VDB_SIZE >= LV_HOR_RES)" +#endif + +#if LV_VDB_SIZE == 0 && USE_LV_REAL_DRAW == 0 +#error "LittlevGL: If LV_VDB_SIZE = 0 Real drawing function are required (lv_conf.h: USE_LV_REAL_DRAW 1)" +#endif + + +#define LV_ANIM_IN 0x00 /*Animation to show an object. 'OR' it with lv_anim_builtin_t*/ +#define LV_ANIM_OUT 0x80 /*Animation to hide an object. 'OR' it with lv_anim_builtin_t*/ +#define LV_ANIM_DIR_MASK 0x80 /*ANIM_IN/ANIM_OUT mask*/ + +#define LV_MAX_ANCESTOR_NUM 8 + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_obj_t; + +enum +{ + LV_DESIGN_DRAW_MAIN, + LV_DESIGN_DRAW_POST, + LV_DESIGN_COVER_CHK, +}; +typedef uint8_t lv_design_mode_t; + +typedef bool (* lv_design_func_t) (struct _lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode); + +enum +{ + LV_RES_INV = 0, /*Typically indicates that the object is deleted (become invalid) in the action function or an operation was failed*/ + LV_RES_OK, /*The object is valid (no deleted) after the action*/ +}; +typedef uint8_t lv_res_t; + +enum +{ + /*General signals*/ + LV_SIGNAL_CLEANUP, + LV_SIGNAL_CHILD_CHG, + LV_SIGNAL_CORD_CHG, + LV_SIGNAL_STYLE_CHG, + LV_SIGNAL_REFR_EXT_SIZE, + LV_SIGNAL_LANG_CHG, + LV_SIGNAL_GET_TYPE, + + _LV_SIGNAL_FEEDBACK_SECTION_START, + /*Input device related*/ + LV_SIGNAL_PRESSED, + LV_SIGNAL_PRESSING, + LV_SIGNAL_PRESS_LOST, + LV_SIGNAL_RELEASED, + LV_SIGNAL_LONG_PRESS, + LV_SIGNAL_LONG_PRESS_REP, + LV_SIGNAL_DRAG_BEGIN, + LV_SIGNAL_DRAG_END, + + /*Group related*/ + LV_SIGNAL_FOCUS, + LV_SIGNAL_DEFOCUS, + LV_SIGNAL_CONTROLL, + _LV_SIGNAL_FEEDBACK_SECTION_END, + LV_SIGNAL_GET_EDITABLE, +}; +typedef uint8_t lv_signal_t; + +typedef lv_res_t (* lv_signal_func_t) (struct _lv_obj_t * obj, lv_signal_t sign, void * param); + +enum +{ + LV_ALIGN_CENTER = 0, + LV_ALIGN_IN_TOP_LEFT, + LV_ALIGN_IN_TOP_MID, + LV_ALIGN_IN_TOP_RIGHT, + LV_ALIGN_IN_BOTTOM_LEFT, + LV_ALIGN_IN_BOTTOM_MID, + LV_ALIGN_IN_BOTTOM_RIGHT, + LV_ALIGN_IN_LEFT_MID, + LV_ALIGN_IN_RIGHT_MID, + LV_ALIGN_OUT_TOP_LEFT, + LV_ALIGN_OUT_TOP_MID, + LV_ALIGN_OUT_TOP_RIGHT, + LV_ALIGN_OUT_BOTTOM_LEFT, + LV_ALIGN_OUT_BOTTOM_MID, + LV_ALIGN_OUT_BOTTOM_RIGHT, + LV_ALIGN_OUT_LEFT_TOP, + LV_ALIGN_OUT_LEFT_MID, + LV_ALIGN_OUT_LEFT_BOTTOM, + LV_ALIGN_OUT_RIGHT_TOP, + LV_ALIGN_OUT_RIGHT_MID, + LV_ALIGN_OUT_RIGHT_BOTTOM, +}; +typedef uint8_t lv_align_t; + +#if LV_OBJ_REALIGN +typedef struct { + const struct _lv_obj_t * base; + lv_coord_t xofs; + lv_coord_t yofs; + lv_align_t align; + uint8_t auto_realign :1; + uint8_t origo_align :1; /*1: the oigo (center of the object) was aligned with `lv_obj_align_origo`*/ +}lv_reailgn_t; +#endif + + +typedef struct _lv_obj_t +{ + struct _lv_obj_t * par; /*Pointer to the parent object*/ + lv_ll_t child_ll; /*Linked list to store the children objects*/ + + lv_area_t coords; /*Coordinates of the object (x1, y1, x2, y2)*/ + + lv_signal_func_t signal_func; /*Object type specific signal function*/ + lv_design_func_t design_func; /*Object type specific design function*/ + + void * ext_attr; /*Object type specific extended data*/ + lv_style_t * style_p; /*Pointer to the object's style*/ + +#if LV_OBJ_FREE_PTR != 0 + void * free_ptr; /*Application specific pointer (set it freely)*/ +#endif + +#if USE_LV_GROUP != 0 + void * group_p; /*Pointer to the group of the object*/ +#endif + /*Attributes and states*/ + uint8_t click :1; /*1: Can be pressed by an input device*/ + uint8_t drag :1; /*1: Enable the dragging*/ + uint8_t drag_throw :1; /*1: Enable throwing with drag*/ + uint8_t drag_parent :1; /*1: Parent will be dragged instead*/ + uint8_t hidden :1; /*1: Object is hidden*/ + uint8_t top :1; /*1: If the object or its children is clicked it goes to the foreground*/ + uint8_t opa_scale_en :1; /*1: opa_scale is set*/ + uint8_t protect; /*Automatically happening actions can be prevented. 'OR'ed values from `lv_protect_t`*/ + lv_opa_t opa_scale; /*Scale down the opacity by this factor. Effects all children as well*/ + + lv_coord_t ext_size; /*EXTtend the size of the object in every direction. E.g. for shadow drawing*/ +#if LV_OBJ_REALIGN + lv_reailgn_t realign; +#endif + +#ifdef LV_OBJ_FREE_NUM_TYPE + LV_OBJ_FREE_NUM_TYPE free_num; /*Application specific identifier (set it freely)*/ +#endif +} lv_obj_t; + +typedef lv_res_t (*lv_action_t) (struct _lv_obj_t * obj); + +/*Protect some attributes (max. 8 bit)*/ +enum +{ + LV_PROTECT_NONE = 0x00, + LV_PROTECT_CHILD_CHG = 0x01, /*Disable the child change signal. Used by the library*/ + LV_PROTECT_PARENT = 0x02, /*Prevent automatic parent change (e.g. in lv_page)*/ + LV_PROTECT_POS = 0x04, /*Prevent automatic positioning (e.g. in lv_cont layout)*/ + LV_PROTECT_FOLLOW = 0x08, /*Prevent the object be followed in automatic ordering (e.g. in lv_cont PRETTY layout)*/ + LV_PROTECT_PRESS_LOST= 0x10, /*If the `indev` was pressing this object but swiped out while pressing do not search other object.*/ + LV_PROTECT_CLICK_FOCUS= 0x20,/*Prevent focusing the object by clicking on it*/ +}; +typedef uint8_t lv_protect_t; + + +/*Used by `lv_obj_get_type()`. The object's and its ancestor types are stored here*/ +typedef struct { + const char * type[LV_MAX_ANCESTOR_NUM]; /*[0]: the actual type, [1]: ancestor, [2] #1's ancestor ... [x]: "lv_obj" */ +} lv_obj_type_t; + +enum +{ + LV_ANIM_NONE = 0, + LV_ANIM_FLOAT_TOP, /*Float from/to the top*/ + LV_ANIM_FLOAT_LEFT, /*Float from/to the left*/ + LV_ANIM_FLOAT_BOTTOM, /*Float from/to the bottom*/ + LV_ANIM_FLOAT_RIGHT, /*Float from/to the right*/ + LV_ANIM_GROW_H, /*Grow/shrink horizontally*/ + LV_ANIM_GROW_V, /*Grow/shrink vertically*/ +}; +typedef uint8_t lv_anim_builtin_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init. the 'lv' library. + */ +void lv_init(void); + +/*-------------------- + * Create and delete + *-------------------*/ + +/** + * Create a basic object + * @param parent pointer to a parent object. + * If NULL then a screen will be created + * @param copy pointer to a base object, if not NULL then the new object will be copied from it + * @return pointer to the new object + */ +lv_obj_t * lv_obj_create(lv_obj_t * parent,const lv_obj_t * copy); + +/** + * Delete 'obj' and all of its children + * @param obj pointer to an object to delete + * @return LV_RES_INV because the object is deleted + */ +lv_res_t lv_obj_del(lv_obj_t * obj); + +/** + * Delete all children of an object + * @param obj pointer to an object + */ +void lv_obj_clean(lv_obj_t *obj); + +/** + * Mark the object as invalid therefore its current position will be redrawn by 'lv_refr_task' + * @param obj pointer to an object + */ +void lv_obj_invalidate(const lv_obj_t * obj); + +/*===================== + * Setter functions + *====================*/ + +/*-------------- + * Screen set + *--------------*/ + +/** + * Load a new screen + * @param scr pointer to a screen + */ +void lv_scr_load(lv_obj_t * scr); + +/*-------------------- + * Parent/children set + *--------------------*/ + +/** + * Set a new parent for an object. Its relative position will be the same. + * @param obj pointer to an object. Can't be a screen. + * @param parent pointer to the new parent object. (Can't be NULL) + */ +void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent); + +/*-------------------- + * Coordinate set + * ------------------*/ + +/** + * Set relative the position of an object (relative to the parent) + * @param obj pointer to an object + * @param x new distance from the left side of the parent + * @param y new distance from the top of the parent + */ +void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y); + +/** + * Set the x coordinate of a object + * @param obj pointer to an object + * @param x new distance from the left side from the parent + */ +void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x); + +/** + * Set the y coordinate of a object + * @param obj pointer to an object + * @param y new distance from the top of the parent + */ +void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y); + +/** + * Set the size of an object + * @param obj pointer to an object + * @param w new width + * @param h new height + */ +void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h); + +/** + * Set the width of an object + * @param obj pointer to an object + * @param w new width + */ +void lv_obj_set_width(lv_obj_t * obj, lv_coord_t w); + +/** + * Set the height of an object + * @param obj pointer to an object + * @param h new height + */ +void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h); + +/** + * Align an object to an other object. + * @param obj pointer to an object to align + * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. + * @param align type of alignment (see 'lv_align_t' enum) + * @param x_mod x coordinate shift after alignment + * @param y_mod y coordinate shift after alignment + */ +void lv_obj_align(lv_obj_t * obj,const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod); + +/** + * Align an object to an other object. + * @param obj pointer to an object to align + * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. + * @param align type of alignment (see 'lv_align_t' enum) + * @param x_mod x coordinate shift after alignment + * @param y_mod y coordinate shift after alignment + */ +void lv_obj_align_origo(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod); + +/** + * Realign the object based on the last `lv_obj_align` parameters. + * @param obj pointer to an object + */ +void lv_obj_realign(lv_obj_t * obj); + +/** + * Enable the automatic realign of the object when its size has changed based on the last `lv_obj_align` parameters. + * @param obj pointer to an object + * @param en true: enable auto realign; false: disable auto realign + */ +void lv_obj_set_auto_realign(lv_obj_t * obj, bool en); + +/*--------------------- + * Appearance set + *--------------------*/ + +/** + * Set a new style for an object + * @param obj pointer to an object + * @param style_p pointer to the new style + */ +void lv_obj_set_style(lv_obj_t * obj, lv_style_t * style); + +/** + * Notify an object about its style is modified + * @param obj pointer to an object + */ +void lv_obj_refresh_style(lv_obj_t * obj); + +/** + * Notify all object if a style is modified + * @param style pointer to a style. Only the objects with this style will be notified + * (NULL to notify all objects) + */ +void lv_obj_report_style_mod(lv_style_t * style); + +/*----------------- + * Attribute set + *----------------*/ + +/** + * Hide an object. It won't be visible and clickable. + * @param obj pointer to an object + * @param en true: hide the object + */ +void lv_obj_set_hidden(lv_obj_t * obj, bool en); + +/** + * Enable or disable the clicking of an object + * @param obj pointer to an object + * @param en true: make the object clickable + */ +void lv_obj_set_click(lv_obj_t * obj, bool en); + +/** + * Enable to bring this object to the foreground if it + * or any of its children is clicked + * @param obj pointer to an object + * @param en true: enable the auto top feature + */ +void lv_obj_set_top(lv_obj_t * obj, bool en); + +/** + * Enable the dragging of an object + * @param obj pointer to an object + * @param en true: make the object dragable + */ +void lv_obj_set_drag(lv_obj_t * obj, bool en); + +/** + * Enable the throwing of an object after is is dragged + * @param obj pointer to an object + * @param en true: enable the drag throw + */ +void lv_obj_set_drag_throw(lv_obj_t * obj, bool en); + +/** + * Enable to use parent for drag related operations. + * If trying to drag the object the parent will be moved instead + * @param obj pointer to an object + * @param en true: enable the 'drag parent' for the object + */ +void lv_obj_set_drag_parent(lv_obj_t * obj, bool en); + +/** + * Set editable parameter Used by groups and keyboard/encoder control. + * Editable object has something inside to choose (the elements of a list) + * @param obj pointer to an object + * @param en true: enable editing + */ +//void lv_obj_set_editable(lv_obj_t * obj, bool en); + +/** + * Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`) + * @param obj pointer to an object + * @param en true: opa scaling is enabled for this object and all children; false: no opa scaling + */ +void lv_obj_set_opa_scale_enable(lv_obj_t * obj, bool en); + +/** + * Set the opa scale of an object + * @param obj pointer to an object + * @param opa_scale a factor to scale down opacity [0..255] + */ +void lv_obj_set_opa_scale(lv_obj_t * obj, lv_opa_t opa_scale); + +/** + * Set a bit or bits in the protect filed + * @param obj pointer to an object + * @param prot 'OR'-ed values from `lv_protect_t` + */ +void lv_obj_set_protect(lv_obj_t * obj, uint8_t prot); + +/** + * Clear a bit or bits in the protect filed + * @param obj pointer to an object + * @param prot 'OR'-ed values from `lv_protect_t` + */ +void lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot); + +/** + * Set the signal function of an object. + * Always call the previous signal function in the new. + * @param obj pointer to an object + * @param fp the new signal function + */ +void lv_obj_set_signal_func(lv_obj_t * obj, lv_signal_func_t fp); + +/** + * Set a new design function for an object + * @param obj pointer to an object + * @param fp the new design function + */ +void lv_obj_set_design_func(lv_obj_t * obj, lv_design_func_t fp); + +/*---------------- + * Other set + *--------------*/ + +/** + * Allocate a new ext. data for an object + * @param obj pointer to an object + * @param ext_size the size of the new ext. data + * @return pointer to the allocated ext + */ +void * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size); + +/** + * Send a 'LV_SIGNAL_REFR_EXT_SIZE' signal to the object + * @param obj pointer to an object + */ +void lv_obj_refresh_ext_size(lv_obj_t * obj); + +#ifdef LV_OBJ_FREE_NUM_TYPE +/** + * Set an application specific number for an object. + * It can help to identify objects in the application. + * @param obj pointer to an object + * @param free_num the new free number + */ +void lv_obj_set_free_num(lv_obj_t * obj, LV_OBJ_FREE_NUM_TYPE free_num); +#endif + +#if LV_OBJ_FREE_PTR != 0 +/** + * Set an application specific pointer for an object. + * It can help to identify objects in the application. + * @param obj pointer to an object + * @param free_p the new free pinter + */ +void lv_obj_set_free_ptr(lv_obj_t * obj, void * free_p); +#endif + +#if USE_LV_ANIMATION +/** + * Animate an object + * @param obj pointer to an object to animate + * @param type type of animation from 'lv_anim_builtin_t'. 'OR' it with ANIM_IN or ANIM_OUT + * @param time time of animation in milliseconds + * @param delay delay before the animation in milliseconds + * @param cb a function to call when the animation is ready + */ +void lv_obj_animate(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint16_t delay, void (*cb) (lv_obj_t *)); +#endif + +/*======================= + * Getter functions + *======================*/ + +/*------------------ + * Screen get + *-----------------*/ + +/** + * Return with a pointer to the active screen + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +lv_obj_t * lv_scr_act(void); + +/** + * Return with the top layer. (Same on every screen and it is above the normal screen layer) + * @return pointer to the top layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_layer_top(void); + +/** + * Return with the system layer. (Same on every screen and it is above the all other layers) + * It is used for example by the cursor + * @return pointer to the system layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_layer_sys(void); + +/** + * Return with the screen of an object + * @param obj pointer to an object + * @return pointer to a screen + */ +lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj); + +/*--------------------- + * Parent/children get + *--------------------*/ + +/** + * Returns with the parent of an object + * @param obj pointer to an object + * @return pointer to the parent of 'obj' + */ +lv_obj_t * lv_obj_get_parent(const lv_obj_t * obj); + +/** + * Iterate through the children of an object (start from the "youngest, lastly created") + * @param obj pointer to an object + * @param child NULL at first call to get the next children + * and the previous return value later + * @return the child after 'act_child' or NULL if no more child + */ +lv_obj_t * lv_obj_get_child(const lv_obj_t * obj, const lv_obj_t * child); + +/** + * Iterate through the children of an object (start from the "oldest", firstly created) + * @param obj pointer to an object + * @param child NULL at first call to get the next children + * and the previous return value later + * @return the child after 'act_child' or NULL if no more child + */ +lv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child); + +/** + * Count the children of an object (only children directly on 'obj') + * @param obj pointer to an object + * @return children number of 'obj' + */ +uint16_t lv_obj_count_children(const lv_obj_t * obj); + +/*--------------------- + * Coordinate get + *--------------------*/ + +/** + * Copy the coordinates of an object to an area + * @param obj pointer to an object + * @param cords_p pointer to an area to store the coordinates + */ +void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * cords_p); + +/** + * Get the x coordinate of object + * @param obj pointer to an object + * @return distance of 'obj' from the left side of its parent + */ +lv_coord_t lv_obj_get_x(const lv_obj_t * obj); + +/** + * Get the y coordinate of object + * @param obj pointer to an object + * @return distance of 'obj' from the top of its parent + */ +lv_coord_t lv_obj_get_y(const lv_obj_t * obj); + +/** + * Get the width of an object + * @param obj pointer to an object + * @return the width + */ +lv_coord_t lv_obj_get_width(const lv_obj_t * obj); + +/** + * Get the height of an object + * @param obj pointer to an object + * @return the height + */ +lv_coord_t lv_obj_get_height(const lv_obj_t * obj); + +/** + * Get the extended size attribute of an object + * @param obj pointer to an object + * @return the extended size attribute + */ +lv_coord_t lv_obj_get_ext_size(const lv_obj_t * obj); + +/** + * Get the automatic realign property of the object. + * @param obj pointer to an object + * @return true: auto realign is enabled; false: auto realign is disabled + */ +bool lv_obj_get_auto_realign(lv_obj_t * obj); + +/*----------------- + * Appearance get + *---------------*/ + +/** + * Get the style pointer of an object (if NULL get style of the parent) + * @param obj pointer to an object + * @return pointer to a style + */ +lv_style_t * lv_obj_get_style(const lv_obj_t * obj); + +/*----------------- + * Attribute get + *----------------*/ + +/** + * Get the hidden attribute of an object + * @param obj pointer to an object + * @return true: the object is hidden + */ +bool lv_obj_get_hidden(const lv_obj_t * obj); + +/** + * Get the click enable attribute of an object + * @param obj pointer to an object + * @return true: the object is clickable + */ +bool lv_obj_get_click(const lv_obj_t * obj); + +/** + * Get the top enable attribute of an object + * @param obj pointer to an object + * @return true: the auto top feature is enabled + */ +bool lv_obj_get_top(const lv_obj_t * obj); + +/** + * Get the drag enable attribute of an object + * @param obj pointer to an object + * @return true: the object is dragable + */ +bool lv_obj_get_drag(const lv_obj_t * obj); + +/** + * Get the drag throw enable attribute of an object + * @param obj pointer to an object + * @return true: drag throw is enabled + */ +bool lv_obj_get_drag_throw(const lv_obj_t * obj); + +/** + * Get the drag parent attribute of an object + * @param obj pointer to an object + * @return true: drag parent is enabled + */ +bool lv_obj_get_drag_parent(const lv_obj_t * obj); + + +/** + * Get the opa scale enable parameter + * @param obj pointer to an object + * @return true: opa scaling is enabled for this object and all children; false: no opa scaling + */ +lv_opa_t lv_obj_get_opa_scale_enable(const lv_obj_t * obj); + +/** + * Get the opa scale parameter of an object + * @param obj pointer to an object + * @return opa scale [0..255] + */ +lv_opa_t lv_obj_get_opa_scale(const lv_obj_t * obj); + +/** + * Get the protect field of an object + * @param obj pointer to an object + * @return protect field ('OR'ed values of `lv_protect_t`) + */ +uint8_t lv_obj_get_protect(const lv_obj_t * obj); + +/** + * Check at least one bit of a given protect bitfield is set + * @param obj pointer to an object + * @param prot protect bits to test ('OR'ed values of `lv_protect_t`) + * @return false: none of the given bits are set, true: at least one bit is set + */ +bool lv_obj_is_protected(const lv_obj_t * obj, uint8_t prot); + +/** + * Get the signal function of an object + * @param obj pointer to an object + * @return the signal function + */ +lv_signal_func_t lv_obj_get_signal_func(const lv_obj_t * obj); + +/** + * Get the design function of an object + * @param obj pointer to an object + * @return the design function + */ +lv_design_func_t lv_obj_get_design_func(const lv_obj_t * obj); + +/*------------------ + * Other get + *-----------------*/ + +/** + * Get the ext pointer + * @param obj pointer to an object + * @return the ext pointer but not the dynamic version + * Use it as ext->data1, and NOT da(ext)->data1 + */ +void * lv_obj_get_ext_attr(const lv_obj_t * obj); + +/** + * Get object's and its ancestors type. Put their name in `type_buf` starting with the current type. + * E.g. buf.type[0]="lv_btn", buf.type[1]="lv_cont", buf.type[2]="lv_obj" + * @param obj pointer to an object which type should be get + * @param buf pointer to an `lv_obj_type_t` buffer to store the types + */ +void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf); + +#ifdef LV_OBJ_FREE_NUM_TYPE +/** + * Get the free number + * @param obj pointer to an object + * @return the free number + */ +LV_OBJ_FREE_NUM_TYPE lv_obj_get_free_num(const lv_obj_t * obj); +#endif + +#if LV_OBJ_FREE_PTR != 0 +/** + * Get the free pointer + * @param obj pointer to an object + * @return the free pointer + */ +void * lv_obj_get_free_ptr(const lv_obj_t * obj); +#endif + +#if USE_LV_GROUP +/** + * Get the group of the object + * @param obj pointer to an object + * @return the pointer to group of the object + */ +void * lv_obj_get_group(const lv_obj_t * obj); + + +/** + * Tell whether the object is the focused object of a group or not. + * @param obj pointer to an object + * @return true: the object is focused, false: the object is not focused or not in a group + */ +bool lv_obj_is_focused(const lv_obj_t * obj); + +#endif + + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_OBJ_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_core/lv_refr.h b/old-code/v5_hal/firmware/include/display/lv_core/lv_refr.h new file mode 100644 index 00000000..75b22d01 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_core/lv_refr.h @@ -0,0 +1,95 @@ +/** + * @file lv_refr.h + * + */ + +#ifndef LV_REFR_H +#define LV_REFR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the screen refresh subsystem + */ +void lv_refr_init(void); + +/** + * Redraw the invalidated areas now. + * Normally the redrawing is periodically executed in `lv_task_handler` but a long blocking process can + * prevent the call of `lv_task_handler`. In this case if the the GUI is updated in the process (e.g. progress bar) + * this function can be called when the screen should be updated. + */ +void lv_refr_now(void); + +/** + * Invalidate an area + * @param area_p pointer to area which should be invalidated + */ +void lv_inv_area(const lv_area_t * area_p); + +/** + * Set a function to call after every refresh to announce the refresh time and the number of refreshed pixels + * @param cb pointer to a callback function (void my_refr_cb(uint32_t time_ms, uint32_t px_num)) + */ +void lv_refr_set_monitor_cb(void (*cb)(uint32_t, uint32_t)); + +/** + * Called when an area is invalidated to modify the coordinates of the area. + * Special display controllers may require special coordinate rounding + * @param cb pointer to the a function which will modify the area + */ +void lv_refr_set_round_cb(void(*cb)(lv_area_t*)); + +/** + * Get the number of areas in the buffer + * @return number of invalid areas + */ +uint16_t lv_refr_get_buf_size(void); + +/** + * Pop (delete) the last 'num' invalidated areas from the buffer + * @param num number of areas to delete + */ +void lv_refr_pop_from_buf(uint16_t num); +/********************** + * STATIC FUNCTIONS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_REFR_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_core/lv_style.h b/old-code/v5_hal/firmware/include/display/lv_core/lv_style.h new file mode 100644 index 00000000..4206ada3 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_core/lv_style.h @@ -0,0 +1,199 @@ +/** + * @file lv_style.h + * + */ + +#ifndef LV_STYLE_H +#define LV_STYLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_area.h" +#include "display/lv_misc/lv_font.h" +#include "display/lv_misc/lv_anim.h" + +/********************* + * DEFINES + *********************/ +#define LV_RADIUS_CIRCLE (LV_COORD_MAX) /*A very big radius to always draw as circle*/ + +/********************** + * TYPEDEFS + **********************/ + +/*Border types (Use 'OR'ed values)*/ +enum +{ + LV_BORDER_NONE = 0x00, + LV_BORDER_BOTTOM = 0x01, + LV_BORDER_TOP = 0x02, + LV_BORDER_LEFT = 0x04, + LV_BORDER_RIGHT = 0x08, + LV_BORDER_FULL = 0x0F, + LV_BORDER_INTERNAL = 0x10, /*FOR matrix-like objects (e.g. Button matrix)*/ +}; +typedef uint8_t lv_border_part_t; + +/*Shadow types*/ +enum +{ + LV_SHADOW_BOTTOM = 0, + LV_SHADOW_FULL, +}; +typedef uint8_t lv_shadow_type_t; + +typedef struct +{ + uint8_t glass :1; /*1: Do not inherit this style*/ + + struct { + lv_color_t main_color; + lv_color_t grad_color; /*`grad_color` will be removed in v6.0, use `aux_color` instead*/ + lv_coord_t radius; + lv_opa_t opa; + + struct { + lv_color_t color; + lv_coord_t width; + lv_border_part_t part; + lv_opa_t opa; + } border; + + struct { + lv_color_t color; + lv_coord_t width; + lv_shadow_type_t type; + } shadow; + + struct { + lv_coord_t ver; + lv_coord_t hor; + lv_coord_t inner; + } padding; + + uint8_t empty :1; /*Transparent background (border still drawn)*/ + } body; + + + struct { + lv_color_t color; + const lv_font_t * font; + lv_coord_t letter_space; + lv_coord_t line_space; + lv_opa_t opa; + } text; + + struct { + lv_color_t color; + lv_opa_t intense; + lv_opa_t opa; + } image; + + struct { + lv_color_t color; + lv_coord_t width; + lv_opa_t opa; + uint8_t rounded :1; /*1: rounded line endings*/ + } line; +} lv_style_t; + +#if USE_LV_ANIMATION +typedef struct { + const lv_style_t * style_start; /*Pointer to the starting style*/ + const lv_style_t * style_end; /*Pointer to the destination style*/ + lv_style_t * style_anim; /*Pointer to a style to animate*/ + lv_anim_cb_t end_cb; /*Call it when the animation is ready (NULL if unused)*/ + int16_t time; /*Animation time in ms*/ + int16_t act_time; /*Current time in animation. Set to negative to make delay.*/ + uint16_t playback_pause; /*Wait before play back*/ + uint16_t repeat_pause; /*Wait before repeat*/ + uint8_t playback :1; /*When the animation is ready play it back*/ + uint8_t repeat :1; /*Repeat the animation infinitely*/ +} lv_style_anim_t; + +/* Example initialization +lv_style_anim_t a; +a.style_anim = &style_to_anim; +a.style_start = &style_1; +a.style_end = &style_2; +a.act_time = 0; +a.time = 1000; +a.playback = 0; +a.playback_pause = 0; +a.repeat = 0; +a.repeat_pause = 0; +a.end_cb = NULL; +lv_style_anim_create(&a); + */ +#endif + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init the basic styles + */ +void lv_style_init (void); + +/** + * Copy a style to an other + * @param dest pointer to the destination style + * @param src pointer to the source style + */ +void lv_style_copy(lv_style_t * dest, const lv_style_t * src); + + +/** + * Mix two styles according to a given ratio + * @param start start style + * @param end end style + * @param res store the result style here + * @param ratio the ratio of mix [0..256]; 0: `start` style; 256: `end` style + */ +void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * res, uint16_t ratio); + +#if USE_LV_ANIMATION + +/** + * Create an animation from a pre-configured 'lv_style_anim_t' variable + * @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied) + * @return pointer to a descriptor. Really this variable will be animated. (Can be used in `lv_anim_del(dsc, NULL)`) + */ +void * lv_style_anim_create(lv_style_anim_t * anim); +#endif + +/************************* + * GLOBAL VARIABLES + *************************/ +extern lv_style_t lv_style_scr; +extern lv_style_t lv_style_transp; +extern lv_style_t lv_style_transp_fit; +extern lv_style_t lv_style_transp_tight; +extern lv_style_t lv_style_plain; +extern lv_style_t lv_style_plain_color; +extern lv_style_t lv_style_pretty; +extern lv_style_t lv_style_pretty_color; +extern lv_style_t lv_style_btn_rel; +extern lv_style_t lv_style_btn_pr; +extern lv_style_t lv_style_btn_tgl_rel; +extern lv_style_t lv_style_btn_tgl_pr; +extern lv_style_t lv_style_btn_ina; + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_STYLE_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_core/lv_vdb.h b/old-code/v5_hal/firmware/include/display/lv_core/lv_vdb.h new file mode 100644 index 00000000..32aac5df --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_core/lv_vdb.h @@ -0,0 +1,119 @@ +/** + * @file lv_vdb.h + * + */ + +#ifndef LV_VDB_H +#define LV_VDB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if LV_VDB_SIZE != 0 + +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_area.h" + +/********************* + * DEFINES + *********************/ +/*Can be used in `lv_conf.h` the set an invalid address for the VDB. It should be replaced later by a valid address using `lv_vdb_set_adr()`*/ +#define LV_VDB_ADR_INV 8 /*8 is still too small to be valid but it's aligned on 64 bit machines as well*/ + +#ifndef LV_VDB_PX_BPP +#define LV_VDB_PX_BPP LV_COLOR_SIZE /* Default is LV_COLOR_SIZE */ +#endif + + +#if LV_VDB_TRUE_DOUBLE_BUFFERED && (LV_VDB_SIZE != LV_HOR_RES * LV_VER_RES || LV_VDB_DOUBLE == 0) +#error "With LV_VDB_TRUE_DOUBLE_BUFFERED: (LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES and LV_VDB_DOUBLE = 1 is required" +#endif + + +/* The size of VDB in bytes. + * (LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3): just divide by 8 to convert bits to bytes + * (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0): add an extra byte to round up. + * E.g. if LV_VDB_SIZE = 10 and LV_VDB_PX_BPP = 1 -> 10 bits -> 2 bytes*/ +#define LV_VDB_SIZE_IN_BYTES ((LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3) + (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0) + +/********************** + * TYPEDEFS + **********************/ + +typedef struct +{ + lv_area_t area; + lv_color_t *buf; +} lv_vdb_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Get the 'vdb' variable or allocate one in LV_VDB_DOUBLE mode + * @return pointer to a 'vdb' variable + */ +lv_vdb_t * lv_vdb_get(void); + +/** + * Flush the content of the vdb + */ +void lv_vdb_flush(void); + +/** + * Set the address of VDB buffer(s) manually. To use this set `LV_VDB_ADR` (and `LV_VDB2_ADR`) to `LV_VDB_ADR_INV` in `lv_conf.h`. + * It should be called before `lv_init()`. The size of the buffer should be: `LV_VDB_SIZE_IN_BYTES` + * @param buf1 address of the VDB. + * @param buf2 address of the second buffer. `NULL` if `LV_VDB_DOUBLE 0` + */ +void lv_vdb_set_adr(void * buf1, void * buf2); + +/** + * Call in the display driver's 'disp_flush' function when the flushing is finished + */ +void lv_flush_ready(void); + +/** + * Get currently active VDB, where the drawing happens. Used with `LV_VDB_DOUBLE 1` + * @return pointer to the active VDB. If `LV_VDB_DOUBLE 0` give the single VDB + */ +lv_vdb_t * lv_vdb_get_active(void); + +/** + * Get currently inactive VDB, which is being displayed or being flushed. Used with `LV_VDB_DOUBLE 1` + * @return pointer to the inactive VDB. If `LV_VDB_DOUBLE 0` give the single VDB + */ +lv_vdb_t * lv_vdb_get_inactive(void); + +/** + * Whether the flushing is in progress or not + * @return true: flushing is in progress; false: flushing ready + */ +bool lv_vdb_is_flushing(void); + +/********************** + * MACROS + **********************/ + +#else /*LV_VDB_SIZE != 0*/ + +/*Just for compatibility*/ +void lv_flush_ready(void); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_VDB_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw.h b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw.h new file mode 100644 index 00000000..55038836 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw.h @@ -0,0 +1,115 @@ +/** + * @file lv_draw.h + * + */ + +#ifndef LV_DRAW_H +#define LV_DRAW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include "display/lv_core/lv_style.h" +#include "display/lv_misc/lv_txt.h" + +/********************* + * DEFINES + *********************/ +/*If image pixels contains alpha we need to know how much byte is a pixel*/ +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 +# define LV_IMG_PX_SIZE_ALPHA_BYTE 2 +#elif LV_COLOR_DEPTH == 16 +# define LV_IMG_PX_SIZE_ALPHA_BYTE 3 +#elif LV_COLOR_DEPTH == 32 +# define LV_IMG_PX_SIZE_ALPHA_BYTE 4 +#endif + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_IMG_SRC_VARIABLE, + LV_IMG_SRC_FILE, + LV_IMG_SRC_SYMBOL, + LV_IMG_SRC_UNKNOWN, +}; +typedef uint8_t lv_img_src_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +#if LV_ANTIALIAS != 0 + +/** + * Get the opacity of a pixel based it's position in a line segment + * @param seg segment length + * @param px_id position of of a pixel which opacity should be get [0..seg-1] + * @param base_opa the base opacity + * @return the opacity of the given pixel + */ +lv_opa_t lv_draw_aa_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t base_opa); + +/** + * Add a vertical anti-aliasing segment (pixels with decreasing opacity) + * @param x start point x coordinate + * @param y start point y coordinate + * @param length length of segment (negative value to start from 0 opacity) + * @param mask draw only in this area + * @param color color of pixels + * @param opa maximum opacity + */ +void lv_draw_aa_ver_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); + +/** + * Add a horizontal anti-aliasing segment (pixels with decreasing opacity) + * @param x start point x coordinate + * @param y start point y coordinate + * @param length length of segment (negative value to start from 0 opacity) + * @param mask draw only in this area + * @param color color of pixels + * @param opa maximum opacity + */ +void lv_draw_aa_hor_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); +#endif + +/********************** + * GLOBAL VARIABLES + **********************/ +extern void (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); +extern void (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); +extern void (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa); +extern void (*const map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa); + +/********************** + * MACROS + **********************/ + +/********************** + * POST INCLUDES + *********************/ +#include "lv_draw_rect.h" +#include "lv_draw_label.h" +#include "lv_draw_img.h" +#include "lv_draw_line.h" +#include "lv_draw_triangle.h" + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw.mk b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw.mk new file mode 100644 index 00000000..a384eefe --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw.mk @@ -0,0 +1,14 @@ +CSRCS += lv_draw_vbasic.c +CSRCS += lv_draw_rbasic.c +CSRCS += lv_draw.c +CSRCS += lv_draw_rect.c +CSRCS += lv_draw_label.c +CSRCS += lv_draw_line.c +CSRCS += lv_draw_img.c +CSRCS += lv_draw_arc.c +CSRCS += lv_draw_triangle.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_draw +VPATH += :$(LVGL_DIR)/lvgl/lv_draw + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_draw" diff --git a/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_arc.h b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_arc.h new file mode 100644 index 00000000..203eabe6 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_arc.h @@ -0,0 +1,53 @@ +/** + * @file lv_draw_arc.h + * + */ + +#ifndef LV_DRAW_ARC_H +#define LV_DRAW_ARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw an arc. (Can draw pie too with great thickness.) + * @param center_x the x coordinate of the center of the arc + * @param center_y the y coordinate of the center of the arc + * @param radius the radius of the arc + * @param mask the arc will be drawn only in this mask + * @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right) + * @param end_angle the end angle of the arc + * @param style style of the arc (`body.thickness`, `body.main_color`, `body.opa` is used) + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, const lv_area_t * mask, + uint16_t start_angle, uint16_t end_angle, const lv_style_t * style, lv_opa_t opa_scale); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_ARC*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_img.h b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_img.h new file mode 100644 index 00000000..ff779580 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_img.h @@ -0,0 +1,167 @@ +/** + * @file lv_draw_img.h + * + */ + +#ifndef LV_DRAW_IMG_H +#define LV_DRAW_IMG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ +#define LV_IMG_DECODER_OPEN_FAIL ((void*)(-1)) + +/********************** + * TYPEDEFS + **********************/ +struct _lv_img_t; + +typedef struct { + + /* The first 8 bit is very important to distinguish the different source types. + * For more info see `lv_img_get_src_type()` in lv_img.c */ + uint32_t cf :5; /* Color format: See `lv_img_color_format_t`*/ + uint32_t always_zero :3; /*It the upper bits of the first byte. Always zero to look like a non-printable character*/ + + uint32_t reserved :2; /*Reserved to be used later*/ + + uint32_t w:11; /*Width of the image map*/ + uint32_t h:11; /*Height of the image map*/ +} lv_img_header_t; + +/*Image color format*/ +enum { + LV_IMG_CF_UNKOWN = 0, + + LV_IMG_CF_RAW, /*Contains the file as it is. Needs custom decoder function*/ + LV_IMG_CF_RAW_ALPHA, /*Contains the file as it is. The image has alpha. Needs custom decoder function*/ + LV_IMG_CF_RAW_CHROMA_KEYED, /*Contains the file as it is. The image is chroma keyed. Needs custom decoder function*/ + + LV_IMG_CF_TRUE_COLOR, /*Color format and depth should match with LV_COLOR settings*/ + LV_IMG_CF_TRUE_COLOR_ALPHA, /*Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/ + LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /*Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels will be transparent*/ + + LV_IMG_CF_INDEXED_1BIT, /*Can have 2 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_2BIT, /*Can have 4 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_4BIT, /*Can have 16 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_8BIT, /*Can have 256 different colors in a palette (always chroma keyed)*/ + + LV_IMG_CF_ALPHA_1BIT, /*Can have one color and it can be drawn or not*/ + LV_IMG_CF_ALPHA_2BIT, /*Can have one color but 4 different alpha value*/ + LV_IMG_CF_ALPHA_4BIT, /*Can have one color but 16 different alpha value*/ + LV_IMG_CF_ALPHA_8BIT, /*Can have one color but 256 different alpha value*/ +}; +typedef uint8_t lv_img_cf_t; + +/* Image header it is compatible with + * the result image converter utility*/ +typedef struct +{ + lv_img_header_t header; + uint32_t data_size; + const uint8_t * data; +} lv_img_dsc_t; + +/* Decoder function definitions */ + + +/** + * Get info from an image and store in the `header` + * @param src the image source. Can be a pointer to a C array or a file name (Use `lv_img_src_get_type` to determine the type) + * @param header store the info here + * @return LV_RES_OK: info written correctly; LV_RES_INV: failed + */ +typedef lv_res_t (*lv_img_decoder_info_f_t)(const void * src, lv_img_header_t * header); + +/** + * Open an image for decoding. Prepare it as it is required to read it later + * @param src the image source. Can be a pointer to a C array or a file name (Use `lv_img_src_get_type` to determine the type) + * @param style the style of image (maybe it will be required to determine a color or something) + * @return there are 3 possible return values: + * 1) buffer with the decoded image + * 2) if can decode the whole image NULL. decoder_read_line will be called to read the image line-by-line + * 3) LV_IMG_DECODER_OPEN_FAIL if the image format is unknown to the decoder or an error occurred + */ +typedef const uint8_t * (*lv_img_decoder_open_f_t)(const void * src, const lv_style_t * style); + +/** + * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`. + * Required only if the "open" function can't return with the whole decoded pixel array. + * @param x start x coordinate + * @param y startt y coordinate + * @param len number of pixels to decode + * @param buf a buffer to store the decoded pixels + * @return LV_RES_OK: ok; LV_RES_INV: failed + */ +typedef lv_res_t (*lv_img_decoder_read_line_f_t)(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); + +/** + * Close the pending decoding. Free resources etc. + */ +typedef void (*lv_img_decoder_close_f_t)(void); + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw an image + * @param coords the coordinates of the image + * @param mask the image will be drawn only in this area + * @param src pointer to a lv_color_t array which contains the pixels of the image + * @param style style of the image + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, + const void * src, const lv_style_t * style, lv_opa_t opa_scale); + + +/** + * Get the type of an image source + * @param src pointer to an image source: + * - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code) + * - a path to a file (e.g. "S:/folder/image.bin") + * - or a symbol (e.g. SYMBOL_CLOSE) + * @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKOWN + */ +lv_img_src_t lv_img_src_get_type(const void * src); + +/** + * Set custom decoder functions. See the typdefs of the function typed above for more info about them + * @param info_fp info get function + * @param open_fp open function + * @param read_fp read line function + * @param close_fp clode function + */ +void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp, + lv_img_decoder_read_line_f_t read_fp, lv_img_decoder_close_f_t close_fp); + +lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header); + +uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf); + +bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf); + +bool lv_img_color_format_has_alpha(lv_img_cf_t cf); + + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_label.h b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_label.h new file mode 100644 index 00000000..8798573d --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_label.h @@ -0,0 +1,53 @@ +/** + * @file lv_draw_label.h + * + */ + +#ifndef LV_DRAW_LABEL_H +#define LV_DRAW_LABEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Write a text + * @param coords coordinates of the label + * @param mask the label will be drawn only in this area + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + * @param txt 0 terminated text to write + * @param flag settings for the text from 'txt_flag_t' enum + * @param offset text offset in x and y direction (NULL if unused) + * + */ +void lv_draw_label(const lv_area_t * coords,const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale, + const char * txt, lv_txt_flag_t flag, lv_point_t * offset); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_LABEL_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_line.h b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_line.h new file mode 100644 index 00000000..4269475e --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_line.h @@ -0,0 +1,49 @@ +/** + * @file lv_draw_line.h + * + */ + +#ifndef LV_DRAW_LINE_H +#define LV_DRAW_LINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw a line + * @param point1 first point of the line + * @param point2 second point of the line + * @param mask the line will be drawn only on this area + * @param style pointer to a line's style + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask, + const lv_style_t * style, lv_opa_t opa_scale); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_LINE_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_rbasic.h b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_rbasic.h new file mode 100644 index 00000000..403cb806 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_rbasic.h @@ -0,0 +1,96 @@ +/** + * @file lv_draw_rbasic..h + * + */ + +#ifndef LV_DRAW_RBASIC_H +#define LV_DRAW_RBASIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_REAL_DRAW != 0 + +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_area.h" +#include "display/lv_misc/lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_rpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa); + +/** + * Fill an area on the display + * @param cords_p coordinates of the area to fill + * @param mask_p fill only o this mask + * @param color fill color + * @param opa opacity (ignored, only for compatibility with lv_vfill) + */ +void lv_rfill(const lv_area_t * cords_p, const lv_area_t * mask_p, + lv_color_t color, lv_opa_t opa); + +/** + * Draw a letter to the display + * @param pos_p left-top coordinate of the latter + * @param mask_p the letter will be drawn only on this area + * @param font_p pointer to font + * @param letter a letter to draw + * @param color color of letter + * @param opa opacity of letter (ignored, only for compatibility with lv_vletter) + */ +void lv_rletter(const lv_point_t * pos_p, const lv_area_t * mask_p, + const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa); + +/** + * When the letter is ant-aliased it needs to know the background color + * @param bg_color the background color of the currently drawn letter + */ +void lv_rletter_set_background(lv_color_t color); + + +/** + * Draw a color map to the display (image) + * @param cords_p coordinates the color map + * @param mask_p the map will drawn only on this area + * @param map_p pointer to a lv_color_t array + * @param opa opacity of the map (ignored, only for compatibility with 'lv_vmap') + * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels + * @param alpha_byte true: extra alpha byte is inserted for every pixel (not supported, only l'v_vmap' can draw it) + * @param recolor mix the pixels with this color + * @param recolor_opa the intense of recoloring + */ +void lv_rmap(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa); +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_REAL_DRAW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_RBASIC_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_rect.h b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_rect.h new file mode 100644 index 00000000..933590ca --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_rect.h @@ -0,0 +1,48 @@ +/** + * @file lv_draw_rect.h + * + */ + +#ifndef LV_DRAW_RECT_H +#define LV_DRAW_RECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw a rectangle + * @param coords the coordinates of the rectangle + * @param mask the rectangle will be drawn only in this mask + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_RECT_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_triangle.h b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_triangle.h new file mode 100644 index 00000000..c3c6208d --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_triangle.h @@ -0,0 +1,51 @@ +/** + * @file lv_draw_triangle.h + * + */ + +#ifndef LV_DRAW_TRIANGLE_H +#define LV_DRAW_TRIANGLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/*Experimental use for 3D modeling*/ +#define USE_LV_TRIANGLE 1 + +#if USE_LV_TRIANGLE != 0 +/** + * + * @param points pointer to an array with 3 points + * @param mask the triangle will be drawn only in this mask + * @param color color of the triangle + */ +void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color); +#endif + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_TRIANGLE_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_vbasic.h b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_vbasic.h new file mode 100644 index 00000000..82d4b7a1 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_draw/lv_draw_vbasic.h @@ -0,0 +1,89 @@ +/** + * @file lv_draw_vbasic.h + * + */ + +#ifndef LV_DRAW_VBASIC_H +#define LV_DRAW_VBASIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if LV_VDB_SIZE != 0 + +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_area.h" +#include "display/lv_misc/lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_vpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa); +/** + * Fill an area in the Virtual Display Buffer + * @param cords_p coordinates of the area to fill + * @param mask_p fill only o this mask + * @param color fill color + * @param opa opacity of the area (0..255) + */ +void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p, + lv_color_t color, lv_opa_t opa); + +/** + * Draw a letter in the Virtual Display Buffer + * @param pos_p left-top coordinate of the latter + * @param mask_p the letter will be drawn only on this area + * @param font_p pointer to font + * @param letter a letter to draw + * @param color color of letter + * @param opa opacity of letter (0..255) + */ +void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p, + const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa); + +/** + * Draw a color map to the display (image) + * @param cords_p coordinates the color map + * @param mask_p the map will drawn only on this area (truncated to VDB area) + * @param map_p pointer to a lv_color_t array + * @param opa opacity of the map + * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels + * @param alpha_byte true: extra alpha byte is inserted for every pixel + * @param recolor mix the pixels with this color + * @param recolor_opa the intense of recoloring + */ +void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa); + +/********************** + * MACROS + **********************/ + +#endif /*LV_VDB_SIZE != 0*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_RBASIC_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_fonts/lv_font_builtin.h b/old-code/v5_hal/firmware/include/display/lv_fonts/lv_font_builtin.h new file mode 100644 index 00000000..5687fa1f --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_fonts/lv_font_builtin.h @@ -0,0 +1,150 @@ +/** + * @file lv_font_builtin.h + * + */ + +#ifndef LV_FONT_BUILTIN_H +#define LV_FONT_BUILTIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include "display/lv_misc/lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the built-in fonts + */ +void lv_font_builtin_init(void); + +/********************** + * MACROS + **********************/ + +/********************** + * FONT DECLARATIONS + **********************/ + +/*10 px */ +#if USE_LV_FONT_DEJAVU_10 +LV_FONT_DECLARE(lv_font_dejavu_10); +#endif + +#if USE_LV_FONT_DEJAVU_10_LATIN_SUP +LV_FONT_DECLARE(lv_font_dejavu_10_latin_sup); +#endif + +#if USE_LV_FONT_DEJAVU_10_CYRILLIC +LV_FONT_DECLARE(lv_font_dejavu_10_cyrillic); +#endif + +#if USE_LV_FONT_SYMBOL_10 +LV_FONT_DECLARE(lv_font_symbol_10); +#endif + +/*20 px */ +#if USE_LV_FONT_DEJAVU_20 +LV_FONT_DECLARE(lv_font_dejavu_20); +#endif + +#if USE_LV_FONT_DEJAVU_20_LATIN_SUP +LV_FONT_DECLARE(lv_font_dejavu_20_latin_sup); +#endif + +#if USE_LV_FONT_DEJAVU_20_CYRILLIC +LV_FONT_DECLARE(lv_font_dejavu_20_cyrillic); +#endif + +#if USE_LV_FONT_SYMBOL_20 +LV_FONT_DECLARE(lv_font_symbol_20); +#endif + +/*30 px */ +#if USE_LV_FONT_DEJAVU_30 +LV_FONT_DECLARE(lv_font_dejavu_30); +#endif + +#if USE_LV_FONT_DEJAVU_30_LATIN_SUP +LV_FONT_DECLARE(lv_font_dejavu_30_latin_sup); +#endif + +#if USE_LV_FONT_DEJAVU_30_CYRILLIC +LV_FONT_DECLARE(lv_font_dejavu_30_cyrillic); +#endif + +#if USE_LV_FONT_SYMBOL_30 +LV_FONT_DECLARE(lv_font_symbol_30); +#endif + +/*40 px */ +#if USE_LV_FONT_DEJAVU_40 +LV_FONT_DECLARE(lv_font_dejavu_40); +#endif + +#if USE_LV_FONT_DEJAVU_40_LATIN_SUP +LV_FONT_DECLARE(lv_font_dejavu_40_latin_sup); +#endif + +#if USE_LV_FONT_DEJAVU_40_CYRILLIC +LV_FONT_DECLARE(lv_font_dejavu_40_cyrillic); +#endif + +#if USE_LV_FONT_SYMBOL_40 +LV_FONT_DECLARE(lv_font_symbol_40); +#endif + +#if USE_LV_FONT_MONOSPACE_8 +LV_FONT_DECLARE(lv_font_monospace_8); +#endif + +#if USE_PROS_FONT_DEJAVU_MONO_10 +LV_FONT_DECLARE(pros_font_dejavu_mono_10); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_10_LATIN_SUP +LV_FONT_DECLARE(pros_font_dejavu_mono_10_latin_sup); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_20 +LV_FONT_DECLARE(pros_font_dejavu_mono_20); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_20_LATIN_SUP +LV_FONT_DECLARE(pros_font_dejavu_mono_20_latin_sup); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_30 +LV_FONT_DECLARE(pros_font_dejavu_mono_30); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_30_LATIN_SUP +LV_FONT_DECLARE(pros_font_dejavu_mono_30_latin_sup); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_40 +LV_FONT_DECLARE(pros_font_dejavu_mono_40); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_40_LATIN_SUP +LV_FONT_DECLARE(pros_font_dejavu_mono_40_latin_sup); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_FONT_BUILTIN_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_fonts/lv_fonts.mk b/old-code/v5_hal/firmware/include/display/lv_fonts/lv_fonts.mk new file mode 100644 index 00000000..f124b559 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_fonts/lv_fonts.mk @@ -0,0 +1,23 @@ +CSRCS += lv_font_builtin.c +CSRCS += lv_font_dejavu_10.c +CSRCS += lv_font_dejavu_20.c +CSRCS += lv_font_dejavu_30.c +CSRCS += lv_font_dejavu_40.c +CSRCS += lv_font_dejavu_10_cyrillic.c +CSRCS += lv_font_dejavu_20_cyrillic.c +CSRCS += lv_font_dejavu_30_cyrillic.c +CSRCS += lv_font_dejavu_40_cyrillic.c +CSRCS += lv_font_dejavu_10_latin_sup.c +CSRCS += lv_font_dejavu_20_latin_sup.c +CSRCS += lv_font_dejavu_30_latin_sup.c +CSRCS += lv_font_dejavu_40_latin_sup.c +CSRCS += lv_font_symbol_10.c +CSRCS += lv_font_symbol_20.c +CSRCS += lv_font_symbol_30.c +CSRCS += lv_font_symbol_40.c +CSRCS += lv_font_monospace_8.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_fonts +VPATH += :$(LVGL_DIR)/lvgl/lv_fonts + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_fonts" diff --git a/old-code/v5_hal/firmware/include/display/lv_hal/lv_hal.h b/old-code/v5_hal/firmware/include/display/lv_hal/lv_hal.h new file mode 100644 index 00000000..5ab28f2a --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_hal/lv_hal.h @@ -0,0 +1,40 @@ +/** + * @file hal.h + * + */ + +#ifndef HAL_H +#define HAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_hal_disp.h" +#include "lv_hal_indev.h" +#include "lv_hal_tick.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/old-code/v5_hal/firmware/include/display/lv_hal/lv_hal.mk b/old-code/v5_hal/firmware/include/display/lv_hal/lv_hal.mk new file mode 100644 index 00000000..83f4bf17 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_hal/lv_hal.mk @@ -0,0 +1,8 @@ +CSRCS += lv_hal_disp.c +CSRCS += lv_hal_indev.c +CSRCS += lv_hal_tick.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_hal +VPATH += :$(LVGL_DIR)/lvgl/lv_hal + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_hal" diff --git a/old-code/v5_hal/firmware/include/display/lv_hal/lv_hal_disp.h b/old-code/v5_hal/firmware/include/display/lv_hal/lv_hal_disp.h new file mode 100644 index 00000000..273f3314 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_hal/lv_hal_disp.h @@ -0,0 +1,174 @@ +/** + * @file hal_disp.h + * + * @description Display Driver HAL interface header file + * + */ + +#ifndef HAL_DISP_H +#define HAL_DISP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include +#include "lv_hal.h" +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_area.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** + * Display Driver structure to be registered by HAL + */ +typedef struct _disp_drv_t { + /*Write the internal buffer (VDB) to the display. 'lv_flush_ready()' has to be called when finished*/ + void (*disp_flush)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); + + /*Fill an area with a color on the display*/ + void (*disp_fill)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); + + /*Write pixel map (e.g. image) to the display*/ + void (*disp_map)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); + + /*Optional interface functions to use GPU*/ +#if USE_LV_GPU + /*Blend two memories using opacity (GPU only)*/ + void (*mem_blend)(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa); + + /*Fill a memory with a color (GPU only)*/ + void (*mem_fill)(lv_color_t * dest, uint32_t length, lv_color_t color); +#endif + +#if LV_VDB_SIZE + /*Optional: Set a pixel in a buffer according to the requirements of the display*/ + void (*vdb_wr)(uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa); +#endif +} lv_disp_drv_t; + +typedef struct _disp_t { + lv_disp_drv_t driver; + struct _disp_t *next; +} lv_disp_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize a display driver with default values. + * It is used to surly have known values in the fields ant not memory junk. + * After it you can set the fields. + * @param driver pointer to driver variable to initialize + */ +void lv_disp_drv_init(lv_disp_drv_t *driver); + +/** + * Register an initialized display driver. + * Automatically set the first display as active. + * @param driver pointer to an initialized 'lv_disp_drv_t' variable (can be local variable) + * @return pointer to the new display or NULL on error + */ +lv_disp_t * lv_disp_drv_register(lv_disp_drv_t *driver); + +/** + * Set the active display + * @param disp pointer to a display (return value of 'lv_disp_register') + */ +void lv_disp_set_active(lv_disp_t * disp); + +/** + * Get a pointer to the active display + * @return pointer to the active display + */ +lv_disp_t * lv_disp_get_active(void); + +/** + * Get the next display. + * @param disp pointer to the current display. NULL to initialize. + * @return the next display or NULL if no more. Give the first display when the parameter is NULL + */ +lv_disp_t * lv_disp_next(lv_disp_t * disp); + +/** + * Fill a rectangular area with a color on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_p pointer to an array of colors + */ +void lv_disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t *color_p); + +/** + * Fill a rectangular area with a color on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color fill color + */ +void lv_disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); + +/** + * Put a color map to a rectangular area on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_map pointer to an array of colors + */ +void lv_disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_map); + +#if USE_LV_GPU +/** + * Blend pixels to a destination memory from a source memory + * In 'lv_disp_drv_t' 'mem_blend' is optional. (NULL if not available) + * @param dest a memory address. Blend 'src' here. + * @param src pointer to pixel map. Blend it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +void lv_disp_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa); + +/** + * Fill a memory with a color (GPUs may support it) + * In 'lv_disp_drv_t' 'mem_fill' is optional. (NULL if not available) + * @param dest a memory address. Copy 'src' here. + * @param src pointer to pixel map. Copy it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +void lv_disp_mem_fill(lv_color_t * dest, uint32_t length, lv_color_t color); +/** + * Shows if memory blending (by GPU) is supported or not + * @return false: 'mem_blend' is not supported in the driver; true: 'mem_blend' is supported in the driver + */ +bool lv_disp_is_mem_blend_supported(void); + +/** + * Shows if memory fill (by GPU) is supported or not + * @return false: 'mem_fill' is not supported in the drover; true: 'mem_fill' is supported in the driver + */ +bool lv_disp_is_mem_fill_supported(void); +#endif +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/old-code/v5_hal/firmware/include/display/lv_hal/lv_hal_indev.h b/old-code/v5_hal/firmware/include/display/lv_hal/lv_hal_indev.h new file mode 100644 index 00000000..0252dc47 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_hal/lv_hal_indev.h @@ -0,0 +1,166 @@ +/** + * @file hal_indev.h + * + * @description Input Device HAL interface layer header file + * + */ + +#ifndef HAL_INDEV_H +#define HAL_INDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include +#include "lv_hal.h" +#include "display/lv_misc/lv_area.h" +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Possible input device types*/ +enum { + LV_INDEV_TYPE_NONE, /*Show uninitialized state*/ + LV_INDEV_TYPE_POINTER, /*Touch pad, mouse, external button*/ + LV_INDEV_TYPE_KEYPAD, /*Keypad or keyboard*/ + LV_INDEV_TYPE_BUTTON, /*External (hardware button) which is assinged to a specific point of the screen*/ + LV_INDEV_TYPE_ENCODER, /*Encoder with only Left, Right turn and a Button*/ +}; +typedef uint8_t lv_hal_indev_type_t; + +/*States for input devices*/ +enum { + LV_INDEV_STATE_REL = 0, + LV_INDEV_STATE_PR +}; +typedef uint8_t lv_indev_state_t; + +/*Data type when an input device is read */ +typedef struct { + union { + lv_point_t point; /*For LV_INDEV_TYPE_POINTER the currently pressed point*/ + uint32_t key; /*For LV_INDEV_TYPE_KEYPAD the currently pressed key*/ + uint32_t btn; /*For LV_INDEV_TYPE_BUTTON the currently pressed button*/ + int16_t enc_diff; /*For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/ + }; + void *user_data; /*'lv_indev_drv_t.priv' for this driver*/ + lv_indev_state_t state; /*LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/ +} lv_indev_data_t; + +/*Initialized by the user and registered by 'lv_indev_add()'*/ +typedef struct { + lv_hal_indev_type_t type; /*Input device type*/ + bool (*read)(lv_indev_data_t *data); /*Function pointer to read data. Return 'true' if there is still data to be read (buffered)*/ + void *user_data; /*Pointer to user defined data, passed in 'lv_indev_data_t' on read*/ +} lv_indev_drv_t; + +struct _lv_obj_t; + +/*Run time data of input devices*/ +typedef struct _lv_indev_proc_t { + lv_indev_state_t state; + union { + struct { /*Pointer and button data*/ + lv_point_t act_point; + lv_point_t last_point; + lv_point_t vect; + lv_point_t drag_sum; /*Count the dragged pixels to check LV_INDEV_DRAG_LIMIT*/ + struct _lv_obj_t * act_obj; + struct _lv_obj_t * last_obj; + + /*Flags*/ + uint8_t drag_range_out :1; + uint8_t drag_in_prog :1; + uint8_t wait_unil_release :1; + }; + struct { /*Keypad data*/ + lv_indev_state_t last_state; + uint32_t last_key; + }; + }; + + uint32_t pr_timestamp; /*Pressed time stamp*/ + uint32_t longpr_rep_timestamp; /*Long press repeat time stamp*/ + + /*Flags*/ + uint8_t long_pr_sent :1; + uint8_t reset_query :1; + uint8_t disabled :1; +} lv_indev_proc_t; + +struct _lv_indev_t; + +typedef void (*lv_indev_feedback_t)(struct _lv_indev_t *, lv_signal_t); + +struct _lv_obj_t; +struct _lv_group_t; + +/*The main input device descriptor with driver, runtime data ('proc') and some additional information*/ +typedef struct _lv_indev_t { + lv_indev_drv_t driver; + lv_indev_proc_t proc; + lv_indev_feedback_t feedback; + uint32_t last_activity_time; + union { + struct _lv_obj_t *cursor; /*Cursor for LV_INPUT_TYPE_POINTER*/ + struct _lv_group_t *group; /*Keypad destination group*/ + const lv_point_t * btn_points; /*Array points assigned to the button ()screen will be pressed here by the buttons*/ + + }; + struct _lv_indev_t *next; +} lv_indev_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize an input device driver with default values. + * It is used to surly have known values in the fields ant not memory junk. + * After it you can set the fields. + * @param driver pointer to driver variable to initialize + */ +void lv_indev_drv_init(lv_indev_drv_t *driver); + +/** + * Register an initialized input device driver. + * @param driver pointer to an initialized 'lv_indev_drv_t' variable (can be local variable) + * @return pointer to the new input device or NULL on error + */ +lv_indev_t * lv_indev_drv_register(lv_indev_drv_t *driver); + +/** + * Get the next input device. + * @param indev pointer to the current input device. NULL to initialize. + * @return the next input devise or NULL if no more. Gives the first input device when the parameter is NULL + */ +lv_indev_t * lv_indev_next(lv_indev_t * indev); + +/** + * Read data from an input device. + * @param indev pointer to an input device + * @param data input device will write its data here + * @return false: no more data; true: there more data to read (buffered) + */ +bool lv_indev_read(lv_indev_t * indev, lv_indev_data_t *data); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/old-code/v5_hal/firmware/include/display/lv_hal/lv_hal_tick.h b/old-code/v5_hal/firmware/include/display/lv_hal/lv_hal_tick.h new file mode 100644 index 00000000..c59ed0b2 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_hal/lv_hal_tick.h @@ -0,0 +1,66 @@ +/** + * @file lv_hal_tick.h + * Provide access to the system tick with 1 millisecond resolution + */ + +#ifndef LV_HAL_TICK_H +#define LV_HAL_TICK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif +#include +#include + +/********************* + * DEFINES + *********************/ +#ifndef LV_ATTRIBUTE_TICK_INC +#define LV_ATTRIBUTE_TICK_INC +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * You have to call this function periodically + * @param tick_period the call period of this function in milliseconds + */ +LV_ATTRIBUTE_TICK_INC void lv_tick_inc(uint32_t tick_period); + +/** + * Get the elapsed milliseconds since start up + * @return the elapsed milliseconds + */ +uint32_t lv_tick_get(void); + +/** + * Get the elapsed milliseconds since a previous time stamp + * @param prev_tick a previous time stamp (return value of systick_get() ) + * @return the elapsed milliseconds since 'prev_tick' + */ +uint32_t lv_tick_elaps(uint32_t prev_tick); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_HAL_TICK_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_anim.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_anim.h new file mode 100644 index 00000000..b3b8553b --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_anim.h @@ -0,0 +1,177 @@ +/** + * @file anim.h + * + */ + +#ifndef ANIM_H +#define ANIM_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_ANIMATION + +#include +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_anim_t; + +typedef int32_t(*lv_anim_path_t)(const struct _lv_anim_t*); + +typedef void (*lv_anim_fp_t)(void *, int32_t); +typedef void (*lv_anim_cb_t)(void *); + +typedef struct _lv_anim_t +{ + void * var; /*Variable to animate*/ + lv_anim_fp_t fp; /*Animator function*/ + lv_anim_cb_t end_cb; /*Call it when the animation is ready*/ + lv_anim_path_t path; /*An array with the steps of animations*/ + int32_t start; /*Start value*/ + int32_t end; /*End value*/ + uint16_t time; /*Animation time in ms*/ + int16_t act_time; /*Current time in animation. Set to negative to make delay.*/ + uint16_t playback_pause; /*Wait before play back*/ + uint16_t repeat_pause; /*Wait before repeat*/ + uint8_t playback :1; /*When the animation is ready play it back*/ + uint8_t repeat :1; /*Repeat the animation infinitely*/ + /*Animation system use these - user shouldn't set*/ + uint8_t playback_now :1; /*Play back is in progress*/ + uint32_t has_run :1; /*Indicates the animation has run it this round*/ +} lv_anim_t; + +/*Example initialization +lv_anim_t a; +a.var = obj; +a.start = lv_obj_get_height(obj); +a.end = new_height; +a.fp = (lv_anim_fp_t)lv_obj_set_height; +a.path = lv_anim_path_linear; +a.end_cb = NULL; +a.act_time = 0; +a.time = 200; +a.playback = 0; +a.playback_pause = 0; +a.repeat = 0; +a.repeat_pause = 0; +lv_anim_create(&a); + */ +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init. the animation module + */ +void lv_anim_init(void); + +/** + * Create an animation + * @param anim_p an initialized 'anim_t' variable. Not required after call. + */ +void lv_anim_create(lv_anim_t * anim_p); + +/** + * Delete an animation for a variable with a given animatior function + * @param var pointer to variable + * @param fp a function pointer which is animating 'var', + * or NULL to ignore it and delete all animation with 'var + * @return true: at least 1 animation is deleted, false: no animation is deleted + */ +bool lv_anim_del(void * var, lv_anim_fp_t fp); + +/** + * Get the number of currently running animations + * @return the number of running animations + */ +uint16_t lv_anim_count_running(void); + +/** + * Calculate the time of an animation with a given speed and the start and end values + * @param speed speed of animation in unit/sec + * @param start start value of the animation + * @param end end value of the animation + * @return the required time [ms] for the animation with the given parameters + */ +uint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end); + +/** + * Calculate the current value of an animation applying linear characteristic + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_linear(const lv_anim_t *a); + +/** + * Calculate the current value of an animation slowing down the start phase + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_in(const lv_anim_t * a); + +/** + * Calculate the current value of an animation slowing down the end phase + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_out(const lv_anim_t * a); + +/** + * Calculate the current value of an animation applying an "S" characteristic (cosine) + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_in_out(const lv_anim_t *a); + +/** + * Calculate the current value of an animation with overshoot at the end + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_overshoot(const lv_anim_t * a); + +/** + * Calculate the current value of an animation with 3 bounces + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_bounce(const lv_anim_t * a); + +/** + * Calculate the current value of an animation applying step characteristic. + * (Set end value on the end of the animation) + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_step(const lv_anim_t *a); +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_ANIMATION == 0*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ANIM_H*/ + diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_area.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_area.h new file mode 100644 index 00000000..fc8b7dec --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_area.h @@ -0,0 +1,169 @@ +/** + * @file lv_area.h + * + */ + +#ifndef LV_AREA_H +#define LV_AREA_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include +#include +#include + +/********************* + * DEFINES + *********************/ +#define LV_COORD_MAX (16383) /*To avoid overflow don't let the max [-32,32k] range */ +#define LV_COORD_MIN (-16384) + +/********************** + * TYPEDEFS + **********************/ +typedef int16_t lv_coord_t; + +typedef struct +{ + lv_coord_t x; + lv_coord_t y; +} lv_point_t; + +typedef struct +{ + lv_coord_t x1; + lv_coord_t y1; + lv_coord_t x2; + lv_coord_t y2; +} lv_area_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize an area + * @param area_p pointer to an area + * @param x1 left coordinate of the area + * @param y1 top coordinate of the area + * @param x2 right coordinate of the area + * @param y2 bottom coordinate of the area + */ +void lv_area_set(lv_area_t * area_p, lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2); + +/** + * Copy an area + * @param dest pointer to the destination area + * @param src pointer to the source area + */ +inline static void lv_area_copy(lv_area_t * dest, const lv_area_t * src) +{ + memcpy(dest, src, sizeof(lv_area_t)); +} + +/** + * Get the width of an area + * @param area_p pointer to an area + * @return the width of the area (if x1 == x2 -> width = 1) + */ +static inline lv_coord_t lv_area_get_width(const lv_area_t * area_p) +{ + return area_p->x2 - area_p->x1 + 1; +} + +/** + * Get the height of an area + * @param area_p pointer to an area + * @return the height of the area (if y1 == y2 -> height = 1) + */ +static inline lv_coord_t lv_area_get_height(const lv_area_t * area_p) +{ + return area_p->y2 - area_p->y1 + 1; +} + +/** + * Set the width of an area + * @param area_p pointer to an area + * @param w the new width of the area (w == 1 makes x1 == x2) + */ +void lv_area_set_width(lv_area_t * area_p, lv_coord_t w); + +/** + * Set the height of an area + * @param area_p pointer to an area + * @param h the new height of the area (h == 1 makes y1 == y2) + */ +void lv_area_set_height(lv_area_t * area_p, lv_coord_t h); + +/** + * Set the position of an area (width and height will be kept) + * @param area_p pointer to an area + * @param x the new x coordinate of the area + * @param y the new y coordinate of the area + */ +void lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y); + +/** + * Return with area of an area (x * y) + * @param area_p pointer to an area + * @return size of area + */ +uint32_t lv_area_get_size(const lv_area_t * area_p); + +/** + * Get the common parts of two areas + * @param res_p pointer to an area, the result will be stored her + * @param a1_p pointer to the first area + * @param a2_p pointer to the second area + * @return false: the two area has NO common parts, res_p is invalid + */ +bool lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p); + +/** + * Join two areas into a third which involves the other two + * @param res_p pointer to an area, the result will be stored here + * @param a1_p pointer to the first area + * @param a2_p pointer to the second area + */ +void lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p); + +/** + * Check if a point is on an area + * @param a_p pointer to an area + * @param p_p pointer to a point + * @return false:the point is out of the area + */ +bool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p); + +/** + * Check if two area has common parts + * @param a1_p pointer to an area. + * @param a2_p pointer to an other area + * @return false: a1_p and a2_p has no common parts + */ +bool lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p); + +/** + * Check if an area is fully on an other + * @param ain_p pointer to an area which could be on aholder_p + * @param aholder pointer to an area which could involve ain_p + * @return + */ +bool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_circ.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_circ.h new file mode 100644 index 00000000..f2065f71 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_circ.h @@ -0,0 +1,79 @@ +/** + * @file lv_circ.h + * + */ + +#ifndef LV_CIRC_H +#define LV_CIRC_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_area.h" + +/********************* + * DEFINES + *********************/ +#define LV_CIRC_OCT1_X(p) (p.x) +#define LV_CIRC_OCT1_Y(p) (p.y) +#define LV_CIRC_OCT2_X(p) (p.y) +#define LV_CIRC_OCT2_Y(p) (p.x) +#define LV_CIRC_OCT3_X(p) (-p.y) +#define LV_CIRC_OCT3_Y(p) (p.x) +#define LV_CIRC_OCT4_X(p) (-p.x) +#define LV_CIRC_OCT4_Y(p) (p.y) +#define LV_CIRC_OCT5_X(p) (-p.x) +#define LV_CIRC_OCT5_Y(p) (-p.y) +#define LV_CIRC_OCT6_X(p) (-p.y) +#define LV_CIRC_OCT6_Y(p) (-p.x) +#define LV_CIRC_OCT7_X(p) (p.y) +#define LV_CIRC_OCT7_Y(p) (-p.x) +#define LV_CIRC_OCT8_X(p) (p.x) +#define LV_CIRC_OCT8_Y(p) (-p.y) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the circle drawing + * @param c pointer to a point. The coordinates will be calculated here + * @param tmp point to a variable. It will store temporary data + * @param radius radius of the circle + */ +void lv_circ_init(lv_point_t * c, lv_coord_t * tmp, lv_coord_t radius); + +/** + * Test the circle drawing is ready or not + * @param c same as in circ_init + * @return true if the circle is not ready yet + */ +bool lv_circ_cont(lv_point_t * c); + +/** + * Get the next point from the circle + * @param c same as in circ_init. The next point stored here. + * @param tmp same as in circ_init. + */ +void lv_circ_next(lv_point_t * c, lv_coord_t * tmp); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_color.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_color.h new file mode 100644 index 00000000..4a3e3351 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_color.h @@ -0,0 +1,441 @@ +/** + * @file lv_color.h + * + */ + +#ifndef LV_COLOR_H +#define LV_COLOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +/*Error checking*/ +#if LV_COLOR_DEPTH == 24 +#error "LV_COLOR_DEPTH 24 is deprecated. Use LV_COLOR_DEPTH 32 instead (lv_conf.h)" +#endif + +#if LV_COLOR_DEPTH != 32 && LV_COLOR_SCREEN_TRANSP != 0 +#error "LV_COLOR_SCREEN_TRANSP requires LV_COLOR_DEPTH == 32. Set it in lv_conf.h" +#endif + +#if LV_COLOR_DEPTH != 16 && LV_COLOR_16_SWAP != 0 +#error "LV_COLOR_16_SWAP requires LV_COLOR_DEPTH == 16. Set it in lv_conf.h" +#endif + + +#include + +/********************* + * DEFINES + *********************/ +#define LV_COLOR_WHITE LV_COLOR_MAKE(0xFF,0xFF,0xFF) +#define LV_COLOR_SILVER LV_COLOR_MAKE(0xC0,0xC0,0xC0) +#define LV_COLOR_GRAY LV_COLOR_MAKE(0x80,0x80,0x80) +#define LV_COLOR_BLACK LV_COLOR_MAKE(0x00,0x00,0x00) +#define LV_COLOR_RED LV_COLOR_MAKE(0xFF,0x00,0x00) +#define LV_COLOR_MAROON LV_COLOR_MAKE(0x80,0x00,0x00) +#define LV_COLOR_YELLOW LV_COLOR_MAKE(0xFF,0xFF,0x00) +#define LV_COLOR_OLIVE LV_COLOR_MAKE(0x80,0x80,0x00) +#define LV_COLOR_LIME LV_COLOR_MAKE(0x00,0xFF,0x00) +#define LV_COLOR_GREEN LV_COLOR_MAKE(0x00,0x80,0x00) +#define LV_COLOR_CYAN LV_COLOR_MAKE(0x00,0xFF,0xFF) +#define LV_COLOR_AQUA LV_COLOR_CYAN +#define LV_COLOR_TEAL LV_COLOR_MAKE(0x00,0x80,0x80) +#define LV_COLOR_BLUE LV_COLOR_MAKE(0x00,0x00,0xFF) +#define LV_COLOR_NAVY LV_COLOR_MAKE(0x00,0x00,0x80) +#define LV_COLOR_MAGENTA LV_COLOR_MAKE(0xFF,0x00,0xFF) +#define LV_COLOR_PURPLE LV_COLOR_MAKE(0x80,0x00,0x80) +#define LV_COLOR_ORANGE LV_COLOR_MAKE(0xFF,0xA5,0x00) + +enum { + LV_OPA_TRANSP = 0, + LV_OPA_0 = 0, + LV_OPA_10 = 25, + LV_OPA_20 = 51, + LV_OPA_30 = 76, + LV_OPA_40 = 102, + LV_OPA_50 = 127, + LV_OPA_60 = 153, + LV_OPA_70 = 178, + LV_OPA_80 = 204, + LV_OPA_90 = 229, + LV_OPA_100 = 255, + LV_OPA_COVER = 255, +}; + +#define LV_OPA_MIN 16 /*Opacities below this will be transparent*/ +#define LV_OPA_MAX 251 /*Opacities above this will fully cover*/ + +#if LV_COLOR_DEPTH == 1 +#define LV_COLOR_SIZE 8 +#elif LV_COLOR_DEPTH == 8 +#define LV_COLOR_SIZE 8 +#elif LV_COLOR_DEPTH == 16 +#define LV_COLOR_SIZE 16 +#elif LV_COLOR_DEPTH == 32 +#define LV_COLOR_SIZE 32 +#else +#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!" +#endif + +/********************** + * TYPEDEFS + **********************/ + +typedef union +{ + uint8_t blue :1; + uint8_t green :1; + uint8_t red :1; + uint8_t full :1; +} lv_color1_t; + +typedef union +{ + struct + { + uint8_t blue :2; + uint8_t green :3; + uint8_t red :3; + }; + uint8_t full; +} lv_color8_t; + +typedef union +{ + struct + { +#if LV_COLOR_16_SWAP == 0 + uint16_t blue :5; + uint16_t green :6; + uint16_t red :5; +#else + uint16_t green_h :3; + uint16_t red :5; + uint16_t blue :5; + uint16_t green_l :3; +#endif + }; + uint16_t full; +} lv_color16_t; + +typedef union +{ + struct + { + uint8_t blue; + uint8_t green; + uint8_t red; + uint8_t alpha; + }; + uint32_t full; +} lv_color32_t; + +#if LV_COLOR_DEPTH == 1 +typedef uint8_t lv_color_int_t; +typedef lv_color1_t lv_color_t; +#elif LV_COLOR_DEPTH == 8 +typedef uint8_t lv_color_int_t; +typedef lv_color8_t lv_color_t; +#elif LV_COLOR_DEPTH == 16 +typedef uint16_t lv_color_int_t; +typedef lv_color16_t lv_color_t; +#elif LV_COLOR_DEPTH == 32 +typedef uint32_t lv_color_int_t; +typedef lv_color32_t lv_color_t; +#else +#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!" +#endif + +typedef uint8_t lv_opa_t; + +typedef struct +{ + uint16_t h; + uint8_t s; + uint8_t v; +} lv_color_hsv_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/*In color conversations: + * - When converting to bigger color type the LSB weight of 1 LSB is calculated + * E.g. 16 bit Red has 5 bits + * 8 bit Red has 2 bits + * ---------------------- + * 8 bit red LSB = (2^5 - 1) / (2^2 - 1) = 31 / 3 = 10 + * + * - When calculating to smaller color type simply shift out the LSBs + * E.g. 8 bit Red has 2 bits + * 16 bit Red has 5 bits + * ---------------------- + * Shift right with 5 - 3 = 2 + */ + +static inline uint8_t lv_color_to1(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + return color.full; +#elif LV_COLOR_DEPTH == 8 + if((color.red & 0x4) || + (color.green & 0x4) || + (color.blue & 0x2)) { + return 1; + } else { + return 0; + } +#elif LV_COLOR_DEPTH == 16 +# if LV_COLOR_16_SWAP == 0 + if((color.red & 0x10) || + (color.green & 0x20) || + (color.blue & 0x10)) { + return 1; +# else + if((color.red & 0x10) || + (color.green_h & 0x20) || + (color.blue & 0x10)) { + return 1; +# endif + } else { + return 0; + } +#elif LV_COLOR_DEPTH == 32 + if((color.red & 0x80) || + (color.green & 0x80) || + (color.blue & 0x80)) { + return 1; + } else { + return 0; + } +#endif +} + +static inline uint8_t lv_color_to8(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + if(color.full == 0) return 0; + else return 0xFF; +#elif LV_COLOR_DEPTH == 8 + return color.full; +#elif LV_COLOR_DEPTH == 16 + +# if LV_COLOR_16_SWAP == 0 + lv_color8_t ret; + ret.red = color.red >> 2; /* 5 - 3 = 2*/ + ret.green = color.green >> 3; /* 6 - 3 = 3*/ + ret.blue = color.blue >> 3; /* 5 - 2 = 3*/ + return ret.full; +# else + lv_color8_t ret; + ret.red = color.red >> 2; /* 5 - 3 = 2*/ + ret.green = color.green_h; /* 6 - 3 = 3*/ + ret.blue = color.blue >> 3; /* 5 - 2 = 3*/ + return ret.full; +# endif +#elif LV_COLOR_DEPTH == 32 + lv_color8_t ret; + ret.red = color.red >> 5; /* 8 - 3 = 5*/ + ret.green = color.green >> 5; /* 8 - 3 = 5*/ + ret.blue = color.blue >> 6; /* 8 - 2 = 6*/ + return ret.full; +#endif +} + +static inline uint16_t lv_color_to16(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + if(color.full == 0) return 0; + else return 0xFFFF; +#elif LV_COLOR_DEPTH == 8 + lv_color16_t ret; +# if LV_COLOR_16_SWAP == 0 + ret.red = color.red * 4; /*(2^5 - 1)/(2^3 - 1) = 31/7 = 4*/ + ret.green = color.green * 9; /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/ + ret.blue = color.blue * 10; /*(2^5 - 1)/(2^2 - 1) = 31/3 = 10*/ +# else + ret.red = color.red * 4; + uint8_t g_tmp = color.green * 9; + ret.green_h = (g_tmp & 0x1F) >> 3; + ret.green_l = g_tmp & 0x07; + ret.blue = color.blue * 10; +# endif + return ret.full; +#elif LV_COLOR_DEPTH == 16 + return color.full; +#elif LV_COLOR_DEPTH == 32 + lv_color16_t ret; +# if LV_COLOR_16_SWAP == 0 + ret.red = color.red >> 3; /* 8 - 5 = 3*/ + ret.green = color.green >> 2; /* 8 - 6 = 2*/ + ret.blue = color.blue >> 3; /* 8 - 5 = 3*/ +# else + ret.red = color.red >> 3; + ret.green_h = (color.green & 0xE0) >> 5; + ret.green_l = (color.green & 0x1C) >> 2; + ret.blue = color.blue >> 3; +# endif + return ret.full; +#endif +} + +static inline uint32_t lv_color_to32(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + if(color.full == 0) return 0; + else return 0xFFFFFFFF; +#elif LV_COLOR_DEPTH == 8 + lv_color32_t ret; + ret.red = color.red * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/ + ret.green = color.green * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/ + ret.blue = color.blue * 85; /*(2^8 - 1)/(2^2 - 1) = 255/3 = 85*/ + ret.alpha = 0xFF; + return ret.full; +#elif LV_COLOR_DEPTH == 16 +# if LV_COLOR_16_SWAP == 0 + lv_color32_t ret; + ret.red = color.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.green = color.green * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/ + ret.blue = color.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.alpha = 0xFF; + return ret.full; +# else + lv_color32_t ret; + ret.red = color.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.green = ((color.green_h << 3) + color.green_l) * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/ + ret.blue = color.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.alpha = 0xFF; + return ret.full; +# endif +#elif LV_COLOR_DEPTH == 32 + return color.full; +#endif +} + +static inline lv_color_t lv_color_mix(lv_color_t c1, lv_color_t c2, uint8_t mix) +{ + lv_color_t ret; +#if LV_COLOR_DEPTH != 1 + /*LV_COLOR_DEPTH == 8, 16 or 32*/ + ret.red = (uint16_t)((uint16_t) c1.red * mix + (c2.red * (255 - mix))) >> 8; +# if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP + /*If swapped Green is in 2 parts*/ + uint16_t g_1 = (c1.green_h << 3) + c1.green_l; + uint16_t g_2 = (c2.green_h << 3) + c2.green_l; + uint16_t g_out = (uint16_t)((uint16_t) g_1 * mix + (g_2 * (255 - mix))) >> 8; + ret.green_h = g_out >> 3; + ret.green_l = g_out & 0x7; +# else + ret.green = (uint16_t)((uint16_t) c1.green * mix + (c2.green * (255 - mix))) >> 8; +# endif + ret.blue = (uint16_t)((uint16_t) c1.blue * mix + (c2.blue * (255 - mix))) >> 8; +# if LV_COLOR_DEPTH == 32 + ret.alpha = 0xFF; +# endif +#else + /*LV_COLOR_DEPTH == 1*/ + ret.full = mix > LV_OPA_50 ? c1.full : c2.full; +#endif + + return ret; +} + +/** + * Get the brightness of a color + * @param color a color + * @return the brightness [0..255] + */ +static inline uint8_t lv_color_brightness(lv_color_t color) +{ + lv_color32_t c32; + c32.full = lv_color_to32(color); + uint16_t bright = 3 * c32.red + c32.blue + 4 * c32.green; + return (uint16_t) bright >> 3; +} + +/* The most simple macro to create a color from R,G and B values + * The order of bit field is different on Big-endian and Little-endian machines*/ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#if LV_COLOR_DEPTH == 1 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){(b8 >> 7 | g8 >> 7 | r8 >> 7)}) +#elif LV_COLOR_DEPTH == 8 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 6, g8 >> 5, r8 >> 5}}) +#elif LV_COLOR_DEPTH == 16 +# if LV_COLOR_16_SWAP == 0 +# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 3, g8 >> 2, r8 >> 3}}) +# else +# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{g8 >> 5, r8 >> 3, b8 >> 3, (g8 >> 2) & 0x7}}) +# endif +#elif LV_COLOR_DEPTH == 32 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8, g8, r8, 0xff}}) /*Fix 0xff alpha*/ +#endif +#else +#if LV_COLOR_DEPTH == 1 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){(r8 >> 7 | g8 >> 7 | b8 >> 7)}) +#elif LV_COLOR_DEPTH == 8 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{r8 >> 6, g8 >> 5, b8 >> 5}}) +#elif LV_COLOR_DEPTH == 16 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{r8 >> 3, g8 >> 2, b8 >> 3}}) +#elif LV_COLOR_DEPTH == 32 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{0xff, r8, g8, b8}}) /*Fix 0xff alpha*/ +#endif +#endif + + +#define LV_COLOR_HEX(c) LV_COLOR_MAKE((uint8_t) ((uint32_t)((uint32_t)c >> 16) & 0xFF), \ + (uint8_t) ((uint32_t)((uint32_t)c >> 8) & 0xFF), \ + (uint8_t) ((uint32_t) c & 0xFF)) + +/*Usage LV_COLOR_HEX3(0x16C) which means LV_COLOR_HEX(0x1166CC)*/ +#define LV_COLOR_HEX3(c) LV_COLOR_MAKE((uint8_t) (((c >> 4) & 0xF0) | ((c >> 8) & 0xF)), \ + (uint8_t) ((uint32_t)(c & 0xF0) | ((c & 0xF0) >> 4)), \ + (uint8_t) ((uint32_t)(c & 0xF) | ((c & 0xF) << 4))) + +static inline lv_color_t lv_color_hex(uint32_t c){ + return LV_COLOR_HEX(c); +} + +static inline lv_color_t lv_color_hex3(uint32_t c){ + return LV_COLOR_HEX3(c); +} + + +/** + * Convert a HSV color to RGB + * @param h hue [0..359] + * @param s saturation [0..100] + * @param v value [0..100] + * @return the given RGB color in RGB (with LV_COLOR_DEPTH depth) + */ +lv_color_t lv_color_hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v); + +/** + * Convert an RGB color to HSV + * @param r red + * @param g green + * @param b blue + * @return the given RGB color n HSV + */ +lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r, uint8_t g, uint8_t b); + + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*USE_COLOR*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_font.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_font.h new file mode 100644 index 00000000..0b1675c5 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_font.h @@ -0,0 +1,192 @@ +/** + * @file lv_font.h + * + */ + +#ifndef LV_FONT_H +#define LV_FONT_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include +#include + +#include "lv_symbol_def.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct +{ + uint32_t w_px :8; + uint32_t glyph_index :24; +} lv_font_glyph_dsc_t; + +typedef struct +{ + uint32_t unicode :21; + uint32_t glyph_dsc_index :11; +} lv_font_unicode_map_t; + +typedef struct _lv_font_struct +{ + uint32_t unicode_first; + uint32_t unicode_last; + const uint8_t * glyph_bitmap; + const lv_font_glyph_dsc_t * glyph_dsc; + const uint32_t * unicode_list; + const uint8_t * (*get_bitmap)(const struct _lv_font_struct *,uint32_t); /*Get a glyph's bitmap from a font*/ + int16_t (*get_width)(const struct _lv_font_struct *,uint32_t); /*Get a glyph's with with a given font*/ + struct _lv_font_struct * next_page; /*Pointer to a font extension*/ + uint32_t h_px :8; + uint32_t bpp :4; /*Bit per pixel: 1, 2 or 4*/ + uint32_t monospace :8; /*Fix width (0: normal width)*/ + uint16_t glyph_cnt; /*Number of glyphs (letters) in the font*/ +} lv_font_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the fonts + */ +void lv_font_init(void); + +/** + * Add a font to an other to extend the character set. + * @param child the font to add + * @param parent this font will be extended. Using it later will contain the characters from `child` + */ +void lv_font_add(lv_font_t *child, lv_font_t *parent); + +/** + * Remove a font from a character set. + * @param child the font to remove + * @param parent remove `child` from here + */ +void lv_font_remove(lv_font_t * child, lv_font_t * parent); + +/** + * Tells if font which contains `letter` is monospace or not + * @param font_p point to font + * @param letter an UNICODE character code + * @return true: the letter is monospace; false not monospace + */ +bool lv_font_is_monospace(const lv_font_t * font_p, uint32_t letter); + +/** + * Return with the bitmap of a font. + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return pointer to the bitmap of the letter + */ +const uint8_t * lv_font_get_bitmap(const lv_font_t * font_p, uint32_t letter); + +/** + * Get the width of a letter in a font. If `monospace` is set then return with it. + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return the width of a letter + */ +uint8_t lv_font_get_width(const lv_font_t * font_p, uint32_t letter); + + +/** + * Get the width of the letter without overwriting it with the `monospace` attribute + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return the width of a letter + */ +uint8_t lv_font_get_real_width(const lv_font_t * font_p, uint32_t letter); + +/** + * Get the height of a font + * @param font_p pointer to a font + * @return the height of a font + */ +static inline uint8_t lv_font_get_height(const lv_font_t * font_p) +{ + return font_p->h_px; +} + +/** + * Get the bit-per-pixel of font + * @param font pointer to font + * @param letter a letter from font (font extensions can have different bpp) + * @return bpp of the font (or font extension) + */ +uint8_t lv_font_get_bpp(const lv_font_t * font, uint32_t letter); + +/** + * Generic bitmap get function used in 'font->get_bitmap' when the font contains all characters in the range + * @param font pointer to font + * @param unicode_letter an unicode letter which bitmap should be get + * @return pointer to the bitmap or NULL if not found + */ +const uint8_t * lv_font_get_bitmap_continuous(const lv_font_t * font, uint32_t unicode_letter); + +/** + * Generic bitmap get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse) + * @param font pointer to font + * @param unicode_letter an unicode letter which bitmap should be get + * @return pointer to the bitmap or NULL if not found + */ +const uint8_t * lv_font_get_bitmap_sparse(const lv_font_t * font, uint32_t unicode_letter); +/** + * Generic glyph width get function used in 'font->get_width' when the font contains all characters in the range + * @param font pointer to font + * @param unicode_letter an unicode letter which width should be get + * @return width of the gylph or -1 if not found + */ +int16_t lv_font_get_width_continuous(const lv_font_t * font, uint32_t unicode_letter); + +/** + * Generic glyph width get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse) + * @param font pointer to font + * @param unicode_letter an unicode letter which width should be get + * @return width of the glyph or -1 if not found + */ +int16_t lv_font_get_width_sparse(const lv_font_t * font, uint32_t unicode_letter); + +/********************** + * MACROS + **********************/ + +#define LV_FONT_DECLARE(font_name) extern lv_font_t font_name + + +/********************** + * ADD BUILT IN FONTS + **********************/ +#include "display/lv_fonts/lv_font_builtin.h" + +/*Declare the custom (user defined) fonts*/ +#ifdef LV_FONT_CUSTOM_DECLARE +LV_FONT_CUSTOM_DECLARE +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*USE_FONT*/ + diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_fs.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_fs.h new file mode 100644 index 00000000..845b4794 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_fs.h @@ -0,0 +1,277 @@ +/** + * @file lv_fs.h + * + */ + +#ifndef LV_FS_H +#define LV_FS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_FILESYSTEM + +#include +#include +#include "lv_mem.h" + +/********************* + * DEFINES + *********************/ +#define LV_FS_MAX_FN_LENGTH 64 + +/********************** + * TYPEDEFS + **********************/ +enum +{ + LV_FS_RES_OK = 0, + LV_FS_RES_HW_ERR, /*Low level hardware error*/ + LV_FS_RES_FS_ERR, /*Error in the file system structure */ + LV_FS_RES_NOT_EX, /*Driver, file or directory is not exists*/ + LV_FS_RES_FULL, /*Disk full*/ + LV_FS_RES_LOCKED, /*The file is already opened*/ + LV_FS_RES_DENIED, /*Access denied. Check 'fs_open' modes and write protect*/ + LV_FS_RES_BUSY, /*The file system now can't handle it, try later*/ + LV_FS_RES_TOUT, /*Process time outed*/ + LV_FS_RES_NOT_IMP, /*Requested function is not implemented*/ + LV_FS_RES_OUT_OF_MEM, /*Not enough memory for an internal operation*/ + LV_FS_RES_INV_PARAM, /*Invalid parameter among arguments*/ + LV_FS_RES_UNKNOWN, /*Other unknown error*/ +}; +typedef uint8_t lv_fs_res_t; + +struct __lv_fs_drv_t; + +typedef struct +{ + void * file_d; + struct __lv_fs_drv_t* drv; +} lv_fs_file_t; + + +typedef struct +{ + void * dir_d; + struct __lv_fs_drv_t * drv; +} lv_fs_dir_t; + +enum +{ + LV_FS_MODE_WR = 0x01, + LV_FS_MODE_RD = 0x02, +}; +typedef uint8_t lv_fs_mode_t; + +typedef struct __lv_fs_drv_t +{ + char letter; + uint16_t file_size; + uint16_t rddir_size; + bool (*ready) (void); + + lv_fs_res_t (*open) (void * file_p, const char * path, lv_fs_mode_t mode); + lv_fs_res_t (*close) (void * file_p); + lv_fs_res_t (*remove) (const char * fn); + lv_fs_res_t (*read) (void * file_p, void * buf, uint32_t btr, uint32_t * br); + lv_fs_res_t (*write) (void * file_p, const void * buf, uint32_t btw, uint32_t * bw); + lv_fs_res_t (*seek) (void * file_p, uint32_t pos); + lv_fs_res_t (*tell) (void * file_p, uint32_t * pos_p); + lv_fs_res_t (*trunc) (void * file_p); + lv_fs_res_t (*size) (void * file_p, uint32_t * size_p); + lv_fs_res_t (*rename) (const char * oldname, const char * newname); + lv_fs_res_t (*free) (uint32_t * total_p, uint32_t * free_p); + + lv_fs_res_t (*dir_open) (void * rddir_p, const char * path); + lv_fs_res_t (*dir_read) (void * rddir_p, char * fn); + lv_fs_res_t (*dir_close) (void * rddir_p); +} lv_fs_drv_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the File system interface + */ +void lv_fs_init(void); + +/** + * Add a new drive + * @param drv_p pointer to an lv_fs_drv_t structure which is inited with the + * corresponding function pointers. The data will be copied so the variable can be local. + */ +void lv_fs_add_drv(lv_fs_drv_t * drv_p); + +/** + * Test if a drive is rady or not. If the `ready` function was not initialized `true` will be returned. + * @param letter letter of the drive + * @return true: drive is ready; false: drive is not ready + */ +bool lv_fs_is_ready(char letter); + +/** + * Open a file + * @param file_p pointer to a lv_fs_file_t variable + * @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt) + * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_open (lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode); + +/** + * Close an already opened file + * @param file_p pointer to a lv_fs_file_t variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_close (lv_fs_file_t * file_p); + +/** + * Delete a file + * @param path path of the file to delete + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_remove (const char * path); + +/** + * Read from a file + * @param file_p pointer to a lv_fs_file_t variable + * @param buf pointer to a buffer where the read bytes are stored + * @param btr Bytes To Read + * @param br the number of real read bytes (Bytes Read). NULL if unused. + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_read (lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br); + +/** + * Write into a file + * @param file_p pointer to a lv_fs_file_t variable + * @param buf pointer to a buffer with the bytes to write + * @param btr Bytes To Write + * @param br the number of real written bytes (Bytes Written). NULL if unused. + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_write (lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw); + +/** + * Set the position of the 'cursor' (read write pointer) in a file + * @param file_p pointer to a lv_fs_file_t variable + * @param pos the new position expressed in bytes index (0: start of file) + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_seek (lv_fs_file_t * file_p, uint32_t pos); + +/** + * Give the position of the read write pointer + * @param file_p pointer to a lv_fs_file_t variable + * @param pos_p pointer to store the position of the read write pointer + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_fs_tell (lv_fs_file_t * file_p, uint32_t * pos); + +/** + * Truncate the file size to the current position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_fs_open ) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_trunc (lv_fs_file_t * file_p); + +/** + * Give the size of a file bytes + * @param file_p pointer to a lv_fs_file_t variable + * @param size pointer to a variable to store the size + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_size (lv_fs_file_t * file_p, uint32_t * size); + +/** + * Rename a file + * @param oldname path to the file + * @param newname path with the new name + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_fs_rename (const char * oldname, const char * newname); + +/** + * Initialize a 'fs_dir_t' variable for directory reading + * @param rddir_p pointer to a 'fs_read_dir_t' variable + * @param path path to a directory + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path); + +/** + * Read the next filename form a directory. + * The name of the directories will begin with '/' + * @param rddir_p pointer to an initialized 'fs_rdir_t' variable + * @param fn pointer to a buffer to store the filename + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_read (lv_fs_dir_t * rddir_p, char * fn); + +/** + * Close the directory reading + * @param rddir_p pointer to an initialized 'fs_dir_t' variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_close (lv_fs_dir_t * rddir_p); + +/** + * Get the free and total size of a driver in kB + * @param letter the driver letter + * @param total_p pointer to store the total size [kB] + * @param free_p pointer to store the free size [kB] + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_free (char letter, uint32_t * total_p, uint32_t * free_p); + +/** + * Fill a buffer with the letters of existing drivers + * @param buf buffer to store the letters ('\0' added after the last letter) + * @return the buffer + */ +char * lv_fs_get_letters(char * buf); + +/** + * Return with the extension of the filename + * @param fn string with a filename + * @return pointer to the beginning extension or empty string if no extension + */ +const char * lv_fs_get_ext(const char * fn); + +/** + * Step up one level + * @param path pointer to a file name + * @return the truncated file name + */ +char * lv_fs_up(char * path); + +/** + * Get the last element of a path (e.g. U:/folder/file -> file) + * @param buf buffer to store the letters ('\0' added after the last letter) + * @return pointer to the beginning of the last element in the path + */ +const char * lv_fs_get_last(const char * path); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_FILESYSTEM*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_FS_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_gc.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_gc.h new file mode 100644 index 00000000..e3d0d8ac --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_gc.h @@ -0,0 +1,77 @@ +/** + * @file lv_gc.h + * + */ + +#ifndef LV_GC_H +#define LV_GC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include +#include "lv_mem.h" +#include "lv_ll.h" + +/********************* + * DEFINES + *********************/ + +#define LV_GC_ROOTS(prefix) \ + prefix lv_ll_t _lv_task_ll; /*Linked list to store the lv_tasks*/ \ + prefix lv_ll_t _lv_scr_ll; /*Linked list of screens*/ \ + prefix lv_ll_t _lv_drv_ll;\ + prefix lv_ll_t _lv_file_ll;\ + prefix lv_ll_t _lv_anim_ll;\ + prefix void * _lv_def_scr;\ + prefix void * _lv_act_scr;\ + prefix void * _lv_top_layer;\ + prefix void * _lv_sys_layer;\ + prefix void * _lv_task_act;\ + prefix void * _lv_indev_list;\ + prefix void * _lv_disp_list;\ + + +#define LV_NO_PREFIX +#define LV_ROOTS LV_GC_ROOTS(LV_NO_PREFIX) + +#if LV_ENABLE_GC == 1 +# if LV_MEM_CUSTOM != 1 +# error "GC requires CUSTOM_MEM" +# endif /* LV_MEM_CUSTOM */ +#else /* LV_ENABLE_GC */ +# define LV_GC_ROOT(x) x + LV_GC_ROOTS(extern) +#endif /* LV_ENABLE_GC */ + + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GC_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_ll.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_ll.h new file mode 100644 index 00000000..086ba405 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_ll.h @@ -0,0 +1,145 @@ +/** + * @file lv_ll.c + * Handle linked lists. The nodes are dynamically allocated by the 'lv_mem' module. + */ + +#ifndef LV_LL_H +#define LV_LL_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include "lv_mem.h" +#include +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Dummy type to make handling easier*/ +typedef uint8_t lv_ll_node_t; + +/*Description of a linked list*/ +typedef struct +{ + uint32_t n_size; + lv_ll_node_t* head; + lv_ll_node_t* tail; +} lv_ll_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize linked list + * @param ll_dsc pointer to ll_dsc variable + * @param node_size the size of 1 node in bytes + */ +void lv_ll_init(lv_ll_t * ll_p, uint32_t node_size); + +/** + * Add a new head to a linked list + * @param ll_p pointer to linked list + * @return pointer to the new head + */ +void * lv_ll_ins_head(lv_ll_t * ll_p); + +/** + * Insert a new node in front of the n_act node + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the new head + */ +void * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act); + +/** + * Add a new tail to a linked list + * @param ll_p pointer to linked list + * @return pointer to the new tail + */ +void * lv_ll_ins_tail(lv_ll_t * ll_p); + +/** + * Remove the node 'node_p' from 'll_p' linked list. + * It does not free the the memory of node. + * @param ll_p pointer to the linked list of 'node_p' + * @param node_p pointer to node in 'll_p' linked list + */ +void lv_ll_rem(lv_ll_t * ll_p, void * node_p); + +/** + * Remove and free all elements from a linked list. The list remain valid but become empty. + * @param ll_p pointer to linked list + */ +void lv_ll_clear(lv_ll_t * ll_p); + +/** + * Move a node to a new linked list + * @param ll_ori_p pointer to the original (old) linked list + * @param ll_new_p pointer to the new linked list + * @param node pointer to a node + */ +void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node); + +/** + * Return with head node of the linked list + * @param ll_p pointer to linked list + * @return pointer to the head of 'll_p' + */ +void * lv_ll_get_head(const lv_ll_t * ll_p); + +/** + * Return with tail node of the linked list + * @param ll_p pointer to linked list + * @return pointer to the head of 'll_p' + */ +void * lv_ll_get_tail(const lv_ll_t * ll_p); + +/** + * Return with the pointer of the next node after 'n_act' + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the next node + */ +void * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act); + +/** + * Return with the pointer of the previous node after 'n_act' + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the previous node + */ +void * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act); + +/** + * Move a nodw before an other node in the same linked list + * @param ll_p pointer to a linked list + * @param n_act pointer to node to move + * @param n_after pointer to a node which should be after `n_act` + */ +void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after); + +/********************** + * MACROS + **********************/ + +#define LL_READ(list, i) for(i = lv_ll_get_head(&list); i != NULL; i = lv_ll_get_next(&list, i)) + +#define LL_READ_BACK(list, i) for(i = lv_ll_get_tail(&list); i != NULL; i = lv_ll_get_prev(&list, i)) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_log.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_log.h new file mode 100644 index 00000000..adcb846d --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_log.h @@ -0,0 +1,86 @@ +/** + * @file lv_log.h + * + */ + +#ifndef LV_LOG_H +#define LV_LOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif +#include + +/********************* + * DEFINES + *********************/ + +/*Possible log level. For compatibility declare it independently from `USE_LV_LOG`*/ + +#define LV_LOG_LEVEL_TRACE 0 /*A lot of logs to give detailed information*/ +#define LV_LOG_LEVEL_INFO 1 /*Log important events*/ +#define LV_LOG_LEVEL_WARN 2 /*Log if something unwanted happened but didn't caused problem*/ +#define LV_LOG_LEVEL_ERROR 3 /*Only critical issue, when the system may fail*/ +#define _LV_LOG_LEVEL_NUM 4 + +typedef int8_t lv_log_level_t; + +#if USE_LV_LOG +/********************** + * TYPEDEFS + **********************/ + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Register custom print (or anything else) function to call when log is added + * @param f a function pointer: + * `void my_print (lv_log_level_t level, const char * file, uint32_t line, const char * dsc)` + */ +void lv_log_register_print(void f(lv_log_level_t, const char *, uint32_t, const char *)); + +/** + * Add a log + * @param level the level of log. (From `lv_log_level_t` enum) + * @param file name of the file when the log added + * @param line line number in the source code where the log added + * @param dsc description of the log + */ +void lv_log_add(lv_log_level_t level, const char * file, int line, const char * dsc); + +/********************** + * MACROS + **********************/ + +#define LV_LOG_TRACE(dsc) lv_log_add(LV_LOG_LEVEL_TRACE, __FILE__, __LINE__, dsc); +#define LV_LOG_INFO(dsc) lv_log_add(LV_LOG_LEVEL_INFO, __FILE__, __LINE__, dsc); +#define LV_LOG_WARN(dsc) lv_log_add(LV_LOG_LEVEL_WARN, __FILE__, __LINE__, dsc); +#define LV_LOG_ERROR(dsc) lv_log_add(LV_LOG_LEVEL_ERROR, __FILE__, __LINE__, dsc); + +#else /*USE_LV_LOG*/ + +/*Do nothing if `USE_LV_LOG 0`*/ +#define lv_log_add(level, file, line, dsc) {;} +#define LV_LOG_TRACE(dsc) {;} +#define LV_LOG_INFO(dsc) {;} +#define LV_LOG_WARN(dsc) {;} +#define LV_LOG_ERROR(dsc) {;} +#endif /*USE_LV_LOG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LOG_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_math.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_math.h new file mode 100644 index 00000000..a0229eb1 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_math.h @@ -0,0 +1,73 @@ +/** + * @file math_base.h + * + */ + +#ifndef LV_MATH_H +#define LV_MATH_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include + +/********************* + * DEFINES + *********************/ +#define LV_MATH_MIN(a,b) ((a) < (b) ? (a) : (b)) +#define LV_MATH_MAX(a,b) ((a) > (b) ? (a) : (b)) +#define LV_MATH_ABS(x) ((x) > 0 ? (x) : (-(x))) + +#define LV_TRIGO_SIN_MAX 32767 +#define LV_TRIGO_SHIFT 15 /* >> LV_TRIGO_SHIFT to normalize*/ + +#define LV_BEZIER_VAL_MAX 1024 /*Max time in Bezier functions (not [0..1] to use integers) */ +#define LV_BEZIER_VAL_SHIFT 10 /*log2(LV_BEZIER_VAL_MAX): used to normalize up scaled values*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/** + * Convert a number to string + * @param num a number + * @param buf pointer to a `char` buffer. The result will be stored here (max 10 elements) + * @return same as `buf` (just for convenience) + */ +char * lv_math_num_to_str(int32_t num, char * buf); + +/** + * Return with sinus of an angle + * @param angle + * @return sinus of 'angle'. sin(-90) = -32767, sin(90) = 32767 + */ +int16_t lv_trigo_sin(int16_t angle); + +/** + * Calculate a value of a Cubic Bezier function. + * @param t time in range of [0..LV_BEZIER_VAL_MAX] + * @param u0 start values in range of [0..LV_BEZIER_VAL_MAX] + * @param u1 control value 1 values in range of [0..LV_BEZIER_VAL_MAX] + * @param u2 control value 2 in range of [0..LV_BEZIER_VAL_MAX] + * @param u3 end values in range of [0..LV_BEZIER_VAL_MAX] + * @return the value calculated from the given parameters in range of [0..LV_BEZIER_VAL_MAX] + */ +int32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_mem.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_mem.h new file mode 100644 index 00000000..77429018 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_mem.h @@ -0,0 +1,127 @@ +/** + * @file lv_mem.h + * + */ + +#ifndef LV_MEM_H +#define LV_MEM_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include +#include "lv_log.h" + +/********************* + * DEFINES + *********************/ +// Check windows +#ifdef __WIN64 +# define LV_MEM_ENV64 +#endif + +// Check GCC +#ifdef __GNUC__ +# if defined(__x86_64__) || defined(__ppc64__) +# define LV_MEM_ENV64 +# endif +#endif + +/********************** + * TYPEDEFS + **********************/ + +typedef struct +{ + uint32_t total_size; + uint32_t free_cnt; + uint32_t free_size; + uint32_t free_biggest_size; + uint32_t used_cnt; + uint8_t used_pct; + uint8_t frag_pct; +} lv_mem_monitor_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Initiaize the dyn_mem module (work memory and other variables) + */ +void lv_mem_init(void); + +/** + * Allocate a memory dynamically + * @param size size of the memory to allocate in bytes + * @return pointer to the allocated memory + */ +void * lv_mem_alloc(uint32_t size); + +/** + * Free an allocated data + * @param data pointer to an allocated memory + */ +void lv_mem_free(const void * data); + +/** + * Reallocate a memory with a new size. The old content will be kept. + * @param data pointer to an allocated memory. + * Its content will be copied to the new memory block and freed + * @param new_size the desired new size in byte + * @return pointer to the new memory + */ +void * lv_mem_realloc(void * data_p, uint32_t new_size); + +/** + * Join the adjacent free memory blocks + */ +void lv_mem_defrag(void); + +/** + * Give information about the work memory of dynamic allocation + * @param mon_p pointer to a dm_mon_p variable, + * the result of the analysis will be stored here + */ +void lv_mem_monitor(lv_mem_monitor_t * mon_p); + +/** + * Give the size of an allocated memory + * @param data pointer to an allocated memory + * @return the size of data memory in bytes + */ +uint32_t lv_mem_get_size(const void * data); + + +/********************** + * MACROS + **********************/ + +/** + * Halt on NULL pointer + * p pointer to a memory + */ +#if USE_LV_LOG == 0 +# define lv_mem_assert(p) {if(p == NULL) while(1); } +#else +# define lv_mem_assert(p) {if(p == NULL) {LV_LOG_ERROR("Out of memory!"); while(1); }} +#endif +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_MEM_H*/ + diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_misc.mk b/old-code/v5_hal/firmware/include/display/lv_misc/lv_misc.mk new file mode 100644 index 00000000..470f1230 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_misc.mk @@ -0,0 +1,19 @@ +CSRCS += lv_font.c +CSRCS += lv_circ.c +CSRCS += lv_area.c +CSRCS += lv_task.c +CSRCS += lv_fs.c +CSRCS += lv_anim.c +CSRCS += lv_mem.c +CSRCS += lv_ll.c +CSRCS += lv_color.c +CSRCS += lv_txt.c +CSRCS += lv_ufs.c +CSRCS += lv_math.c +CSRCS += lv_log.c +CSRCS += lv_gc.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_misc +VPATH += :$(LVGL_DIR)/lvgl/lv_misc + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_misc" diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_symbol_def.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_symbol_def.h new file mode 100644 index 00000000..6ba6241c --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_symbol_def.h @@ -0,0 +1,207 @@ +#ifndef LV_SYMBOL_DEF_H +#define LV_SYMBOL_DEF_H + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +/* + * With no UTF-8 support (192- 255) (192..241 is used) + * + * With UTF-8 support (in Supplemental Private Use Area-A): 0xF800 .. 0xF831 + * - Basic symbols: 0xE000..0xE01F + * - File symbols: 0xE020..0xE03F + * - Feedback symbols: 0xE040..0xE05F + * - Reserved: 0xE060..0xE07F + */ + +#if LV_TXT_UTF8 == 0 +#define LV_SYMBOL_GLYPH_FIRST 0xC0 +#define SYMBOL_AUDIO _SYMBOL_VALUE1(C0) +#define SYMBOL_VIDEO _SYMBOL_VALUE1(C1) +#define SYMBOL_LIST _SYMBOL_VALUE1(C2) +#define SYMBOL_OK _SYMBOL_VALUE1(C3) +#define SYMBOL_CLOSE _SYMBOL_VALUE1(C4) +#define SYMBOL_POWER _SYMBOL_VALUE1(C5) +#define SYMBOL_SETTINGS _SYMBOL_VALUE1(C6) +#define SYMBOL_TRASH _SYMBOL_VALUE1(C7) +#define SYMBOL_HOME _SYMBOL_VALUE1(C8) +#define SYMBOL_DOWNLOAD _SYMBOL_VALUE1(C9) +#define SYMBOL_DRIVE _SYMBOL_VALUE1(CA) +#define SYMBOL_REFRESH _SYMBOL_VALUE1(CB) +#define SYMBOL_MUTE _SYMBOL_VALUE1(CC) +#define SYMBOL_VOLUME_MID _SYMBOL_VALUE1(CD) +#define SYMBOL_VOLUME_MAX _SYMBOL_VALUE1(CE) +#define SYMBOL_IMAGE _SYMBOL_VALUE1(CF) +#define SYMBOL_EDIT _SYMBOL_VALUE1(D0) +#define SYMBOL_PREV _SYMBOL_VALUE1(D1) +#define SYMBOL_PLAY _SYMBOL_VALUE1(D2) +#define SYMBOL_PAUSE _SYMBOL_VALUE1(D3) +#define SYMBOL_STOP _SYMBOL_VALUE1(D4) +#define SYMBOL_NEXT _SYMBOL_VALUE1(D5) +#define SYMBOL_EJECT _SYMBOL_VALUE1(D6) +#define SYMBOL_LEFT _SYMBOL_VALUE1(D7) +#define SYMBOL_RIGHT _SYMBOL_VALUE1(D8) +#define SYMBOL_PLUS _SYMBOL_VALUE1(D9) +#define SYMBOL_MINUS _SYMBOL_VALUE1(DA) +#define SYMBOL_WARNING _SYMBOL_VALUE1(DB) +#define SYMBOL_SHUFFLE _SYMBOL_VALUE1(DC) +#define SYMBOL_UP _SYMBOL_VALUE1(DD) +#define SYMBOL_DOWN _SYMBOL_VALUE1(DE) +#define SYMBOL_LOOP _SYMBOL_VALUE1(DF) +#define SYMBOL_DIRECTORY _SYMBOL_VALUE1(E0) +#define SYMBOL_UPLOAD _SYMBOL_VALUE1(E1) +#define SYMBOL_CALL _SYMBOL_VALUE1(E2) +#define SYMBOL_CUT _SYMBOL_VALUE1(E3) +#define SYMBOL_COPY _SYMBOL_VALUE1(E4) +#define SYMBOL_SAVE _SYMBOL_VALUE1(E5) +#define SYMBOL_CHARGE _SYMBOL_VALUE1(E6) +#define SYMBOL_BELL _SYMBOL_VALUE1(E7) +#define SYMBOL_KEYBOARD _SYMBOL_VALUE1(E8) +#define SYMBOL_GPS _SYMBOL_VALUE1(E9) +#define SYMBOL_FILE _SYMBOL_VALUE1(EA) +#define SYMBOL_WIFI _SYMBOL_VALUE1(EB) +#define SYMBOL_BATTERY_FULL _SYMBOL_VALUE1(EC) +#define SYMBOL_BATTERY_3 _SYMBOL_VALUE1(ED) +#define SYMBOL_BATTERY_2 _SYMBOL_VALUE1(EE) +#define SYMBOL_BATTERY_1 _SYMBOL_VALUE1(EF) +#define SYMBOL_BATTERY_EMPTY _SYMBOL_VALUE1(F0) +#define SYMBOL_BLUETOOTH _SYMBOL_VALUE1(F1) +#define LV_SYMBOL_GLYPH_LAST 0xF1 +#define SYMBOL_DUMMY _SYMBOL_VALUE1(FF) /*Invalid symbol. If written before a string then `lv_img` will show it as a label*/ + +#else +#define LV_SYMBOL_GLYPH_FIRST 0xF800 +#define SYMBOL_AUDIO _SYMBOL_VALUE3(EF,A0,80) +#define SYMBOL_VIDEO _SYMBOL_VALUE3(EF,A0,81) +#define SYMBOL_LIST _SYMBOL_VALUE3(EF,A0,82) +#define SYMBOL_OK _SYMBOL_VALUE3(EF,A0,83) +#define SYMBOL_CLOSE _SYMBOL_VALUE3(EF,A0,84) +#define SYMBOL_POWER _SYMBOL_VALUE3(EF,A0,85) +#define SYMBOL_SETTINGS _SYMBOL_VALUE3(EF,A0,86) +#define SYMBOL_TRASH _SYMBOL_VALUE3(EF,A0,87) +#define SYMBOL_HOME _SYMBOL_VALUE3(EF,A0,88) +#define SYMBOL_DOWNLOAD _SYMBOL_VALUE3(EF,A0,89) +#define SYMBOL_DRIVE _SYMBOL_VALUE3(EF,A0,8A) +#define SYMBOL_REFRESH _SYMBOL_VALUE3(EF,A0,8B) +#define SYMBOL_MUTE _SYMBOL_VALUE3(EF,A0,8C) +#define SYMBOL_VOLUME_MID _SYMBOL_VALUE3(EF,A0,8D) +#define SYMBOL_VOLUME_MAX _SYMBOL_VALUE3(EF,A0,8E) +#define SYMBOL_IMAGE _SYMBOL_VALUE3(EF,A0,8F) +#define SYMBOL_EDIT _SYMBOL_VALUE3(EF,A0,90) +#define SYMBOL_PREV _SYMBOL_VALUE3(EF,A0,91) +#define SYMBOL_PLAY _SYMBOL_VALUE3(EF,A0,92) +#define SYMBOL_PAUSE _SYMBOL_VALUE3(EF,A0,93) +#define SYMBOL_STOP _SYMBOL_VALUE3(EF,A0,94) +#define SYMBOL_NEXT _SYMBOL_VALUE3(EF,A0,95) +#define SYMBOL_EJECT _SYMBOL_VALUE3(EF,A0,96) +#define SYMBOL_LEFT _SYMBOL_VALUE3(EF,A0,97) +#define SYMBOL_RIGHT _SYMBOL_VALUE3(EF,A0,98) +#define SYMBOL_PLUS _SYMBOL_VALUE3(EF,A0,99) +#define SYMBOL_MINUS _SYMBOL_VALUE3(EF,A0,9A) +#define SYMBOL_WARNING _SYMBOL_VALUE3(EF,A0,9B) +#define SYMBOL_SHUFFLE _SYMBOL_VALUE3(EF,A0,9C) +#define SYMBOL_UP _SYMBOL_VALUE3(EF,A0,9D) +#define SYMBOL_DOWN _SYMBOL_VALUE3(EF,A0,9E) +#define SYMBOL_LOOP _SYMBOL_VALUE3(EF,A0,9F) +#define SYMBOL_DIRECTORY _SYMBOL_VALUE3(EF,A0,A0) +#define SYMBOL_UPLOAD _SYMBOL_VALUE3(EF,A0,A1) +#define SYMBOL_CALL _SYMBOL_VALUE3(EF,A0,A2) +#define SYMBOL_CUT _SYMBOL_VALUE3(EF,A0,A3) +#define SYMBOL_COPY _SYMBOL_VALUE3(EF,A0,A4) +#define SYMBOL_SAVE _SYMBOL_VALUE3(EF,A0,A5) +#define SYMBOL_CHARGE _SYMBOL_VALUE3(EF,A0,A6) +#define SYMBOL_BELL _SYMBOL_VALUE3(EF,A0,A7) +#define SYMBOL_KEYBOARD _SYMBOL_VALUE3(EF,A0,A8) +#define SYMBOL_GPS _SYMBOL_VALUE3(EF,A0,A9) +#define SYMBOL_FILE _SYMBOL_VALUE3(EF,A0,AA) +#define SYMBOL_WIFI _SYMBOL_VALUE3(EF,A0,AB) +#define SYMBOL_BATTERY_FULL _SYMBOL_VALUE3(EF,A0,AC) +#define SYMBOL_BATTERY_3 _SYMBOL_VALUE3(EF,A0,AD) +#define SYMBOL_BATTERY_2 _SYMBOL_VALUE3(EF,A0,AE) +#define SYMBOL_BATTERY_1 _SYMBOL_VALUE3(EF,A0,AF) +#define SYMBOL_BATTERY_EMPTY _SYMBOL_VALUE3(EF,A0,B0) +#define SYMBOL_BLUETOOTH _SYMBOL_VALUE3(EF,A0,B1) +#define LV_SYMBOL_GLYPH_LAST 0xF831 +#define SYMBOL_DUMMY _SYMBOL_VALUE3(EF,A3,BF) /*Invalid symbol at (U+F831). If written before a string then `lv_img` will show it as a label*/ +#endif + +#define _SYMBOL_VALUE1(x) (0x ## x) +#define _SYMBOL_VALUE3(x, y, z) (0x ## z ## y ## x) +#define _SYMBOL_NUMSTR(sym) LV_ ## sym ## _NUMSTR = sym + +enum +{ + _SYMBOL_NUMSTR(SYMBOL_AUDIO), + _SYMBOL_NUMSTR(SYMBOL_VIDEO), + _SYMBOL_NUMSTR(SYMBOL_LIST), + _SYMBOL_NUMSTR(SYMBOL_OK), + _SYMBOL_NUMSTR(SYMBOL_CLOSE), + _SYMBOL_NUMSTR(SYMBOL_POWER), + _SYMBOL_NUMSTR(SYMBOL_SETTINGS), + _SYMBOL_NUMSTR(SYMBOL_TRASH), + _SYMBOL_NUMSTR(SYMBOL_HOME), + _SYMBOL_NUMSTR(SYMBOL_DOWNLOAD), + _SYMBOL_NUMSTR(SYMBOL_DRIVE), + _SYMBOL_NUMSTR(SYMBOL_REFRESH), + _SYMBOL_NUMSTR(SYMBOL_MUTE), + _SYMBOL_NUMSTR(SYMBOL_VOLUME_MID), + _SYMBOL_NUMSTR(SYMBOL_VOLUME_MAX), + _SYMBOL_NUMSTR(SYMBOL_IMAGE), + _SYMBOL_NUMSTR(SYMBOL_EDIT), + _SYMBOL_NUMSTR(SYMBOL_PREV), + _SYMBOL_NUMSTR(SYMBOL_PLAY), + _SYMBOL_NUMSTR(SYMBOL_PAUSE), + _SYMBOL_NUMSTR(SYMBOL_STOP), + _SYMBOL_NUMSTR(SYMBOL_NEXT), + _SYMBOL_NUMSTR(SYMBOL_EJECT), + _SYMBOL_NUMSTR(SYMBOL_LEFT), + _SYMBOL_NUMSTR(SYMBOL_RIGHT), + _SYMBOL_NUMSTR(SYMBOL_PLUS), + _SYMBOL_NUMSTR(SYMBOL_MINUS), + _SYMBOL_NUMSTR(SYMBOL_WARNING), + _SYMBOL_NUMSTR(SYMBOL_SHUFFLE), + _SYMBOL_NUMSTR(SYMBOL_UP), + _SYMBOL_NUMSTR(SYMBOL_DOWN), + _SYMBOL_NUMSTR(SYMBOL_LOOP), + _SYMBOL_NUMSTR(SYMBOL_DIRECTORY), + _SYMBOL_NUMSTR(SYMBOL_UPLOAD), + _SYMBOL_NUMSTR(SYMBOL_CALL), + _SYMBOL_NUMSTR(SYMBOL_CUT), + _SYMBOL_NUMSTR(SYMBOL_COPY), + _SYMBOL_NUMSTR(SYMBOL_SAVE), + _SYMBOL_NUMSTR(SYMBOL_CHARGE), + _SYMBOL_NUMSTR(SYMBOL_BELL), + _SYMBOL_NUMSTR(SYMBOL_KEYBOARD), + _SYMBOL_NUMSTR(SYMBOL_GPS), + _SYMBOL_NUMSTR(SYMBOL_FILE), + _SYMBOL_NUMSTR(SYMBOL_WIFI), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_FULL), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_3), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_2), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_1), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_EMPTY), + _SYMBOL_NUMSTR(SYMBOL_BLUETOOTH), + _SYMBOL_NUMSTR(SYMBOL_DUMMY), +}; + +#undef _SYMBOL_VALUE1 +#undef _SYMBOL_VALUE3 + +#define _SYMBOL_STR_(x) #x +#define _SYMBOL_STR(x) _SYMBOL_STR_(x) +#define _SYMBOL_CHAR(c) \x ## c +#define _SYMBOL_VALUE1(x) _SYMBOL_STR(_SYMBOL_CHAR(x)) +#define _SYMBOL_VALUE3(x, y, z) _SYMBOL_STR(_SYMBOL_CHAR(x)_SYMBOL_CHAR(y)_SYMBOL_CHAR(z)) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /*LV_SYMBOL_DEF_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_task.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_task.h new file mode 100644 index 00000000..6cac3efd --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_task.h @@ -0,0 +1,149 @@ +/** + * @file lv_task.c + * An 'lv_task' is a void (*fp) (void* param) type function which will be called periodically. + * A priority (5 levels + disable) can be assigned to lv_tasks. + */ + +#ifndef LV_TASK_H +#define LV_TASK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include +#include "lv_mem.h" +#include "lv_ll.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_ATTRIBUTE_TASK_HANDLER +#define LV_ATTRIBUTE_TASK_HANDLER +#endif +/********************** + * TYPEDEFS + **********************/ +/** + * Possible priorities for lv_tasks + */ +enum +{ + LV_TASK_PRIO_OFF = 0, + LV_TASK_PRIO_LOWEST, + LV_TASK_PRIO_LOW, + LV_TASK_PRIO_MID, + LV_TASK_PRIO_HIGH, + LV_TASK_PRIO_HIGHEST, + LV_TASK_PRIO_NUM, +}; +typedef uint8_t lv_task_prio_t; + +/** + * Descriptor of a lv_task + */ +typedef struct +{ + uint32_t period; + uint32_t last_run; + void (*task) (void*); + void * param; + uint8_t prio:3; + uint8_t once:1; +} lv_task_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init the lv_task module + */ +void lv_task_init(void); + +/** + * Call it periodically to handle lv_tasks. + */ +LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void); + +/** + * Create a new lv_task + * @param task a function which is the task itself + * @param period call period in ms unit + * @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped) + * @param param free parameter + * @return pointer to the new task + */ +lv_task_t* lv_task_create(void (*task) (void *), uint32_t period, lv_task_prio_t prio, void * param); + +/** + * Delete a lv_task + * @param lv_task_p pointer to task created by lv_task_p + */ +void lv_task_del(lv_task_t* lv_task_p); + +/** + * Set new priority for a lv_task + * @param lv_task_p pointer to a lv_task + * @param prio the new priority + */ +void lv_task_set_prio(lv_task_t* lv_task_p, lv_task_prio_t prio); + +/** + * Set new period for a lv_task + * @param lv_task_p pointer to a lv_task + * @param period the new period + */ +void lv_task_set_period(lv_task_t* lv_task_p, uint32_t period); + +/** + * Make a lv_task ready. It will not wait its period. + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_ready(lv_task_t* lv_task_p); + + +/** + * Delete the lv_task after one call + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_once(lv_task_t * lv_task_p); + +/** + * Reset a lv_task. + * It will be called the previously set period milliseconds later. + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_reset(lv_task_t* lv_task_p); + +/** + * Enable or disable the whole lv_task handling + * @param en: true: lv_task handling is running, false: lv_task handling is suspended + */ +void lv_task_enable(bool en); + +/** + * Get idle percentage + * @return the lv_task idle in percentage + */ +uint8_t lv_task_get_idle(void); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_templ.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_templ.h new file mode 100644 index 00000000..a5459e8d --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_templ.h @@ -0,0 +1,38 @@ +/** + * @file lv_templ.h + * + */ + +#ifndef LV_TEMPL_H +#define LV_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_txt.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_txt.h new file mode 100644 index 00000000..2e98b60e --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_txt.h @@ -0,0 +1,198 @@ +/** + * @file lv_text.h + * + */ + +#ifndef LV_TXT_H +#define LV_TXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include "lv_area.h" +#include "lv_font.h" +#include "lv_area.h" + +/********************* + * DEFINES + *********************/ +#define LV_TXT_COLOR_CMD "#" + +/********************** + * TYPEDEFS + **********************/ +enum +{ + LV_TXT_FLAG_NONE = 0x00, + LV_TXT_FLAG_RECOLOR = 0x01, /*Enable parsing of recolor command*/ + LV_TXT_FLAG_EXPAND = 0x02, /*Ignore width to avoid automatic word wrapping*/ + LV_TXT_FLAG_CENTER = 0x04, /*Align the text to the middle*/ + LV_TXT_FLAG_RIGHT = 0x08, /*Align the text to the right*/ +}; +typedef uint8_t lv_txt_flag_t; + +enum +{ + LV_TXT_CMD_STATE_WAIT, /*Waiting for command*/ + LV_TXT_CMD_STATE_PAR, /*Processing the parameter*/ + LV_TXT_CMD_STATE_IN, /*Processing the command*/ +}; +typedef uint8_t lv_txt_cmd_state_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Get size of a text + * @param size_res pointer to a 'point_t' variable to store the result + * @param text pointer to a text + * @param font pinter to font of the text + * @param letter_space letter space of the text + * @param line_space line space of the text + * @param flags settings for the text from 'txt_flag_t' enum + * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks + */ +void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t line_space, lv_coord_t max_width, lv_txt_flag_t flag); + +/** + * Get the next line of text. Check line length and break chars too. + * @param txt a '\0' terminated string + * @param font pointer to a font + * @param letter_space letter space + * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks + * @param flags settings for the text from 'txt_flag_type' enum + * @return the index of the first char of the new line (in byte index not letter index. With UTF-8 they are different) + */ +uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t max_width, lv_txt_flag_t flag); + +/** + * Give the length of a text with a given font + * @param txt a '\0' terminate string + * @param length length of 'txt' in byte count and not characters (Á is 1 character but 2 bytes in UTF-8) + * @param font pointer to a font + * @param letter_space letter space + * @param flags settings for the text from 'txt_flag_t' enum + * @return length of a char_num long text + */ +lv_coord_t lv_txt_get_width(const char * txt, uint16_t length, + const lv_font_t * font, lv_coord_t letter_space, lv_txt_flag_t flag); + + +/** + * Check next character in a string and decide if te character is part of the command or not + * @param state pointer to a txt_cmd_state_t variable which stores the current state of command processing + * @param c the current character + * @return true: the character is part of a command and should not be written, + * false: the character should be written + */ +bool lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c); + +/** + * Insert a string into an other + * @param txt_buf the original text (must be big enough for the result text) + * @param pos position to insert (0: before the original text, 1: after the first char etc.) + * @param ins_txt text to insert + */ +void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt); + +/** + * Delete a part of a string + * @param txt string to modify + * @param pos position where to start the deleting (0: before the first char, 1: after the first char etc.) + * @param len number of characters to delete + */ +void lv_txt_cut(char * txt, uint32_t pos, uint32_t len); + +/*************************************************************** + * GLOBAL FUNCTION POINTERS FOR CAHRACTER ENCODING INTERFACE + ***************************************************************/ + +/** + * Give the size of an encoded character + * @param str pointer to a character in a string + * @return length of the encoded character (1,2,3 ...). O in invalid + */ +extern uint8_t (*lv_txt_encoded_size)(const char *); + + +/** + * Convert an Unicode letter to encoded + * @param letter_uni an Unicode letter + * @return Encoded character in Little Endian to be compatible with C chars (e.g. 'Á', 'Ü') + */ +extern uint32_t (*lv_txt_unicode_to_encoded)(uint32_t ); + +/** + * Convert a wide character, e.g. 'Á' little endian to be compatible with the encoded format. + * @param c a wide character + * @return `c` in the encoded format + */ +extern uint32_t (*lv_txt_encoded_conv_wc) (uint32_t c); + +/** + * Decode the next encoded character from a string. + * @param txt pointer to '\0' terminated string + * @param i start index in 'txt' where to start. + * After the call it will point to the next encoded char in 'txt'. + * NULL to use txt[0] as index + * @return the decoded Unicode character or 0 on invalid data code + */ +extern uint32_t (*lv_txt_encoded_next)(const char *, uint32_t * ); + +/** + * Get the previous encoded character form a string. + * @param txt pointer to '\0' terminated string + * @param i_start index in 'txt' where to start. After the call it will point to the previous encoded char in 'txt'. + * @return the decoded Unicode character or 0 on invalid data + */ +extern uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *); + +/** + * Convert a letter index (in an the encoded text) to byte index. + * E.g. in UTF-8 "AÁRT" index of 'R' is 2 but start at byte 3 because 'Á' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param enc_id letter index + * @return byte index of the 'enc_id'th letter + */ +extern uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t); + +/** + * Convert a byte index (in an encoded text) to character index. + * E.g. in UTF-8 "AÁRT" index of 'R' is 2 but start at byte 3 because 'Á' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param byte_id byte index + * @return character index of the letter at 'byte_id'th position + */ +extern uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t); + +/** + * Get the number of characters (and NOT bytes) in a string. + * E.g. in UTF-8 "ÁBC" is 3 characters (but 4 bytes) + * @param txt a '\0' terminated char string + * @return number of characters + */ +extern uint32_t (*lv_txt_get_encoded_length)(const char *); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*USE_TXT*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_misc/lv_ufs.h b/old-code/v5_hal/firmware/include/display/lv_misc/lv_ufs.h new file mode 100644 index 00000000..d30cbe0f --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_misc/lv_ufs.h @@ -0,0 +1,214 @@ +/** + * @file lv_ufs.h + * Implementation of RAM file system which do NOT support directories. + * The API is compatible with the lv_fs_int module. + */ + +#ifndef LV_UFS_H +#define LV_UFS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_FILESYSTEM + +#include +#include "lv_fs.h" +#include "lv_mem.h" + +/********************* + * DEFINES + *********************/ +#define UFS_LETTER 'U' + +/********************** + * TYPEDEFS + **********************/ +/*Description of a file entry */ +typedef struct +{ + char * fn_d; + void * data_d; + uint32_t size; /*Data length in bytes*/ + uint16_t oc; /*Open Count*/ + uint8_t const_data :1; +} lv_ufs_ent_t; + +/*File descriptor, used to handle opening an entry more times simultaneously + Contains unique informations about the specific opening*/ +typedef struct +{ + lv_ufs_ent_t* ent; /*Pointer to the entry*/ + uint32_t rwp; /*Read Write Pointer*/ + uint8_t ar :1; /*1: Access for read is enabled */ + uint8_t aw :1; /*1: Access for write is enabled */ +} lv_ufs_file_t; + +/* Read directory descriptor. + * It is used to to iterate through the entries in a directory*/ +typedef struct +{ + lv_ufs_ent_t * last_ent; +} lv_ufs_dir_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a driver for ufs and initialize it. + */ +void lv_ufs_init(void); + +/** + * Give the state of the ufs + * @return true if ufs is initialized and can be used else false + */ +bool lv_ufs_ready(void); + +/** + * Open a file in ufs + * @param file_p pointer to a lv_ufs_file_t variable + * @param fn name of the file. There are no directories so e.g. "myfile.txt" + * @param mode element of 'fs_mode_t' enum or its 'OR' connection (e.g. FS_MODE_WR | FS_MODE_RD) + * @return LV_FS_RES_OK: no error, the file is opened + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_open (void * file_p, const char * fn, lv_fs_mode_t mode); + +/** + * Create a file with a constant data + * @param fn name of the file (directories are not supported) + * @param const_p pointer to a constant data + * @param len length of the data pointed by 'const_p' in bytes + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_create_const(const char * fn, const void * const_p, uint32_t len); + +/** + * Close an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_close (void * file_p); + +/** + * Remove a file. The file can not be opened. + * @param fn '\0' terminated string + * @return LV_FS_RES_OK: no error, the file is removed + * LV_FS_RES_DENIED: the file was opened, remove failed + */ +lv_fs_res_t lv_ufs_remove(const char * fn); + +/** + * Read data from an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param buf pointer to a memory block where to store the read data + * @param btr number of Bytes To Read + * @param br the real number of read bytes (Byte Read) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_read (void * file_p, void * buf, uint32_t btr, uint32_t * br); + +/** + * Write data to an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open) + * @param buf pointer to a memory block which content will be written + * @param btw the number Bytes To Write + * @param bw The real number of written bytes (Byte Written) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_write (void * file_p, const void * buf, uint32_t btw, uint32_t * bw); + +/** + * Set the read write pointer. Also expand the file size if necessary. + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param pos the new position of read write pointer + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_seek (void * file_p, uint32_t pos); + +/** + * Give the position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param pos_p pointer to to store the result + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_tell (void * file_p, uint32_t * pos_p); + +/** + * Truncate the file size to the current position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_trunc (void * file_p); + +/** + * Give the size of the file in bytes + * @param file_p file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param size_p pointer to store the size + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_size (void * file_p, uint32_t * size_p); + +/** + * Initialize a lv_ufs_read_dir_t variable to directory reading + * @param rddir_p pointer to a 'ufs_read_dir_t' variable + * @param path uFS doesn't support folders so it has to be "" + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_open(void * rddir_p, const char * path); + +/** + * Read the next file name + * @param dir_p pointer to an initialized 'ufs_read_dir_t' variable + * @param fn pointer to buffer to sore the file name + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_read(void * dir_p, char * fn); + +/** + * Close the directory reading + * @param rddir_p pointer to an initialized 'ufs_read_dir_t' variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_close(void * rddir_p); + +/** + * Give the size of a drive + * @param total_p pointer to store the total size [kB] + * @param free_p pointer to store the free site [kB] + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_ufs_free (uint32_t * total_p, uint32_t * free_p); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_FILESYSTEM*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_arc.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_arc.h new file mode 100644 index 00000000..4f82e0d8 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_arc.h @@ -0,0 +1,127 @@ +/** + * @file lv_arc.h + * + */ + + +#ifndef LV_ARC_H +#define LV_ARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_ARC != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of arc*/ +typedef struct { + /*New data for this type */ + lv_coord_t angle_start; + lv_coord_t angle_end; +} lv_arc_ext_t; + + +/*Styles*/ +enum { + LV_ARC_STYLE_MAIN, +}; +typedef uint8_t lv_arc_style_t; + + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a arc objects + * @param par pointer to an object, it will be the parent of the new arc + * @param copy pointer to a arc object, if not NULL then the new object will be copied from it + * @return pointer to the created arc + */ +lv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the start and end angles of an arc. 0 deg: bottom, 90 deg: right etc. + * @param arc pointer to an arc object + * @param start the start angle [0..360] + * @param end the end angle [0..360] + */ +void lv_arc_set_angles(lv_obj_t * arc, uint16_t start, uint16_t end); + +/** + * Set a style of a arc. + * @param arc pointer to arc object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_arc_set_style(lv_obj_t * arc, lv_arc_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the start angle of an arc. + * @param arc pointer to an arc object + * @return the start angle [0..360] + */ +uint16_t lv_arc_get_angle_start(lv_obj_t * arc); + +/** + * Get the end angle of an arc. + * @param arc pointer to an arc object + * @return the end angle [0..360] + */ +uint16_t lv_arc_get_angle_end(lv_obj_t * arc); + +/** + * Get style of a arc. + * @param arc pointer to arc object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_arc_get_style(const lv_obj_t * arc, lv_arc_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_ARC*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ARC_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_bar.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_bar.h new file mode 100644 index 00000000..3938aa28 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_bar.h @@ -0,0 +1,160 @@ +/** + * @file lv_bar.h + * + */ + +#ifndef LV_BAR_H +#define LV_BAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_BAR != 0 + +#include "display/lv_core/lv_obj.h" +#include "lv_cont.h" +#include "lv_btn.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of bar*/ +typedef struct +{ + /*No inherited ext*/ /*Ext. of ancestor*/ + /*New data for this type */ + int16_t cur_value; /*Current value of the bar*/ + int16_t min_value; /*Minimum value of the bar*/ + int16_t max_value; /*Maximum value of the bar*/ + uint8_t sym :1; /*Symmetric: means the center is around zero value*/ + lv_style_t *style_indic; /*Style of the indicator*/ +} lv_bar_ext_t; + +enum { + LV_BAR_STYLE_BG, + LV_BAR_STYLE_INDIC, +}; +typedef uint8_t lv_bar_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a bar objects + * @param par pointer to an object, it will be the parent of the new bar + * @param copy pointer to a bar object, if not NULL then the new object will be copied from it + * @return pointer to the created bar + */ +lv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the bar + * @param bar pointer to a bar object + * @param value new value + */ +void lv_bar_set_value(lv_obj_t * bar, int16_t value); + +/** + * Set a new value with animation on the bar + * @param bar pointer to a bar object + * @param value new value + * @param anim_time animation time in milliseconds + */ +void lv_bar_set_value_anim(lv_obj_t * bar, int16_t value, uint16_t anim_time); + + +/** + * Set minimum and the maximum values of a bar + * @param bar pointer to the bar object + * @param min minimum value + * @param max maximum value + */ +void lv_bar_set_range(lv_obj_t * bar, int16_t min, int16_t max); + +/** + * Make the bar symmetric to zero. The indicator will grow from zero instead of the minimum position. + * @param bar pointer to a bar object + * @param en true: enable disable symmetric behavior; false: disable + */ +void lv_bar_set_sym(lv_obj_t * bar, bool en); + +/** + * Set a style of a bar + * @param bar pointer to a bar object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_bar_set_style(lv_obj_t *bar, lv_bar_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a bar + * @param bar pointer to a bar object + * @return the value of the bar + */ +int16_t lv_bar_get_value(const lv_obj_t * bar); + +/** + * Get the minimum value of a bar + * @param bar pointer to a bar object + * @return the minimum value of the bar + */ +int16_t lv_bar_get_min_value(const lv_obj_t * bar); + +/** + * Get the maximum value of a bar + * @param bar pointer to a bar object + * @return the maximum value of the bar + */ +int16_t lv_bar_get_max_value(const lv_obj_t * bar); + +/** + * Get whether the bar is symmetric or not. + * @param bar pointer to a bar object + * @return true: symmetric is enabled; false: disable + */ +bool lv_bar_get_sym(lv_obj_t * bar); + +/** + * Get a style of a bar + * @param bar pointer to a bar object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_bar_get_style(const lv_obj_t *bar, lv_bar_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_BAR*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BAR_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_btn.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_btn.h new file mode 100644 index 00000000..805b5d78 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_btn.h @@ -0,0 +1,279 @@ +/** + * @file lv_btn.h + * + */ + +#ifndef LV_BTN_H +#define LV_BTN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_BTN != 0 + +/*Testing of dependencies*/ +#if USE_LV_CONT == 0 +#error "lv_btn: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT 1) " +#endif + +#include "lv_cont.h" +#include "display/lv_core/lv_indev.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/* Button states + * It can be used not only by buttons but other button-like objects too*/ +enum +{ + LV_BTN_STATE_REL, + LV_BTN_STATE_PR, + LV_BTN_STATE_TGL_REL, + LV_BTN_STATE_TGL_PR, + LV_BTN_STATE_INA, + LV_BTN_STATE_NUM, +}; +typedef uint8_t lv_btn_state_t; + +enum +{ + LV_BTN_ACTION_CLICK, + LV_BTN_ACTION_PR, + LV_BTN_ACTION_LONG_PR, + LV_BTN_ACTION_LONG_PR_REPEAT, + LV_BTN_ACTION_NUM, +}; +typedef uint8_t lv_btn_action_t; + + +/*Data of button*/ +typedef struct +{ + lv_cont_ext_t cont; /*Ext. of ancestor*/ + /*New data for this type */ + lv_action_t actions[LV_BTN_ACTION_NUM]; + lv_style_t * styles[LV_BTN_STATE_NUM]; /*Styles in each state*/ + lv_btn_state_t state; /*Current state of the button from 'lv_btn_state_t' enum*/ +#if LV_BTN_INK_EFFECT + uint16_t ink_in_time; /*[ms] Time of ink fill effect (0: disable ink effect)*/ + uint16_t ink_wait_time; /*[ms] Wait before the ink disappears */ + uint16_t ink_out_time; /*[ms] Time of ink disappearing*/ +#endif + uint8_t toggle :1; /*1: Toggle enabled*/ + uint8_t long_pr_action_executed :1; /*1: Long press action executed (Handled by the library)*/ +} lv_btn_ext_t; + +/*Styles*/ +enum { + LV_BTN_STYLE_REL, + LV_BTN_STYLE_PR, + LV_BTN_STYLE_TGL_REL, + LV_BTN_STYLE_TGL_PR, + LV_BTN_STYLE_INA, +}; +typedef uint8_t lv_btn_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a button objects + * @param par pointer to an object, it will be the parent of the new button + * @param copy pointer to a button object, if not NULL then the new object will be copied from it + * @return pointer to the created button + */ +lv_obj_t * lv_btn_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Enable the toggled states. On release the button will change from/to toggled state. + * @param btn pointer to a button object + * @param tgl true: enable toggled states, false: disable + */ +void lv_btn_set_toggle(lv_obj_t * btn, bool tgl); + +/** + * Set the state of the button + * @param btn pointer to a button object + * @param state the new state of the button (from lv_btn_state_t enum) + */ +void lv_btn_set_state(lv_obj_t * btn, lv_btn_state_t state); + +/** + * Toggle the state of the button (ON->OFF, OFF->ON) + * @param btn pointer to a button object + */ +void lv_btn_toggle(lv_obj_t * btn); + +/** + * Set a function to call when a button event happens + * @param btn pointer to a button object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +void lv_btn_set_action(lv_obj_t * btn, lv_btn_action_t type, lv_action_t action); + +/** + * Set the layout on a button + * @param btn pointer to a button object + * @param layout a layout from 'lv_cont_layout_t' + */ +static inline void lv_btn_set_layout(lv_obj_t * btn, lv_layout_t layout) +{ + lv_cont_set_layout(btn, layout); +} + +/** + * Enable the horizontal or vertical fit. + * The button size will be set to involve the children horizontally or vertically. + * @param btn pointer to a button object + * @param hor_en true: enable the horizontal fit + * @param ver_en true: enable the vertical fit + */ +static inline void lv_btn_set_fit(lv_obj_t * btn, bool hor_en, bool ver_en) +{ + lv_cont_set_fit(btn, hor_en, ver_en); +} + +/** + * Set time of the ink effect (draw a circle on click to animate in the new state) + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_in_time(lv_obj_t * btn, uint16_t time); + +/** + * Set the wait time before the ink disappears + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_wait_time(lv_obj_t * btn, uint16_t time); + +/** + * Set time of the ink out effect (animate to the released state) + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_out_time(lv_obj_t * btn, uint16_t time); + +/** + * Set a style of a button. + * @param btn pointer to button object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_btn_set_style(lv_obj_t * btn, lv_btn_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current state of the button + * @param btn pointer to a button object + * @return the state of the button (from lv_btn_state_t enum) + */ +lv_btn_state_t lv_btn_get_state(const lv_obj_t * btn); + +/** + * Get the toggle enable attribute of the button + * @param btn pointer to a button object + * @return ture: toggle enabled, false: disabled + */ +bool lv_btn_get_toggle(const lv_obj_t * btn); + +/** + * Get the release action of a button + * @param btn pointer to a button object + * @return pointer to the release action function + */ +lv_action_t lv_btn_get_action(const lv_obj_t * btn, lv_btn_action_t type); + +/** + * Get the layout of a button + * @param btn pointer to button object + * @return the layout from 'lv_cont_layout_t' + */ +static inline lv_layout_t lv_btn_get_layout(const lv_obj_t * btn) +{ + return lv_cont_get_layout(btn); +} + +/** + * Get horizontal fit enable attribute of a button + * @param btn pointer to a button object + * @return true: horizontal fit is enabled; false: disabled + */ +static inline bool lv_btn_get_hor_fit(const lv_obj_t * btn) +{ + return lv_cont_get_hor_fit(btn); +} + +/** + * Get vertical fit enable attribute of a container + * @param btn pointer to a button object + * @return true: vertical fit is enabled; false: disabled + */ +static inline bool lv_btn_get_ver_fit(const lv_obj_t * btn) +{ + return lv_cont_get_ver_fit(btn); +} + +/** + * Get time of the ink in effect (draw a circle on click to animate in the new state) + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_in_time(const lv_obj_t * btn); + +/** + * Get the wait time before the ink disappears + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_wait_time(const lv_obj_t * btn); + +/** + * Get time of the ink out effect (animate to the releases state) + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_out_time(const lv_obj_t * btn); + +/** + * Get style of a button. + * @param btn pointer to button object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_btn_get_style(const lv_obj_t * btn, lv_btn_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_BUTTON*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BTN_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_btnm.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_btnm.h new file mode 100644 index 00000000..89c066a4 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_btnm.h @@ -0,0 +1,197 @@ +/** + * @file lv_btnm.h + * + */ + + +#ifndef LV_BTNM_H +#define LV_BTNM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_BTNM != 0 + +#include "display/lv_core/lv_obj.h" +#include "lv_label.h" +#include "lv_btn.h" + +/********************* + * DEFINES + *********************/ + +/*Control byte*/ +#define LV_BTNM_CTRL_CODE 0x80 /*The control byte has to begin (if present) with 0b10xxxxxx*/ +#define LV_BTNM_CTRL_MASK 0xC0 +#define LV_BTNM_WIDTH_MASK 0x07 +#define LV_BTNM_HIDE_MASK 0x08 +#define LV_BTNM_REPEAT_DISABLE_MASK 0x10 +#define LV_BTNM_INACTIVE_MASK 0x20 + + +#define LV_BTNM_PR_NONE 0xFFFF +/********************** + * TYPEDEFS + **********************/ + +/* Type of callback function which is called when a button is released or long pressed on the button matrix + * Parameters: button matrix, text of the released button + * return LV_ACTION_RES_INV if the button matrix is deleted else LV_ACTION_RES_OK*/ +typedef lv_res_t (*lv_btnm_action_t) (lv_obj_t *, const char *txt); + +/*Data of button matrix*/ +typedef struct +{ + /*No inherited ext.*/ /*Ext. of ancestor*/ + /*New data for this type */ + const char ** map_p; /*Pointer to the current map*/ + lv_area_t *button_areas; /*Array of areas of buttons*/ + lv_btnm_action_t action; /*A function to call when a button is releases*/ + lv_style_t *styles_btn[LV_BTN_STATE_NUM]; /*Styles of buttons in each state*/ + uint16_t btn_cnt; /*Number of button in 'map_p'(Handled by the library)*/ + uint16_t btn_id_pr; /*Index of the currently pressed button (in `button_areas`) or LV_BTNM_PR_NONE*/ + uint16_t btn_id_tgl; /*Index of the currently toggled button (in `button_areas`) or LV_BTNM_PR_NONE */ + uint8_t toggle :1; /*Enable toggling*/ + uint8_t recolor :1; /*Enable button recoloring*/ +} lv_btnm_ext_t; + +enum { + LV_BTNM_STYLE_BG, + LV_BTNM_STYLE_BTN_REL, + LV_BTNM_STYLE_BTN_PR, + LV_BTNM_STYLE_BTN_TGL_REL, + LV_BTNM_STYLE_BTN_TGL_PR, + LV_BTNM_STYLE_BTN_INA, +}; +typedef uint8_t lv_btnm_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a button matrix objects + * @param par pointer to an object, it will be the parent of the new button matrix + * @param copy pointer to a button matrix object, if not NULL then the new object will be copied from it + * @return pointer to the created button matrix + */ +lv_obj_t * lv_btnm_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new map. Buttons will be created/deleted according to the map. + * @param btnm pointer to a button matrix object + * @param map pointer a string array. The last string has to be: "". + * Use "\n" to begin a new line. + * The first byte can be a control data: + * - bit 7: always 1 + * - bit 6: always 0 + * - bit 5: inactive (disabled) + * - bit 4: no repeat (on long press) + * - bit 3: hidden + * - bit 2..0: button relative width + * Example (practically use octal numbers): "\224abc": "abc" text with 4 width and no long press + */ +void lv_btnm_set_map(lv_obj_t * btnm, const char ** map); + +/** + * Set a new callback function for the buttons (It will be called when a button is released) + * @param btnm: pointer to button matrix object + * @param action pointer to a callback function + */ +void lv_btnm_set_action(lv_obj_t * btnm, lv_btnm_action_t action); + +/** + * Enable or disable button toggling + * @param btnm pointer to button matrix object + * @param en true: enable toggling; false: disable toggling + * @param id index of the currently toggled button (ignored if 'en' == false) + */ +void lv_btnm_set_toggle(lv_obj_t * btnm, bool en, uint16_t id); + +/** + * Set a style of a button matrix + * @param btnm pointer to a button matrix object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_btnm_set_style(lv_obj_t *btnm, lv_btnm_style_t type, lv_style_t *style); + +/** + * Set whether recoloring is enabled + * @param btnm pointer to button matrix object + * @param en whether recoloring is enabled + */ +void lv_btnm_set_recolor(const lv_obj_t * btnm, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current map of a button matrix + * @param btnm pointer to a button matrix object + * @return the current map + */ +const char ** lv_btnm_get_map(const lv_obj_t * btnm); + +/** + * Get a the callback function of the buttons on a button matrix + * @param btnm: pointer to button matrix object + * @return pointer to the callback function + */ +lv_btnm_action_t lv_btnm_get_action(const lv_obj_t * btnm); + +/** + * Get the pressed button + * @param btnm pointer to button matrix object + * @return index of the currently pressed button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_pressed(const lv_obj_t * btnm); + +/** + * Get the toggled button + * @param btnm pointer to button matrix object + * @return index of the currently toggled button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_toggled(const lv_obj_t * btnm); + +/** + * Get a style of a button matrix + * @param btnm pointer to a button matrix object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_btnm_get_style(const lv_obj_t *btnm, lv_btnm_style_t type); + +/** + * Find whether recoloring is enabled + * @param btnm pointer to button matrix object + * @return whether recoloring is enabled + */ +bool lv_btnm_get_recolor(const lv_obj_t * btnm); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_BTNM*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BTNM_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_calendar.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_calendar.h new file mode 100644 index 00000000..3ef4b025 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_calendar.h @@ -0,0 +1,246 @@ +/** + * @file lv_calendar.h + * + */ + +#ifndef LV_CALENDAR_H +#define LV_CALENDAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_CALENDAR != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + uint16_t year; + int8_t month; + int8_t day; +} lv_calendar_date_t; + +enum +{ + LV_CALENDAR_ACTION_CLICK, + LV_CALENDAR_ACTION_PR, + LV_CALENDAR_ACTION_LONG_PR, + LV_CALENDAR_ACTION_LONG_PR_REPEAT, + LV_CALENDAR_ACTION_NUM, +}; +typedef uint8_t lv_calendar_action_t; + +/*Data of calendar*/ +typedef struct { + /*None*/ /*Ext. of ancestor*/ + /*New data for this type */ + lv_calendar_date_t today; /*Date of today*/ + lv_calendar_date_t showed_date; /*Currently visible month (day is ignored)*/ + lv_calendar_date_t * highlighted_dates; /*Apply different style on these days (pointer to an array defined by the user)*/ + uint8_t highlighted_dates_num; /*Number of elements in `highlighted_days`*/ + int8_t btn_pressing; /*-1: prev month pressing, +1 next month pressing on the header*/ + lv_calendar_date_t pressed_date; + const char ** day_names; /*Pointer to an array with the name of the days (NULL: use default names)*/ + const char ** month_names; /*Pointer to an array with the name of the month (NULL. use default names)*/ + lv_action_t actions[LV_CALENDAR_ACTION_NUM]; + + /*Styles*/ + lv_style_t * style_header; + lv_style_t * style_header_pr; + lv_style_t * style_day_names; + lv_style_t * style_highlighted_days; + lv_style_t * style_inactive_days; + lv_style_t * style_week_box; + lv_style_t * style_today_box; +} lv_calendar_ext_t; + +/*Styles*/ +enum { + LV_CALENDAR_STYLE_BG, /*Also the style of the "normal" date numbers*/ + LV_CALENDAR_STYLE_HEADER, + LV_CALENDAR_STYLE_HEADER_PR, + LV_CALENDAR_STYLE_DAY_NAMES, + LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS, + LV_CALENDAR_STYLE_INACTIVE_DAYS, + LV_CALENDAR_STYLE_WEEK_BOX, + LV_CALENDAR_STYLE_TODAY_BOX, +}; +typedef uint8_t lv_calendar_style_t; + + + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a calendar objects + * @param par pointer to an object, it will be the parent of the new calendar + * @param copy pointer to a calendar object, if not NULL then the new object will be copied from it + * @return pointer to the created calendar + */ +lv_obj_t * lv_calendar_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ +/** + * Set a function to call when a calendar event happens + * @param calendar pointer to a calendar object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +void lv_calendar_set_action(lv_obj_t * calendar, lv_calendar_action_t type, lv_action_t action); + +/** + * Set the today's date + * @param calendar pointer to a calendar object + * @param today pointer to an `lv_calendar_date_t` variable containing the date of today. The value will be saved it can be local variable too. + */ +void lv_calendar_set_today_date(lv_obj_t * calendar, lv_calendar_date_t * today); + +/** + * Set the currently showed + * @param calendar pointer to a calendar object + * @param showed pointer to an `lv_calendar_date_t` variable containing the date to show. The value will be saved it can be local variable too. + */ +void lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showed); + +/** + * Set the the highlighted dates + * @param calendar pointer to a calendar object + * @param highlighted pointer to an `lv_calendar_date_t` array containing the dates. ONLY A POINTER WILL BE SAVED! CAN'T BE LOCAL ARRAY. + * @param date_num number of dates in the array + */ +void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t * highlighted, uint16_t date_num); + + +/** + * Set the name of the days + * @param calendar pointer to a calendar object + * @param day_names pointer to an array with the names. E.g. `const char * days[7] = {"Sun", "Mon", ...}` + * Only the pointer will be saved so this variable can't be local which will be destroyed later. + */ +void lv_calendar_set_day_names(lv_obj_t * calendar, const char ** day_names); + +/** + * Set the name of the month + * @param calendar pointer to a calendar object + * @param day_names pointer to an array with the names. E.g. `const char * days[12] = {"Jan", "Feb", ...}` + * Only the pointer will be saved so this variable can't be local which will be destroyed later. + */ +void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** day_names); + +/** + * Set a style of a calendar. + * @param calendar pointer to calendar object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_calendar_set_style(lv_obj_t * calendar, lv_calendar_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ +/** + * Get the action of a calendar + * @param calendar pointer to a calendar object + * @return pointer to the action function + */ +lv_action_t lv_calendar_get_action(const lv_obj_t * calendar, lv_calendar_action_t type); + +/** + * Get the today's date + * @param calendar pointer to a calendar object + * @return return pointer to an `lv_calendar_date_t` variable containing the date of today. + */ +lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar); + +/** + * Get the currently showed + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the date is being shown. + */ +lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar); + +/** + * Get the the pressed date. + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the pressed date. + */ +lv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar); + +/** + * Get the the highlighted dates + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` array containing the dates. + */ +lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar); + +/** + * Get the number of the highlighted dates + * @param calendar pointer to a calendar object + * @return number of highlighted days + */ +uint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar); + + +/** + * Get the name of the days + * @param calendar pointer to a calendar object + * @return pointer to the array of day names + */ +const char ** lv_calendar_get_day_names(const lv_obj_t * calendar); + +/** + * Get the name of the month + * @param calendar pointer to a calendar object + * @return pointer to the array of month names + */ +const char ** lv_calendar_get_month_names(const lv_obj_t * calendar); + +/** + * Get style of a calendar. + * @param calendar pointer to calendar object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_calendar_get_style(const lv_obj_t * calendar, lv_calendar_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CALENDAR*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CALENDAR_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_canvas.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_canvas.h new file mode 100644 index 00000000..14d6e87b --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_canvas.h @@ -0,0 +1,229 @@ +/** + * @file lv_canvas.h + * + */ + +#ifndef LV_CANVAS_H +#define LV_CANVAS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_CANVAS != 0 + +#include "display/lv_core/lv_obj.h" +#include "display/lv_objx/lv_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of canvas*/ +typedef struct { + lv_img_ext_t img; /*Ext. of ancestor*/ + /*New data for this type */ + lv_img_dsc_t dsc; +} lv_canvas_ext_t; + + +/*Styles*/ +enum { + LV_CANVAS_STYLE_MAIN, +}; +typedef uint8_t lv_canvas_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a canvas object + * @param par pointer to an object, it will be the parent of the new canvas + * @param copy pointer to a canvas object, if not NULL then the new object will be copied from it + * @return pointer to the created canvas + */ +lv_obj_t * lv_canvas_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a buffer for the canvas. + * @param buf a buffer where the content of the canvas will be. + * The required size is (lv_img_color_format_get_px_size(cf) * w * h) / 8) + * It can be allocated with `lv_mem_alloc()` or + * it can be statically allocated array (e.g. static lv_color_t buf[100*50]) or + * it can be an address in RAM or external SRAM + * @param canvas pointer to a canvas object + * @param w width of the canvas + * @param h height of the canvas + * @param cf color format. The following formats are supported: + * LV_IMG_CF_TRUE_COLOR, LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, LV_IMG_CF_INDEXES_1/2/4/8BIT + */ +void lv_canvas_set_buffer(lv_obj_t * canvas, void * buf, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf); + +/** + * Set the color of a pixel on the canvas + * @param canvas + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @param c color of the point + */ +void lv_canvas_set_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t c); + +/** + * Set a style of a canvas. + * @param canvas pointer to canvas object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_canvas_set_style(lv_obj_t * canvas, lv_canvas_style_t type, lv_style_t * style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the color of a pixel on the canvas + * @param canvas + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @return color of the point + */ +lv_color_t lv_canvas_get_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y); + +/** + * Get style of a canvas. + * @param canvas pointer to canvas object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_canvas_get_style(const lv_obj_t * canvas, lv_canvas_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Copy a buffer to the canvas + * @param canvas pointer to a canvas object + * @param to_copy buffer to copy. The color format has to match with the canvas's buffer color format + * @param w width of the buffer to copy + * @param h height of the buffer to copy + * @param x left side of the destination position + * @param y top side of the destination position + */ +void lv_canvas_copy_buf(lv_obj_t * canvas, const void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y); + +/** + * Multiply a buffer with the canvas + * @param canvas pointer to a canvas object + * @param to_copy buffer to copy (multiply). LV_IMG_CF_TRUE_COLOR_ALPHA is not supported + * @param w width of the buffer to copy + * @param h height of the buffer to copy + * @param x left side of the destination position + * @param y top side of the destination position + */ +void lv_canvas_mult_buf(lv_obj_t * canvas, void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y); + +/** + * Draw circle function of the canvas + * @param canvas pointer to a canvas object + * @param x0 x coordinate of the circle + * @param y0 y coordinate of the circle + * @param radius radius of the circle + * @param color border color of the circle + */ +void lv_canvas_draw_circle(lv_obj_t * canvas, lv_coord_t x0, lv_coord_t y0, lv_coord_t radius, lv_color_t color); + +/** + * Draw line function of the canvas + * @param canvas pointer to a canvas object + * @param point1 start point of the line + * @param point2 end point of the line + * @param color color of the line + * + * NOTE: The lv_canvas_draw_line function originates from https://github.com/jb55/bresenham-line.c. + */ +void lv_canvas_draw_line(lv_obj_t * canvas, lv_point_t point1, lv_point_t point2, lv_color_t color); + +/** + * Draw triangle function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the triangle + * @param color line color of the triangle + */ +void lv_canvas_draw_triangle(lv_obj_t * canvas, lv_point_t * points, lv_color_t color); + +/** + * Draw rectangle function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the rectangle + * @param color line color of the rectangle + */ +void lv_canvas_draw_rect(lv_obj_t * canvas, lv_point_t * points, lv_color_t color); + +/** + * Draw polygon function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the polygon + * @param size edge count of the polygon + * @param color line color of the polygon + */ +void lv_canvas_draw_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t color); + +/** + * Fill polygon function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the polygon + * @param size edge count of the polygon + * @param boundary_color line color of the polygon + * @param fill_color fill color of the polygon + */ +void lv_canvas_fill_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t boundary_color, lv_color_t fill_color); +/** + * Boundary fill function of the canvas + * @param canvas pointer to a canvas object + * @param x x coordinate of the start position (seed) + * @param y y coordinate of the start position (seed) + * @param boundary_color edge/boundary color of the area + * @param fill_color fill color of the area + */ +void lv_canvas_boundary_fill4(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t boundary_color, lv_color_t fill_color); + +/** + * Flood fill function of the canvas + * @param canvas pointer to a canvas object + * @param x x coordinate of the start position (seed) + * @param y y coordinate of the start position (seed) + * @param fill_color fill color of the area + * @param bg_color background color of the area + */ +void lv_canvas_flood_fill(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t fill_color, lv_color_t bg_color); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CANVAS*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CANVAS_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_cb.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_cb.h new file mode 100644 index 00000000..5c550b6f --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_cb.h @@ -0,0 +1,174 @@ +/** + * @file lv_cb.h + * + */ + +#ifndef LV_CB_H +#define LV_CB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_CB != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTN == 0 +#error "lv_cb: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_cb: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_btn.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of check box*/ +typedef struct +{ + lv_btn_ext_t bg_btn; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * bullet; /*Pointer to button*/ + lv_obj_t * label; /*Pointer to label*/ +} lv_cb_ext_t; + +enum { + LV_CB_STYLE_BG, + LV_CB_STYLE_BOX_REL, + LV_CB_STYLE_BOX_PR, + LV_CB_STYLE_BOX_TGL_REL, + LV_CB_STYLE_BOX_TGL_PR, + LV_CB_STYLE_BOX_INA, +}; +typedef uint8_t lv_cb_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a check box objects + * @param par pointer to an object, it will be the parent of the new check box + * @param copy pointer to a check box object, if not NULL then the new object will be copied from it + * @return pointer to the created check box + */ +lv_obj_t * lv_cb_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a check box + * @param cb pointer to a check box + * @param txt the text of the check box + */ +void lv_cb_set_text(lv_obj_t * cb, const char * txt); + +/** + * Set the state of the check box + * @param cb pointer to a check box object + * @param checked true: make the check box checked; false: make it unchecked + */ +static inline void lv_cb_set_checked(lv_obj_t * cb, bool checked) +{ + lv_btn_set_state(cb, checked ? LV_BTN_STATE_TGL_REL : LV_BTN_STATE_REL); +} + +/** + * Make the check box inactive (disabled) + * @param cb pointer to a check box object + */ +static inline void lv_cb_set_inactive(lv_obj_t * cb) +{ + lv_btn_set_state(cb, LV_BTN_STATE_INA); +} + +/** + * Set a function to call when the check box is clicked + * @param cb pointer to a check box object + */ +static inline void lv_cb_set_action(lv_obj_t * cb, lv_action_t action) +{ + lv_btn_set_action(cb, LV_BTN_ACTION_CLICK, action); +} + + +/** + * Set a style of a check box + * @param cb pointer to check box object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_cb_set_style(lv_obj_t * cb, lv_cb_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a check box + * @param cb pointer to check box object + * @return pointer to the text of the check box + */ +const char * lv_cb_get_text(const lv_obj_t * cb); + +/** + * Get the current state of the check box + * @param cb pointer to a check box object + * @return true: checked; false: not checked + */ +static inline bool lv_cb_is_checked(const lv_obj_t * cb) +{ + return lv_btn_get_state(cb) == LV_BTN_STATE_REL ? false : true; +} + +/** + * Get the action of a check box + * @param cb pointer to a button object + * @return pointer to the action function + */ +static inline lv_action_t lv_cb_get_action(const lv_obj_t * cb) +{ + return lv_btn_get_action(cb, LV_BTN_ACTION_CLICK); +} + + +/** + * Get a style of a button + * @param cb pointer to check box object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_cb_get_style(const lv_obj_t * cb, lv_cb_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CB*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CB_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_chart.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_chart.h new file mode 100644 index 00000000..92637e89 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_chart.h @@ -0,0 +1,262 @@ +/** + * @file lv_chart.h + * + */ + +#ifndef LV_CHART_H +#define LV_CHART_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_CHART != 0 + +#include "display/lv_core/lv_obj.h" +#include "lv_line.h" + +/********************* + * DEFINES + *********************/ +#define LV_CHART_POINT_DEF (LV_COORD_MIN) + +/********************** + * TYPEDEFS + **********************/ +typedef struct +{ + lv_coord_t * points; + lv_color_t color; + uint16_t start_point; +} lv_chart_series_t; + +/*Data of chart */ +typedef struct +{ + /*No inherited ext*/ /*Ext. of ancestor*/ + /*New data for this type */ + lv_ll_t series_ll; /*Linked list for the data line pointers (stores lv_chart_dl_t)*/ + lv_coord_t ymin; /*y min value (used to scale the data)*/ + lv_coord_t ymax; /*y max value (used to scale the data)*/ + uint8_t hdiv_cnt; /*Number of horizontal division lines*/ + uint8_t vdiv_cnt; /*Number of vertical division lines*/ + uint16_t point_cnt; /*Point number in a data line*/ + uint8_t type :4; /*Line, column or point chart (from 'lv_chart_type_t')*/ + struct { + lv_coord_t width; /*Line width or point radius*/ + uint8_t num; /*Number of data lines in dl_ll*/ + lv_opa_t opa; /*Opacity of data lines*/ + lv_opa_t dark; /*Dark level of the point/column bottoms*/ + } series; +} lv_chart_ext_t; + +/*Chart types*/ +enum +{ + LV_CHART_TYPE_LINE = 0x01, /*Connect the points with lines*/ + LV_CHART_TYPE_COLUMN = 0x02, /*Draw columns*/ + LV_CHART_TYPE_POINT = 0x04, /*Draw circles on the points*/ + LV_CHART_TYPE_VERTICAL_LINE = 0x08, /*Draw vertical lines on points (useful when chart width == point count)*/ +}; +typedef uint8_t lv_chart_type_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a chart background objects + * @param par pointer to an object, it will be the parent of the new chart background + * @param copy pointer to a chart background object, if not NULL then the new object will be copied from it + * @return pointer to the created chart background + */ +lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Allocate and add a data series to the chart + * @param chart pointer to a chart object + * @param color color of the data series + * @return pointer to the allocated data series + */ +lv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, lv_color_t color); + +/** + * Clear the point of a serie + * @param chart pointer to a chart object + * @param serie pointer to the chart's serie to clear + */ +void lv_chart_clear_serie(lv_obj_t * chart, lv_chart_series_t * serie); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the number of horizontal and vertical division lines + * @param chart pointer to a graph background object + * @param hdiv number of horizontal division lines + * @param vdiv number of vertical division lines + */ +void lv_chart_set_div_line_count(lv_obj_t * chart, uint8_t hdiv, uint8_t vdiv); + +/** + * Set the minimal and maximal y values + * @param chart pointer to a graph background object + * @param ymin y minimum value + * @param ymax y maximum value + */ +void lv_chart_set_range(lv_obj_t * chart, lv_coord_t ymin, lv_coord_t ymax); + +/** + * Set a new type for a chart + * @param chart pointer to a chart object + * @param type new type of the chart (from 'lv_chart_type_t' enum) + */ +void lv_chart_set_type(lv_obj_t * chart, lv_chart_type_t type); + +/** + * Set the number of points on a data line on a chart + * @param chart pointer r to chart object + * @param point_cnt new number of points on the data lines + */ +void lv_chart_set_point_count(lv_obj_t * chart, uint16_t point_cnt); + +/** + * Set the opacity of the data series + * @param chart pointer to a chart object + * @param opa opacity of the data series + */ +void lv_chart_set_series_opa(lv_obj_t * chart, lv_opa_t opa); + +/** + * Set the line width or point radius of the data series + * @param chart pointer to a chart object + * @param width the new width + */ +void lv_chart_set_series_width(lv_obj_t * chart, lv_coord_t width); + +/** + * Set the dark effect on the bottom of the points or columns + * @param chart pointer to a chart object + * @param dark_eff dark effect level (LV_OPA_TRANSP to turn off) + */ +void lv_chart_set_series_darking(lv_obj_t * chart, lv_opa_t dark_eff); + +/** + * Initialize all data points with a value + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y the new value for all points + */ +void lv_chart_init_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y); + +/** + * Set the value s of points from an array + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y_array array of 'lv_coord_t' points (with 'points count' elements ) + */ +void lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t * y_array); + +/** + * Shift all data right and set the most right data on a data line + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y the new value of the most right data + */ +void lv_chart_set_next(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y); + +/** + * Set the style of a chart + * @param chart pointer to a chart object + * @param style pointer to a style + */ +static inline void lv_chart_set_style(lv_obj_t *chart, lv_style_t *style) +{ + lv_obj_set_style(chart, style); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the type of a chart + * @param chart pointer to chart object + * @return type of the chart (from 'lv_chart_t' enum) + */ +lv_chart_type_t lv_chart_get_type(const lv_obj_t * chart); + +/** + * Get the data point number per data line on chart + * @param chart pointer to chart object + * @return point number on each data line + */ +uint16_t lv_chart_get_point_cnt(const lv_obj_t * chart); + +/** + * Get the opacity of the data series + * @param chart pointer to chart object + * @return the opacity of the data series + */ +lv_opa_t lv_chart_get_series_opa(const lv_obj_t * chart); + +/** + * Get the data series width + * @param chart pointer to chart object + * @return the width the data series (lines or points) + */ +lv_coord_t lv_chart_get_series_width(const lv_obj_t * chart); + +/** + * Get the dark effect level on the bottom of the points or columns + * @param chart pointer to chart object + * @return dark effect level (LV_OPA_TRANSP to turn off) + */ +lv_opa_t lv_chart_get_series_darking(const lv_obj_t * chart); + +/** + * Get the style of an chart object + * @param chart pointer to an chart object + * @return pointer to the chart's style + */ +static inline lv_style_t* lv_chart_get_style(const lv_obj_t *chart) +{ + return lv_obj_get_style(chart); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Refresh a chart if its data line has changed + * @param chart pointer to chart object + */ +void lv_chart_refresh(lv_obj_t * chart); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CHART*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CHART_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_cont.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_cont.h new file mode 100644 index 00000000..3f4923dc --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_cont.h @@ -0,0 +1,163 @@ +/** + * @file lv_cont.h + * + */ + +#ifndef LV_CONT_H +#define LV_CONT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_CONT != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Layout options*/ +enum +{ + LV_LAYOUT_OFF = 0, + LV_LAYOUT_CENTER, + LV_LAYOUT_COL_L, /*Column left align*/ + LV_LAYOUT_COL_M, /*Column middle align*/ + LV_LAYOUT_COL_R, /*Column right align*/ + LV_LAYOUT_ROW_T, /*Row top align*/ + LV_LAYOUT_ROW_M, /*Row middle align*/ + LV_LAYOUT_ROW_B, /*Row bottom align*/ + LV_LAYOUT_PRETTY, /*Put as many object as possible in row and begin a new row*/ + LV_LAYOUT_GRID, /*Align same-sized object into a grid*/ +}; +typedef uint8_t lv_layout_t; + +typedef struct +{ + /*Inherited from 'base_obj' so no inherited ext. */ /*Ext. of ancestor*/ + /*New data for this type */ + uint8_t layout :4; /*A layout from 'lv_cont_layout_t' enum*/ + uint8_t hor_fit :1; /*1: Enable horizontal fit to involve all children*/ + uint8_t ver_fit :1; /*1: Enable horizontal fit to involve all children*/ +} lv_cont_ext_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a container objects + * @param par pointer to an object, it will be the parent of the new container + * @param copy pointer to a container object, if not NULL then the new object will be copied from it + * @return pointer to the created container + */ +lv_obj_t * lv_cont_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a layout on a container + * @param cont pointer to a container object + * @param layout a layout from 'lv_cont_layout_t' + */ +void lv_cont_set_layout(lv_obj_t * cont, lv_layout_t layout); + + +/** + * Enable the horizontal or vertical fit. + * The container size will be set to involve the children horizontally or vertically. + * @param cont pointer to a container object + * @param hor_en true: enable the horizontal fit + * @param ver_en true: enable the vertical fit + */ +void lv_cont_set_fit(lv_obj_t * cont, bool hor_en, bool ver_en); + +/** + * Set the style of a container + * @param cont pointer to a container object + * @param style pointer to the new style + */ +static inline void lv_cont_set_style(lv_obj_t *cont, lv_style_t * style) +{ + lv_obj_set_style(cont, style); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the layout of a container + * @param cont pointer to container object + * @return the layout from 'lv_cont_layout_t' + */ +lv_layout_t lv_cont_get_layout(const lv_obj_t * cont); + +/** + * Get horizontal fit enable attribute of a container + * @param cont pointer to a container object + * @return true: horizontal fit is enabled; false: disabled + */ +bool lv_cont_get_hor_fit(const lv_obj_t * cont); + +/** + * Get vertical fit enable attribute of a container + * @param cont pointer to a container object + * @return true: vertical fit is enabled; false: disabled + */ +bool lv_cont_get_ver_fit(const lv_obj_t * cont); + + +/** + * Get that width reduced by the horizontal padding. Useful if a layout is used. + * @param cont pointer to a container object + * @return the width which still fits into the container + */ +lv_coord_t lv_cont_get_fit_width(lv_obj_t * cont); + +/** + * Get that height reduced by the vertical padding. Useful if a layout is used. + * @param cont pointer to a container object + * @return the height which still fits into the container + */ +lv_coord_t lv_cont_get_fit_height(lv_obj_t * cont); + +/** + * Get the style of a container + * @param cont pointer to a container object + * @return pointer to the container's style + */ +static inline lv_style_t * lv_cont_get_style(const lv_obj_t *cont) +{ + return lv_obj_get_style(cont); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CONT*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CONT_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_ddlist.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_ddlist.h new file mode 100644 index 00000000..cd9de975 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_ddlist.h @@ -0,0 +1,265 @@ +/** + * @file lv_ddlist.h + * + */ + +#ifndef LV_DDLIST_H +#define LV_DDLIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_DDLIST != 0 + +/*Testing of dependencies*/ +#if USE_LV_PAGE == 0 +#error "lv_ddlist: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_ddlist: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "display/lv_objx/lv_page.h" +#include "display/lv_objx/lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of drop down list*/ +typedef struct +{ + lv_page_ext_t page; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t *label; /*Label for the options*/ + lv_style_t * sel_style; /*Style of the selected option*/ + lv_action_t action; /*Pointer to function to call when an option is selected*/ + uint16_t option_cnt; /*Number of options*/ + uint16_t sel_opt_id; /*Index of the current option*/ + uint16_t sel_opt_id_ori; /*Store the original index on focus*/ + uint16_t anim_time; /*Open/Close animation time [ms]*/ + uint8_t opened :1; /*1: The list is opened (handled by the library)*/ + uint8_t draw_arrow :1; /*1: Draw arrow*/ + + lv_coord_t fix_height; /*Height of the ddlist when opened. (0: auto-size)*/ +} lv_ddlist_ext_t; + +enum { + LV_DDLIST_STYLE_BG, + LV_DDLIST_STYLE_SEL, + LV_DDLIST_STYLE_SB, +}; +typedef uint8_t lv_ddlist_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/** + * Create a drop down list objects + * @param par pointer to an object, it will be the parent of the new drop down list + * @param copy pointer to a drop down list object, if not NULL then the new object will be copied from it + * @return pointer to the created drop down list + */ +lv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set arrow draw in a drop down list + * @param ddlist pointer to drop down list object + * @param en enable/disable a arrow draw. E.g. "true" for draw. + */ +void lv_ddlist_set_draw_arrow(lv_obj_t * ddlist, bool en); + +/** + * Set the options in a drop down list from a string + * @param ddlist pointer to drop down list object + * @param options a string with '\n' separated options. E.g. "One\nTwo\nThree" + */ +void lv_ddlist_set_options(lv_obj_t * ddlist, const char * options); + +/** + * Set the selected option + * @param ddlist pointer to drop down list object + * @param sel_opt id of the selected option (0 ... number of option - 1); + */ +void lv_ddlist_set_selected(lv_obj_t * ddlist, uint16_t sel_opt); + +/** + * Set a function to call when a new option is chosen + * @param ddlist pointer to a drop down list + * @param action pointer to a call back function + */ +void lv_ddlist_set_action(lv_obj_t * ddlist, lv_action_t action); + +/** + * Set the fix height for the drop down list + * If 0 then the opened ddlist will be auto. sized else the set height will be applied. + * @param ddlist pointer to a drop down list + * @param h the height when the list is opened (0: auto size) + */ +void lv_ddlist_set_fix_height(lv_obj_t * ddlist, lv_coord_t h); + +/** + * Enable or disable the horizontal fit to the content + * @param ddlist pointer to a drop down list + * @param en true: enable auto fit; false: disable auto fit + */ +void lv_ddlist_set_hor_fit(lv_obj_t * ddlist, bool en); + +/** + * Set the scroll bar mode of a drop down list + * @param ddlist pointer to a drop down list object + * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum + */ +static inline void lv_ddlist_set_sb_mode(lv_obj_t * ddlist, lv_sb_mode_t mode) +{ + lv_page_set_sb_mode(ddlist, mode); +} + +/** + * Set the open/close animation time. + * @param ddlist pointer to a drop down list + * @param anim_time: open/close animation time [ms] + */ +void lv_ddlist_set_anim_time(lv_obj_t * ddlist, uint16_t anim_time); + + +/** + * Set a style of a drop down list + * @param ddlist pointer to a drop down list object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_ddlist_set_style(lv_obj_t *ddlist, lv_ddlist_style_t type, lv_style_t *style); + +/** + * Set the alignment of the labels in a drop down list + * @param ddlist pointer to a drop down list object + * @param align alignment of labels + */ +void lv_ddlist_set_align(lv_obj_t *ddlist, lv_label_align_t align); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get arrow draw in a drop down list + * @param ddlist pointer to drop down list object + */ +bool lv_ddlist_get_draw_arrow(lv_obj_t * ddlist); + +/** + * Get the options of a drop down list + * @param ddlist pointer to drop down list object + * @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3") + */ +const char * lv_ddlist_get_options(const lv_obj_t * ddlist); + +/** + * Get the selected option + * @param ddlist pointer to drop down list object + * @return id of the selected option (0 ... number of option - 1); + */ +uint16_t lv_ddlist_get_selected(const lv_obj_t * ddlist); + +/** + * Get the current selected option as a string + * @param ddlist pointer to ddlist object + * @param buf pointer to an array to store the string + */ +void lv_ddlist_get_selected_str(const lv_obj_t * ddlist, char * buf); + +/** + * Get the "option selected" callback function + * @param ddlist pointer to a drop down list + * @return pointer to the call back function + */ +lv_action_t lv_ddlist_get_action(const lv_obj_t * ddlist); + +/** + * Get the fix height value. + * @param ddlist pointer to a drop down list object + * @return the height if the ddlist is opened (0: auto size) + */ +lv_coord_t lv_ddlist_get_fix_height(const lv_obj_t * ddlist); + +/** + * Get the scroll bar mode of a drop down list + * @param ddlist pointer to a drop down list object + * @return scrollbar mode from 'lv_page_sb_mode_t' enum + */ +static inline lv_sb_mode_t lv_ddlist_get_sb_mode(const lv_obj_t * ddlist) +{ + return lv_page_get_sb_mode(ddlist); +} + +/** + * Get the open/close animation time. + * @param ddlist pointer to a drop down list + * @return open/close animation time [ms] + */ +uint16_t lv_ddlist_get_anim_time(const lv_obj_t * ddlist); + +/** + * Get a style of a drop down list + * @param ddlist pointer to a drop down list object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_ddlist_get_style(const lv_obj_t *ddlist, lv_ddlist_style_t type); + +/** + * Get the alignment of the labels in a drop down list + * @param ddlist pointer to a drop down list object + * @return alignment of labels + */ +lv_label_align_t lv_ddlist_get_align(const lv_obj_t *ddlist); + +/*===================== + * Other functions + *====================*/ + +/** + * Open the drop down list with or without animation + * @param ddlist pointer to drop down list object + * @param anim_en true: use animation; false: not use animations + */ +void lv_ddlist_open(lv_obj_t * ddlist, bool anim_en); + +/** + * Close (Collapse) the drop down list + * @param ddlist pointer to drop down list object + * @param anim_en true: use animation; false: not use animations + */ +void lv_ddlist_close(lv_obj_t * ddlist, bool anim_en); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_DDLIST*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DDLIST_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_gauge.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_gauge.h new file mode 100644 index 00000000..3f269cd0 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_gauge.h @@ -0,0 +1,222 @@ +/** + * @file lv_gauge.h + * + */ + +#ifndef LV_GAUGE_H +#define LV_GAUGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_GAUGE != 0 + +/*Testing of dependencies*/ +#if USE_LV_LMETER == 0 +#error "lv_gauge: lv_lmeter is required. Enable it in lv_conf.h (USE_LV_LMETER 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_lmeter.h" +#include "lv_label.h" +#include "lv_line.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of gauge*/ +typedef struct +{ + lv_lmeter_ext_t lmeter; /*Ext. of ancestor*/ + /*New data for this type */ + int16_t * values; /*Array of the set values (for needles) */ + const lv_color_t * needle_colors; /*Color of the needles (lv_color_t my_colors[needle_num])*/ + uint8_t needle_count; /*Number of needles*/ + uint8_t label_count; /*Number of labels on the scale*/ +} lv_gauge_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a gauge objects + * @param par pointer to an object, it will be the parent of the new gauge + * @param copy pointer to a gauge object, if not NULL then the new object will be copied from it + * @return pointer to the created gauge + */ +lv_obj_t * lv_gauge_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the number of needles + * @param gauge pointer to gauge object + * @param needle_cnt new count of needles + * @param colors an array of colors for needles (with 'num' elements) + */ +void lv_gauge_set_needle_count(lv_obj_t * gauge, uint8_t needle_cnt, const lv_color_t * colors); + +/** + * Set the value of a needle + * @param gauge pointer to a gauge + * @param needle_id the id of the needle + * @param value the new value + */ +void lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int16_t value); + +/** + * Set minimum and the maximum values of a gauge + * @param gauge pointer to he gauge object + * @param min minimum value + * @param max maximum value + */ +static inline void lv_gauge_set_range(lv_obj_t *gauge, int16_t min, int16_t max) +{ + lv_lmeter_set_range(gauge, min, max); +} + +/** + * Set a critical value on the scale. After this value 'line.color' scale lines will be drawn + * @param gauge pointer to a gauge object + * @param value the critical value + */ +static inline void lv_gauge_set_critical_value(lv_obj_t * gauge, int16_t value) +{ + lv_lmeter_set_value(gauge, value); +} + +/** + * Set the scale settings of a gauge + * @param gauge pointer to a gauge object + * @param angle angle of the scale (0..360) + * @param line_cnt count of scale lines. + * The get a given "subdivision" lines between label, `line_cnt` = (sub_div + 1) * (label_cnt - 1) + 1 + * @param label_cnt count of scale labels. + */ +void lv_gauge_set_scale(lv_obj_t * gauge, uint16_t angle, uint8_t line_cnt, uint8_t label_cnt); + +/** + * Set the styles of a gauge + * @param gauge pointer to a gauge object + * @param bg set the style of the gauge + * */ +static inline void lv_gauge_set_style(lv_obj_t *gauge, lv_style_t *bg) +{ + lv_obj_set_style(gauge, bg); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a needle + * @param gauge pointer to gauge object + * @param needle the id of the needle + * @return the value of the needle [min,max] + */ +int16_t lv_gauge_get_value(const lv_obj_t * gauge, uint8_t needle); + +/** + * Get the count of needles on a gauge + * @param gauge pointer to gauge + * @return count of needles + */ +uint8_t lv_gauge_get_needle_count(const lv_obj_t * gauge); + +/** + * Get the minimum value of a gauge + * @param gauge pointer to a gauge object + * @return the minimum value of the gauge + */ +static inline int16_t lv_gauge_get_min_value(const lv_obj_t * lmeter) +{ + return lv_lmeter_get_min_value(lmeter); +} + +/** + * Get the maximum value of a gauge + * @param gauge pointer to a gauge object + * @return the maximum value of the gauge + */ +static inline int16_t lv_gauge_get_max_value(const lv_obj_t * lmeter) +{ + return lv_lmeter_get_max_value(lmeter); +} + +/** + * Get a critical value on the scale. + * @param gauge pointer to a gauge object + * @return the critical value + */ +static inline int16_t lv_gauge_get_critical_value(const lv_obj_t * gauge) +{ + return lv_lmeter_get_value(gauge); +} + +/** + * Set the number of labels (and the thicker lines too) + * @param gauge pointer to a gauge object + * @return count of labels + */ +uint8_t lv_gauge_get_label_count(const lv_obj_t * gauge); + +/** + * Get the scale number of a gauge + * @param gauge pointer to a gauge object + * @return number of the scale units + */ +static inline uint8_t lv_gauge_get_line_count(const lv_obj_t * gauge) +{ + return lv_lmeter_get_line_count(gauge); +} + +/** + * Get the scale angle of a gauge + * @param gauge pointer to a gauge object + * @return angle of the scale + */ +static inline uint16_t lv_gauge_get_scale_angle(const lv_obj_t * gauge) +{ + return lv_lmeter_get_scale_angle(gauge); +} + +/** + * Get the style of a gauge + * @param gauge pointer to a gauge object + * @return pointer to the gauge's style + */ +static inline lv_style_t * lv_gauge_get_style(const lv_obj_t *gauge) +{ + return lv_obj_get_style(gauge); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_GAUGE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GAUGE_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_img.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_img.h new file mode 100644 index 00000000..03eca247 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_img.h @@ -0,0 +1,195 @@ +/** + * @file lv_img.h + * + */ + +#ifndef LV_IMG_H +#define LV_IMG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_IMG != 0 + +#include "display/lv_core/lv_obj.h" +#include "display/lv_misc/lv_fs.h" +#include "display/lv_misc/lv_symbol_def.h" +#include "lv_label.h" +#include "display/lv_draw/lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of image*/ +typedef struct +{ + /*No inherited ext. because inherited from the base object*/ /*Ext. of ancestor*/ + /*New data for this type */ + const void * src; /*Image source: Pointer to an array or a file or a symbol*/ + + lv_coord_t w; /*Width of the image (Handled by the library)*/ + lv_coord_t h; /*Height of the image (Handled by the library)*/ +#if USE_LV_MULTI_LANG + uint16_t lang_txt_id; /*The ID of the image to display. */ +#endif + uint8_t src_type :2; /*See: lv_img_src_t*/ + uint8_t auto_size :1; /*1: automatically set the object size to the image size*/ + uint8_t cf :5; /*Color format from `lv_img_color_format_t`*/ +} lv_img_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create an image objects + * @param par pointer to an object, it will be the parent of the new button + * @param copy pointer to a image object, if not NULL then the new object will be copied from it + * @return pointer to the created image + */ +lv_obj_t * lv_img_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the pixel map to display by the image + * @param img pointer to an image object + * @param data the image data + */ +void lv_img_set_src(lv_obj_t * img, const void * src_img); + +#if USE_LV_MULTI_LANG +/** + * Set an ID which means a the same source but on different languages + * @param img pointer to an image object + * @param src_id ID of the source + */ +void lv_img_set_src_id(lv_obj_t * img, uint32_t txt_id); +#endif + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0. + * Use 'lv_img_set_src()' instead. + * @param img - + * @param fn - + */ +static inline void lv_img_set_file(lv_obj_t * img, const char * fn) +{ + (void) img; + (void) fn; +} + +/** + * Enable the auto size feature. + * If enabled the object size will be same as the picture size. + * @param img pointer to an image + * @param en true: auto size enable, false: auto size disable + */ +void lv_img_set_auto_size(lv_obj_t * img, bool autosize_en); + +/** + * Set the style of an image + * @param img pointer to an image object + * @param style pointer to a style + */ +static inline void lv_img_set_style(lv_obj_t *img, lv_style_t *style) +{ + lv_obj_set_style(img, style); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param img - + * @param upscale - + */ +static inline void lv_img_set_upscale(lv_obj_t * img, bool upcale) +{ + (void) img; + (void) upcale; +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the source of the image + * @param img pointer to an image object + * @return the image source (symbol, file name or C array) + */ +const void * lv_img_get_src(lv_obj_t * img); + +/** + * Get the name of the file set for an image + * @param img pointer to an image + * @return file name + */ +const char * lv_img_get_file_name(const lv_obj_t * img); + +#if USE_LV_MULTI_LANG +/** + * Get the source ID of the image. (Used by the multi-language feature) + * @param img pointer to an image + * @return ID of the source + */ +uint16_t lv_img_get_src_id(lv_obj_t * img); +#endif + +/** + * Get the auto size enable attribute + * @param img pointer to an image + * @return true: auto size is enabled, false: auto size is disabled + */ +bool lv_img_get_auto_size(const lv_obj_t * img); + +/** + * Get the style of an image object + * @param img pointer to an image object + * @return pointer to the image's style + */ +static inline lv_style_t* lv_img_get_style(const lv_obj_t *img) +{ + return lv_obj_get_style(img); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param img - + * @return false + */ +static inline bool lv_img_get_upscale(const lv_obj_t * img) +{ + (void)img; + return false; +} + +/********************** + * MACROS + **********************/ + +/*Use this macro to declare an image in a c file*/ +#define LV_IMG_DECLARE(var_name) extern const lv_img_dsc_t var_name; + +#endif /*USE_LV_IMG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_IMG_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_imgbtn.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_imgbtn.h new file mode 100644 index 00000000..295be8f2 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_imgbtn.h @@ -0,0 +1,248 @@ +/** + * @file lv_imgbtn.h + * + */ + +#ifndef LV_IMGBTN_H +#define LV_IMGBTN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_IMGBTN != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTN == 0 +#error "lv_imgbtn: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_btn.h" +#include "display/lv_draw/lv_draw_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of image button*/ +typedef struct { + lv_btn_ext_t btn; /*Ext. of ancestor*/ + /*New data for this type */ +#if LV_IMGBTN_TILED == 0 + const void * img_src[LV_BTN_STATE_NUM]; /*Store images to each state*/ +#else + const void * img_src_left[LV_BTN_STATE_NUM]; /*Store left side images to each state*/ + const void * img_src_mid[LV_BTN_STATE_NUM]; /*Store center images to each state*/ + const void * img_src_right[LV_BTN_STATE_NUM]; /*Store right side images to each state*/ +#endif + lv_img_cf_t act_cf; /*Color format of the currently active image*/ +} lv_imgbtn_ext_t; + + +/*Styles*/ +enum { + LV_IMGBTN_STYLE_REL, + LV_IMGBTN_STYLE_PR, + LV_IMGBTN_STYLE_TGL_REL, + LV_IMGBTN_STYLE_TGL_PR, + LV_IMGBTN_STYLE_INA, +}; +typedef uint8_t lv_imgbtn_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a image button objects + * @param par pointer to an object, it will be the parent of the new image button + * @param copy pointer to a image button object, if not NULL then the new object will be copied from it + * @return pointer to the created image button + */ +lv_obj_t * lv_imgbtn_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ + +#if LV_IMGBTN_TILED == 0 +/** + * Set images for a state of the image button + * @param imgbtn pointer to an image button object + * @param state for which state set the new image (from `lv_btn_state_t`) ` + * @param src pointer to an image source (a C array or path to a file) + */ +void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src); +#else +/** + * Set images for a state of the image button + * @param imgbtn pointer to an image button object + * @param state for which state set the new image (from `lv_btn_state_t`) ` + * @param src_left pointer to an image source for the left side of the button (a C array or path to a file) + * @param src_mid pointer to an image source for the middle of the button (ideally 1px wide) (a C array or path to a file) + * @param src_right pointer to an image source for the right side of the button (a C array or path to a file) + */ +void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src_left, const void * src_mid, const void * src_right); + +#endif + +/** + * Enable the toggled states. On release the button will change from/to toggled state. + * @param imgbtn pointer to an image button object + * @param tgl true: enable toggled states, false: disable + */ +static inline void lv_imgbtn_set_toggle(lv_obj_t * imgbtn, bool tgl) +{ + lv_btn_set_toggle(imgbtn, tgl); +} + +/** + * Set the state of the image button + * @param imgbtn pointer to an image button object + * @param state the new state of the button (from lv_btn_state_t enum) + */ +static inline void lv_imgbtn_set_state(lv_obj_t * imgbtn, lv_btn_state_t state) +{ + lv_btn_set_state(imgbtn, state); +} + +/** + * Toggle the state of the image button (ON->OFF, OFF->ON) + * @param imgbtn pointer to a image button object + */ +static inline void lv_imgbtn_toggle(lv_obj_t * imgbtn) +{ + lv_btn_toggle(imgbtn); +} + +/** + * Set a function to call when a button event happens + * @param imgbtn pointer to an image button object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +static inline void lv_imgbtn_set_action(lv_obj_t * imgbtn, lv_btn_action_t type, lv_action_t action) +{ + lv_btn_set_action(imgbtn, type, action); +} + +/** + * Set a style of a image button. + * @param imgbtn pointer to image button object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_imgbtn_set_style(lv_obj_t * imgbtn, lv_imgbtn_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + + +#if LV_IMGBTN_TILED == 0 +/** + * Get the images in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to an image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src(lv_obj_t * imgbtn, lv_btn_state_t state); + +#else + +/** + * Get the left image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the left image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_left(lv_obj_t * imgbtn, lv_btn_state_t state); + +/** + * Get the middle image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the middle image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_middle(lv_obj_t * imgbtn, lv_btn_state_t state); + +/** + * Get the right image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the left image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_right(lv_obj_t * imgbtn, lv_btn_state_t state); + +#endif +/** + * Get the current state of the image button + * @param imgbtn pointer to a image button object + * @return the state of the button (from lv_btn_state_t enum) + */ +static inline lv_btn_state_t lv_imgbtn_get_state(const lv_obj_t * imgbtn) +{ + return lv_btn_get_state(imgbtn); +} + +/** + * Get the toggle enable attribute of the image button + * @param imgbtn pointer to a image button object + * @return ture: toggle enabled, false: disabled + */ +static inline bool lv_imgbtn_get_toggle(const lv_obj_t * imgbtn) +{ + return lv_btn_get_toggle(imgbtn); +} + +/** + * Get the release action of a image button + * @param imgbtn pointer to a image button object + * @return pointer to the release action function + */ +static inline lv_action_t lv_imgbtn_get_action(const lv_obj_t * imgbtn, lv_btn_action_t type) +{ + return lv_btn_get_action(imgbtn, type); +} + +/** + * Get style of a image button. + * @param imgbtn pointer to image button object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_imgbtn_get_style(const lv_obj_t * imgbtn, lv_imgbtn_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_IMGBTN*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_IMGBTN_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_kb.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_kb.h new file mode 100644 index 00000000..d6ab9795 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_kb.h @@ -0,0 +1,199 @@ +/** + * @file lv_kb.h + * + */ + +#ifndef LV_KB_H +#define LV_KB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_KB != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTNM == 0 +#error "lv_kb: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM 1) " +#endif + +#if USE_LV_TA == 0 +#error "lv_kb: lv_ta is required. Enable it in lv_conf.h (USE_LV_TA 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_btnm.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_KB_MODE_TEXT, + LV_KB_MODE_NUM, +}; +typedef uint8_t lv_kb_mode_t; + +/*Data of keyboard*/ +typedef struct { + lv_btnm_ext_t btnm; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t *ta; /*Pointer to the assigned text area*/ + lv_kb_mode_t mode; /*Key map type*/ + uint8_t cursor_mng :1; /*1: automatically show/hide cursor when a text area is assigned or left*/ + lv_action_t ok_action; /*Called when the "Ok" button is clicked*/ + lv_action_t hide_action; /*Called when the "Hide" button is clicked*/ +} lv_kb_ext_t; + +enum { + LV_KB_STYLE_BG, + LV_KB_STYLE_BTN_REL, + LV_KB_STYLE_BTN_PR, + LV_KB_STYLE_BTN_TGL_REL, + LV_KB_STYLE_BTN_TGL_PR, + LV_KB_STYLE_BTN_INA, +}; +typedef uint8_t lv_kb_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a keyboard objects + * @param par pointer to an object, it will be the parent of the new keyboard + * @param copy pointer to a keyboard object, if not NULL then the new object will be copied from it + * @return pointer to the created keyboard + */ +lv_obj_t * lv_kb_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Assign a Text Area to the Keyboard. The pressed characters will be put there. + * @param kb pointer to a Keyboard object + * @param ta pointer to a Text Area object to write there + */ +void lv_kb_set_ta(lv_obj_t * kb, lv_obj_t * ta); + +/** + * Set a new a mode (text or number map) + * @param kb pointer to a Keyboard object + * @param mode the mode from 'lv_kb_mode_t' + */ +void lv_kb_set_mode(lv_obj_t * kb, lv_kb_mode_t mode); + +/** + * Automatically hide or show the cursor of the current Text Area + * @param kb pointer to a Keyboard object + * @param en true: show cursor on the current text area, false: hide cursor + */ +void lv_kb_set_cursor_manage(lv_obj_t * kb, bool en); + +/** + * Set call back to call when the "Ok" button is pressed + * @param kb pointer to Keyboard object + * @param action a callback with 'lv_action_t' type + */ +void lv_kb_set_ok_action(lv_obj_t * kb, lv_action_t action); + +/** + * Set call back to call when the "Hide" button is pressed + * @param kb pointer to Keyboard object + * @param action a callback with 'lv_action_t' type + */ +void lv_kb_set_hide_action(lv_obj_t * kb, lv_action_t action); + +/** + * Set a new map for the keyboard + * @param kb pointer to a Keyboard object + * @param map pointer to a string array to describe the map. + * See 'lv_btnm_set_map()' for more info. + */ +static inline void lv_kb_set_map(lv_obj_t *kb, const char ** map) +{ + lv_btnm_set_map(kb, map); +} + +/** + * Set a style of a keyboard + * @param kb pointer to a keyboard object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_kb_set_style(lv_obj_t *kb, lv_kb_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Assign a Text Area to the Keyboard. The pressed characters will be put there. + * @param kb pointer to a Keyboard object + * @return pointer to the assigned Text Area object + */ +lv_obj_t * lv_kb_get_ta(const lv_obj_t * kb); + +/** + * Set a new a mode (text or number map) + * @param kb pointer to a Keyboard object + * @return the current mode from 'lv_kb_mode_t' + */ +lv_kb_mode_t lv_kb_get_mode(const lv_obj_t * kb); + +/** + * Get the current cursor manage mode. + * @param kb pointer to a Keyboard object + * @return true: show cursor on the current text area, false: hide cursor + */ +bool lv_kb_get_cursor_manage(const lv_obj_t * kb); + +/** + * Get the callback to call when the "Ok" button is pressed + * @param kb pointer to Keyboard object + * @return the ok callback + */ +lv_action_t lv_kb_get_ok_action(const lv_obj_t * kb); + +/** + * Get the callback to call when the "Hide" button is pressed + * @param kb pointer to Keyboard object + * @return the close callback + */ +lv_action_t lv_kb_get_hide_action(const lv_obj_t * kb); + +/** + * Get a style of a keyboard + * @param kb pointer to a keyboard object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_kb_get_style(const lv_obj_t *kb, lv_kb_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_KB*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_KB_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_label.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_label.h new file mode 100644 index 00000000..abd176a0 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_label.h @@ -0,0 +1,295 @@ +/** + * @file lv_rect.h + * + */ + +#ifndef LV_LABEL_H +#define LV_LABEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_LABEL != 0 + +#include "display/lv_core/lv_obj.h" +#include "display/lv_misc/lv_font.h" +#include "display/lv_misc/lv_txt.h" +#include "display/lv_misc/lv_symbol_def.h" + +/********************* + * DEFINES + *********************/ +#define LV_LABEL_DOT_NUM 3 +#define LV_LABEL_POS_LAST 0xFFFF + +/********************** + * TYPEDEFS + **********************/ + +/*Long mode behaviors. Used in 'lv_label_ext_t' */ +enum +{ + LV_LABEL_LONG_EXPAND, /*Expand the object size to the text size*/ + LV_LABEL_LONG_BREAK, /*Keep the object width, break the too long lines and expand the object height*/ + LV_LABEL_LONG_SCROLL, /*Expand the object size and scroll the text on the parent (move the label object)*/ + LV_LABEL_LONG_DOT, /*Keep the size and write dots at the end if the text is too long*/ + LV_LABEL_LONG_ROLL, /*Keep the size and roll the text infinitely*/ + LV_LABEL_LONG_CROP, /*Keep the size and crop the text out of it*/ +}; +typedef uint8_t lv_label_long_mode_t; + +/*Label align policy*/ +enum { + LV_LABEL_ALIGN_LEFT, + LV_LABEL_ALIGN_CENTER, + LV_LABEL_ALIGN_RIGHT, +}; +typedef uint8_t lv_label_align_t; + +/*Data of label*/ +typedef struct +{ + /*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/ + /*New data for this type */ + char * text; /*Text of the label*/ + lv_label_long_mode_t long_mode; /*Determinate what to do with the long texts*/ +#if LV_TXT_UTF8 == 0 + char dot_tmp[LV_LABEL_DOT_NUM + 1]; /*Store the character which are replaced by dots (Handled by the library)*/ +#else + char dot_tmp[LV_LABEL_DOT_NUM * 4 + 1]; /*Store the character which are replaced by dots (Handled by the library)*/ +#endif + +#if USE_LV_MULTI_LANG + uint16_t lang_txt_id; /*The ID of the text to display*/ +#endif + uint16_t dot_end; /*The text end position in dot mode (Handled by the library)*/ + uint16_t anim_speed; /*Speed of scroll and roll animation in px/sec unit*/ + lv_point_t offset; /*Text draw position offset*/ + uint8_t static_txt :1; /*Flag to indicate the text is static*/ + uint8_t align :2; /*Align type from 'lv_label_align_t'*/ + uint8_t recolor :1; /*Enable in-line letter re-coloring*/ + uint8_t expand :1; /*Ignore real width (used by the library with LV_LABEL_LONG_ROLL)*/ + uint8_t body_draw :1; /*Draw background body*/ +} lv_label_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a label objects + * @param par pointer to an object, it will be the parent of the new label + * @param copy pointer to a button object, if not NULL then the new object will be copied from it + * @return pointer to the created button + */ +lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new text for a label. Memory will be allocated to store the text by the label. + * @param label pointer to a label object + * @param text '\0' terminated character string. NULL to refresh with the current text. + */ +void lv_label_set_text(lv_obj_t * label, const char * text); + +/** + * Set a new text for a label from a character array. The array don't has to be '\0' terminated. + * Memory will be allocated to store the array by the label. + * @param label pointer to a label object + * @param array array of characters or NULL to refresh the label + * @param size the size of 'array' in bytes + */ +void lv_label_set_array_text(lv_obj_t * label, const char * array, uint16_t size); + +/** + * Set a static text. It will not be saved by the label so the 'text' variable + * has to be 'alive' while the label exist. + * @param label pointer to a label object + * @param text pointer to a text. NULL to refresh with the current text. + */ +void lv_label_set_static_text(lv_obj_t * label, const char * text); + +/** + *Set a text ID which means a the same text but on different languages + * @param label pointer to a label object + * @param txt_id ID of the text + */ +#if USE_LV_MULTI_LANG +void lv_label_set_text_id(lv_obj_t * label, uint32_t txt_id); +#endif + +/** + * Set the behavior of the label with longer text then the object size + * @param label pointer to a label object + * @param long_mode the new mode from 'lv_label_long_mode' enum. + * In LV_LONG_BREAK/LONG/ROLL the size of the label should be set AFTER this function + */ +void lv_label_set_long_mode(lv_obj_t * label, lv_label_long_mode_t long_mode); + +/** + * Set the align of the label (left or center) + * @param label pointer to a label object + * @param align 'LV_LABEL_ALIGN_LEFT' or 'LV_LABEL_ALIGN_LEFT' + */ +void lv_label_set_align(lv_obj_t *label, lv_label_align_t align); + +/** + * Enable the recoloring by in-line commands + * @param label pointer to a label object + * @param en true: enable recoloring, false: disable + */ +void lv_label_set_recolor(lv_obj_t * label, bool en); + +/** + * Set the label to draw (or not draw) background specified in its style's body + * @param label pointer to a label object + * @param en true: draw body; false: don't draw body + */ +void lv_label_set_body_draw(lv_obj_t *label, bool en); + +/** + * Set the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes + * @param label pointer to a label object + * @param anim_speed speed of animation in px/sec unit + */ +void lv_label_set_anim_speed(lv_obj_t *label, uint16_t anim_speed); + +/** + * Set the style of an label + * @param label pointer to an label object + * @param style pointer to a style + */ +static inline void lv_label_set_style(lv_obj_t *label, lv_style_t *style) +{ + lv_obj_set_style(label, style); +} +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a label + * @param label pointer to a label object + * @return the text of the label + */ +char * lv_label_get_text(const lv_obj_t * label); + +#if USE_LV_MULTI_LANG +/** + * Get the text ID of the label. (Used by the multi-language feature) + * @param label pointer to a label object + * @return ID of the text + */ +uint16_t lv_label_get_text_id(lv_obj_t * label); +#endif + +/** + * Get the long mode of a label + * @param label pointer to a label object + * @return the long mode + */ +lv_label_long_mode_t lv_label_get_long_mode(const lv_obj_t * label); + +/** + * Get the align attribute + * @param label pointer to a label object + * @return LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_label_get_align(const lv_obj_t * label); + +/** + * Get the recoloring attribute + * @param label pointer to a label object + * @return true: recoloring is enabled, false: disable + */ +bool lv_label_get_recolor(const lv_obj_t * label); + +/** + * Get the body draw attribute + * @param label pointer to a label object + * @return true: draw body; false: don't draw body + */ +bool lv_label_get_body_draw(const lv_obj_t *label); + +/** + * Get the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes + * @param label pointer to a label object + * @return speed of animation in px/sec unit + */ +uint16_t lv_label_get_anim_speed(const lv_obj_t *label); + +/** + * Get the relative x and y coordinates of a letter + * @param label pointer to a label object + * @param index index of the letter [0 ... text length]. Expressed in character index, not byte index (different in UTF-8) + * @param pos store the result here (E.g. index = 0 gives 0;0 coordinates) + */ +void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t * pos); + +/** + * Get the index of letter on a relative point of a label + * @param label pointer to label object + * @param pos pointer to point with coordinates on a the label + * @return the index of the letter on the 'pos_p' point (E.g. on 0;0 is the 0. letter) + * Expressed in character index and not byte index (different in UTF-8) + */ +uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos); + +/** + * Get the style of an label object + * @param label pointer to an label object + * @return pointer to the label's style + */ +static inline lv_style_t* lv_label_get_style(const lv_obj_t *label) +{ + return lv_obj_get_style(label); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Insert a text to the label. The label text can not be static. + * @param label pointer to a label object + * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8) + * 0: before first char. + * LV_LABEL_POS_LAST: after last char. + * @param txt pointer to the text to insert + */ +void lv_label_ins_text(lv_obj_t * label, uint32_t pos, const char * txt); + +/** + * Delete characters from a label. The label text can not be static. + * @param label pointer to a label object + * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8) + * 0: before first char. + * @param cnt number of characters to cut + */ +void lv_label_cut_text(lv_obj_t * label, uint32_t pos, uint32_t cnt); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LABEL*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LABEL_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_led.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_led.h new file mode 100644 index 00000000..f6a18acb --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_led.h @@ -0,0 +1,116 @@ +/** + * @file lv_led.h + * + */ + +#ifndef LV_LED_H +#define LV_LED_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_LED != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of led*/ +typedef struct +{ + /*No inherited ext.*/ + /*New data for this type */ + uint8_t bright; /*Current brightness of the LED (0..255)*/ +} lv_led_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a led objects + * @param par pointer to an object, it will be the parent of the new led + * @param copy pointer to a led object, if not NULL then the new object will be copied from it + * @return pointer to the created led + */ +lv_obj_t * lv_led_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Set the brightness of a LED object + * @param led pointer to a LED object + * @param bright 0 (max. dark) ... 255 (max. light) + */ +void lv_led_set_bright(lv_obj_t * led, uint8_t bright); + +/** + * Light on a LED + * @param led pointer to a LED object + */ +void lv_led_on(lv_obj_t * led); + +/** + * Light off a LED + * @param led pointer to a LED object + */ +void lv_led_off(lv_obj_t * led); + +/** + * Toggle the state of a LED + * @param led pointer to a LED object + */ +void lv_led_toggle(lv_obj_t * led); + +/** + * Set the style of a led + * @param led pointer to a led object + * @param style pointer to a style + */ +static inline void lv_led_set_style(lv_obj_t *led, lv_style_t *style) +{ + lv_obj_set_style(led, style); +} + +/** + * Get the brightness of a LEd object + * @param led pointer to LED object + * @return bright 0 (max. dark) ... 255 (max. light) + */ +uint8_t lv_led_get_bright(const lv_obj_t * led); + +/** + * Get the style of an led object + * @param led pointer to an led object + * @return pointer to the led's style + */ +static inline lv_style_t* lv_led_get_style(const lv_obj_t *led) +{ + return lv_obj_get_style(led); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LED*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LED_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_line.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_line.h new file mode 100644 index 00000000..e7be8a32 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_line.h @@ -0,0 +1,158 @@ +/** + * @file lv_line.h + * + */ + +#ifndef LV_LINE_H +#define LV_LINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_LINE != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of line*/ +typedef struct +{ + /*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/ + const lv_point_t * point_array; /*Pointer to an array with the points of the line*/ + uint16_t point_num; /*Number of points in 'point_array' */ + uint8_t auto_size :1; /*1: set obj. width to x max and obj. height to y max */ + uint8_t y_inv :1; /*1: y == 0 will be on the bottom*/ +} lv_line_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a line objects + * @param par pointer to an object, it will be the parent of the new line + * @return pointer to the created line + */ +lv_obj_t * lv_line_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set an array of points. The line object will connect these points. + * @param line pointer to a line object + * @param point_a an array of points. Only the address is saved, + * so the array can NOT be a local variable which will be destroyed + * @param point_num number of points in 'point_a' + */ +void lv_line_set_points(lv_obj_t * line, const lv_point_t * point_a, uint16_t point_num); + +/** + * Enable (or disable) the auto-size option. The size of the object will fit to its points. + * (set width to x max and height to y max) + * @param line pointer to a line object + * @param en true: auto size is enabled, false: auto size is disabled + */ +void lv_line_set_auto_size(lv_obj_t * line, bool en); + +/** + * Enable (or disable) the y coordinate inversion. + * If enabled then y will be subtracted from the height of the object, + * therefore the y=0 coordinate will be on the bottom. + * @param line pointer to a line object + * @param en true: enable the y inversion, false:disable the y inversion + */ +void lv_line_set_y_invert(lv_obj_t * line, bool en); + +#define lv_line_set_y_inv lv_line_set_y_invert /*The name was inconsistent. In v.6.0 only `lv_line_set_y_invert`will work */ + +/** + * Set the style of a line + * @param line pointer to a line object + * @param style pointer to a style + */ +static inline void lv_line_set_style(lv_obj_t *line, lv_style_t *style) +{ + lv_obj_set_style(line, style); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param line - + * @param upscale - + */ +static inline void lv_line_set_upscale(lv_obj_t * line, bool upcale) +{ + (void) line; + (void) upcale; +} +/*===================== + * Getter functions + *====================*/ + +/** + * Get the auto size attribute + * @param line pointer to a line object + * @return true: auto size is enabled, false: disabled + */ +bool lv_line_get_auto_size(const lv_obj_t * line); + +/** + * Get the y inversion attribute + * @param line pointer to a line object + * @return true: y inversion is enabled, false: disabled + */ +bool lv_line_get_y_invert(const lv_obj_t * line); + +/** + * Get the style of an line object + * @param line pointer to an line object + * @return pointer to the line's style + */ +static inline lv_style_t* lv_line_get_style(const lv_obj_t *line) +{ + return lv_obj_get_style(line); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param line - + * @return false + */ +static inline bool lv_line_get_upscale(const lv_obj_t * line) +{ + (void) line; + return false; +} + + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LINE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LINE_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_list.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_list.h new file mode 100644 index 00000000..397059a5 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_list.h @@ -0,0 +1,336 @@ +/** + * @file lv_list.h + * + */ + +#ifndef LV_LIST_H +#define LV_LIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_LIST != 0 + +/*Testing of dependencies*/ +#if USE_LV_PAGE == 0 +#error "lv_list: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#if USE_LV_BTN == 0 +#error "lv_list: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_list: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + + +#include "display/lv_core/lv_obj.h" +#include "lv_page.h" +#include "lv_btn.h" +#include "lv_label.h" +#include "lv_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of list*/ +typedef struct +{ + lv_page_ext_t page; /*Ext. of ancestor*/ + /*New data for this type */ + uint16_t anim_time; /*Scroll animation time*/ + lv_style_t *styles_btn[LV_BTN_STATE_NUM]; /*Styles of the list element buttons*/ + lv_style_t *style_img; /*Style of the list element images on buttons*/ + uint32_t size; /*the number of items(buttons) in the list*/ + bool single_mode; /* whether single selected mode is enabled */ +#if USE_LV_GROUP + lv_obj_t * last_sel; /* The last selected button. It will be reverted when the list is focused again */ + lv_obj_t * selected_btn; /* The button is currently being selected*/ +#endif +} lv_list_ext_t; + +enum { + LV_LIST_STYLE_BG, + LV_LIST_STYLE_SCRL, + LV_LIST_STYLE_SB, + LV_LIST_STYLE_EDGE_FLASH, + LV_LIST_STYLE_BTN_REL, + LV_LIST_STYLE_BTN_PR, + LV_LIST_STYLE_BTN_TGL_REL, + LV_LIST_STYLE_BTN_TGL_PR, + LV_LIST_STYLE_BTN_INA, +}; +typedef uint8_t lv_list_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a list objects + * @param par pointer to an object, it will be the parent of the new list + * @param copy pointer to a list object, if not NULL then the new object will be copied from it + * @return pointer to the created list + */ +lv_obj_t * lv_list_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_list_clean(lv_obj_t *obj); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add a list element to the list + * @param list pointer to list object + * @param img_fn file name of an image before the text (NULL if unused) + * @param txt text of the list element (NULL if unused) + * @param rel_action pointer to release action function (like with lv_btn) + * @return pointer to the new list element which can be customized (a button) + */ +lv_obj_t * lv_list_add(lv_obj_t * list, const void * img_src, const char * txt, lv_action_t rel_action); + +/** + * Remove the index of the button in the list + * @param list pointer to a list object + * @param index pointer to a the button's index in the list, index must be 0 <= index < lv_list_ext_t.size + * @return true: successfully deleted + */ +bool lv_list_remove(const lv_obj_t * list, uint32_t index); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set single button selected mode, only one button will be selected if enabled. + * @param list pointer to the currently pressed list object + * @param mode, enable(true)/disable(false) single selected mode. + */ +void lv_list_set_single_mode(lv_obj_t *list, bool mode); + +#if USE_LV_GROUP + +/** + * Make a button selected. Can be used while navigating in the list with a keypad. + * @param list pointer to a list object + * @param btn pointer to a button to select + */ +void lv_list_set_btn_selected(lv_obj_t * list, lv_obj_t * btn); +#endif + +/** + * Set scroll animation duration on 'list_up()' 'list_down()' 'list_focus()' + * @param list pointer to a list object + * @param anim_time duration of animation [ms] + */ +void lv_list_set_anim_time(lv_obj_t *list, uint16_t anim_time); + +/** + * Set the scroll bar mode of a list + * @param list pointer to a list object + * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum + */ +static inline void lv_list_set_sb_mode(lv_obj_t * list, lv_sb_mode_t mode) +{ + lv_page_set_sb_mode(list, mode); +} + +/** + * Enable the scroll propagation feature. If enabled then the List will move its parent if there is no more space to scroll. + * @param list pointer to a List + * @param en true or false to enable/disable scroll propagation + */ +static inline void lv_list_set_scroll_propagation(lv_obj_t * list, bool en) +{ + lv_page_set_scroll_propagation(list, en); +} + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param list pointer to a List + * @param en true or false to enable/disable end flash + */ +static inline void lv_list_set_edge_flash(lv_obj_t * list, bool en) +{ + lv_page_set_edge_flash(list, en); +} + +/** + * Set a style of a list + * @param list pointer to a list object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_list_set_style(lv_obj_t *list, lv_list_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get single button selected mode. + * @param list pointer to the currently pressed list object. + */ +bool lv_list_get_single_mode(lv_obj_t *list); + +/** + * Get the text of a list element + * @param btn pointer to list element + * @return pointer to the text + */ +const char * lv_list_get_btn_text(const lv_obj_t * btn); +/** + * Get the label object from a list element + * @param btn pointer to a list element (button) + * @return pointer to the label from the list element or NULL if not found + */ +lv_obj_t * lv_list_get_btn_label(const lv_obj_t * btn); + +/** + * Get the image object from a list element + * @param btn pointer to a list element (button) + * @return pointer to the image from the list element or NULL if not found + */ +lv_obj_t * lv_list_get_btn_img(const lv_obj_t * btn); + +/** + * Get the next button from list. (Starts from the bottom button) + * @param list pointer to a list object + * @param prev_btn pointer to button. Search the next after it. + * @return pointer to the next button or NULL when no more buttons + */ +lv_obj_t * lv_list_get_prev_btn(const lv_obj_t * list, lv_obj_t * prev_btn); + +/** + * Get the previous button from list. (Starts from the top button) + * @param list pointer to a list object + * @param prev_btn pointer to button. Search the previous before it. + * @return pointer to the previous button or NULL when no more buttons + */ +lv_obj_t * lv_list_get_next_btn(const lv_obj_t * list, lv_obj_t * prev_btn); + +/** + * Get the index of the button in the list + * @param list pointer to a list object. If NULL, assumes btn is part of a list. + * @param btn pointer to a list element (button) + * @return the index of the button in the list, or -1 of the button not in this list + */ +int32_t lv_list_get_btn_index(const lv_obj_t * list, const lv_obj_t * btn); + +/** + * Get the number of buttons in the list + * @param list pointer to a list object + * @return the number of buttons in the list + */ +uint32_t lv_list_get_size(const lv_obj_t * list); + +#if USE_LV_GROUP +/** + * Get the currently selected button. Can be used while navigating in the list with a keypad. + * @param list pointer to a list object + * @return pointer to the selected button + */ +lv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list); +#endif + + +/** + * Get scroll animation duration + * @param list pointer to a list object + * @return duration of animation [ms] + */ +uint16_t lv_list_get_anim_time(const lv_obj_t *list); + + +/** + * Get the scroll bar mode of a list + * @param list pointer to a list object + * @return scrollbar mode from 'lv_page_sb_mode_t' enum + */ +static inline lv_sb_mode_t lv_list_get_sb_mode(const lv_obj_t * list) +{ + return lv_page_get_sb_mode(list); +} + +/** + * Get the scroll propagation property + * @param list pointer to a List + * @return true or false + */ +static inline bool lv_list_get_scroll_propagation(lv_obj_t * list) +{ + return lv_page_get_scroll_propagation(list); +} + +/** + * Get the scroll propagation property + * @param list pointer to a List + * @return true or false + */ +static inline bool lv_list_get_edge_flash(lv_obj_t * list) +{ + return lv_page_get_edge_flash(list); +} + +/** + * Get a style of a list + * @param list pointer to a list object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_list_get_style(const lv_obj_t *list, lv_list_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Move the list elements up by one + * @param list pointer a to list object + */ +void lv_list_up(const lv_obj_t * list); +/** + * Move the list elements down by one + * @param list pointer to a list object + */ +void lv_list_down(const lv_obj_t * list); + +/** + * Focus on a list button. It ensures that the button will be visible on the list. + * @param btn pointer to a list button to focus + * @param anim_en true: scroll with animation, false: without animation + */ +void lv_list_focus(const lv_obj_t *btn, bool anim_en); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LIST*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LIST_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_lmeter.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_lmeter.h new file mode 100644 index 00000000..dcb42bf4 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_lmeter.h @@ -0,0 +1,153 @@ +/** + * @file lv_lmeter.h + * + */ + +#ifndef LV_LMETER_H +#define LV_LMETER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_LMETER != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of line meter*/ +typedef struct +{ + /*No inherited ext.*/ /*Ext. of ancestor*/ + /*New data for this type */ + uint16_t scale_angle; /*Angle of the scale in deg. (0..360)*/ + uint8_t line_cnt; /*Count of lines */ + int16_t cur_value; + int16_t min_value; + int16_t max_value; +} lv_lmeter_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a line meter objects + * @param par pointer to an object, it will be the parent of the new line meter + * @param copy pointer to a line meter object, if not NULL then the new object will be copied from it + * @return pointer to the created line meter + */ +lv_obj_t * lv_lmeter_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the line meter + * @param lmeter pointer to a line meter object + * @param value new value + */ +void lv_lmeter_set_value(lv_obj_t *lmeter, int16_t value); + +/** + * Set minimum and the maximum values of a line meter + * @param lmeter pointer to he line meter object + * @param min minimum value + * @param max maximum value + */ +void lv_lmeter_set_range(lv_obj_t *lmeter, int16_t min, int16_t max); + +/** + * Set the scale settings of a line meter + * @param lmeter pointer to a line meter object + * @param angle angle of the scale (0..360) + * @param line_cnt number of lines + */ +void lv_lmeter_set_scale(lv_obj_t * lmeter, uint16_t angle, uint8_t line_cnt); + +/** + * Set the styles of a line meter + * @param lmeter pointer to a line meter object + * @param bg set the style of the line meter + */ +static inline void lv_lmeter_set_style(lv_obj_t *lmeter, lv_style_t *bg) +{ + lv_obj_set_style(lmeter, bg); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a line meter + * @param lmeter pointer to a line meter object + * @return the value of the line meter + */ +int16_t lv_lmeter_get_value(const lv_obj_t *lmeter); + +/** + * Get the minimum value of a line meter + * @param lmeter pointer to a line meter object + * @return the minimum value of the line meter + */ +int16_t lv_lmeter_get_min_value(const lv_obj_t * lmeter); + +/** + * Get the maximum value of a line meter + * @param lmeter pointer to a line meter object + * @return the maximum value of the line meter + */ +int16_t lv_lmeter_get_max_value(const lv_obj_t * lmeter); + +/** + * Get the scale number of a line meter + * @param lmeter pointer to a line meter object + * @return number of the scale units + */ +uint8_t lv_lmeter_get_line_count(const lv_obj_t * lmeter); + +/** + * Get the scale angle of a line meter + * @param lmeter pointer to a line meter object + * @return angle of the scale + */ +uint16_t lv_lmeter_get_scale_angle(const lv_obj_t * lmeter); + +/** + * Get the style of a line meter + * @param lmeter pointer to a line meter object + * @return pointer to the line meter's style + */ +static inline lv_style_t * lv_lmeter_get_style(const lv_obj_t * lmeter) +{ + return lv_obj_get_style(lmeter); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LMETER*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LMETER_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_mbox.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_mbox.h new file mode 100644 index 00000000..2dc0c6dc --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_mbox.h @@ -0,0 +1,203 @@ +/** + * @file lv_mbox.h + * + */ + +#ifndef LV_MBOX_H +#define LV_MBOX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_MBOX != 0 + +/*Testing of dependencies*/ +#if USE_LV_CONT == 0 +#error "lv_mbox: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT 1) " +#endif + +#if USE_LV_BTNM == 0 +#error "lv_mbox: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_mbox: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + + +#include "display/lv_core/lv_obj.h" +#include "lv_cont.h" +#include "lv_btnm.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of message box*/ +typedef struct +{ + lv_cont_ext_t bg; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t *text; /*Text of the message box*/ + lv_obj_t *btnm; /*Button matrix for the buttons*/ + uint16_t anim_time; /*Duration of close animation [ms] (0: no animation)*/ +} lv_mbox_ext_t; + +enum { + LV_MBOX_STYLE_BG, + LV_MBOX_STYLE_BTN_BG, + LV_MBOX_STYLE_BTN_REL, + LV_MBOX_STYLE_BTN_PR, + LV_MBOX_STYLE_BTN_TGL_REL, + LV_MBOX_STYLE_BTN_TGL_PR, + LV_MBOX_STYLE_BTN_INA, +}; +typedef uint8_t lv_mbox_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a message box objects + * @param par pointer to an object, it will be the parent of the new message box + * @param copy pointer to a message box object, if not NULL then the new object will be copied from it + * @return pointer to the created message box + */ +lv_obj_t * lv_mbox_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add button to the message box + * @param mbox pointer to message box object + * @param btn_map button descriptor (button matrix map). + * E.g. a const char *txt[] = {"ok", "close", ""} (Can not be local variable) + * @param action a function which will be called when a button is released + */ +void lv_mbox_add_btns(lv_obj_t * mbox, const char **btn_map, lv_btnm_action_t action); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of the message box + * @param mbox pointer to a message box + * @param txt a '\0' terminated character string which will be the message box text + */ +void lv_mbox_set_text(lv_obj_t * mbox, const char * txt); + +/** + * Stop the action to call when button is released + * @param mbox pointer to a message box object + * @param pointer to an 'lv_btnm_action_t' action. In the action you need to use `lv_mbox_get_from_btn()` to get the `mbox`. + */ +void lv_mbox_set_action(lv_obj_t * mbox, lv_btnm_action_t action); + +/** + * Set animation duration + * @param mbox pointer to a message box object + * @param anim_time animation length in milliseconds (0: no animation) + */ +void lv_mbox_set_anim_time(lv_obj_t * mbox, uint16_t anim_time); + +/** + * Automatically delete the message box after a given time + * @param mbox pointer to a message box object + * @param delay a time (in milliseconds) to wait before delete the message box + */ +void lv_mbox_start_auto_close(lv_obj_t * mbox, uint16_t delay); + +/** + * Stop the auto. closing of message box + * @param mbox pointer to a message box object + */ +void lv_mbox_stop_auto_close(lv_obj_t * mbox); + +/** + * Set a style of a message box + * @param mbox pointer to a message box object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_mbox_set_style(lv_obj_t *mbox, lv_mbox_style_t type, lv_style_t *style); + +/** + * Set whether recoloring is enabled. Must be called after `lv_mbox_add_btns`. + * @param btnm pointer to button matrix object + * @param en whether recoloring is enabled + */ +void lv_mbox_set_recolor(lv_obj_t * mbox, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of the message box + * @param mbox pointer to a message box object + * @return pointer to the text of the message box + */ +const char * lv_mbox_get_text(const lv_obj_t * mbox); + +/** + * Get the message box object from one of its button. + * It is useful in the button release actions where only the button is known + * @param btn pointer to a button of a message box + * @return pointer to the button's message box + */ +lv_obj_t * lv_mbox_get_from_btn(const lv_obj_t * btn); + +/** + * Get the animation duration (close animation time) + * @param mbox pointer to a message box object + * @return animation length in milliseconds (0: no animation) + */ +uint16_t lv_mbox_get_anim_time(const lv_obj_t * mbox); + + +/** + * Get a style of a message box + * @param mbox pointer to a message box object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_mbox_get_style(const lv_obj_t *mbox, lv_mbox_style_t type); + +/** + * Get whether recoloring is enabled + * @param btnm pointer to button matrix object + * @return whether recoloring is enabled + */ +bool lv_mbox_get_recolor(const lv_obj_t * mbox); + +/********************** + * MACROS + **********************/ + + +#endif /*USE_LV_MBOX*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_MBOX_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_objx.mk b/old-code/v5_hal/firmware/include/display/lv_objx/lv_objx.mk new file mode 100644 index 00000000..d35252bc --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_objx.mk @@ -0,0 +1,36 @@ +CSRCS += lv_arc.c +CSRCS += lv_bar.c +CSRCS += lv_cb.c +CSRCS += lv_ddlist.c +CSRCS += lv_kb.c +CSRCS += lv_line.c +CSRCS += lv_mbox.c +CSRCS += lv_preload.c +CSRCS += lv_roller.c +CSRCS += lv_table.c +CSRCS += lv_tabview.c +CSRCS += lv_tileview.c +CSRCS += lv_btn.c +CSRCS += lv_calendar.c +CSRCS += lv_chart.c +CSRCS += lv_canvas.c +CSRCS += lv_gauge.c +CSRCS += lv_label.c +CSRCS += lv_list.c +CSRCS += lv_slider.c +CSRCS += lv_ta.c +CSRCS += lv_spinbox.c +CSRCS += lv_btnm.c +CSRCS += lv_cont.c +CSRCS += lv_img.c +CSRCS += lv_imgbtn.c +CSRCS += lv_led.c +CSRCS += lv_lmeter.c +CSRCS += lv_page.c +CSRCS += lv_sw.c +CSRCS += lv_win.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_objx +VPATH += :$(LVGL_DIR)/lvgl/lv_objx + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_objx" diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_objx_templ.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_objx_templ.h new file mode 100644 index 00000000..b8473dfb --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_objx_templ.h @@ -0,0 +1,111 @@ +/** + * @file lv_templ.h + * + */ + + +/* TODO Remove these instructions + * Search an replace: template -> object normal name with lower case (e.g. button, label etc.) + * templ -> object short name with lower case(e.g. btn, label etc) + * TEMPL -> object short name with upper case (e.g. BTN, LABEL etc.) + * + */ + +#ifndef LV_TEMPL_H +#define LV_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_TEMPL != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of template*/ +typedef struct { + lv_ANCESTOR_ext_t ANCESTOR; /*Ext. of ancestor*/ + /*New data for this type */ +} lv_templ_ext_t; + + +/*Styles*/ +enum { + LV_TEMPL_STYLE_X, + LV_TEMPL_STYLE_Y, +}; +typedef uint8_t lv_templ_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a template objects + * @param par pointer to an object, it will be the parent of the new template + * @param copy pointer to a template object, if not NULL then the new object will be copied from it + * @return pointer to the created template + */ +lv_obj_t * lv_templ_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a template. + * @param templ pointer to template object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_templ_set_style(lv_obj_t * templ, lv_templ_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get style of a template. + * @param templ pointer to template object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_templ_get_style(const lv_obj_t * templ, lv_templ_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TEMPL*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_page.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_page.h new file mode 100644 index 00000000..d01de358 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_page.h @@ -0,0 +1,382 @@ +/** + * @file lv_page.h + * + */ + +#ifndef LV_PAGE_H +#define LV_PAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_PAGE != 0 + +/*Testing of dependencies*/ +#if USE_LV_CONT == 0 +#error "lv_page: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT 1) " +#endif + +#include "lv_cont.h" +#include "display/lv_core/lv_indev.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Scrollbar modes: shows when should the scrollbars be visible*/ +enum +{ + LV_SB_MODE_OFF = 0x0, /*Never show scrollbars*/ + LV_SB_MODE_ON = 0x1, /*Always show scrollbars*/ + LV_SB_MODE_DRAG = 0x2, /*Show scrollbars when page is being dragged*/ + LV_SB_MODE_AUTO = 0x3, /*Show scrollbars when the scrollable container is large enough to be scrolled*/ + LV_SB_MODE_HIDE = 0x4, /*Hide the scroll bar temporally*/ + LV_SB_MODE_UNHIDE = 0x5, /*Unhide the previously hidden scrollbar. Recover it's type too*/ +}; +typedef uint8_t lv_sb_mode_t; + +/*Data of page*/ +typedef struct +{ + lv_cont_ext_t bg; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * scrl; /*The scrollable object on the background*/ + lv_action_t rel_action; /*Function to call when the page is released*/ + lv_action_t pr_action; /*Function to call when the page is pressed*/ + struct { + lv_style_t *style; /*Style of scrollbars*/ + lv_area_t hor_area; /*Horizontal scrollbar area relative to the page. (Handled by the library) */ + lv_area_t ver_area; /*Vertical scrollbar area relative to the page (Handled by the library)*/ + uint8_t hor_draw :1; /*1: horizontal scrollbar is visible now (Handled by the library)*/ + uint8_t ver_draw :1; /*1: vertical scrollbar is visible now (Handled by the library)*/ + lv_sb_mode_t mode:3; /*Scrollbar visibility from 'lv_page_sb_mode_t'*/ + } sb; + struct { + uint16_t state; /*Store the current size of the edge flash effect*/ + lv_style_t *style; /*Style of edge flash effect (usually homogeneous circle)*/ + uint8_t enabled :1; /*1: Show a flash animation on the edge*/ + uint8_t top_ip :1; /*Used internally to show that top most position is reached (flash is In Progress)*/ + uint8_t bottom_ip :1; /*Used internally to show that bottom most position is reached (flash is In Progress)*/ + uint8_t right_ip :1; /*Used internally to show that right most position is reached (flash is In Progress)*/ + uint8_t left_ip :1; /*Used internally to show that left most position is reached (flash is In Progress)*/ + }edge_flash; + + uint8_t arrow_scroll :1; /*1: Enable scrolling with LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN*/ + uint8_t scroll_prop :1; /*1: Propagate the scrolling the the parent if the edge is reached*/ + uint8_t scroll_prop_ip :1; /*1: Scroll propagation is in progress (used by the library)*/ +} lv_page_ext_t; + +enum { + LV_PAGE_STYLE_BG, + LV_PAGE_STYLE_SCRL, + LV_PAGE_STYLE_SB, + LV_PAGE_STYLE_EDGE_FLASH, +}; +typedef uint8_t lv_page_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a page objects + * @param par pointer to an object, it will be the parent of the new page + * @param copy pointer to a page object, if not NULL then the new object will be copied from it + * @return pointer to the created page + */ +lv_obj_t * lv_page_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_page_clean(lv_obj_t *obj); + +/** + * Get the press action of the page + * @param page pointer to a page object + * @return a function to call when the page is pressed + */ +lv_action_t lv_page_get_pr_action(lv_obj_t * page); + +/** + * Get the release action of the page + * @param page pointer to a page object + * @return a function to call when the page is released + */ +lv_action_t lv_page_get_rel_action(lv_obj_t * page); + +/** + * Get the scrollable object of a page + * @param page pointer to a page object + * @return pointer to a container which is the scrollable part of the page + */ +lv_obj_t * lv_page_get_scrl(const lv_obj_t * page); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a release action for the page + * @param page pointer to a page object + * @param rel_action a function to call when the page is released + */ +void lv_page_set_rel_action(lv_obj_t * page, lv_action_t rel_action); + +/** + * Set a press action for the page + * @param page pointer to a page object + * @param pr_action a function to call when the page is pressed + */ +void lv_page_set_pr_action(lv_obj_t * page, lv_action_t pr_action); + +/** + * Set the scroll bar mode on a page + * @param page pointer to a page object + * @param sb_mode the new mode from 'lv_page_sb.mode_t' enum + */ +void lv_page_set_sb_mode(lv_obj_t * page, lv_sb_mode_t sb_mode); + +/** + * Enable/Disable scrolling with arrows if the page is in group (arrows: LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) + * @param page pointer to a page object + * @param en true: enable scrolling with arrows + */ +void lv_page_set_arrow_scroll(lv_obj_t * page, bool en); + +/** + * Enable the scroll propagation feature. If enabled then the page will move its parent if there is no more space to scroll. + * @param page pointer to a Page + * @param en true or false to enable/disable scroll propagation + */ +void lv_page_set_scroll_propagation(lv_obj_t * page, bool en); + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param page pointer to a Page + * @param en true or false to enable/disable end flash + */ +void lv_page_set_edge_flash(lv_obj_t * page, bool en); + +/** + * Set the fit attribute of the scrollable part of a page. + * It means it can set its size automatically to involve all children. + * (Can be set separately horizontally and vertically) + * @param page pointer to a page object + * @param hor_en true: enable horizontal fit + * @param ver_en true: enable vertical fit + */ +static inline void lv_page_set_scrl_fit(lv_obj_t *page, bool hor_en, bool ver_en) +{ + lv_cont_set_fit(lv_page_get_scrl(page), hor_en, ver_en); +} + +/** + * Set width of the scrollable part of a page + * @param page pointer to a page object + * @param w the new width of the scrollable (it ha no effect is horizontal fit is enabled) + */ +static inline void lv_page_set_scrl_width(lv_obj_t *page, lv_coord_t w) +{ + lv_obj_set_width(lv_page_get_scrl(page), w); +} + +/** + * Set height of the scrollable part of a page + * @param page pointer to a page object + * @param h the new height of the scrollable (it ha no effect is vertical fit is enabled) + */ +static inline void lv_page_set_scrl_height(lv_obj_t *page, lv_coord_t h) +{ + lv_obj_set_height(lv_page_get_scrl(page), h); + +} + +/** +* Set the layout of the scrollable part of the page +* @param page pointer to a page object +* @param layout a layout from 'lv_cont_layout_t' +*/ +static inline void lv_page_set_scrl_layout(lv_obj_t * page, lv_layout_t layout) +{ + lv_cont_set_layout(lv_page_get_scrl(page), layout); +} + +/** + * Set a style of a page + * @param page pointer to a page object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_page_set_style(lv_obj_t *page, lv_page_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Set the scroll bar mode on a page + * @param page pointer to a page object + * @return the mode from 'lv_page_sb.mode_t' enum + */ +lv_sb_mode_t lv_page_get_sb_mode(const lv_obj_t * page); + + +/** + * Get the the scrolling with arrows (LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) is enabled or not + * @param page pointer to a page object + * @return true: scrolling with arrows is enabled + */ +bool lv_page_get_arrow_scroll(const lv_obj_t * page); + +/** + * Get the scroll propagation property + * @param page pointer to a Page + * @return true or false + */ +bool lv_page_get_scroll_propagation(lv_obj_t * page); + +/** + * Get the edge flash effect property. + * @param page pointer to a Page + * return true or false + */ +bool lv_page_get_edge_flash(lv_obj_t * page); + +/** + * Get that width which can be set to the children to still not cause overflow (show scrollbars) + * @param page pointer to a page object + * @return the width which still fits into the page + */ +lv_coord_t lv_page_get_fit_width(lv_obj_t * page); + +/** + * Get that height which can be set to the children to still not cause overflow (show scrollbars) + * @param page pointer to a page object + * @return the height which still fits into the page + */ +lv_coord_t lv_page_get_fit_height(lv_obj_t * page); + +/** + * Get width of the scrollable part of a page + * @param page pointer to a page object + * @return the width of the scrollable + */ +static inline lv_coord_t lv_page_get_scrl_width(const lv_obj_t *page) +{ + return lv_obj_get_width(lv_page_get_scrl(page)); +} + +/** + * Get height of the scrollable part of a page + * @param page pointer to a page object + * @return the height of the scrollable + */ +static inline lv_coord_t lv_page_get_scrl_height(const lv_obj_t *page) +{ + return lv_obj_get_height(lv_page_get_scrl(page)); +} + +/** +* Get the layout of the scrollable part of a page +* @param page pointer to page object +* @return the layout from 'lv_cont_layout_t' +*/ +static inline lv_layout_t lv_page_get_scrl_layout(const lv_obj_t * page) +{ + return lv_cont_get_layout(lv_page_get_scrl(page)); +} + +/** +* Get horizontal fit attribute of the scrollable part of a page +* @param page pointer to a page object +* @return true: horizontal fit is enabled; false: disabled +*/ +static inline bool lv_page_get_scrl_hor_fit(const lv_obj_t * page) +{ + return lv_cont_get_hor_fit(lv_page_get_scrl(page)); +} + +/** +* Get vertical fit attribute of the scrollable part of a page +* @param page pointer to a page object +* @return true: vertical fit is enabled; false: disabled +*/ +static inline bool lv_page_get_scrl_fit_ver(const lv_obj_t * page) +{ + return lv_cont_get_ver_fit(lv_page_get_scrl(page)); +} + +/** + * Get a style of a page + * @param page pointer to page object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_page_get_style(const lv_obj_t *page, lv_page_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Glue the object to the page. After it the page can be moved (dragged) with this object too. + * @param obj pointer to an object on a page + * @param glue true: enable glue, false: disable glue + */ +void lv_page_glue_obj(lv_obj_t * obj, bool glue); + +/** + * Focus on an object. It ensures that the object will be visible on the page. + * @param page pointer to a page object + * @param obj pointer to an object to focus (must be on the page) + * @param anim_time scroll animation time in milliseconds (0: no animation) + */ +void lv_page_focus(lv_obj_t * page, const lv_obj_t * obj, uint16_t anim_time); + +/** + * Scroll the page horizontally + * @param page pointer to a page object + * @param dist the distance to scroll (< 0: scroll left; > 0 scroll right) + */ +void lv_page_scroll_hor(lv_obj_t * page, lv_coord_t dist); + +/** + * Scroll the page vertically + * @param page pointer to a page object + * @param dist the distance to scroll (< 0: scroll down; > 0 scroll up) + */ +void lv_page_scroll_ver(lv_obj_t * page, lv_coord_t dist); + +/** + * Not intended to use directly by the user but by other object types internally. + * Start an edge flash animation. Exactly one `ext->edge_flash.xxx_ip` should be set + * @param page + */ +void lv_page_start_edge_flash(lv_obj_t * page); +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_PAGE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_PAGE_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_preload.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_preload.h new file mode 100644 index 00000000..7e228906 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_preload.h @@ -0,0 +1,168 @@ +/** + * @file lv_preload.h + * + */ + +#ifndef LV_PRELOAD_H +#define LV_PRELOAD_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_PRELOAD != 0 + +/*Testing of dependencies*/ +#if USE_LV_ARC == 0 +#error "lv_preload: lv_arc is required. Enable it in lv_conf.h (USE_LV_ARC 1) " +#endif + +#if USE_LV_ANIMATION == 0 +#error "lv_preload: animations are required. Enable it in lv_conf.h (USE_LV_ANIMATION 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_arc.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_PRELOAD_TYPE_SPINNING_ARC, + LV_PRELOAD_TYPE_FILLSPIN_ARC, +}; +typedef uint8_t lv_preloader_type_t; + +/*Data of pre loader*/ +typedef struct { + lv_arc_ext_t arc; /*Ext. of ancestor*/ + /*New data for this type */ + uint16_t arc_length; /*Length of the spinning indicator in degree*/ + uint16_t time; /*Time of one round*/ + lv_preloader_type_t anim_type; /*Type of the arc animation*/ +} lv_preload_ext_t; + + +/*Styles*/ +enum { + LV_PRELOAD_STYLE_MAIN, +}; +typedef uint8_t lv_preload_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a pre loader objects + * @param par pointer to an object, it will be the parent of the new pre loader + * @param copy pointer to a pre loader object, if not NULL then the new object will be copied from it + * @return pointer to the created pre loader + */ +lv_obj_t * lv_preload_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Set the length of the spinning arc in degrees + * @param preload pointer to a preload object + * @param deg length of the arc + */ +void lv_preload_set_arc_length(lv_obj_t * preload, uint16_t deg); + +/** + * Set the spin time of the arc + * @param preload pointer to a preload object + * @param time time of one round in milliseconds + */ +void lv_preload_set_spin_time(lv_obj_t * preload, uint16_t time); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_preload_set_style(lv_obj_t * preload, lv_preload_style_t type, lv_style_t *style); + +/** + * Set the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @param type animation type of the preload + * */ +void lv_preload_set_animation_type(lv_obj_t * preload, lv_preloader_type_t type); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the arc length [degree] of the a pre loader + * @param preload pointer to a pre loader object + */ +uint16_t lv_preload_get_arc_length(const lv_obj_t * preload); + +/** + * Get the spin time of the arc + * @param preload pointer to a pre loader object [milliseconds] + */ +uint16_t lv_preload_get_spin_time(const lv_obj_t * preload); + +/** + * Get style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_preload_get_style(const lv_obj_t * preload, lv_preload_style_t type); + +/** + * Get the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @return animation type + * */ +lv_preloader_type_t lv_preload_get_animation_type(lv_obj_t * preload); + +/*===================== + * Other functions + *====================*/ + +/** + * Get style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be get + * @return style pointer to the style + * */ +void lv_preload_spinner_animation(void * ptr, int32_t val); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_PRELOAD*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_PRELOAD_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_roller.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_roller.h new file mode 100644 index 00000000..232f5526 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_roller.h @@ -0,0 +1,224 @@ +/** + * @file lv_roller.h + * + */ + +#ifndef LV_ROLLER_H +#define LV_ROLLER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_ROLLER != 0 + +/*Testing of dependencies*/ +#if USE_LV_DDLIST == 0 +#error "lv_roller: lv_ddlist is required. Enable it in lv_conf.h (USE_LV_DDLIST 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_ddlist.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of roller*/ +typedef struct { + lv_ddlist_ext_t ddlist; /*Ext. of ancestor*/ + /*New data for this type */ +} lv_roller_ext_t; + +enum { + LV_ROLLER_STYLE_BG, + LV_ROLLER_STYLE_SEL, +}; +typedef uint8_t lv_roller_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a roller object + * @param par pointer to an object, it will be the parent of the new roller + * @param copy pointer to a roller object, if not NULL then the new object will be copied from it + * @return pointer to the created roller + */ +lv_obj_t * lv_roller_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the align of the roller's options (left, right or center[default]) + * @param roller - pointer to a roller object + * @param align - one of lv_label_align_t values (left, right, center) + */ +void lv_roller_set_align(lv_obj_t * roller, lv_label_align_t align); + +/** + * Set the options on a roller + * @param roller pointer to roller object + * @param options a string with '\n' separated options. E.g. "One\nTwo\nThree" + */ +static inline void lv_roller_set_options(lv_obj_t * roller, const char * options) +{ + lv_ddlist_set_options(roller, options); +} + +/** + * Set the selected option + * @param roller pointer to a roller object + * @param sel_opt id of the selected option (0 ... number of option - 1); + * @param anim_en true: set with animation; false set immediately + */ +void lv_roller_set_selected(lv_obj_t *roller, uint16_t sel_opt, bool anim_en); + +/** + * Set a function to call when a new option is chosen + * @param roller pointer to a roller + * @param action pointer to a callback function + */ +static inline void lv_roller_set_action(lv_obj_t * roller, lv_action_t action) +{ + lv_ddlist_set_action(roller, action); +} + +/** + * Set the height to show the given number of rows (options) + * @param roller pointer to a roller object + * @param row_cnt number of desired visible rows + */ +void lv_roller_set_visible_row_count(lv_obj_t *roller, uint8_t row_cnt); + +/** + * Enable or disable the horizontal fit to the content + * @param roller pointer to a roller + * @param en true: enable auto fit; false: disable auto fit + */ +static inline void lv_roller_set_hor_fit(lv_obj_t * roller, bool en) +{ + lv_ddlist_set_hor_fit(roller, en); +} + +/** + * Set the open/close animation time. + * @param roller pointer to a roller object + * @param anim_time: open/close animation time [ms] + */ +static inline void lv_roller_set_anim_time(lv_obj_t *roller, uint16_t anim_time) +{ + lv_ddlist_set_anim_time(roller, anim_time); +} + +/** + * Set a style of a roller + * @param roller pointer to a roller object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_roller_set_style(lv_obj_t *roller, lv_roller_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the align attribute. Default alignment after _create is LV_LABEL_ALIGN_CENTER + * @param roller pointer to a roller object + * @return LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_roller_get_align(const lv_obj_t * roller); + +/** + * Get the options of a roller + * @param roller pointer to roller object + * @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3") + */ +static inline const char * lv_roller_get_options(const lv_obj_t *roller) +{ + return lv_ddlist_get_options(roller); +} + +/** + * Get the id of the selected option + * @param roller pointer to a roller object + * @return id of the selected option (0 ... number of option - 1); + */ +static inline uint16_t lv_roller_get_selected(const lv_obj_t *roller) +{ + return lv_ddlist_get_selected(roller); +} + +/** + * Get the current selected option as a string + * @param roller pointer to roller object + * @param buf pointer to an array to store the string + */ +static inline void lv_roller_get_selected_str(const lv_obj_t * roller, char * buf) +{ + lv_ddlist_get_selected_str(roller, buf); +} + +/** + * Get the "option selected" callback function + * @param roller pointer to a roller + * @return pointer to the call back function + */ +static inline lv_action_t lv_roller_get_action(const lv_obj_t * roller) +{ + return lv_ddlist_get_action(roller); +} + +/** + * Get the open/close animation time. + * @param roller pointer to a roller + * @return open/close animation time [ms] + */ +static inline uint16_t lv_roller_get_anim_time(const lv_obj_t * roller) +{ + return lv_ddlist_get_anim_time(roller); +} + +/** + * Get the auto width set attribute + * @param roller pointer to a roller object + * @return true: auto size enabled; false: manual width settings enabled + */ +bool lv_roller_get_hor_fit(const lv_obj_t *roller); + +/** + * Get a style of a roller + * @param roller pointer to a roller object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_roller_get_style(const lv_obj_t *roller, lv_roller_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_ROLLER*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ROLLER_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_slider.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_slider.h new file mode 100644 index 00000000..8d0d9d66 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_slider.h @@ -0,0 +1,202 @@ +/** + * @file lv_slider.h + * + */ + +#ifndef LV_SLIDER_H +#define LV_SLIDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_SLIDER != 0 + +/*Testing of dependencies*/ +#if USE_LV_BAR == 0 +#error "lv_slider: lv_bar is required. Enable it in lv_conf.h (USE_LV_BAR 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_bar.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of slider*/ +typedef struct +{ + lv_bar_ext_t bar; /*Ext. of ancestor*/ + /*New data for this type */ + lv_action_t action; /*Function to call when a new value is set*/ + lv_style_t *style_knob; /*Style of the knob*/ + int16_t drag_value; /*Store a temporal value during press until release (Handled by the library)*/ + uint8_t knob_in :1; /*1: Draw the knob inside the bar*/ +} lv_slider_ext_t; + +/*Built-in styles of slider*/ +enum +{ + LV_SLIDER_STYLE_BG, + LV_SLIDER_STYLE_INDIC, + LV_SLIDER_STYLE_KNOB, +}; +typedef uint8_t lv_slider_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a slider objects + * @param par pointer to an object, it will be the parent of the new slider + * @param copy pointer to a slider object, if not NULL then the new object will be copied from it + * @return pointer to the created slider + */ +lv_obj_t * lv_slider_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the slider + * @param slider pointer to a slider object + * @param value new value + */ +static inline void lv_slider_set_value(lv_obj_t * slider, int16_t value) +{ + lv_bar_set_value(slider, value); +} + +/** + * Set a new value with animation on a slider + * @param slider pointer to a slider object + * @param value new value + * @param anim_time animation time in milliseconds + */ +static inline void lv_slider_set_value_anim(lv_obj_t * slider, int16_t value, uint16_t anim_time) +{ + lv_bar_set_value_anim(slider, value, anim_time); +} + +/** + * Set minimum and the maximum values of a bar + * @param slider pointer to the slider object + * @param min minimum value + * @param max maximum value + */ +static inline void lv_slider_set_range(lv_obj_t *slider, int16_t min, int16_t max) +{ + lv_bar_set_range(slider, min, max); +} + +/** + * Set a function which will be called when a new value is set on the slider + * @param slider pointer to slider object + * @param action a callback function + */ +void lv_slider_set_action(lv_obj_t * slider, lv_action_t action); + +/** + * Set the 'knob in' attribute of a slider + * @param slider pointer to slider object + * @param in true: the knob is drawn always in the slider; + * false: the knob can be out on the edges + */ +void lv_slider_set_knob_in(lv_obj_t * slider, bool in); + +/** + * Set a style of a slider + * @param slider pointer to a slider object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_slider_set_style(lv_obj_t *slider, lv_slider_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a slider + * @param slider pointer to a slider object + * @return the value of the slider + */ +int16_t lv_slider_get_value(const lv_obj_t * slider); + +/** + * Get the minimum value of a slider + * @param slider pointer to a slider object + * @return the minimum value of the slider + */ +static inline int16_t lv_slider_get_min_value(const lv_obj_t * slider) +{ + return lv_bar_get_min_value(slider); +} + +/** + * Get the maximum value of a slider + * @param slider pointer to a slider object + * @return the maximum value of the slider + */ +static inline int16_t lv_slider_get_max_value(const lv_obj_t * slider) +{ + return lv_bar_get_max_value(slider); +} + +/** + * Get the slider action function + * @param slider pointer to slider object + * @return the callback function + */ +lv_action_t lv_slider_get_action(const lv_obj_t * slider); + +/** + * Give the slider is being dragged or not + * @param slider pointer to a slider object + * @return true: drag in progress false: not dragged + */ +bool lv_slider_is_dragged(const lv_obj_t * slider); + +/** + * Get the 'knob in' attribute of a slider + * @param slider pointer to slider object + * @return true: the knob is drawn always in the slider; + * false: the knob can be out on the edges + */ +bool lv_slider_get_knob_in(const lv_obj_t * slider); + + +/** + * Get a style of a slider + * @param slider pointer to a slider object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_slider_get_style(const lv_obj_t *slider, lv_slider_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_SLIDER*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SLIDER_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_spinbox.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_spinbox.h new file mode 100644 index 00000000..6ec1e667 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_spinbox.h @@ -0,0 +1,201 @@ +/** + * @file lv_spinbox.h + * + */ + + +#ifndef LV_SPINBOX_H +#define LV_SPINBOX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_SPINBOX != 0 + +/*Testing of dependencies*/ +#if USE_LV_TA == 0 +#error "lv_spinbox: lv_ta is required. Enable it in lv_conf.h (USE_LV_TA 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "display/lv_objx/lv_ta.h" + +/********************* + * DEFINES + *********************/ +#define LV_SPINBOX_MAX_DIGIT_COUNT 16 + +/********************** + * TYPEDEFS + **********************/ + +/*callback on value change*/ +typedef void (*lv_spinbox_value_changed_cb_t)(lv_obj_t * spinbox, int32_t new_value); + +/*Data of spinbox*/ +typedef struct { + lv_ta_ext_t ta; /*Ext. of ancestor*/ + /*New data for this type */ + int32_t value; + int32_t range_max; + int32_t range_min; + int32_t step; + uint16_t digit_count:4; + uint16_t dec_point_pos:4; /*if 0, there is no separator and the number is an integer*/ + uint16_t digit_padding_left:4; + lv_spinbox_value_changed_cb_t value_changed_cb; +} lv_spinbox_ext_t; + + +/*Styles*/ +enum { + LV_SPINBOX_STYLE_BG, + LV_SPINBOX_STYLE_SB, + LV_SPINBOX_STYLE_CURSOR, +}; +typedef uint8_t lv_spinbox_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a spinbox objects + * @param par pointer to an object, it will be the parent of the new spinbox + * @param copy pointer to a spinbox object, if not NULL then the new object will be copied from it + * @return pointer to the created spinbox + */ +lv_obj_t * lv_spinbox_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a spinbox. + * @param templ pointer to template object + * @param type which style should be set + * @param style pointer to a style + */ +static inline void lv_spinbox_set_style(lv_obj_t * spinbox, lv_spinbox_style_t type, lv_style_t *style) +{ + lv_ta_set_style(spinbox, type, style); +} + +/** + * Set spinbox value + * @param spinbox pointer to spinbox + * @param i value to be set + */ +void lv_spinbox_set_value(lv_obj_t * spinbox, int32_t i); + +/** + * Set spinbox digit format (digit count and decimal format) + * @param spinbox pointer to spinbox + * @param digit_count number of digit excluding the decimal separator and the sign + * @param separator_position number of digit before the decimal point. If 0, decimal point is not shown + */ +void lv_spinbox_set_digit_format(lv_obj_t * spinbox, uint8_t digit_count, uint8_t separator_position); + +/** + * Set spinbox step + * @param spinbox pointer to spinbox + * @param step steps on increment/decrement + */ +void lv_spinbox_set_step(lv_obj_t * spinbox, uint32_t step); + +/** + * Set spinbox value range + * @param spinbox pointer to spinbox + * @param range_min maximum value, inclusive + * @param range_max minimum value, inclusive + */ +void lv_spinbox_set_range(lv_obj_t * spinbox, int32_t range_min, int32_t range_max); + +/** + * Set spinbox callback on calue change + * @param spinbox pointer to spinbox + * @param cb Callback function called on value change event + */ +void lv_spinbox_set_value_changed_cb(lv_obj_t * spinbox, lv_spinbox_value_changed_cb_t cb); + +/** + * Set spinbox left padding in digits count (added between sign and first digit) + * @param spinbox pointer to spinbox + * @param cb Callback function called on value change event + */ +void lv_spinbox_set_padding_left(lv_obj_t * spinbox, uint8_t padding); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get style of a spinbox. + * @param templ pointer to template object + * @param type which style should be get + * @return style pointer to the style + */ +static inline lv_style_t * lv_spinbox_get_style(lv_obj_t * spinbox, lv_spinbox_style_t type) +{ + return lv_ta_get_style(spinbox, type); +} + +/** + * Get the spinbox numeral value (user has to convert to float according to its digit format) + * @param spinbox pointer to spinbox + * @return value integer value of the spinbox + */ +int32_t lv_spinbox_get_value(lv_obj_t * spinbox); + +/*===================== + * Other functions + *====================*/ + +/** + * Select next lower digit for edition by dividing the step by 10 + * @param spinbox pointer to spinbox + */ +void lv_spinbox_step_next(lv_obj_t * spinbox); + +/** + * Select next higher digit for edition by multiplying the step by 10 + * @param spinbox pointer to spinbox + */ +void lv_spinbox_step_previous(lv_obj_t * spinbox); + +/** + * Increment spinbox value by one step + * @param spinbox pointer to spinbox + */ +void lv_spinbox_increment(lv_obj_t * spinbox); + +/** + * Decrement spinbox value by one step + * @param spinbox pointer to spinbox + */ +void lv_spinbox_decrement(lv_obj_t * spinbox); + + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_SPINBOX*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SPINBOX_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_sw.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_sw.h new file mode 100644 index 00000000..7f4513c8 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_sw.h @@ -0,0 +1,194 @@ +/** + * @file lv_sw.h + * + */ + +#ifndef LV_SW_H +#define LV_SW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_SW != 0 + +/*Testing of dependencies*/ +#if USE_LV_SLIDER == 0 +#error "lv_sw: lv_slider is required. Enable it in lv_conf.h (USE_LV_SLIDER 1)" +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_slider.h" + +/********************* + * DEFINES + *********************/ +#define LV_SWITCH_SLIDER_ANIM_MAX 1000 + +/********************** + * TYPEDEFS + **********************/ +/*Data of switch*/ +typedef struct +{ + lv_slider_ext_t slider; /*Ext. of ancestor*/ + /*New data for this type */ + lv_style_t *style_knob_off; /*Style of the knob when the switch is OFF*/ + lv_style_t *style_knob_on; /*Style of the knob when the switch is ON (NULL to use the same as OFF)*/ + lv_coord_t start_x; + uint8_t changed :1; /*Indicates the switch state explicitly changed by drag*/ + uint8_t slided :1; +#if USE_LV_ANIMATION + uint16_t anim_time; /*switch animation time */ +#endif +} lv_sw_ext_t; + +enum { + LV_SW_STYLE_BG, + LV_SW_STYLE_INDIC, + LV_SW_STYLE_KNOB_OFF, + LV_SW_STYLE_KNOB_ON, +}; +typedef uint8_t lv_sw_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a switch objects + * @param par pointer to an object, it will be the parent of the new switch + * @param copy pointer to a switch object, if not NULL then the new object will be copied from it + * @return pointer to the created switch + */ +lv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Turn ON the switch + * @param sw pointer to a switch object + */ +void lv_sw_on(lv_obj_t *sw); + +/** + * Turn OFF the switch + * @param sw pointer to a switch object + */ +void lv_sw_off(lv_obj_t *sw); + +/** + * Toggle the position of the switch + * @param sw pointer to a switch object + * @return resulting state of the switch. + */ +bool lv_sw_toggle(lv_obj_t *sw); + +/** + * Turn ON the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_on_anim(lv_obj_t * sw); + +/** + * Turn OFF the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_off_anim(lv_obj_t * sw); + +/** + * Toggle the position of the switch with an animation + * @param sw pointer to a switch object + * @return resulting state of the switch. + */ +bool lv_sw_toggle_anim(lv_obj_t *sw); + +/** + * Set a function which will be called when the switch is toggled by the user + * @param sw pointer to switch object + * @param action a callback function + */ +static inline void lv_sw_set_action(lv_obj_t * sw, lv_action_t action) +{ + lv_slider_set_action(sw, action); +} + +/** + * Set a style of a switch + * @param sw pointer to a switch object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_sw_set_style(lv_obj_t *sw, lv_sw_style_t type, lv_style_t *style); + +#if USE_LV_ANIMATION +/** + * Set the animation time of the switch + * @param sw pointer to a switch object + * @param anim_time animation time + * @return style pointer to a style + */ +void lv_sw_set_anim_time(lv_obj_t *sw, uint16_t anim_time); +#endif + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the state of a switch + * @param sw pointer to a switch object + * @return false: OFF; true: ON + */ +static inline bool lv_sw_get_state(const lv_obj_t *sw) +{ + return lv_bar_get_value(sw) < LV_SWITCH_SLIDER_ANIM_MAX / 2 ? false : true; +} + +/** + * Get the switch action function + * @param slider pointer to a switch object + * @return the callback function + */ +static inline lv_action_t lv_sw_get_action(const lv_obj_t * slider) +{ + return lv_slider_get_action(slider); +} + +/** + * Get a style of a switch + * @param sw pointer to a switch object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_sw_get_style(const lv_obj_t *sw, lv_sw_style_t type); + +/** + * Get the animation time of the switch + * @param sw pointer to a switch object + * @return style pointer to a style + */ +uint16_t lv_sw_get_anim_time(const lv_obj_t *sw); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_SW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SW_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_ta.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_ta.h new file mode 100644 index 00000000..8e12314a --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_ta.h @@ -0,0 +1,390 @@ +/** + * @file lv_ta.h + * + */ + +#ifndef LV_TA_H +#define LV_TA_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_TA != 0 + +/*Testing of dependencies*/ +#if USE_LV_PAGE == 0 +#error "lv_ta: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_ta: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_page.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ +#define LV_TA_CURSOR_LAST (0x7FFF) /*Put the cursor after the last character*/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_CURSOR_NONE, + LV_CURSOR_LINE, + LV_CURSOR_BLOCK, + LV_CURSOR_OUTLINE, + LV_CURSOR_UNDERLINE, + LV_CURSOR_HIDDEN = 0x08, /*Or it to any value to hide the cursor temporally*/ +}; +typedef uint8_t lv_cursor_type_t; + +/*Data of text area*/ +typedef struct +{ + lv_page_ext_t page; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * label; /*Label of the text area*/ + char * pwd_tmp; /*Used to store the original text in password mode*/ + const char * accapted_chars;/*Only these characters will be accepted. NULL: accept all*/ + uint16_t max_length; /*The max. number of characters. 0: no limit*/ + uint8_t pwd_mode :1; /*Replace characters with '*' */ + uint8_t one_line :1; /*One line mode (ignore line breaks)*/ + struct { + lv_style_t *style; /*Style of the cursor (NULL to use label's style)*/ + lv_coord_t valid_x; /*Used when stepping up/down in text area when stepping to a shorter line. (Handled by the library)*/ + uint16_t pos; /*The current cursor position (0: before 1. letter; 1: before 2. letter etc.)*/ + lv_area_t area; /*Cursor area relative to the Text Area*/ + uint16_t txt_byte_pos; /*Byte index of the letter after (on) the cursor*/ + lv_cursor_type_t type:4; /*Shape of the cursor*/ + uint8_t state :1; /*Indicates that the cursor is visible now or not (Handled by the library)*/ + } cursor; +} lv_ta_ext_t; + +enum { + LV_TA_STYLE_BG, + LV_TA_STYLE_SB, + LV_TA_STYLE_EDGE_FLASH, + LV_TA_STYLE_CURSOR, +}; +typedef uint8_t lv_ta_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a text area objects + * @param par pointer to an object, it will be the parent of the new text area + * @param copy pointer to a text area object, if not NULL then the new object will be copied from it + * @return pointer to the created text area + */ +lv_obj_t * lv_ta_create(lv_obj_t * par, const lv_obj_t * copy); + + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Insert a character to the current cursor position. + * To add a wide char, e.g. 'Á' use `lv_txt_encoded_conv_wc('Á')` + * @param ta pointer to a text area object + * @param c a character (e.g. 'a') + */ +void lv_ta_add_char(lv_obj_t * ta, uint32_t c); + +/** + * Insert a text to the current cursor position + * @param ta pointer to a text area object + * @param txt a '\0' terminated string to insert + */ +void lv_ta_add_text(lv_obj_t * ta, const char * txt); + +/** + * Delete a the left character from the current cursor position + * @param ta pointer to a text area object + */ +void lv_ta_del_char(lv_obj_t * ta); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a text area + * @param ta pointer to a text area + * @param txt pointer to the text + */ +void lv_ta_set_text(lv_obj_t * ta, const char * txt); + +/** + * Set the cursor position + * @param obj pointer to a text area object + * @param pos the new cursor position in character index + * < 0 : index from the end of the text + * LV_TA_CURSOR_LAST: go after the last character + */ +void lv_ta_set_cursor_pos(lv_obj_t * ta, int16_t pos); + +/** + * Set the cursor type. + * @param ta pointer to a text area object + * @param cur_type: element of 'lv_cursor_type_t' + */ +void lv_ta_set_cursor_type(lv_obj_t * ta, lv_cursor_type_t cur_type); + +/** + * Enable/Disable password mode + * @param ta pointer to a text area object + * @param en true: enable, false: disable + */ +void lv_ta_set_pwd_mode(lv_obj_t * ta, bool en); + +/** + * Configure the text area to one line or back to normal + * @param ta pointer to a Text area object + * @param en true: one line, false: normal + */ +void lv_ta_set_one_line(lv_obj_t * ta, bool en); + +/** + * Set the alignment of the text area. + * In one line mode the text can be scrolled only with `LV_LABEL_ALIGN_LEFT`. + * This function should be called if the size of text area changes. + * @param ta pointer to a text are object + * @param align the desired alignment from `lv_label_align_t`. (LV_LABEL_ALIGN_LEFT/CENTER/RIGHT) + */ +void lv_ta_set_text_align(lv_obj_t * ta, lv_label_align_t align); + +/** + * Set a list of characters. Only these characters will be accepted by the text area + * @param ta pointer to Text Area + * @param list list of characters. Only the pointer is saved. E.g. "+-.,0123456789" + */ +void lv_ta_set_accepted_chars(lv_obj_t * ta, const char * list); + +/** + * Set max length of a Text Area. + * @param ta pointer to Text Area + * @param num the maximal number of characters can be added (`lv_ta_set_text` ignores it) + */ +void lv_ta_set_max_length(lv_obj_t * ta, uint16_t num); + +/** + * Set an action to call when the Text area is clicked + * @param ta pointer to a Text area + * @param action a function pointer + */ +static inline void lv_ta_set_action(lv_obj_t * ta, lv_action_t action) +{ + lv_page_set_rel_action(ta, action); +} + +/** + * Set the scroll bar mode of a text area + * @param ta pointer to a text area object + * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum + */ +static inline void lv_ta_set_sb_mode(lv_obj_t * ta, lv_sb_mode_t mode) +{ + lv_page_set_sb_mode(ta, mode); +} + +/** + * Enable the scroll propagation feature. If enabled then the Text area will move its parent if there is no more space to scroll. + * @param ta pointer to a Text area + * @param en true or false to enable/disable scroll propagation + */ +static inline void lv_ta_set_scroll_propagation(lv_obj_t * ta, bool en) +{ + lv_page_set_scroll_propagation(ta, en); +} + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param page pointer to a Text Area + * @param en true or false to enable/disable end flash + */ +static inline void lv_ta_set_edge_flash(lv_obj_t * ta, bool en) +{ + lv_page_set_edge_flash(ta, en); +} + +/** + * Set a style of a text area + * @param ta pointer to a text area object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_ta_set_style(lv_obj_t *ta, lv_ta_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a text area. In password mode it gives the real text (not '*'s). + * @param ta pointer to a text area object + * @return pointer to the text + */ +const char * lv_ta_get_text(const lv_obj_t * ta); + +/** + * Get the label of a text area + * @param ta pointer to a text area object + * @return pointer to the label object + */ +lv_obj_t * lv_ta_get_label(const lv_obj_t * ta); + +/** + * Get the current cursor position in character index + * @param ta pointer to a text area object + * @return the cursor position + */ +uint16_t lv_ta_get_cursor_pos(const lv_obj_t * ta); + +/** + * Get the current cursor visibility. + * @param ta pointer to a text area object + * @return true: the cursor is drawn, false: the cursor is hidden + */ +//bool lv_ta_get_cursor_show(const lv_obj_t * ta); + +/** + * Get the current cursor type. + * @param ta pointer to a text area object + * @return element of 'lv_cursor_type_t' + */ +lv_cursor_type_t lv_ta_get_cursor_type(const lv_obj_t * ta); + +/** + * Get the password mode attribute + * @param ta pointer to a text area object + * @return true: password mode is enabled, false: disabled + */ +bool lv_ta_get_pwd_mode(const lv_obj_t * ta); + +/** + * Get the one line configuration attribute + * @param ta pointer to a text area object + * @return true: one line configuration is enabled, false: disabled + */ +bool lv_ta_get_one_line(const lv_obj_t * ta); + +/** + * Get a list of accepted characters. + * @param ta pointer to Text Area + * @return list of accented characters. + */ +const char * lv_ta_get_accepted_chars(lv_obj_t * ta); + +/** + * Set max length of a Text Area. + * @param ta pointer to Text Area + * @return the maximal number of characters to be add + */ +uint16_t lv_ta_get_max_length(lv_obj_t * ta); + +/** + * Set an action to call when the Text area is clicked + * @param ta pointer to a Text area + * @param action a function pointer + */ +static inline lv_action_t lv_ta_get_action(lv_obj_t * ta) +{ + return lv_page_get_rel_action(ta); +} + +/** + * Get the scroll bar mode of a text area + * @param ta pointer to a text area object + * @return scrollbar mode from 'lv_page_sb_mode_t' enum + */ +static inline lv_sb_mode_t lv_ta_get_sb_mode(const lv_obj_t * ta) +{ + return lv_page_get_sb_mode(ta); +} + +/** + * Get the scroll propagation property + * @param ta pointer to a Text area + * @return true or false + */ +static inline bool lv_ta_get_scroll_propagation(lv_obj_t * ta) +{ + return lv_page_get_scroll_propagation(ta); +} + +/** + * Get the scroll propagation property + * @param ta pointer to a Text area + * @return true or false + */ +static inline bool lv_ta_get_edge_flash(lv_obj_t * ta) +{ + return lv_page_get_edge_flash(ta); +} + +/** + * Get a style of a text area + * @param ta pointer to a text area object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_ta_get_style(const lv_obj_t *ta, lv_ta_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Move the cursor one character right + * @param ta pointer to a text area object + */ +void lv_ta_cursor_right(lv_obj_t * ta); + +/** + * Move the cursor one character left + * @param ta pointer to a text area object + */ +void lv_ta_cursor_left(lv_obj_t * ta); + +/** + * Move the cursor one line down + * @param ta pointer to a text area object + */ +void lv_ta_cursor_down(lv_obj_t * ta); + +/** + * Move the cursor one line up + * @param ta pointer to a text area object + */ +void lv_ta_cursor_up(lv_obj_t * ta); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TA_H*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TA_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_table.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_table.h new file mode 100644 index 00000000..79ba22dc --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_table.h @@ -0,0 +1,261 @@ +/** + * @file lv_table.h + * + */ + +#ifndef LV_TABLE_H +#define LV_TABLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_TABLE != 0 + +/*Testing of dependencies*/ +#if USE_LV_LABEL == 0 +#error "lv_table: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_TABLE_COL_MAX +#define LV_TABLE_COL_MAX 12 +#endif + +#define LV_TABLE_CELL_STYLE_CNT 4 +/********************** + * TYPEDEFS + **********************/ + +typedef union { + struct { + uint8_t align:2; + uint8_t right_merge:1; + uint8_t type:2; + uint8_t crop:1; + }; + uint8_t format_byte; +}lv_table_cell_format_t; + +/*Data of table*/ +typedef struct { + /*New data for this type */ + uint16_t col_cnt; + uint16_t row_cnt; + char ** cell_data; + lv_style_t * cell_style[LV_TABLE_CELL_STYLE_CNT]; + lv_coord_t col_w[LV_TABLE_COL_MAX]; +} lv_table_ext_t; + + +/*Styles*/ +enum { + LV_TABLE_STYLE_BG, + LV_TABLE_STYLE_CELL1, + LV_TABLE_STYLE_CELL2, + LV_TABLE_STYLE_CELL3, + LV_TABLE_STYLE_CELL4, +}; +typedef uint8_t lv_table_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a table object + * @param par pointer to an object, it will be the parent of the new table + * @param copy pointer to a table object, if not NULL then the new object will be copied from it + * @return pointer to the created table + */ +lv_obj_t * lv_table_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the value of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param txt text to display in the cell. It will be copied and saved so this variable is not required after this function call. + */ +void lv_table_set_cell_value(lv_obj_t * table, uint16_t row, uint16_t col, const char * txt); + +/** + * Set the number of rows + * @param table table pointer to a Table object + * @param row_cnt number of rows + */ +void lv_table_set_row_cnt(lv_obj_t * table, uint16_t row_cnt); + +/** + * Set the number of columns + * @param table table pointer to a Table object + * @param col_cnt number of columns. Must be < LV_TABLE_COL_MAX + */ +void lv_table_set_col_cnt(lv_obj_t * table, uint16_t col_cnt); + +/** + * Set the width of a column + * @param table table pointer to a Table object + * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1] + * @param w width of the column + */ +void lv_table_set_col_width(lv_obj_t * table, uint16_t col_id, lv_coord_t w); + +/** + * Set the text align in a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param align LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT + */ +void lv_table_set_cell_align(lv_obj_t * table, uint16_t row, uint16_t col, lv_label_align_t align); + +/** + * Set the type of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param type 1,2,3 or 4. The cell style will be chosen accordingly. + */ +void lv_table_set_cell_type(lv_obj_t * table, uint16_t row, uint16_t col, uint8_t type); + +/** + * Set the cell crop. (Don't adjust the height of the cell according to its content) + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param crop true: crop the cell content; false: set the cell height to the content. + */ +void lv_table_set_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col, bool crop); + +/** + * Merge a cell with the right neighbor. The value of the cell to the right won't be displayed. + * @param table table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param en true: merge right; false: don't merge right + */ +void lv_table_set_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col, bool en); + +/** + * Set a style of a table. + * @param table pointer to table object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_table_set_style(lv_obj_t * table, lv_table_style_t type, lv_style_t * style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return text in the cell + */ +const char * lv_table_get_cell_value(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get the number of rows. + * @param table table pointer to a Table object + * @return number of rows. + */ +uint16_t lv_table_get_row_cnt(lv_obj_t * table); + +/** + * Get the number of columns. + * @param table table pointer to a Table object + * @return number of columns. + */ +uint16_t lv_table_get_col_cnt(lv_obj_t * table); + +/** + * Get the width of a column + * @param table table pointer to a Table object + * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1] + * @return width of the column + */ +lv_coord_t lv_table_get_col_width(lv_obj_t * table, uint16_t col_id); + +/** + * Get the text align of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return LV_LABEL_ALIGN_LEFT (default in case of error) or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT + */ +lv_label_align_t lv_table_get_cell_align(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get the type of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return 1,2,3 or 4 + */ +lv_label_align_t lv_table_get_cell_type(lv_obj_t * table, uint16_t row, uint16_t col); + + +/** + * Get the crop property of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return true: text crop enabled; false: disabled + */ +lv_label_align_t lv_table_get_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get the cell merge attribute. + * @param table table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return true: merge right; false: don't merge right + */ +bool lv_table_get_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get style of a table. + * @param table pointer to table object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_table_get_style(const lv_obj_t * table, lv_table_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TABLE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TABLE_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_tabview.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_tabview.h new file mode 100644 index 00000000..73d8b17c --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_tabview.h @@ -0,0 +1,252 @@ +/** + * @file lv_tabview.h + * + */ + +#ifndef LV_TABVIEW_H +#define LV_TABVIEW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_TABVIEW != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTNM == 0 +#error "lv_tabview: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM 1) " +#endif + +#if USE_LV_PAGE == 0 +#error "lv_tabview: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "display/lv_objx/lv_win.h" +#include "display/lv_objx/lv_page.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/* parametes: pointer to a tabview object, tab_id + * return: LV_RES_INV: to prevent the loading of the tab; LV_RES_OK: if everything is fine*/ +typedef lv_res_t (*lv_tabview_action_t)(lv_obj_t *, uint16_t); + + +enum { + LV_TABVIEW_BTNS_POS_TOP, + LV_TABVIEW_BTNS_POS_BOTTOM, +}; +typedef uint8_t lv_tabview_btns_pos_t; + +/*Data of tab*/ +typedef struct +{ + /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * btns; + lv_obj_t * indic; + lv_obj_t * content; /*A rectangle to show the current tab*/ + const char ** tab_name_ptr; + lv_point_t point_last; + uint16_t tab_cur; + uint16_t tab_cnt; + uint16_t anim_time; + uint8_t slide_enable :1; /*1: enable horizontal sliding by touch pad*/ + uint8_t draging :1; + uint8_t drag_hor :1; + uint8_t btns_hide :1; + lv_tabview_btns_pos_t btns_pos :1; + lv_tabview_action_t tab_load_action; +} lv_tabview_ext_t; + +enum { + LV_TABVIEW_STYLE_BG, + LV_TABVIEW_STYLE_INDIC, + LV_TABVIEW_STYLE_BTN_BG, + LV_TABVIEW_STYLE_BTN_REL, + LV_TABVIEW_STYLE_BTN_PR, + LV_TABVIEW_STYLE_BTN_TGL_REL, + LV_TABVIEW_STYLE_BTN_TGL_PR, +}; +typedef uint8_t lv_tabview_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a Tab view object + * @param par pointer to an object, it will be the parent of the new tab + * @param copy pointer to a tab object, if not NULL then the new object will be copied from it + * @return pointer to the created tab + */ +lv_obj_t * lv_tabview_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_tabview_clean(lv_obj_t *obj); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add a new tab with the given name + * @param tabview pointer to Tab view object where to ass the new tab + * @param name the text on the tab button + * @return pointer to the created page object (lv_page). You can create your content here + */ +lv_obj_t * lv_tabview_add_tab(lv_obj_t * tabview, const char * name); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new tab + * @param tabview pointer to Tab view object + * @param id index of a tab to load + * @param anim_en true: set with sliding animation; false: set immediately + */ +void lv_tabview_set_tab_act(lv_obj_t * tabview, uint16_t id, bool anim_en); + +/** + * Set an action to call when a tab is loaded (Good to create content only if required) + * lv_tabview_get_act() still gives the current (old) tab (to remove content from here) + * @param tabview pointer to a tabview object + * @param action pointer to a function to call when a tab is loaded + */ +void lv_tabview_set_tab_load_action(lv_obj_t *tabview, lv_tabview_action_t action); + +/** + * Enable horizontal sliding with touch pad + * @param tabview pointer to Tab view object + * @param en true: enable sliding; false: disable sliding + */ +void lv_tabview_set_sliding(lv_obj_t * tabview, bool en); + +/** + * Set the animation time of tab view when a new tab is loaded + * @param tabview pointer to Tab view object + * @param anim_time time of animation in milliseconds + */ +void lv_tabview_set_anim_time(lv_obj_t * tabview, uint16_t anim_time); + +/** + * Set the style of a tab view + * @param tabview pointer to a tan view object + * @param type which style should be set + * @param style pointer to the new style + */ +void lv_tabview_set_style(lv_obj_t *tabview, lv_tabview_style_t type, lv_style_t *style); + +/** + * Set the position of tab select buttons + * @param tabview pointer to a tab view object + * @param btns_pos which button position + */ +void lv_tabview_set_btns_pos(lv_obj_t *tabview, lv_tabview_btns_pos_t btns_pos); + +/** + * Set whether tab buttons are hidden + * @param tabview pointer to a tab view object + * @param en whether tab buttons are hidden + */ +void lv_tabview_set_btns_hidden(lv_obj_t *tabview, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the index of the currently active tab + * @param tabview pointer to Tab view object + * @return the active tab index + */ +uint16_t lv_tabview_get_tab_act(const lv_obj_t * tabview); + +/** + * Get the number of tabs + * @param tabview pointer to Tab view object + * @return tab count + */ +uint16_t lv_tabview_get_tab_count(const lv_obj_t * tabview); +/** + * Get the page (content area) of a tab + * @param tabview pointer to Tab view object + * @param id index of the tab (>= 0) + * @return pointer to page (lv_page) object + */ +lv_obj_t * lv_tabview_get_tab(const lv_obj_t * tabview, uint16_t id); + +/** + * Get the tab load action + * @param tabview pointer to a tabview object + * @param return the current tab load action + */ +lv_tabview_action_t lv_tabview_get_tab_load_action(const lv_obj_t *tabview); + +/** + * Get horizontal sliding is enabled or not + * @param tabview pointer to Tab view object + * @return true: enable sliding; false: disable sliding + */ +bool lv_tabview_get_sliding(const lv_obj_t * tabview); + +/** + * Get the animation time of tab view when a new tab is loaded + * @param tabview pointer to Tab view object + * @return time of animation in milliseconds + */ +uint16_t lv_tabview_get_anim_time(const lv_obj_t * tabview); + +/** + * Get a style of a tab view + * @param tabview pointer to a ab view object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_tabview_get_style(const lv_obj_t *tabview, lv_tabview_style_t type); + +/** + * Get position of tab select buttons + * @param tabview pointer to a ab view object + */ +lv_tabview_btns_pos_t lv_tabview_get_btns_pos(const lv_obj_t *tabview); + +/** + * Get whether tab buttons are hidden + * @param tabview pointer to a tab view object + * @return whether tab buttons are hidden + */ +bool lv_tabview_get_btns_hidden(const lv_obj_t *tabview); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TABVIEW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TABVIEW_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_tileview.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_tileview.h new file mode 100644 index 00000000..b869e7ce --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_tileview.h @@ -0,0 +1,163 @@ +/** + * @file lv_tileview.h + * + */ + + +#ifndef LV_TILEVIEW_H +#define LV_TILEVIEW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_TILEVIEW != 0 + +#include "display/lv_objx/lv_page.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + + + +/* parametes: pointer to a tileview object, x, y (tile coordinates to load) + * return: LV_RES_INV: to prevent the loading of the tab; LV_RES_OK: if everything is fine*/ +typedef lv_res_t (*lv_tileview_action_t)(lv_obj_t *, lv_coord_t, lv_coord_t); + +/*Data of tileview*/ +typedef struct { + lv_page_ext_t page; + /*New data for this type */ + const lv_point_t * valid_pos; + uint16_t anim_time; + lv_tileview_action_t action; + lv_point_t act_id; + uint8_t drag_top_en :1; + uint8_t drag_bottom_en :1; + uint8_t drag_left_en :1; + uint8_t drag_right_en :1; + uint8_t drag_hor :1; + uint8_t drag_ver :1; +} lv_tileview_ext_t; + + +/*Styles*/ +enum { + LV_TILEVIEW_STYLE_BG, +}; +typedef uint8_t lv_tileview_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a tileview objects + * @param par pointer to an object, it will be the parent of the new tileview + * @param copy pointer to a tileview object, if not NULL then the new object will be copied from it + * @return pointer to the created tileview + */ +lv_obj_t * lv_tileview_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Register an object on the tileview. The register object will able to slide the tileview + * @param element pointer to an object + */ +void lv_tileview_add_element(lv_obj_t * element); + +/*===================== + * Setter functions + *====================*/ + + +/** + * Set the valid position's indices. The scrolling will be possible only to these positions. + * @param tileview pointer to a Tileview object + * @param valid_pos array width the indices. E.g. `lv_point_t p[] = {{0,0}, {1,0}, {1,1}, {LV_COORD_MIN, LV_COORD_MIN}};` + * Must be closed with `{LV_COORD_MIN, LV_COORD_MIN}`. Only the pointer is saved so can't be a local variable. + */ +void lv_tileview_set_valid_positions(lv_obj_t * tileview, const lv_point_t * valid_pos); + +/** + * Set the tile to be shown + * @param tileview pointer to a tileview object + * @param x column id (0, 1, 2...) + * @param y line id (0, 1, 2...) + * @param anim_en true: move with animation + */ +void lv_tileview_set_tile_act(lv_obj_t * tileview, lv_coord_t x, lv_coord_t y, bool anim_en); + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param tileview pointer to a Tileview + * @param en true or false to enable/disable end flash + */ +static inline void lv_tileview_set_edge_flash(lv_obj_t * tileview, bool en) +{ + lv_page_set_edge_flash(tileview, en); +} + +/** + * Set a style of a tileview. + * @param tileview pointer to tileview object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_tileview_set_style(lv_obj_t * tileview, lv_tileview_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the scroll propagation property + * @param tileview pointer to a Tileview + * @return true or false + */ +static inline bool lv_tileview_get_edge_flash(lv_obj_t * tileview) +{ + return lv_page_get_edge_flash(tileview); +} + +/** + * Get style of a tileview. + * @param tileview pointer to tileview object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_tileview_get_style(const lv_obj_t * tileview, lv_tileview_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TILEVIEW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TILEVIEW_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_objx/lv_win.h b/old-code/v5_hal/firmware/include/display/lv_objx/lv_win.h new file mode 100644 index 00000000..4a64aa81 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_objx/lv_win.h @@ -0,0 +1,282 @@ +/** + * @file lv_win.h + * + */ + +#ifndef LV_WIN_H +#define LV_WIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_WIN != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTN == 0 +#error "lv_win: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_win: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#if USE_LV_IMG == 0 +#error "lv_win: lv_img is required. Enable it in lv_conf.h (USE_LV_IMG 1) " +#endif + + +#if USE_LV_PAGE == 0 +#error "lv_win: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_cont.h" +#include "lv_btn.h" +#include "lv_label.h" +#include "lv_img.h" +#include "lv_page.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of window*/ +typedef struct +{ + /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * page; /*Pointer to a page which holds the content*/ + lv_obj_t * header; /*Pointer to the header container of the window*/ + lv_obj_t * title; /*Pointer to the title label of the window*/ + lv_style_t * style_header; /*Style of the header container*/ + lv_style_t * style_btn_rel; /*Control button releases style*/ + lv_style_t * style_btn_pr; /*Control button pressed style*/ + lv_coord_t btn_size; /*Size of the control buttons (square)*/ +} lv_win_ext_t; + +enum { + LV_WIN_STYLE_BG, + LV_WIN_STYLE_CONTENT_BG, + LV_WIN_STYLE_CONTENT_SCRL, + LV_WIN_STYLE_SB, + LV_WIN_STYLE_HEADER, + LV_WIN_STYLE_BTN_REL, + LV_WIN_STYLE_BTN_PR, +}; +typedef uint8_t lv_win_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a window objects + * @param par pointer to an object, it will be the parent of the new window + * @param copy pointer to a window object, if not NULL then the new object will be copied from it + * @return pointer to the created window + */ +lv_obj_t * lv_win_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_win_clean(lv_obj_t *obj); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add control button to the header of the window + * @param win pointer to a window object + * @param img_src an image source ('lv_img_t' variable, path to file or a symbol) + * @param rel_action a function pointer to call when the button is released + * @return pointer to the created button object + */ +lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src, lv_action_t rel_action); + +/*===================== + * Setter functions + *====================*/ + +/** + * A release action which can be assigned to a window control button to close it + * @param btn pointer to the released button + * @return always LV_ACTION_RES_INV because the button is deleted with the window + */ +lv_res_t lv_win_close_action(lv_obj_t * btn); + +/** + * Set the title of a window + * @param win pointer to a window object + * @param title string of the new title + */ +void lv_win_set_title(lv_obj_t * win, const char * title); + +/** + * Set the control button size of a window + * @param win pointer to a window object + * @return control button size + */ +void lv_win_set_btn_size(lv_obj_t * win, lv_coord_t size); + +/** + * Set the layout of the window + * @param win pointer to a window object + * @param layout the layout from 'lv_layout_t' + */ +void lv_win_set_layout(lv_obj_t *win, lv_layout_t layout); + +/** + * Set the scroll bar mode of a window + * @param win pointer to a window object + * @param sb_mode the new scroll bar mode from 'lv_sb_mode_t' + */ +void lv_win_set_sb_mode(lv_obj_t *win, lv_sb_mode_t sb_mode); + +/** + * Set a style of a window + * @param win pointer to a window object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_win_set_style(lv_obj_t *win, lv_win_style_t type, lv_style_t *style); + +/** + * Set drag status of a window. If set to 'true' window can be dragged like on a PC. + * @param win pointer to a window object + * @param en whether dragging is enabled + */ +void lv_win_set_drag(lv_obj_t *win, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the title of a window + * @param win pointer to a window object + * @return title string of the window + */ +const char * lv_win_get_title(const lv_obj_t * win); + +/** +* Get the content holder object of window (`lv_page`) to allow additional customization +* @param win pointer to a window object +* @return the Page object where the window's content is +*/ +lv_obj_t * lv_win_get_content(const lv_obj_t * win); + +/** + * Get the control button size of a window + * @param win pointer to a window object + * @return control button size + */ +lv_coord_t lv_win_get_btn_size(const lv_obj_t * win); + +/** + * Get the pointer of a widow from one of its control button. + * It is useful in the action of the control buttons where only button is known. + * @param ctrl_btn pointer to a control button of a window + * @return pointer to the window of 'ctrl_btn' + */ +lv_obj_t * lv_win_get_from_btn(const lv_obj_t * ctrl_btn); + +/** + * Get the layout of a window + * @param win pointer to a window object + * @return the layout of the window (from 'lv_layout_t') + */ +lv_layout_t lv_win_get_layout(lv_obj_t *win); + +/** + * Get the scroll bar mode of a window + * @param win pointer to a window object + * @return the scroll bar mode of the window (from 'lv_sb_mode_t') + */ +lv_sb_mode_t lv_win_get_sb_mode(lv_obj_t *win); + +/** + * Get width of the content area (page scrollable) of the window + * @param win pointer to a window object + * @return the width of the content area + */ +lv_coord_t lv_win_get_width(lv_obj_t * win); + +/** + * Get a style of a window + * @param win pointer to a button object + * @param type which style window be get + * @return style pointer to a style + */ +lv_style_t * lv_win_get_style(const lv_obj_t *win, lv_win_style_t type); + +/** + * Get drag status of a window. If set to 'true' window can be dragged like on a PC. + * @param win pointer to a window object + * @return whether window is draggable + */ +static inline bool lv_win_get_drag(const lv_obj_t *win) +{ + return lv_obj_get_drag(win); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Focus on an object. It ensures that the object will be visible in the window. + * @param win pointer to a window object + * @param obj pointer to an object to focus (must be in the window) + * @param anim_time scroll animation time in milliseconds (0: no animation) + */ +void lv_win_focus(lv_obj_t * win, lv_obj_t * obj, uint16_t anim_time); + +/** + * Scroll the window horizontally + * @param win pointer to a window object + * @param dist the distance to scroll (< 0: scroll right; > 0 scroll left) + */ +static inline void lv_win_scroll_hor(lv_obj_t * win, lv_coord_t dist) +{ + lv_win_ext_t * ext = (lv_win_ext_t *)lv_obj_get_ext_attr(win); + lv_page_scroll_hor(ext->page, dist); +} +/** + * Scroll the window vertically + * @param win pointer to a window object + * @param dist the distance to scroll (< 0: scroll down; > 0 scroll up) + */ +static inline void lv_win_scroll_ver(lv_obj_t * win, lv_coord_t dist) +{ + lv_win_ext_t * ext = (lv_win_ext_t *)lv_obj_get_ext_attr(win); + lv_page_scroll_ver(ext->page, dist); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_WIN*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_WIN_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme.h b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme.h new file mode 100644 index 00000000..69aae29f --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme.h @@ -0,0 +1,332 @@ +/** + *@file lv_themes.h + * + */ + +#ifndef LV_THEMES_H +#define LV_THEMES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include "display/lv_core/lv_style.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_style_t *bg; + lv_style_t *panel; + +#if USE_LV_CONT != 0 + lv_style_t *cont; +#endif + +#if USE_LV_BTN != 0 + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; +#endif + + +#if USE_LV_IMGBTN != 0 + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } imgbtn; +#endif + +#if USE_LV_LABEL != 0 + struct { + lv_style_t *prim; + lv_style_t *sec; + lv_style_t *hint; + } label; +#endif + +#if USE_LV_IMG != 0 + struct { + lv_style_t *light; + lv_style_t *dark; + } img; +#endif + +#if USE_LV_LINE != 0 + struct { + lv_style_t *decor; + } line; +#endif + +#if USE_LV_LED != 0 + lv_style_t *led; +#endif + +#if USE_LV_BAR != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + } bar; +#endif + +#if USE_LV_SLIDER != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + lv_style_t *knob; + } slider; +#endif + +#if USE_LV_LMETER != 0 + lv_style_t *lmeter; +#endif + +#if USE_LV_GAUGE != 0 + lv_style_t *gauge; +#endif + +#if USE_LV_ARC != 0 + lv_style_t *arc; +#endif + +#if USE_LV_PRELOAD != 0 + lv_style_t *preload; +#endif + +#if USE_LV_SW != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + lv_style_t *knob_off; + lv_style_t *knob_on; + } sw; +#endif + +#if USE_LV_CHART != 0 + lv_style_t *chart; +#endif + +#if USE_LV_CALENDAR != 0 + struct { + lv_style_t *bg; + lv_style_t *header; + lv_style_t *header_pr; + lv_style_t *day_names; + lv_style_t *highlighted_days; + lv_style_t *inactive_days; + lv_style_t *week_box; + lv_style_t *today_box; + } calendar; +#endif + +#if USE_LV_CB != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } box; + } cb; +#endif + +#if USE_LV_BTNM != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; + } btnm; +#endif + +#if USE_LV_KB != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; + } kb; +#endif + +#if USE_LV_MBOX != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *bg; + lv_style_t *rel; + lv_style_t *pr; + } btn; + } mbox; +#endif + +#if USE_LV_PAGE != 0 + struct { + lv_style_t *bg; + lv_style_t *scrl; + lv_style_t *sb; + } page; +#endif + +#if USE_LV_TA != 0 + struct { + lv_style_t *area; + lv_style_t *oneline; + lv_style_t *cursor; + lv_style_t *sb; + } ta; +#endif + +#if USE_LV_SPINBOX != 0 + struct { + lv_style_t *bg; + lv_style_t *cursor; + lv_style_t *sb; + } spinbox; +#endif + +#if USE_LV_LIST + struct { + lv_style_t *bg; + lv_style_t *scrl; + lv_style_t *sb; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; + } list; +#endif + +#if USE_LV_DDLIST != 0 + struct { + lv_style_t *bg; + lv_style_t *sel; + lv_style_t *sb; + } ddlist; +#endif + +#if USE_LV_ROLLER != 0 + struct { + lv_style_t *bg; + lv_style_t *sel; + } roller; +#endif + +#if USE_LV_TABVIEW != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + struct { + lv_style_t *bg; + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + } btn; + } tabview; +#endif + +#if USE_LV_TILEVIEW != 0 + struct { + lv_style_t *bg; + lv_style_t *scrl; + lv_style_t *sb; + } tileview; +#endif + +#if USE_LV_TABLE != 0 + struct { + lv_style_t *bg; + lv_style_t *cell; + } table; +#endif + +#if USE_LV_WIN != 0 + struct { + lv_style_t *bg; + lv_style_t *sb; + lv_style_t *header; + struct { + lv_style_t *bg; + lv_style_t *scrl; + } content; + struct { + lv_style_t *rel; + lv_style_t *pr; + } btn; + } win; +#endif +} lv_theme_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Set a theme for the system. + * From now, all the created objects will use styles from this theme by default + * @param th pointer to theme (return value of: 'lv_theme_init_xxx()') + */ +void lv_theme_set_current(lv_theme_t *th); + +/** + * Get the current system theme. + * @return pointer to the current system theme. NULL if not set. + */ +lv_theme_t * lv_theme_get_current(void); + +/********************** + * MACROS + **********************/ + +/********************** + * POST INCLUDE + *********************/ +#include "lv_theme_templ.h" +#include "lv_theme_default.h" +#include "lv_theme_alien.h" +#include "lv_theme_night.h" +#include "lv_theme_zen.h" +#include "lv_theme_mono.h" +#include "lv_theme_nemo.h" +#include "lv_theme_material.h" + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEMES_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_alien.h b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_alien.h new file mode 100644 index 00000000..1f62315d --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_alien.h @@ -0,0 +1,59 @@ +/** + * @file lv_theme_alien.h + * + */ + +#ifndef LV_THEME_ALIEN_H +#define LV_THEME_ALIEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_ALIEN + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the alien theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_alien_init(uint16_t hue, lv_font_t *font); +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_alien(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_ALIEN_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_default.h b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_default.h new file mode 100644 index 00000000..1348f1fc --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_default.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_default.h + * + */ + +#ifndef LV_THEME_DEFAULT_H +#define LV_THEME_DEFAULT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_DEFAULT + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the default theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_default_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_default(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_TEMPL_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_material.h b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_material.h new file mode 100644 index 00000000..d9da6646 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_material.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_material.h + * + */ + +#ifndef LV_THEME_MATERIAL_H +#define LV_THEME_MATERIAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_MATERIAL + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the material theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_material_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_material(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_MATERIAL_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_mono.h b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_mono.h new file mode 100644 index 00000000..63039fa9 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_mono.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_mono.h + * + */ + +#ifndef LV_THEME_MONO_H +#define LV_THEME_MONO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_MONO + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the mono theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_mono_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_mono(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_MONO_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_nemo.h b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_nemo.h new file mode 100644 index 00000000..46d43bdb --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_nemo.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_nemo.h + * + */ + +#ifndef LV_THEME_NEMO_H +#define LV_THEME_NEMO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_NEMO + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the material theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_nemo_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_nemo(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_NEMO_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_night.h b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_night.h new file mode 100644 index 00000000..3e5efb8f --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_night.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_night.h + * + */ + +#ifndef LV_THEME_NIGHT_H +#define LV_THEME_NIGHT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_NIGHT + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the night theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_night_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_night(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_NIGHT_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_templ.h b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_templ.h new file mode 100644 index 00000000..e7176636 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_templ.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_templ.h + * + */ + +#ifndef LV_THEME_TEMPL_H +#define LV_THEME_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_TEMPL + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the templ theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_templ_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_templ(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_TEMPL_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_zen.h b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_zen.h new file mode 100644 index 00000000..ddd7cb35 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_themes/lv_theme_zen.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_zen.h + * + */ + +#ifndef LV_THEME_ZEN_H +#define LV_THEME_ZEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_ZEN + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the zen theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_zen_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_zen(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_ZEN_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lv_themes/lv_themes.mk b/old-code/v5_hal/firmware/include/display/lv_themes/lv_themes.mk new file mode 100644 index 00000000..0e4a81a5 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_themes/lv_themes.mk @@ -0,0 +1,14 @@ +CSRCS += lv_theme_alien.c +CSRCS += lv_theme.c +CSRCS += lv_theme_default.c +CSRCS += lv_theme_night.c +CSRCS += lv_theme_templ.c +CSRCS += lv_theme_zen.c +CSRCS += lv_theme_material.c +CSRCS += lv_theme_nemo.c +CSRCS += lv_theme_mono.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_themes +VPATH += :$(LVGL_DIR)/lvgl/lv_themes + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_themes" diff --git a/old-code/v5_hal/firmware/include/display/lv_version.h b/old-code/v5_hal/firmware/include/display/lv_version.h new file mode 100644 index 00000000..1e62e1e2 --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lv_version.h @@ -0,0 +1,66 @@ +/** + * @file lv_version.h + * + */ + +#ifndef LV_VERSION_H +#define LV_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +/*Current version of LittlevGL*/ +#define LVGL_VERSION_MAJOR 5 +#define LVGL_VERSION_MINOR 3 +#define LVGL_VERSION_PATCH 0 +#define LVGL_VERSION_INFO "" + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ +/* Gives 1 if the x.y.z version is supported in the current version + * Usage: + * + * - Require v6 + * #if LV_VERSION_CHECK(6,0,0) + * new_func_in_v6(); + * #endif + * + * + * - Require at least v5.3 + * #if LV_VERSION_CHECK(5,3,0) + * new_feature_from_v5_3(); + * #endif + * + * + * - Require v5.3.2 bugfixes + * #if LV_VERSION_CHECK(5,3,2) + * bugfix_in_v5_3_2(); + * #endif + * + * */ +#define LV_VERSION_CHECK(x,y,z) (x == LVGL_VERSION_MAJOR && (y < LVGL_VERSION_MINOR || (y == LVGL_VERSION_MINOR && z <= LVGL_VERSION_PATCH))) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_VERSION_H*/ diff --git a/old-code/v5_hal/firmware/include/display/lvgl.h b/old-code/v5_hal/firmware/include/display/lvgl.h new file mode 100644 index 00000000..d2c93b4e --- /dev/null +++ b/old-code/v5_hal/firmware/include/display/lvgl.h @@ -0,0 +1,88 @@ +/** + * @file lvgl.h + * Include all LittleV GL related headers + */ + +#ifndef LVGL_H +#define LVGL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#include "lv_version.h" + +#include "lv_misc/lv_log.h" +#include "lv_misc/lv_task.h" + +#include "lv_hal/lv_hal.h" + +#include "lv_core/lv_obj.h" +#include "lv_core/lv_group.h" +#include "lv_core/lv_lang.h" +#include "lv_core/lv_vdb.h" +#include "lv_core/lv_refr.h" + +#include "lv_themes/lv_theme.h" + +#include "lv_objx/lv_btn.h" +#include "lv_objx/lv_imgbtn.h" +#include "lv_objx/lv_img.h" +#include "lv_objx/lv_label.h" +#include "lv_objx/lv_line.h" +#include "lv_objx/lv_page.h" +#include "lv_objx/lv_cont.h" +#include "lv_objx/lv_list.h" +#include "lv_objx/lv_chart.h" +#include "lv_objx/lv_table.h" +#include "lv_objx/lv_cb.h" +#include "lv_objx/lv_bar.h" +#include "lv_objx/lv_slider.h" +#include "lv_objx/lv_led.h" +#include "lv_objx/lv_btnm.h" +#include "lv_objx/lv_kb.h" +#include "lv_objx/lv_ddlist.h" +#include "lv_objx/lv_roller.h" +#include "lv_objx/lv_ta.h" +#include "lv_objx/lv_canvas.h" +#include "lv_objx/lv_win.h" +#include "lv_objx/lv_tabview.h" +#include "lv_objx/lv_tileview.h" +#include "lv_objx/lv_mbox.h" +#include "lv_objx/lv_gauge.h" +#include "lv_objx/lv_lmeter.h" +#include "lv_objx/lv_sw.h" +#include "lv_objx/lv_kb.h" +#include "lv_objx/lv_arc.h" +#include "lv_objx/lv_preload.h" +#include "lv_objx/lv_calendar.h" +#include "lv_objx/lv_spinbox.h" +#pragma GCC diagnostic pop + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} +#endif + +#endif /*LVGL_H*/ diff --git a/old-code/v5_hal/firmware/include/kinematics/HolonomicDriveKinematics.h b/old-code/v5_hal/firmware/include/kinematics/HolonomicDriveKinematics.h new file mode 100644 index 00000000..ab10fd22 --- /dev/null +++ b/old-code/v5_hal/firmware/include/kinematics/HolonomicDriveKinematics.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include + +#include "kinematics/IDriveKinematics.h" +#include "util/Constants.h" + +class HolonomicDriveKinematics : public IDriveKinematics { +public: + struct HolonomicWheelLocations { + Vector2d left_front_location; + Vector2d left_rear_location; + Vector2d right_front_location; + Vector2d right_rear_location; + }; + + HolonomicDriveKinematics(EncoderConfig encoder_config, HolonomicWheelLocations wheel_locations, + Pose current_pose=Pose()); + + /** + * This function takes in encoder values of all motors, and uses them to update + * the position of the robot based on the change of position over time + * + * @param encoder_vals struct holding encoder values for all motors + */ + void updateForwardKinematics(IDriveNode::FourMotorDriveEncoderVals encoder_vals); + + /** + * This function takes in movements of a drivetrain in the x, y, and theta axes. + * The inputs of this function must be of the same units (m/s, volts, etc.) and + * the function will return the proportion of the supplied maximum to send to each + * + * @param x float representing the x-movement of the drivetrain + * @param y float representing the y-movement of the drivetrain + * @param theta float representing the rotational movement of the drivetrain + * @returns struct containing percentage of the supplied maximum to send to each motor + */ + FourMotorPercentages inverseKinematics(float x, float y, float theta, float max); + + FourMotorPercentages tankKinematics(float left_x, float left_y, float right_x, float right_y, float max); + + ~HolonomicDriveKinematics(); + +private: + float m_left_front_previous_dist; + float m_left_rear_previous_dist; + float m_right_front_previous_dist; + float m_right_rear_previous_dist; + + HolonomicWheelLocations m_wheel_locations; + +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/kinematics/IDriveKinematics.h b/old-code/v5_hal/firmware/include/kinematics/IDriveKinematics.h new file mode 100644 index 00000000..69eb7d95 --- /dev/null +++ b/old-code/v5_hal/firmware/include/kinematics/IDriveKinematics.h @@ -0,0 +1,66 @@ +#pragma once + +#include "api.h" +#include "nodes/subsystems/drivetrain_nodes/IDriveNode.h" +#include "math/Pose.h" +#include "util/Encoders.h" +#include "util/Timer.h" +#include "eigen/Eigen/Dense" + +class IDriveKinematics { +protected: + Rotation2Dd m_initial_angle; + Pose m_pose = Pose(Vector2d(0, 0), Rotation2Dd()); + bool m_pose_reset = true; + float m_ticks_to_distance_m; + Timer m_timer; + + void m_updateCurrentPosition(Vector2d robot_velocity, float theta_velocity, float delta_time); + +public: + struct FourMotorPercentages { + float left_front_percent; + float left_rear_percent; + float right_front_percent; + float right_rear_percent; + }; + + IDriveKinematics(EncoderConfig encoder_config, Pose current_pose=Pose()); + + /** + * This function returns the current pose of the robot + * + * @returns Pose object containing the position and rotation of the robot + */ + Pose getPose(); + + /** + * This function sets the current pose of the robot + * + * @param current_pose pose to set the robot to + */ + void setCurrentPose(Pose current_pose); + + /** + * This function takes in encoder values of all motors, and uses them to update + * the position of the robot based on the change of position over time + * + * @param encoder_vals struct holding encoder values for all motors + */ + virtual void updateForwardKinematics(IDriveNode::FourMotorDriveEncoderVals encoder_vals) = 0; + + /** + * This function takes in movements of a drivetrain in the x, y, and theta axes. + * The inputs of this function must be of the same units (m/s, volts, etc.) and + * the function will return the proportion of the supplied maximum to send to each + * of four motors + * + * @param x float representing the x-movement of the drivetrain + * @param y float representing the y-movement of the drivetrain + * @param theta float representing the rotational movement of the drivetrain + * @returns struct containing percentage of the supplied maximum to send to each motor + */ + virtual FourMotorPercentages inverseKinematics(float x, float y, float theta, float max) = 0; + + ~IDriveKinematics(); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/kinematics/TankDriveKinematics.h b/old-code/v5_hal/firmware/include/kinematics/TankDriveKinematics.h new file mode 100644 index 00000000..0cce6fbd --- /dev/null +++ b/old-code/v5_hal/firmware/include/kinematics/TankDriveKinematics.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include "kinematics/IDriveKinematics.h" +#include "util/Constants.h" + +class TankDriveKinematics : public IDriveKinematics { +public: + struct TankWheelLocations { + Vector2d left_location; + Vector2d right_location; + }; + + TankDriveKinematics(EncoderConfig encoder_config, TankWheelLocations wheel_locations, + Pose current_pose=Pose()); + + /** + * This function takes in encoder values of all motors, and uses them to update + * the position of the robot based on the change of position over time + * + * @param encoder_vals struct holding encoder values for all motors + */ + virtual void updateForwardKinematics(IDriveNode::FourMotorDriveEncoderVals encoder_vals); + + /** + * This function takes in movements of a drivetrain in the x, y, and theta axes. + * The inputs of this function must be of the same units (m/s, volts, etc.) and + * the function will return the proportion of the supplied maximum to send to each + * + * @param x float representing the x-movement of the drivetrain + * @param y float representing the y-movement of the drivetrain + * @param theta float representing the rotational movement of the drivetrain + * @returns struct containing percentage of the supplied maximum to send to each motor + */ + virtual FourMotorPercentages inverseKinematics(float x, float y, float theta, float max); + + virtual FourMotorPercentages simpleKinematics(float left_x, float left_y, float right_x, float right_y, float max); + + ~TankDriveKinematics(); + +private: + float m_left_previous_dist; + float m_right_previous_dist; + + TankWheelLocations m_wheel_locations; +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/main.h b/old-code/v5_hal/firmware/include/main.h new file mode 100644 index 00000000..1425caa4 --- /dev/null +++ b/old-code/v5_hal/firmware/include/main.h @@ -0,0 +1,95 @@ +/** + * \file main.h + * + * Contains common definitions and header files used throughout your PROS + * project. + * + * Copyright (c) 2017-2020, 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/. + */ + +#ifndef _PROS_MAIN_H_ +#define _PROS_MAIN_H_ + +/** + * If defined, some commonly used enums will have preprocessor macros which give + * a shorter, more convenient naming pattern. If this isn't desired, simply + * comment the following line out. + * + * For instance, E_CONTROLLER_MASTER has a shorter name: CONTROLLER_MASTER. + * E_CONTROLLER_MASTER is pedantically correct within the PROS styleguide, but + * not convienent for most student programmers. + */ +#define PROS_USE_SIMPLE_NAMES + +/** + * If defined, C++ literals will be available for use. All literals are in the + * pros::literals namespace. + * + * For instance, you can do `4_mtr = 50` to set motor 4's target velocity to 50 + */ +#define PROS_USE_LITERALS + +#include "api.h" +#include "auton/auton_actions/DriveStraightAction.h" +#include "auton/auton_actions/FollowPathAction.h" +#include "eigen/Eigen/Dense" +#include "nodes/NodeManager.h" +#include "nodes/actuator_nodes/MotorNode.h" +#include "nodes/auton_nodes/AutonManagerNode.h" +#include "nodes/sensor_nodes/ADIEncoderNode.h" +#include "nodes/sensor_nodes/ControllerNode.h" +#include "nodes/sensor_nodes/InertialSensorNode.h" +#include "nodes/subsystems/drivetrain_nodes/HolonomicDriveNode.h" +#include "nodes/subsystems/drivetrain_nodes/TankDriveNode.h" +#include "nodes/system_nodes/ConnectionCheckerNode.h" +#include "pathing/PathManager.h" +#include "util/Logger.h" + +/** + * You should add more #includes here + */ +// #include "okapi/api.hpp" +// #include "pros/api_legacy.h" + +/** + * If you find doing pros::Motor() to be tedious and you'd prefer just to do + * Motor, you can use the namespace with the following commented out line. + * + * IMPORTANT: Only the okapi or pros namespace may be used, not both + * concurrently! The okapi namespace will export all symbols inside the pros + * namespace. + */ +// using namespace pros; +// using namespace pros::literals; +// using namespace okapi; + +/** + * Prototypes for the competition control tasks are redefined here to ensure + * that they can be called from user code (i.e. calling autonomous from a + * button press in opcontrol() for testing purposes). + */ +#ifdef __cplusplus +extern "C" { +#endif +void autonomous(void); +void initialize(void); +void disabled(void); +void competition_initialize(void); +void opcontrol(void); +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +/** + * You can add C++-only headers here + */ +// #include +#endif + +#endif // _PROS_MAIN_H_ diff --git a/old-code/v5_hal/firmware/include/math/Math.h b/old-code/v5_hal/firmware/include/math/Math.h new file mode 100644 index 00000000..f9cbfcd0 --- /dev/null +++ b/old-code/v5_hal/firmware/include/math/Math.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +#ifndef PI +#define PI 3.141592653589793 +#endif + +#define kEpsilon .000000001 +#define kE .000000001 + +using namespace std; + +inline double toRadians(double degrees) { + return degrees * (PI / 180.0); +} + +inline double toDegrees(double degrees) { + return degrees * (180.0 / PI); +} + +inline double arctan(double x, double y) { + double result = toDegrees(atan2(y, x)); + if(x >= 0 && y >= 0) { + return 90 - result; + } else if(x >= 0 && y < 0) { + return 90 + -1 * result; + } else if(x <= 0 && y < 0) { + return 90 + -1 * result; + } else if(x < 0 && y >= 0) { + return 450 - result; + } + return -1; +} + +inline double pathogram(double x, double y){ + return sqrt(x*x + y*y); +} + +inline double clamp(double value, double minimum, double maximum) { + if(value < minimum) { + return minimum; + } else if(value > maximum) { + return maximum; + } else { + return value; + } +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/math/Pose.h b/old-code/v5_hal/firmware/include/math/Pose.h new file mode 100644 index 00000000..a8b74ff0 --- /dev/null +++ b/old-code/v5_hal/firmware/include/math/Pose.h @@ -0,0 +1,22 @@ +#pragma once + +#include "eigen/Eigen/Dense" + +using namespace Eigen; + +struct Pose { + Vector2d position; + Rotation2Dd angle; + + Pose(Vector2d positionIn, Rotation2Dd angleIn) { + position = positionIn; + angle = angleIn; + } + + Pose() { + position = Vector2d(0, 0); + angle = Rotation2Dd(0); + } + + EIGEN_MAKE_ALIGNED_OPERATOR_NEW +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/nodes/NodeManager.h b/old-code/v5_hal/firmware/include/nodes/NodeManager.h new file mode 100644 index 00000000..b64a8ea7 --- /dev/null +++ b/old-code/v5_hal/firmware/include/nodes/NodeManager.h @@ -0,0 +1,71 @@ +#pragma once + +#include + +#include "api.h" +#include "ros_lib/ros.h" +#include "util/Constants.h" + +class Node; + +// The NodeManager class handles multiple things: +// 1) What nodes need to be called +// 2) When each node needs to be called +// +// Nodes are automatically added to the manager on creation as long as they +// inherit from the Node class below. This means you never should be calling +// addNode() explicitly! +class NodeManager { +private: + struct NodeStructure { + Node* node; + uint32_t trigger_millis; + uint32_t last_executed_millis; + }; + + std::vector m_node_structures; + + uint32_t(*m_get_millis)(void); + +protected: + +public: + ros::NodeHandle* m_handle; + NodeManager(uint32_t(*get_milliseconds)(void)); + + ros::NodeHandle* addNode(Node* node, uint32_t interval_milliseconds); + + void initialize(); + + void reset(); + + void executeTeleop(); + + void executeAuton(); + + ~NodeManager(); +}; + +// The Node class is the parent object of all Nodes on the robot. It outlines +// what a node should have, and gives us a common interface on how to interact +// with nodes. +// +// The constructor of the node object takes in a pointer to the node manager, +// which AUTOMATICALLY ADDS IT to the manager on creation. This means that you +// don't need to add nodes on your own! +// +// The interval at which a node is called is set within the Node's CPP file, in +// the superclass constructor (should look like :Node([manager], [time])) +class Node { +public: + Node(NodeManager* node_manager, uint32_t interval_milliseconds) { + m_handle = node_manager->addNode(this, interval_milliseconds); + } + + ros::NodeHandle* m_handle; + + virtual void initialize() = 0; + virtual void teleopPeriodic() {} + virtual void autonPeriodic() {} + virtual ~Node() {} +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/nodes/actuator_nodes/MotorNode.h b/old-code/v5_hal/firmware/include/nodes/actuator_nodes/MotorNode.h new file mode 100644 index 00000000..04e89c21 --- /dev/null +++ b/old-code/v5_hal/firmware/include/nodes/actuator_nodes/MotorNode.h @@ -0,0 +1,52 @@ +#pragma once + +#include "nodes/NodeManager.h" +#include "api.h" +#include "ros_lib/ros.h" +#include "ros_lib/v5_hal/V5Motor.h" +#include "ros_lib/std_msgs/Int8.h" +#include "ros_lib/std_msgs/Empty.h" + +class MotorNode : public Node { +private: + pros::Motor m_motor; + v5_hal::V5Motor m_motor_msg; + std::string m_handle_name; + std::string m_sub_publish_data_name; + std::string m_sub_move_motor_voltage_name; + ros::Publisher* m_publisher; + ros::Subscriber* m_move_motor_voltage_sub; + ros::Subscriber* m_publish_data_sub; + + void m_populateMessage(); + + void m_publishData(const std_msgs::Empty& msg); + + void m_moveMotorVoltage(const std_msgs::Int8& msg); + + int m_getMaxRPM(); + +public: + MotorNode(NodeManager* node_manager, int port_number, std::string handle_name, + bool reverse=false, pros::motor_gearset_e_t gearset=pros::E_MOTOR_GEARSET_18); + + void initialize(); + + void resetEncoder(); + + int getPosition(); + + void move(int value); + + void moveVoltage(int voltage); + + void moveVelocity(float velocity); + + void moveAbsolute(double position, int max_velocity); + + void teleopPeriodic(); + + void autonPeriodic(); + + ~MotorNode(); +}; diff --git a/old-code/v5_hal/firmware/include/nodes/auton_nodes/AutonManagerNode.h b/old-code/v5_hal/firmware/include/nodes/auton_nodes/AutonManagerNode.h new file mode 100644 index 00000000..5191f475 --- /dev/null +++ b/old-code/v5_hal/firmware/include/nodes/auton_nodes/AutonManagerNode.h @@ -0,0 +1,27 @@ +#pragma once + +#include "api.h" +#include "auton/auton_routines/TestPathAuton.h" +#include "auton/auton_routines/TestPoseAuton.h" +#include "auton/auton_routines/TestTurnAuton.h" +#include "nodes/NodeManager.h" +#include "nodes/odometry_nodes/OdometryNode.h" +#include "nodes/sensor_nodes/InertialSensorNode.h" +#include "nodes/subsystems/drivetrain_nodes/IDriveNode.h" +#include "pathing/PathManager.h" + +class AutonManagerNode : public Node { + private: + Auton* m_test_path_auton; + + public: + AutonManagerNode( + NodeManager* node_manager, IDriveNode* drive_node, + OdometryNode* odometry_node, InertialSensorNode* inertial_sensor_node); + + Auton* selected_auton; + + void initialize(); + + void autonPeriodic(); +}; diff --git a/old-code/v5_hal/firmware/include/nodes/odometry_nodes/OdometryNode.h b/old-code/v5_hal/firmware/include/nodes/odometry_nodes/OdometryNode.h new file mode 100644 index 00000000..7bc66ca5 --- /dev/null +++ b/old-code/v5_hal/firmware/include/nodes/odometry_nodes/OdometryNode.h @@ -0,0 +1,56 @@ +#pragma once + +#include "nodes/NodeManager.h" +#include "api.h" +#include "ros_lib/ros.h" +#include "nodes/subsystems/drivetrain_nodes/TankDriveNode.h" +#include "nodes/sensor_nodes/ADIEncoderNode.h" +#include "nodes/sensor_nodes/InertialSensorNode.h" +#include "nodes/actuator_nodes/MotorNode.h" +#include "odometry/Odometry.h" +#include "odometry/FollowerOdometry.h" +#include "odometry/TankOdometry.h" +#include "util/Encoders.h" +#include "eigen/Eigen/Dense" +#include "util/Logger.h" + +class OdometryNode : public Node { +public: + enum OdomConfig { + FOLLOWER, TANK + }; + + OdometryNode(NodeManager* node_manager, std::string handle_name, ADIEncoderNode* odom_encoder_1, + ADIEncoderNode* odom_encoder_2, InertialSensorNode* inertial_sensor, OdomConfig odom_config); + + OdometryNode(NodeManager* node_manager, std::string handle_name, MotorNode* motor_1, MotorNode* motor_2, + InertialSensorNode* inertial_sensor, OdomConfig odom_config); + + void initialize(); + + void setCurrentPose(Pose pose); + + Pose getCurrentPose(); + + void teleopPeriodic(); + + void autonPeriodic(); + + ~OdometryNode(); + +private: + std::string m_handle_name; + + OdomConfig m_odom_config; + + ADIEncoderNode* m_odom_encoder_1; + ADIEncoderNode* m_odom_encoder_2; + MotorNode* m_motor_1; + MotorNode* m_motor_2; + InertialSensorNode* m_inertial_sensor_node; + Eigen::Rotation2Dd m_current_angle_offset; + + Odometry* m_odom; + + Odometry* m_getOdomClass(OdomConfig odom_config); +}; diff --git a/old-code/v5_hal/firmware/include/nodes/sensor_nodes/ADIEncoderNode.h b/old-code/v5_hal/firmware/include/nodes/sensor_nodes/ADIEncoderNode.h new file mode 100644 index 00000000..051d2771 --- /dev/null +++ b/old-code/v5_hal/firmware/include/nodes/sensor_nodes/ADIEncoderNode.h @@ -0,0 +1,35 @@ +#pragma once + +#include "nodes/NodeManager.h" +#include "api.h" +#include "ros_lib/ros.h" +#include "ros_lib/std_msgs/Int32.h" +#include "ros_lib/std_msgs/Empty.h" + +class ADIEncoderNode : public Node { +private: + pros::ADIEncoder m_encoder; + std_msgs::Int32 m_encoder_msg; + std::string m_handle_name; + std::string m_sub_publish_data_name; + ros::Publisher* m_publisher; + ros::Subscriber* m_publish_data_sub; + + void m_populateMessage(); + + void m_publishData(const std_msgs::Empty& msg); + +public: + ADIEncoderNode(NodeManager* node_manager, int port_top, int port_bottom, + std::string handle_name, bool reverse=false); + + void initialize(); + + int getValue(); + + void teleopPeriodic(); + + void autonPeriodic(); + + ~ADIEncoderNode(); +}; diff --git a/old-code/v5_hal/firmware/include/nodes/sensor_nodes/ControllerNode.h b/old-code/v5_hal/firmware/include/nodes/sensor_nodes/ControllerNode.h new file mode 100644 index 00000000..22592ef9 --- /dev/null +++ b/old-code/v5_hal/firmware/include/nodes/sensor_nodes/ControllerNode.h @@ -0,0 +1,41 @@ +#pragma once + +#include "api.h" +#include "nodes/NodeManager.h" +#include "ros_lib/ros.h" +#include "ros_lib/v5_hal/V5Controller.h" +#include "ros_lib/std_msgs/String.h" +#include "pros/misc.h" +#include "ros_lib/std_msgs/Empty.h" + +class ControllerNode : public Node { +private: + pros::Controller m_controller; //Creates a new Pros Controller object + v5_hal::V5Controller m_controller_msg; //Creates a new V5Controller message object + std::string m_handle_name; //Creates a handle name to specify between objects + std::string m_sub_publish_data_name; + std::string m_sub_controller_rumble_name; + ros::Publisher* m_publisher; //Creates a new publisher object that will prepare messages for sending + ros::Subscriber* m_rumble_controller_sub; + ros::Subscriber* m_publish_data_sub; + + void m_populateMessage(); + + void m_publishData(const std_msgs::Empty& msg); + + void m_rumbleController(const std_msgs::String& msg); + +public: + ControllerNode(NodeManager* node_manager, std::string handle_name, + pros::controller_id_e_t controller_id=pros::E_CONTROLLER_MASTER); + + void initialize(); + + pros::Controller* getController(); + + void teleopPeriodic(); + + void autonPeriodic(); + + ~ControllerNode(); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/nodes/sensor_nodes/InertialSensorNode.h b/old-code/v5_hal/firmware/include/nodes/sensor_nodes/InertialSensorNode.h new file mode 100644 index 00000000..543fe116 --- /dev/null +++ b/old-code/v5_hal/firmware/include/nodes/sensor_nodes/InertialSensorNode.h @@ -0,0 +1,50 @@ +#pragma once + +#include "nodes/NodeManager.h" +#include "api.h" +#include "ros_lib/ros.h" +#include "ros_lib/v5_hal/RollPitchYaw.h" +#include "util/Logger.h" +#include "eigen/Eigen/Dense" + +class InertialSensorNode : public Node { +public: + enum SensorConfig { + V5, ROS + }; + + InertialSensorNode(NodeManager* node_manager, std::string handle_name, + int sensor_port); + + InertialSensorNode(NodeManager* node_manager, std::string handle_name, + std::string subscribe_handle); + + void initialize(); + + Eigen::Rotation2Dd getYaw(); + + bool isAtAngle(Eigen::Rotation2Dd angle); + + void reset(); + + void teleopPeriodic(); + + void autonPeriodic(); + + ~InertialSensorNode(); + +private: + pros::Imu* m_inertial_sensor = nullptr; + std::string m_handle_name; + std::string m_sub_inertial_sensor_name; + double turning_threshold = 0.1; + SensorConfig m_config; + Eigen::Rotation2Dd m_yaw; + Eigen::Rotation2Dd m_gyro_offset_angle; + + ros::Subscriber* m_inertial_sensor_sub; + + void m_handleSensorMsg(const v5_hal::RollPitchYaw& msg); + + Eigen::Rotation2Dd m_getV5Yaw(); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/nodes/subsystems/drivetrain_nodes/HolonomicDriveNode.h b/old-code/v5_hal/firmware/include/nodes/subsystems/drivetrain_nodes/HolonomicDriveNode.h new file mode 100644 index 00000000..9cfb6bd0 --- /dev/null +++ b/old-code/v5_hal/firmware/include/nodes/subsystems/drivetrain_nodes/HolonomicDriveNode.h @@ -0,0 +1,86 @@ +#pragma once + +#include "nodes/NodeManager.h" +#include "api.h" +#include "nodes/subsystems/drivetrain_nodes/IDriveNode.h" +#include "nodes/actuator_nodes/MotorNode.h" +#include "nodes/sensor_nodes/ControllerNode.h" +#include "nodes/sensor_nodes/InertialSensorNode.h" +#include "kinematics/HolonomicDriveKinematics.h" +#include "eigen/Eigen/Dense" +#include +#include + +class HolonomicDriveNode : public IDriveNode { +public: + struct HolonomicEightMotors { + MotorNode* left_front_motor; + MotorNode* left_front_motor_2; + MotorNode* left_rear_motor; + MotorNode* left_rear_motor_2; + MotorNode* right_front_motor; + MotorNode* right_front_motor_2; + MotorNode* right_rear_motor; + MotorNode* right_rear_motor_2; + }; + + HolonomicDriveNode(NodeManager* node_manager, std::string handle_name, ControllerNode* controller, InertialSensorNode* inerrtial_sensor, + HolonomicEightMotors motors, HolonomicDriveKinematics kinematics); + + void initialize(); + + void resetEncoders(); + + IDriveNode::FourMotorDriveEncoderVals getIntegratedEncoderVals(); + + void setDriveVoltage(int x_voltage, int theta_voltage); + + void setDriveVoltage(int x_voltage, int y_voltage, int theta_voltage); + + void setDriveVoltage(int left_x, int left_y, int right_x, int right_y); + + void setDriveVelocity(float x_velocity, float theta_velocity); + + void setDriveVelocity(float x_velocity, float y_velocity, float theta_velocity); + + void teleopPeriodic(); + + void autonPeriodic(); + + ~HolonomicDriveNode(); + +private: + pros::Controller* m_controller; + + InertialSensorNode* m_inertial_sensor; + + std::string m_handle_name; + + HolonomicEightMotors m_motors; + + HolonomicDriveKinematics m_kinematics; + + Eigen::Vector2d controller_target_velocity; + Eigen::Vector2d field_target_velocity; + double rotation_velocity; + + void m_setLeftFrontVoltage(int voltage); + + void m_setLeftRearVoltage(int voltage); + + void m_setRightFrontVoltage(int voltage); + + void m_setRightRearVoltage(int voltage); + + void m_setLeftFrontVelocity(float velocity); + + void m_setLeftRearVelocity(float velocity); + + void m_setRightFrontVelocity(float velocity); + + void m_setRightRearVelocity(float velocity); + + void m_fieldOrientedControl(); + + void m_tankControl(); +}; diff --git a/old-code/v5_hal/firmware/include/nodes/subsystems/drivetrain_nodes/IDriveNode.h b/old-code/v5_hal/firmware/include/nodes/subsystems/drivetrain_nodes/IDriveNode.h new file mode 100644 index 00000000..429ded37 --- /dev/null +++ b/old-code/v5_hal/firmware/include/nodes/subsystems/drivetrain_nodes/IDriveNode.h @@ -0,0 +1,36 @@ +#pragma once + +#include "nodes/NodeManager.h" +#include "api.h" + +class IDriveNode : public Node { +public: + struct FourMotorDriveEncoderVals { + int left_front_encoder_val; + int left_rear_encoder_val; + int right_front_encoder_val; + int right_rear_encoder_val; + }; + + IDriveNode(NodeManager* node_manager): Node(node_manager, 10) {}; + + virtual void initialize() = 0; + + virtual void resetEncoders() = 0; + + virtual FourMotorDriveEncoderVals getIntegratedEncoderVals() = 0; + + virtual void setDriveVoltage(int x_voltage, int theta_voltage) = 0; + + virtual void setDriveVoltage(int x_voltage, int y_voltage, int theta_voltage) {}; + + virtual void setDriveVelocity(float x_velocity, float theta_velocity) = 0; + + virtual void setDriveVelocity(float x_velocity, float y_velocity, float theta_velocity) {}; + + virtual void teleopPeriodic() {}; + + virtual void autonPeriodic() {}; + + virtual ~IDriveNode() {}; +}; diff --git a/old-code/v5_hal/firmware/include/nodes/subsystems/drivetrain_nodes/TankDriveNode.h b/old-code/v5_hal/firmware/include/nodes/subsystems/drivetrain_nodes/TankDriveNode.h new file mode 100644 index 00000000..72d5bded --- /dev/null +++ b/old-code/v5_hal/firmware/include/nodes/subsystems/drivetrain_nodes/TankDriveNode.h @@ -0,0 +1,68 @@ +#pragma once + +#include "nodes/NodeManager.h" +#include "api.h" +#include "nodes/actuator_nodes/MotorNode.h" +#include "nodes/sensor_nodes/ControllerNode.h" +#include "nodes/subsystems/drivetrain_nodes/IDriveNode.h" +#include "kinematics/TankDriveKinematics.h" + +class TankDriveNode : public IDriveNode { +public: + struct TankEightMotors { + MotorNode* left_1_motor; + MotorNode* left_2_motor; + MotorNode* left_3_motor; + MotorNode* left_4_motor; + MotorNode* right_1_motor; + MotorNode* right_2_motor; + MotorNode* right_3_motor; + MotorNode* right_4_motor; + }; + + TankDriveNode(NodeManager* node_manager, std::string handle_name, ControllerNode* controller, + TankEightMotors motors, TankDriveKinematics kinematics); + + void initialize(); + + void resetEncoders(); + + FourMotorDriveEncoderVals getIntegratedEncoderVals(); + + void setDriveVoltage(int y_voltage, int theta_voltage); + + void setDriveVoltage(int x_voltage, int y_voltage, int theta_voltage); + + void setDriveVelocity(float y_velocity, float theta_velocity); + + void setDriveVelocity(float x_velocity, float y_velocity, float theta_velocity); + + void setLeftVoltage(int voltage); + + void setRightVoltage(int voltage); + + void setLeftVelocity(float velocity); + + void setRightVelocity(float velocity); + + void teleopPeriodic(); + + void autonPeriodic(); + + ~TankDriveNode(); + +private: + pros::Controller* m_controller; + + std::string m_handle_name; + + TankEightMotors m_motors; + + TankDriveKinematics m_kinematics; + + Eigen::Vector2d controller_target_velocity; + + void m_setLeftPosition(float distance, int max_velocity); + + void m_setRightPosition(float distance, int max_velocity); +}; diff --git a/old-code/v5_hal/firmware/include/nodes/system_nodes/ConnectionCheckerNode.h b/old-code/v5_hal/firmware/include/nodes/system_nodes/ConnectionCheckerNode.h new file mode 100644 index 00000000..7cf80379 --- /dev/null +++ b/old-code/v5_hal/firmware/include/nodes/system_nodes/ConnectionCheckerNode.h @@ -0,0 +1,25 @@ +#pragma once + +#include "nodes/NodeManager.h" +#include "api.h" +#include "ros_lib/ros.h" + +class ConnectionCheckerNode : public Node { +private: + lv_style_t *notConnectedStyle; + lv_style_t *connectedStyle; + lv_obj_t * obj1; + + void m_checkStatus(); + +public: + ConnectionCheckerNode(NodeManager* node_manager); + + void initialize(); + + void teleopPeriodic(); + + void autonPeriodic(); + + ~ConnectionCheckerNode(); +}; diff --git a/old-code/v5_hal/firmware/include/odometry/FollowerOdometry.h b/old-code/v5_hal/firmware/include/odometry/FollowerOdometry.h new file mode 100644 index 00000000..8b44e97f --- /dev/null +++ b/old-code/v5_hal/firmware/include/odometry/FollowerOdometry.h @@ -0,0 +1,19 @@ +#pragma once + +#include "odometry/Odometry.h" +#include "util/Constants.h" +#include "util/Logger.h" + +#include + +class FollowerOdometry : public Odometry { +private: + bool m_previously_positive = true; + +public: + FollowerOdometry(EncoderConfig x_encoder_config, EncoderConfig y_encoder_config, Pose current_pose=Pose()); + + void Update(double x_encoder_raw_ticks, double y_encoder_raw_ticks, Rotation2Dd gyro_angle); + + ~FollowerOdometry(); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/odometry/Odometry.h b/old-code/v5_hal/firmware/include/odometry/Odometry.h new file mode 100644 index 00000000..92e84644 --- /dev/null +++ b/old-code/v5_hal/firmware/include/odometry/Odometry.h @@ -0,0 +1,38 @@ +#pragma once + +#include "api.h" +#include "math/Pose.h" +#include "math/Math.h" +#include "util/Encoders.h" +#include "util/Constants.h" + +class Odometry { +protected: + Rotation2Dd m_gyro_initial_angle; + + Pose m_robot_pose = Pose(Vector2d(0, 0), Rotation2Dd()); + + bool m_pose_reset = true; + + double m_encoder_1_ticks_to_dist; + double m_encoder_2_ticks_to_dist; + + double m_last_encoder_1_dist; + double m_last_encoder_2_dist; + + Rotation2Dd m_gyro_offset = Rotation2Dd(GYRO_OFFSET); + +public: + Odometry(EncoderConfig encoder_1_config, EncoderConfig encoder_2_config, Pose current_pose=Pose()); + + void ResetEncoderTicks(double encoder_1_ticks=0, double encoder_2_ticks=0); + + Pose GetPose(); + + void SetCurrentPose(Pose current_pose); + + virtual void Update(double encoder_1_raw_ticks, double encoder_2_raw_ticks, double track_width) {} + virtual void Update(double encoder_1_raw_ticks, double encoder_2_raw_ticks, Rotation2Dd gyro_angle) = 0; + + ~Odometry(); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/odometry/TankOdometry.h b/old-code/v5_hal/firmware/include/odometry/TankOdometry.h new file mode 100644 index 00000000..61d7a385 --- /dev/null +++ b/old-code/v5_hal/firmware/include/odometry/TankOdometry.h @@ -0,0 +1,14 @@ +#pragma once + +#include "odometry/Odometry.h" + +class TankOdometry : public Odometry { +public: + TankOdometry(EncoderConfig left_encoder_config, EncoderConfig right_encoder_config, Pose current_pose=Pose()); + + void Update(double left_encoder_raw_ticks, double right_encoder_raw_ticks, double track_width); + + void Update(double left_encoder_raw_ticks, double right_encoder_raw_ticks, Rotation2Dd gyro_angle); + + ~TankOdometry(); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/okapi/api.hpp b/old-code/v5_hal/firmware/include/okapi/api.hpp new file mode 100644 index 00000000..f5f42b51 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api.hpp @@ -0,0 +1,129 @@ +/* + * 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 + +/** @mainpage OkapiLib Index Page + * + * @section intro_sec Introduction + * + * **OkapiLib** is a PROS library for programming VEX V5 robots. This library is intended to raise + * the floor for teams with all levels of experience. New teams should have an easier time getting + * their robot up and running, and veteran teams should find that OkapiLib doesn't get in the way or + * place any limits on functionality. + * + * For tutorials on how to get the most out of OkapiLib, see the + * [Tutorials](docs/tutorials/index.md) section. For documentation on using the OkapiLib API, see + * the [API](docs/api/index.md) section. + * + * @section getting_started Getting Started + * Not sure where to start? Take a look at the + * [Getting Started](docs/tutorials/walkthrough/gettingStarted.md) tutorial. + * Once you have OkapiLib set up, check out the + * [Clawbot](docs/tutorials/walkthrough/clawbot.md) tutorial. + * + * @section using_docs Using The Documentation + * + * Start with reading the [Tutorials](docs/tutorials/index.md). Use the [API](docs/api/index.md) + * section to explore the class hierarchy. To see a list of all available classes, use the + * [Classes](annotated.html) section. + * + * This documentation has a powerful search feature, which can be brought up with the keyboard + * shortcuts `Tab` or `T`. All exports to the `okapi` namespace such as enums, constants, units, or + * functions can be found [here](@ref okapi). + */ + +#include "okapi/api/chassis/controller/chassisControllerIntegrated.hpp" +#include "okapi/api/chassis/controller/chassisControllerPid.hpp" +#include "okapi/api/chassis/controller/chassisScales.hpp" +#include "okapi/api/chassis/controller/defaultOdomChassisController.hpp" +#include "okapi/api/chassis/controller/odomChassisController.hpp" +#include "okapi/api/chassis/model/hDriveModel.hpp" +#include "okapi/api/chassis/model/readOnlyChassisModel.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp" +#include "okapi/api/chassis/model/threeEncoderXDriveModel.hpp" +#include "okapi/api/chassis/model/xDriveModel.hpp" +#include "okapi/impl/chassis/controller/chassisControllerBuilder.hpp" + +#include "okapi/api/control/async/asyncLinearMotionProfileController.hpp" +#include "okapi/api/control/async/asyncMotionProfileController.hpp" +#include "okapi/api/control/async/asyncPosIntegratedController.hpp" +#include "okapi/api/control/async/asyncPosPidController.hpp" +#include "okapi/api/control/async/asyncVelIntegratedController.hpp" +#include "okapi/api/control/async/asyncVelPidController.hpp" +#include "okapi/api/control/async/asyncWrapper.hpp" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/control/iterative/iterativeMotorVelocityController.hpp" +#include "okapi/api/control/iterative/iterativePosPidController.hpp" +#include "okapi/api/control/iterative/iterativeVelPidController.hpp" +#include "okapi/api/control/util/controllerRunner.hpp" +#include "okapi/api/control/util/flywheelSimulator.hpp" +#include "okapi/api/control/util/pidTuner.hpp" +#include "okapi/api/control/util/settledUtil.hpp" +#include "okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp" +#include "okapi/impl/control/async/asyncPosControllerBuilder.hpp" +#include "okapi/impl/control/async/asyncVelControllerBuilder.hpp" +#include "okapi/impl/control/iterative/iterativeControllerFactory.hpp" +#include "okapi/impl/control/util/controllerRunnerFactory.hpp" +#include "okapi/impl/control/util/pidTunerFactory.hpp" + +#include "okapi/api/odometry/odomMath.hpp" +#include "okapi/api/odometry/odometry.hpp" +#include "okapi/api/odometry/threeEncoderOdometry.hpp" + +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" +#include "okapi/api/device/rotarysensor/rotarySensor.hpp" +#include "okapi/impl/device/adiUltrasonic.hpp" +#include "okapi/impl/device/button/adiButton.hpp" +#include "okapi/impl/device/button/controllerButton.hpp" +#include "okapi/impl/device/controller.hpp" +#include "okapi/impl/device/motor/adiMotor.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/device/rotarysensor/IMU.hpp" +#include "okapi/impl/device/rotarysensor/adiEncoder.hpp" +#include "okapi/impl/device/rotarysensor/adiGyro.hpp" +#include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" +#include "okapi/impl/device/rotarysensor/potentiometer.hpp" + +#include "okapi/api/filter/averageFilter.hpp" +#include "okapi/api/filter/composableFilter.hpp" +#include "okapi/api/filter/demaFilter.hpp" +#include "okapi/api/filter/ekfFilter.hpp" +#include "okapi/api/filter/emaFilter.hpp" +#include "okapi/api/filter/filter.hpp" +#include "okapi/api/filter/filteredControllerInput.hpp" +#include "okapi/api/filter/medianFilter.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include "okapi/api/filter/velMath.hpp" +#include "okapi/impl/filter/velMathFactory.hpp" + +#include "okapi/api/units/QAcceleration.hpp" +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QAngularAcceleration.hpp" +#include "okapi/api/units/QAngularJerk.hpp" +#include "okapi/api/units/QAngularSpeed.hpp" +#include "okapi/api/units/QArea.hpp" +#include "okapi/api/units/QForce.hpp" +#include "okapi/api/units/QFrequency.hpp" +#include "okapi/api/units/QJerk.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/QMass.hpp" +#include "okapi/api/units/QPressure.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/QTorque.hpp" +#include "okapi/api/units/QVolume.hpp" + +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/abstractTimer.hpp" +#include "okapi/api/util/mathUtil.hpp" +#include "okapi/api/util/supplier.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include "okapi/impl/util/rate.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" +#include "okapi/impl/util/timer.hpp" diff --git a/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/chassisController.hpp b/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/chassisController.hpp new file mode 100644 index 00000000..9e3dcf9a --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/chassisController.hpp @@ -0,0 +1,142 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisScales.hpp" +#include "okapi/api/chassis/model/chassisModel.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QLength.hpp" +#include +#include + +namespace okapi { +class ChassisController { + public: + /** + * A ChassisController adds a closed-loop layer on top of a ChassisModel. moveDistance and + * turnAngle both use closed-loop control to move the robot. There are passthrough functions for + * everything defined in ChassisModel. + * + * @param imodel underlying ChassisModel + */ + explicit ChassisController() = default; + + virtual ~ChassisController() = default; + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * @param itarget distance to travel + */ + virtual void moveDistance(QLength itarget) = 0; + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * @param itarget distance to travel in motor degrees + */ + virtual void moveRaw(double itarget) = 0; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel + */ + virtual void moveDistanceAsync(QLength itarget) = 0; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel in motor degrees + */ + virtual void moveRawAsync(double itarget) = 0; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for + */ + virtual void turnAngle(QAngle idegTarget) = 0; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for in motor degrees + */ + virtual void turnRaw(double idegTarget) = 0; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for + */ + virtual void turnAngleAsync(QAngle idegTarget) = 0; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for in motor degrees + */ + virtual void turnRawAsync(double idegTarget) = 0; + + /** + * Sets whether turns should be mirrored. + * + * @param ishouldMirror whether turns should be mirrored + */ + virtual void setTurnsMirrored(bool ishouldMirror) = 0; + + /** + * Checks whether the internal controllers are currently settled. + * + * @return Whether this ChassisController is settled. + */ + virtual bool isSettled() = 0; + + /** + * Delays until the currently executing movement completes. + */ + virtual void waitUntilSettled() = 0; + + /** + * Interrupts the current movement to stop the robot. + */ + virtual void stop() = 0; + + /** + * Sets a new maximum velocity in RPM [0-600]. + * + * @param imaxVelocity The new maximum velocity. + */ + virtual void setMaxVelocity(double imaxVelocity) = 0; + + /** + * @return The maximum velocity in RPM [0-600]. + */ + virtual double getMaxVelocity() const = 0; + + /** + * Get the ChassisScales. + */ + virtual ChassisScales getChassisScales() const = 0; + + /** + * Get the GearsetRatioPair. + */ + virtual AbstractMotor::GearsetRatioPair getGearsetRatioPair() const = 0; + + /** + * @return The internal ChassisModel. + */ + virtual std::shared_ptr getModel() = 0; + + /** + * @return The internal ChassisModel. + */ + virtual ChassisModel &model() = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/chassisControllerIntegrated.hpp b/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/chassisControllerIntegrated.hpp new file mode 100644 index 00000000..6bee44ef --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/chassisControllerIntegrated.hpp @@ -0,0 +1,184 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisController.hpp" +#include "okapi/api/control/async/asyncPosIntegratedController.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" + +namespace okapi { +class ChassisControllerIntegrated : public ChassisController { + public: + /** + * ChassisController using the V5 motor's integrated control. Puts the motors into encoder count + * units. Throws a `std::invalid_argument` exception if the gear ratio is zero. The initial + * model's max velocity will be propagated to the controllers. + * + * @param itimeUtil The TimeUtil. + * @param imodel The ChassisModel used to read from sensors/write to motors. + * @param ileftController The controller used for the left side motors. + * @param irightController The controller used for the right side motors. + * @param igearset The internal gearset and external ratio used on the drive motors. + * @param iscales The ChassisScales. + * @param ilogger The logger this instance will log to. + */ + ChassisControllerIntegrated( + const TimeUtil &itimeUtil, + std::shared_ptr imodel, + std::unique_ptr ileftController, + std::unique_ptr irightController, + const AbstractMotor::GearsetRatioPair &igearset = AbstractMotor::gearset::green, + const ChassisScales &iscales = ChassisScales({1, 1}, imev5GreenTPR), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * ```cpp + * // Drive forward 6 inches + * chassis->moveDistance(6_in); + * + * // Drive backward 0.2 meters + * chassis->moveDistance(-0.2_m); + * ``` + * + * @param itarget distance to travel + */ + void moveDistance(QLength itarget) override; + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * ```cpp + * // Drive forward by spinning the motors 400 degrees + * chassis->moveRaw(400); + * ``` + * + * @param itarget distance to travel in motor degrees + */ + void moveRaw(double itarget) override; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel + */ + void moveDistanceAsync(QLength itarget) override; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel in motor degrees + */ + void moveRawAsync(double itarget) override; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * ```cpp + * // Turn 90 degrees clockwise + * chassis->turnAngle(90_deg); + * ``` + * + * @param idegTarget angle to turn for + */ + void turnAngle(QAngle idegTarget) override; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * ```cpp + * // Turn clockwise by spinning the motors 200 degrees + * chassis->turnRaw(200); + * ``` + * + * @param idegTarget angle to turn for in motor degrees + */ + void turnRaw(double idegTarget) override; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for + */ + void turnAngleAsync(QAngle idegTarget) override; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for in motor degrees + */ + void turnRawAsync(double idegTarget) override; + + /** + * Sets whether turns should be mirrored. + * + * @param ishouldMirror whether turns should be mirrored + */ + void setTurnsMirrored(bool ishouldMirror) override; + + /** + * Checks whether the internal controllers are currently settled. + * + * @return Whether this ChassisController is settled. + */ + bool isSettled() override; + + /** + * Delays until the currently executing movement completes. + */ + void waitUntilSettled() override; + + /** + * Interrupts the current movement to stop the robot. + */ + void stop() override; + + /** + * Get the ChassisScales. + */ + ChassisScales getChassisScales() const override; + + /** + * Get the GearsetRatioPair. + */ + AbstractMotor::GearsetRatioPair getGearsetRatioPair() const override; + + /** + * @return The internal ChassisModel. + */ + std::shared_ptr getModel() override; + + /** + * @return The internal ChassisModel. + */ + ChassisModel &model() override; + + /** + * Sets a new maximum velocity in RPM [0-600]. + * + * @param imaxVelocity The new maximum velocity. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * @return The maximum velocity in RPM [0-600]. + */ + double getMaxVelocity() const override; + + protected: + std::shared_ptr logger; + bool normalTurns{true}; + std::shared_ptr chassisModel; + TimeUtil timeUtil; + std::unique_ptr leftController; + std::unique_ptr rightController; + int lastTarget; + ChassisScales scales; + AbstractMotor::GearsetRatioPair gearsetRatioPair; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/chassisControllerPid.hpp b/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/chassisControllerPid.hpp new file mode 100644 index 00000000..91441ecb --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/chassisControllerPid.hpp @@ -0,0 +1,275 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisController.hpp" +#include "okapi/api/control/iterative/iterativePosPidController.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include +#include + +namespace okapi { +class ChassisControllerPID : public ChassisController { + public: + /** + * ChassisController using PID control. Puts the motors into encoder count units. Throws a + * `std::invalid_argument` exception if the gear ratio is zero. + * + * @param itimeUtil The TimeUtil. + * @param imodel The ChassisModel used to read from sensors/write to motors. + * @param idistanceController The PID controller that controls chassis distance for driving + * straight. + * @param iturnController The PID controller that controls chassis angle for turning. + * @param iangleController The PID controller that controls chassis angle for driving straight. + * @param igearset The internal gearset and external ratio used on the drive motors. + * @param iscales The ChassisScales. + * @param ilogger The logger this instance will log to. + */ + ChassisControllerPID( + TimeUtil itimeUtil, + std::shared_ptr imodel, + std::unique_ptr idistanceController, + std::unique_ptr iturnController, + std::unique_ptr iangleController, + const AbstractMotor::GearsetRatioPair &igearset = AbstractMotor::gearset::green, + const ChassisScales &iscales = ChassisScales({1, 1}, imev5GreenTPR), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + ChassisControllerPID(const ChassisControllerPID &) = delete; + ChassisControllerPID(ChassisControllerPID &&other) = delete; + ChassisControllerPID &operator=(const ChassisControllerPID &other) = delete; + ChassisControllerPID &operator=(ChassisControllerPID &&other) = delete; + + ~ChassisControllerPID() override; + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * ```cpp + * // Drive forward 6 inches + * chassis->moveDistance(6_in); + * + * // Drive backward 0.2 meters + * chassis->moveDistance(-0.2_m); + * ``` + * + * @param itarget distance to travel + */ + void moveDistance(QLength itarget) override; + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * ```cpp + * // Drive forward by spinning the motors 400 degrees + * chassis->moveRaw(400); + * ``` + * + * @param itarget distance to travel in motor degrees + */ + void moveRaw(double itarget) override; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel + */ + void moveDistanceAsync(QLength itarget) override; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel in motor degrees + */ + void moveRawAsync(double itarget) override; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * ```cpp + * // Turn 90 degrees clockwise + * chassis->turnAngle(90_deg); + * ``` + * + * @param idegTarget angle to turn for + */ + void turnAngle(QAngle idegTarget) override; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * ```cpp + * // Turn clockwise by spinning the motors 200 degrees + * chassis->turnRaw(200); + * ``` + * + * @param idegTarget angle to turn for in motor degrees + */ + void turnRaw(double idegTarget) override; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for + */ + void turnAngleAsync(QAngle idegTarget) override; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for in motor degrees + */ + void turnRawAsync(double idegTarget) override; + + /** + * Sets whether turns should be mirrored. + * + * @param ishouldMirror whether turns should be mirrored + */ + void setTurnsMirrored(bool ishouldMirror) override; + + /** + * Checks whether the internal controllers are currently settled. + * + * @return Whether this ChassisController is settled. + */ + bool isSettled() override; + + /** + * Delays until the currently executing movement completes. + */ + void waitUntilSettled() override; + + /** + * Gets the ChassisScales. + */ + ChassisScales getChassisScales() const override; + + /** + * Gets the GearsetRatioPair. + */ + AbstractMotor::GearsetRatioPair getGearsetRatioPair() const override; + + /** + * Sets the velocity mode flag. When the controller is in velocity mode, the control loop will + * set motor velocities. When the controller is in voltage mode (`ivelocityMode = false`), the + * control loop will set motor voltages. Additionally, when the controller is in voltage mode, + * it will not obey maximum velocity limits. + * + * @param ivelocityMode Whether the controller should be in velocity or voltage mode. + */ + void setVelocityMode(bool ivelocityMode); + + /** + * Sets the gains for all controllers. + * + * @param idistanceGains The distance controller gains. + * @param iturnGains The turn controller gains. + * @param iangleGains The angle controller gains. + */ + void setGains(const IterativePosPIDController::Gains &idistanceGains, + const IterativePosPIDController::Gains &iturnGains, + const IterativePosPIDController::Gains &iangleGains); + + /** + * Gets the current controller gains. + * + * @return The current controller gains in the order: distance, turn, angle. + */ + std::tuple + getGains() const; + + /** + * Starts the internal thread. This method is called by the ChassisControllerBuilder when making a + * new instance of this class. + */ + void startThread(); + + /** + * Returns the underlying thread handle. + * + * @return The underlying thread handle. + */ + CrossplatformThread *getThread() const; + + /** + * Interrupts the current movement to stop the robot. + */ + void stop() override; + + /** + * Sets a new maximum velocity in RPM [0-600]. In voltage mode, the max velocity is ignored and a + * max voltage should be set on the underlying ChassisModel instead. + * + * @param imaxVelocity The new maximum velocity. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * @return The maximum velocity in RPM [0-600]. + */ + double getMaxVelocity() const override; + + /** + * @return The internal ChassisModel. + */ + std::shared_ptr getModel() override; + + /** + * @return The internal ChassisModel. + */ + ChassisModel &model() override; + + protected: + std::shared_ptr logger; + bool normalTurns{true}; + std::shared_ptr chassisModel; + TimeUtil timeUtil; + std::unique_ptr distancePid; + std::unique_ptr turnPid; + std::unique_ptr anglePid; + ChassisScales scales; + AbstractMotor::GearsetRatioPair gearsetRatioPair; + bool velocityMode{true}; + std::atomic_bool doneLooping{true}; + std::atomic_bool doneLoopingSeen{true}; + std::atomic_bool newMovement{false}; + std::atomic_bool dtorCalled{false}; + QTime threadSleepTime{10_ms}; + + static void trampoline(void *context); + void loop(); + + /** + * Wait for the distance setup (distancePid and anglePid) to settle. + * + * @return true if done settling; false if settling should be tried again + */ + bool waitForDistanceSettled(); + + /** + * Wait for the angle setup (anglePid) to settle. + * + * @return true if done settling; false if settling should be tried again + */ + bool waitForAngleSettled(); + + /** + * Stops all the controllers and the ChassisModel. + */ + void stopAfterSettled(); + + typedef enum { distance, angle, none } modeType; + modeType mode{none}; + + CrossplatformThread *task{nullptr}; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/chassisScales.hpp b/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/chassisScales.hpp new file mode 100644 index 00000000..d4d29096 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/chassisScales.hpp @@ -0,0 +1,88 @@ +/* + * 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 + +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/RQuantity.hpp" +#include "okapi/api/util/logging.hpp" +#include +#include +#include + +namespace okapi { +class ChassisScales { + public: + /** + * The scales a ChassisController needs to do all of its closed-loop control. The first element is + * the wheel diameter, the second element is the wheel track. For three-encoder configurations, + * the length from the center of rotation to the middle wheel and the middle wheel diameter are + * passed as the third and fourth elements. + * + * The wheel track is the center-to-center distance between the wheels (center-to-center + * meaning the width between the centers of both wheels). For example, if you are using four inch + * omni wheels and there are 11.5 inches between the centers of each wheel, you would call the + * constructor like so: + * `ChassisScales scales({4_in, 11.5_in}, imev5GreenTPR); // imev5GreenTPR for a green gearset` + * + * Wheel diameter + * + * +-+ Center of rotation + * | | | + * v v +----------+ Length to middle wheel + * | | from center of rotation + * +---> === | === | + * | + v + | + * | ++---------------++ | + * | | | v + * Wheel track | | | + * | | x |+| <-- Middle wheel + * | | | + * | | | + * | ++---------------++ + * | + + + * +---> === === + * + * + * @param idimensions {wheel diameter, wheel track} or {wheel diameter, wheel track, length to + * middle wheel, middle wheel diameter}. + * @param itpr The ticks per revolution of the encoders. + * @param ilogger The logger this instance will log to. + */ + ChassisScales(const std::initializer_list &idimensions, + double itpr, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * The scales a ChassisController needs to do all of its closed-loop control. The first element is + * the straight scale, the second element is the turn scale. Optionally, the length from the + * center of rotation to the middle wheel and the middle scale can be passed as the third and + * fourth elements. The straight scale converts motor degrees to meters, the turn scale converts + * motor degrees to robot turn degrees, and the middle scale converts middle wheel degrees to + * meters. + * + * @param iscales {straight scale, turn scale} or {straight scale, turn scale, length to middle + * wheel in meters, middle scale}. + * @param itpr The ticks per revolution of the encoders. + * @param ilogger The logger this instance will log to. + */ + ChassisScales(const std::initializer_list &iscales, + double itpr, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + QLength wheelDiameter; + QLength wheelTrack; + QLength middleWheelDistance; + QLength middleWheelDiameter; + double straight; + double turn; + double middle; + double tpr; + + protected: + static void validateInputSize(std::size_t inputSize, const std::shared_ptr &logger); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/defaultOdomChassisController.hpp b/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/defaultOdomChassisController.hpp new file mode 100644 index 00000000..91bbeb8d --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/defaultOdomChassisController.hpp @@ -0,0 +1,177 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisControllerIntegrated.hpp" +#include "okapi/api/chassis/controller/odomChassisController.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/odometry/odometry.hpp" +#include + +namespace okapi { +class DefaultOdomChassisController : public OdomChassisController { + public: + /** + * Odometry based chassis controller that moves using a separately constructed chassis controller. + * Spins up a task at the default priority plus 1 for odometry when constructed. + * + * Moves the robot around in the odom frame. Instead of telling the robot to drive forward or + * turn some amount, you instead tell it to drive to a specific point on the field or turn to + * a specific angle, relative to its starting position. + * + * @param itimeUtil The TimeUtil. + * @param iodometry The odometry to read state estimates from. + * @param icontroller The chassis controller to delegate to. + * @param imode The new default StateMode used to interpret target points and query the Odometry + * state. + * @param imoveThreshold minimum length movement (smaller movements will be skipped) + * @param iturnThreshold minimum angle turn (smaller turns will be skipped) + * @param ilogger The logger this instance will log to. + */ + DefaultOdomChassisController(const TimeUtil &itimeUtil, + std::shared_ptr iodometry, + std::shared_ptr icontroller, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION, + QLength imoveThreshold = 0_mm, + QAngle iturnThreshold = 0_deg, + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + DefaultOdomChassisController(const DefaultOdomChassisController &) = delete; + DefaultOdomChassisController(DefaultOdomChassisController &&other) = delete; + DefaultOdomChassisController &operator=(const DefaultOdomChassisController &other) = delete; + DefaultOdomChassisController &operator=(DefaultOdomChassisController &&other) = delete; + + /** + * Drives the robot straight to a point in the odom frame. + * + * @param ipoint The target point to navigate to. + * @param ibackwards Whether to drive to the target point backwards. + * @param ioffset An offset from the target point in the direction pointing towards the robot. The + * robot will stop this far away from the target point. + */ + void driveToPoint(const Point &ipoint, + bool ibackwards = false, + const QLength &ioffset = 0_mm) override; + + /** + * Turns the robot to face a point in the odom frame. + * + * @param ipoint The target point to turn to face. + */ + void turnToPoint(const Point &ipoint) override; + + /** + * @return The internal ChassisController. + */ + std::shared_ptr getChassisController(); + + /** + * @return The internal ChassisController. + */ + ChassisController &chassisController(); + + /** + * This delegates to the input ChassisController. + */ + void turnToAngle(const QAngle &iangle) override; + + /** + * This delegates to the input ChassisController. + */ + void moveDistance(QLength itarget) override; + + /** + * This delegates to the input ChassisController. + */ + void moveRaw(double itarget) override; + + /** + * This delegates to the input ChassisController. + */ + void moveDistanceAsync(QLength itarget) override; + + /** + * This delegates to the input ChassisController. + */ + void moveRawAsync(double itarget) override; + + /** + * This delegates to the input ChassisController. + */ + void turnAngle(QAngle idegTarget) override; + + /** + * This delegates to the input ChassisController. + */ + void turnRaw(double idegTarget) override; + + /** + * This delegates to the input ChassisController. + */ + void turnAngleAsync(QAngle idegTarget) override; + + /** + * This delegates to the input ChassisController. + */ + void turnRawAsync(double idegTarget) override; + + /** + * This delegates to the input ChassisController. + */ + void setTurnsMirrored(bool ishouldMirror) override; + + /** + * This delegates to the input ChassisController. + */ + bool isSettled() override; + + /** + * This delegates to the input ChassisController. + */ + void waitUntilSettled() override; + + /** + * This delegates to the input ChassisController. + */ + void stop() override; + + /** + * This delegates to the input ChassisController. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * This delegates to the input ChassisController. + */ + double getMaxVelocity() const override; + + /** + * This delegates to the input ChassisController. + */ + ChassisScales getChassisScales() const override; + + /** + * This delegates to the input ChassisController. + */ + AbstractMotor::GearsetRatioPair getGearsetRatioPair() const override; + + /** + * This delegates to the input ChassisController. + */ + std::shared_ptr getModel() override; + + /** + * This delegates to the input ChassisController. + */ + ChassisModel &model() override; + + protected: + std::shared_ptr logger; + std::shared_ptr controller; + + void waitForOdomTask(); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/odomChassisController.hpp b/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/odomChassisController.hpp new file mode 100644 index 00000000..e2de53a7 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/chassis/controller/odomChassisController.hpp @@ -0,0 +1,154 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisController.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/coreProsAPI.hpp" +#include "okapi/api/odometry/odometry.hpp" +#include "okapi/api/odometry/point.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include +#include + +namespace okapi { +class OdomChassisController : public ChassisController { + public: + /** + * Odometry based chassis controller. Starts task at the default for odometry when constructed, + * which calls `Odometry::step` every `10ms`. The default StateMode is + * `StateMode::FRAME_TRANSFORMATION`. + * + * Moves the robot around in the odom frame. Instead of telling the robot to drive forward or + * turn some amount, you instead tell it to drive to a specific point on the field or turn to + * a specific angle relative to its starting position. + * + * @param itimeUtil The TimeUtil. + * @param iodometry The Odometry instance to run in a new task. + * @param imode The new default StateMode used to interpret target points and query the Odometry + * state. + * @param imoveThreshold minimum length movement (smaller movements will be skipped) + * @param iturnThreshold minimum angle turn (smaller turns will be skipped) + */ + OdomChassisController(TimeUtil itimeUtil, + std::shared_ptr iodometry, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION, + const QLength &imoveThreshold = 0_mm, + const QAngle &iturnThreshold = 0_deg, + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + ~OdomChassisController() override; + + OdomChassisController(const OdomChassisController &) = delete; + OdomChassisController(OdomChassisController &&other) = delete; + OdomChassisController &operator=(const OdomChassisController &other) = delete; + OdomChassisController &operator=(OdomChassisController &&other) = delete; + + /** + * Drives the robot straight to a point in the odom frame. + * + * @param ipoint The target point to navigate to. + * @param ibackwards Whether to drive to the target point backwards. + * @param ioffset An offset from the target point in the direction pointing towards the robot. The + * robot will stop this far away from the target point. + */ + virtual void + driveToPoint(const Point &ipoint, bool ibackwards = false, const QLength &ioffset = 0_mm) = 0; + + /** + * Turns the robot to face a point in the odom frame. + * + * @param ipoint The target point to turn to face. + */ + virtual void turnToPoint(const Point &ipoint) = 0; + + /** + * Turns the robot to face an angle in the odom frame. + * + * @param iangle The angle to turn to. + */ + virtual void turnToAngle(const QAngle &iangle) = 0; + + /** + * @return The current state. + */ + virtual OdomState getState() const; + + /** + * Set a new state to be the current state. The default StateMode is + * `StateMode::FRAME_TRANSFORMATION`. + * + * @param istate The new state in the given format. + * @param imode The mode to treat the input state as. + */ + virtual void setState(const OdomState &istate); + + /** + * Sets a default StateMode that will be used to interpret target points and query the Odometry + * state. + * + * @param imode The new default StateMode. + */ + void setDefaultStateMode(const StateMode &imode); + + /** + * Set a new move threshold. Any requested movements smaller than this threshold will be skipped. + * + * @param imoveThreshold new move threshold + */ + virtual void setMoveThreshold(const QLength &imoveThreshold); + + /** + * Set a new turn threshold. Any requested turns smaller than this threshold will be skipped. + * + * @param iturnTreshold new turn threshold + */ + virtual void setTurnThreshold(const QAngle &iturnTreshold); + + /** + * @return The current move threshold. + */ + virtual QLength getMoveThreshold() const; + + /** + * @return The current turn threshold. + */ + virtual QAngle getTurnThreshold() const; + + /** + * Starts the internal odometry thread. This should not be called by normal users. + */ + void startOdomThread(); + + /** + * @return The underlying thread handle. + */ + CrossplatformThread *getOdomThread() const; + + /** + * @return The internal odometry. + */ + std::shared_ptr getOdometry(); + + protected: + std::shared_ptr logger; + TimeUtil timeUtil; + QLength moveThreshold; + QAngle turnThreshold; + std::shared_ptr odom; + CrossplatformThread *odomTask{nullptr}; + std::atomic_bool dtorCalled{false}; + StateMode defaultStateMode{StateMode::FRAME_TRANSFORMATION}; + std::atomic_bool odomTaskRunning{false}; + + static void trampoline(void *context); + void loop(); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/chassis/model/chassisModel.hpp b/old-code/v5_hal/firmware/include/okapi/api/chassis/model/chassisModel.hpp new file mode 100644 index 00000000..efe01dbe --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/chassis/model/chassisModel.hpp @@ -0,0 +1,153 @@ +/* + * 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 + +#include "okapi/api/chassis/model/readOnlyChassisModel.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include +#include +#include +#include + +namespace okapi { +/** + * A version of the ReadOnlyChassisModel that also supports write methods, such as setting motor + * speed. Because this class can write to motors, there can only be one owner and as such copying + * is disabled. + */ +class ChassisModel : public ReadOnlyChassisModel { + public: + explicit ChassisModel() = default; + ChassisModel(const ChassisModel &) = delete; + ChassisModel &operator=(const ChassisModel &) = delete; + + /** + * Drive the robot forwards (using open-loop control). Uses velocity mode. + * + * @param ipower motor power + */ + virtual void forward(double ispeed) = 0; + + /** + * Drive the robot in an arc (using open-loop control). Uses velocity mode. + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwadSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + virtual void driveVector(double iforwardSpeed, double iyaw) = 0; + + /** + * Drive the robot in an arc. Uses voltage mode. + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwadSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + virtual void driveVectorVoltage(double iforwardSpeed, double iyaw) = 0; + + /** + * Turn the robot clockwise (using open-loop control). Uses velocity mode. + * + * @param ispeed motor power + */ + virtual void rotate(double ispeed) = 0; + + /** + * Stop the robot (set all the motors to 0). Uses velocity mode. + */ + virtual void stop() = 0; + + /** + * Drive the robot with a tank drive layout. Uses voltage mode. + * + * @param ileftSpeed left side speed + * @param irightSpeed right side speed + * @param ithreshold deadband on joystick values + */ + virtual void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) = 0; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. + * + * @param iforwardSpeed speed forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + virtual void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) = 0; + + /** + * Power the left side motors. Uses velocity mode. + * + * @param ipower motor power + */ + virtual void left(double ispeed) = 0; + + /** + * Power the right side motors. Uses velocity mode. + * + * @param ipower motor power + */ + virtual void right(double ispeed) = 0; + + /** + * Reset the sensors to their zero point. + */ + virtual void resetSensors() = 0; + + /** + * Set the brake mode for each motor. + * + * @param mode new brake mode + */ + virtual void setBrakeMode(AbstractMotor::brakeMode mode) = 0; + + /** + * Set the encoder units for each motor. + * + * @param units new motor encoder units + */ + virtual void setEncoderUnits(AbstractMotor::encoderUnits units) = 0; + + /** + * Set the gearset for each motor. + * + * @param gearset new motor gearset + */ + virtual void setGearing(AbstractMotor::gearset gearset) = 0; + + /** + * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the + * currently installed gearset. If the configured maximum velocity is greater than the attainable + * maximum velocity from the currently installed gearset, the ChassisModel will still scale to + * that velocity. + * + * @param imaxVelocity The new maximum velocity. + */ + virtual void setMaxVelocity(double imaxVelocity) = 0; + + /** + * @return The current maximum velocity. + */ + virtual double getMaxVelocity() const = 0; + + /** + * Sets a new maximum voltage in mV in the range `[0-12000]`. + * + * @param imaxVoltage The new maximum voltage. + */ + virtual void setMaxVoltage(double imaxVoltage) = 0; + + /** + * @return The maximum voltage in mV `[0-12000]`. + */ + virtual double getMaxVoltage() const = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/chassis/model/hDriveModel.hpp b/old-code/v5_hal/firmware/include/okapi/api/chassis/model/hDriveModel.hpp new file mode 100644 index 00000000..4224bf26 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/chassis/model/hDriveModel.hpp @@ -0,0 +1,224 @@ +/* + * 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 + +#include "okapi/api/chassis/model/chassisModel.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +class HDriveModel : public ChassisModel { + public: + /** + * Model for an h-drive (wheels parallel with robot's direction of motion, with an additional + * wheel perpendicular to those). When the left and right side motors are powered +100%, the robot + * should move forward in a straight line. When the middle motor is powered +100%, the robot + * should strafe right in a straight line. + * + * @param ileftSideMotor The left side motor. + * @param irightSideMotor The right side motor. + * @param imiddleMotor The middle (perpendicular) motor. + * @param ileftEnc The left side encoder. + * @param irightEnc The right side encoder. + * @param imiddleEnc The middle encoder. + */ + HDriveModel(std::shared_ptr ileftSideMotor, + std::shared_ptr irightSideMotor, + std::shared_ptr imiddleMotor, + std::shared_ptr ileftEnc, + std::shared_ptr irightEnc, + std::shared_ptr imiddleEnc, + double imaxVelocity, + double imaxVoltage); + + /** + * Drive the robot forwards (using open-loop control). Uses velocity mode. Sets the middle motor + * to zero velocity. + * + * @param ispeed motor power + */ + void forward(double ispeed) override; + + /** + * Drive the robot in an arc (using open-loop control). Uses velocity mode. Sets the middle motor + * to zero velocity. + * + * The algorithm is (approximately): + * leftPower = ySpeed + zRotation + * rightPower = ySpeed - zRotation + * + * @param iySpeed speed on y axis (forward) + * @param izRotation speed around z axis (up) + */ + void driveVector(double iySpeed, double izRotation) override; + + /** + * Drive the robot in an arc. Uses voltage mode. Sets the middle motor to zero velocity. + * + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwadSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + void driveVectorVoltage(double iforwardSpeed, double iyaw) override; + + /** + * Turn the robot clockwise (using open-loop control). Uses velocity mode. Sets the middle motor + * to zero velocity. + * + * @param ispeed motor power + */ + void rotate(double ispeed) override; + + /** + * Stop the robot (set all the motors to 0). Uses velocity mode. + */ + void stop() override; + + /** + * Drive the robot with a tank drive layout. Uses voltage mode. Sets the middle motor to zero + * velocity. + * + * @param ileftSpeed left side speed + * @param irightSpeed right side speed + * @param ithreshold deadband on joystick values + */ + void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) override; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. Sets the middle motor to zero + * velocity. + * + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) override; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. + * + * @param irightSpeed speed to the right + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + virtual void + hArcade(double irightSpeed, double iforwardSpeed, double iyaw, double ithreshold = 0); + + /** + * Power the left side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void left(double ispeed) override; + + /** + * Power the right side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void right(double ispeed) override; + + /** + * Power the middle motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + virtual void middle(double ispeed); + + /** + * Read the sensors. + * + * @return sensor readings in the format {left, right, middle} + */ + std::valarray getSensorVals() const override; + + /** + * Reset the sensors to their zero point. + */ + void resetSensors() override; + + /** + * Set the brake mode for each motor. + * + * @param mode new brake mode + */ + void setBrakeMode(AbstractMotor::brakeMode mode) override; + + /** + * Set the encoder units for each motor. + * + * @param units new motor encoder units + */ + void setEncoderUnits(AbstractMotor::encoderUnits units) override; + + /** + * Set the gearset for each motor. + * + * @param gearset new motor gearset + */ + void setGearing(AbstractMotor::gearset gearset) override; + + /** + * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the + * currently installed gearset. If the configured maximum velocity is greater than the attainable + * maximum velocity from the currently installed gearset, the ChassisModel will still scale to + * that velocity. + * + * @param imaxVelocity The new maximum velocity. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * @return The current maximum velocity. + */ + double getMaxVelocity() const override; + + /** + * Sets a new maximum voltage in mV in the range `[0-12000]`. + * + * @param imaxVoltage The new maximum voltage. + */ + void setMaxVoltage(double imaxVoltage) override; + + /** + * @return The maximum voltage in mV in the range `[0-12000]`. + */ + double getMaxVoltage() const override; + + /** + * Returns the left side motor. + * + * @return the left side motor + */ + std::shared_ptr getLeftSideMotor() const; + + /** + * Returns the left side motor. + * + * @return the left side motor + */ + std::shared_ptr getRightSideMotor() const; + + /** + * @return The middle motor. + */ + std::shared_ptr getMiddleMotor() const; + + protected: + double maxVelocity; + double maxVoltage; + std::shared_ptr leftSideMotor; + std::shared_ptr rightSideMotor; + std::shared_ptr middleMotor; + std::shared_ptr leftSensor; + std::shared_ptr rightSensor; + std::shared_ptr middleSensor; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/chassis/model/readOnlyChassisModel.hpp b/old-code/v5_hal/firmware/include/okapi/api/chassis/model/readOnlyChassisModel.hpp new file mode 100644 index 00000000..01526f16 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/chassis/model/readOnlyChassisModel.hpp @@ -0,0 +1,28 @@ +/* + * 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 + +#include "okapi/api/coreProsAPI.hpp" +#include + +namespace okapi { +/** + * A version of the ChassisModel that only supports read methods, such as querying sensor values. + * This class does not let you write to motors, so it supports having multiple owners and as a + * result copying is enabled. + */ +class ReadOnlyChassisModel { + public: + virtual ~ReadOnlyChassisModel() = default; + + /** + * Read the sensors. + * + * @return sensor readings (format is implementation dependent) + */ + virtual std::valarray getSensorVals() const = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/chassis/model/skidSteerModel.hpp b/old-code/v5_hal/firmware/include/okapi/api/chassis/model/skidSteerModel.hpp new file mode 100644 index 00000000..6a2ae6f0 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/chassis/model/skidSteerModel.hpp @@ -0,0 +1,186 @@ +/* + * 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 + +#include "okapi/api/chassis/model/chassisModel.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +class SkidSteerModel : public ChassisModel { + public: + /** + * Model for a skid steer drive (wheels parallel with robot's direction of motion). When all + * motors are powered +100%, the robot should move forward in a straight line. + * + * @param ileftSideMotor The left side motor. + * @param irightSideMotor The right side motor. + * @param ileftEnc The left side encoder. + * @param irightEnc The right side encoder. + */ + SkidSteerModel(std::shared_ptr ileftSideMotor, + std::shared_ptr irightSideMotor, + std::shared_ptr ileftEnc, + std::shared_ptr irightEnc, + double imaxVelocity, + double imaxVoltage); + + /** + * Drive the robot forwards (using open-loop control). Uses velocity mode. + * + * @param ispeed motor power + */ + void forward(double ispeed) override; + + /** + * Drive the robot in an arc (using open-loop control). Uses velocity mode. + * The algorithm is (approximately): + * leftPower = ySpeed + zRotation + * rightPower = ySpeed - zRotation + * + * @param iySpeed speed on y axis (forward) + * @param izRotation speed around z axis (up) + */ + void driveVector(double iySpeed, double izRotation) override; + + /** + * Drive the robot in an arc. Uses voltage mode. + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwadSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + void driveVectorVoltage(double iforwardSpeed, double iyaw) override; + + /** + * Turn the robot clockwise (using open-loop control). Uses velocity mode. + * + * @param ispeed motor power + */ + void rotate(double ispeed) override; + + /** + * Stop the robot (set all the motors to 0). Uses velocity mode. + */ + void stop() override; + + /** + * Drive the robot with a tank drive layout. Uses voltage mode. + * + * @param ileftSpeed left side speed + * @param irightSpeed right side speed + * @param ithreshold deadband on joystick values + */ + void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) override; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. + * + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) override; + + /** + * Power the left side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void left(double ispeed) override; + + /** + * Power the right side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void right(double ispeed) override; + + /** + * Read the sensors. + * + * @return sensor readings in the format {left, right} + */ + std::valarray getSensorVals() const override; + + /** + * Reset the sensors to their zero point. + */ + void resetSensors() override; + + /** + * Set the brake mode for each motor. + * + * @param mode new brake mode + */ + void setBrakeMode(AbstractMotor::brakeMode mode) override; + + /** + * Set the encoder units for each motor. + * + * @param units new motor encoder units + */ + void setEncoderUnits(AbstractMotor::encoderUnits units) override; + + /** + * Set the gearset for each motor. + * + * @param gearset new motor gearset + */ + void setGearing(AbstractMotor::gearset gearset) override; + + /** + * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the + * currently installed gearset. If the configured maximum velocity is greater than the attainable + * maximum velocity from the currently installed gearset, the ChassisModel will still scale to + * that velocity. + * + * @param imaxVelocity The new maximum velocity. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * @return The current maximum velocity. + */ + double getMaxVelocity() const override; + + /** + * Sets a new maximum voltage in mV in the range `[0-12000]`. + * + * @param imaxVoltage The new maximum voltage. + */ + void setMaxVoltage(double imaxVoltage) override; + + /** + * @return The maximum voltage in mV in the range `[0-12000]`. + */ + double getMaxVoltage() const override; + + /** + * Returns the left side motor. + * + * @return the left side motor + */ + std::shared_ptr getLeftSideMotor() const; + + /** + * Returns the left side motor. + * + * @return the left side motor + */ + std::shared_ptr getRightSideMotor() const; + + protected: + double maxVelocity; + double maxVoltage; + std::shared_ptr leftSideMotor; + std::shared_ptr rightSideMotor; + std::shared_ptr leftSensor; + std::shared_ptr rightSensor; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp b/old-code/v5_hal/firmware/include/okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp new file mode 100644 index 00000000..2acbe3c9 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp @@ -0,0 +1,46 @@ +/* + * 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 + +#include "okapi/api/chassis/model/skidSteerModel.hpp" + +namespace okapi { +class ThreeEncoderSkidSteerModel : public SkidSteerModel { + public: + /** + * Model for a skid steer drive (wheels parallel with robot's direction of motion). When all + * motors are powered +127, the robot should move forward in a straight line. + * + * @param ileftSideMotor left side motor + * @param irightSideMotor right side motor + * @param ileftEnc left side encoder + * @param imiddleEnc middle encoder (mounted perpendicular to the left and right side encoders) + * @param irightEnc right side encoder + */ + ThreeEncoderSkidSteerModel(std::shared_ptr ileftSideMotor, + std::shared_ptr irightSideMotor, + std::shared_ptr ileftEnc, + std::shared_ptr irightEnc, + std::shared_ptr imiddleEnc, + double imaxVelocity, + double imaxVoltage); + + /** + * Read the sensors. + * + * @return sensor readings in the format {left, right, middle} + */ + std::valarray getSensorVals() const override; + + /** + * Reset the sensors to their zero point. + */ + void resetSensors() override; + + protected: + std::shared_ptr middleSensor; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/chassis/model/threeEncoderXDriveModel.hpp b/old-code/v5_hal/firmware/include/okapi/api/chassis/model/threeEncoderXDriveModel.hpp new file mode 100644 index 00000000..14e4ee04 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/chassis/model/threeEncoderXDriveModel.hpp @@ -0,0 +1,50 @@ +/* + * 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 + +#include "okapi/api/chassis/model/xDriveModel.hpp" + +namespace okapi { +class ThreeEncoderXDriveModel : public XDriveModel { + public: + /** + * Model for an x drive (wheels at 45 deg from a skid steer drive). When all motors are powered + * +100%, the robot should move forward in a straight line. + * + * @param itopLeftMotor The top left motor. + * @param itopRightMotor The top right motor. + * @param ibottomRightMotor The bottom right motor. + * @param ibottomLeftMotor The bottom left motor. + * @param ileftEnc The left side encoder. + * @param irightEnc The right side encoder. + * @param imiddleEnc The middle encoder. + */ + ThreeEncoderXDriveModel(std::shared_ptr itopLeftMotor, + std::shared_ptr itopRightMotor, + std::shared_ptr ibottomRightMotor, + std::shared_ptr ibottomLeftMotor, + std::shared_ptr ileftEnc, + std::shared_ptr irightEnc, + std::shared_ptr imiddleEnc, + double imaxVelocity, + double imaxVoltage); + + /** + * Read the sensors. + * + * @return sensor readings in the format {left, right, middle} + */ + std::valarray getSensorVals() const override; + + /** + * Reset the sensors to their zero point. + */ + void resetSensors() override; + + protected: + std::shared_ptr middleSensor; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/chassis/model/xDriveModel.hpp b/old-code/v5_hal/firmware/include/okapi/api/chassis/model/xDriveModel.hpp new file mode 100644 index 00000000..29874eab --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/chassis/model/xDriveModel.hpp @@ -0,0 +1,239 @@ +/* + * 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 + +#include "okapi/api/chassis/model/chassisModel.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +class XDriveModel : public ChassisModel { + public: + /** + * Model for an x drive (wheels at 45 deg from a skid steer drive). When all motors are powered + * +100%, the robot should move forward in a straight line. + * + * @param itopLeftMotor The top left motor. + * @param itopRightMotor The top right motor. + * @param ibottomRightMotor The bottom right motor. + * @param ibottomLeftMotor The bottom left motor. + * @param ileftEnc The left side encoder. + * @param irightEnc The right side encoder. + */ + XDriveModel(std::shared_ptr itopLeftMotor, + std::shared_ptr itopRightMotor, + std::shared_ptr ibottomRightMotor, + std::shared_ptr ibottomLeftMotor, + std::shared_ptr ileftEnc, + std::shared_ptr irightEnc, + double imaxVelocity, + double imaxVoltage); + + /** + * Drive the robot forwards (using open-loop control). Uses velocity mode. + * + * @param ispeed motor power + */ + void forward(double ipower) override; + + /** + * Drive the robot in an arc (using open-loop control). Uses velocity mode. + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + void driveVector(double iforwardSpeed, double iyaw) override; + + /** + * Drive the robot in an arc. Uses voltage mode. + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwadSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + void driveVectorVoltage(double iforwardSpeed, double iyaw) override; + + /** + * Turn the robot clockwise (using open-loop control). Uses velocity mode. + * + * @param ipower motor power + */ + void rotate(double ipower) override; + + /** + * Drive the robot side-ways (using open-loop control) where positive ipower is + * to the right and negative ipower is to the left. Uses velocity mode. + * + * @param ispeed motor power + */ + void strafe(double ipower); + + /** + * Strafe the robot in an arc (using open-loop control) where positive istrafeSpeed is + * to the right and negative istrafeSpeed is to the left. Uses velocity mode. + * The algorithm is (approximately): + * topLeftPower = -1 * istrafeSpeed + yaw + * topRightPower = istrafeSpeed - yaw + * bottomRightPower = -1 * istrafeSpeed - yaw + * bottomLeftPower = istrafeSpeed + yaw + * + * @param istrafeSpeed speed to the right + * @param iyaw speed around the vertical axis + */ + void strafeVector(double istrafeSpeed, double iyaw); + + /** + * Stop the robot (set all the motors to 0). Uses velocity mode. + */ + void stop() override; + + /** + * Drive the robot with a tank drive layout. Uses voltage mode. + * + * @param ileftSpeed left side speed + * @param irightSpeed right side speed + * @param ithreshold deadband on joystick values + */ + void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) override; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. + * + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) override; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. + * + * @param irightSpeed speed to the right + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + virtual void + xArcade(double irightSpeed, double iforwardSpeed, double iyaw, double ithreshold = 0); + + /** + * Power the left side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void left(double ispeed) override; + + /** + * Power the right side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void right(double ispeed) override; + + /** + * Read the sensors. + * + * @return sensor readings in the format {left, right} + */ + std::valarray getSensorVals() const override; + + /** + * Reset the sensors to their zero point. + */ + void resetSensors() override; + + /** + * Set the brake mode for each motor. + * + * @param mode new brake mode + */ + void setBrakeMode(AbstractMotor::brakeMode mode) override; + + /** + * Set the encoder units for each motor. + * + * @param units new motor encoder units + */ + void setEncoderUnits(AbstractMotor::encoderUnits units) override; + + /** + * Set the gearset for each motor. + * + * @param gearset new motor gearset + */ + void setGearing(AbstractMotor::gearset gearset) override; + + /** + * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the + * currently installed gearset. If the configured maximum velocity is greater than the attainable + * maximum velocity from the currently installed gearset, the ChassisModel will still scale to + * that velocity. + * + * @param imaxVelocity The new maximum velocity. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * @return The current maximum velocity. + */ + double getMaxVelocity() const override; + + /** + * Sets a new maximum voltage in mV in the range `[0-12000]`. + * + * @param imaxVoltage The new maximum voltage. + */ + void setMaxVoltage(double imaxVoltage) override; + + /** + * @return The maximum voltage in mV in the range `[0-12000]`. + */ + double getMaxVoltage() const override; + + /** + * Returns the top left motor. + * + * @return the top left motor + */ + std::shared_ptr getTopLeftMotor() const; + + /** + * Returns the top right motor. + * + * @return the top right motor + */ + std::shared_ptr getTopRightMotor() const; + + /** + * Returns the bottom right motor. + * + * @return the bottom right motor + */ + std::shared_ptr getBottomRightMotor() const; + + /** + * Returns the bottom left motor. + * + * @return the bottom left motor + */ + std::shared_ptr getBottomLeftMotor() const; + + protected: + double maxVelocity; + double maxVoltage; + std::shared_ptr topLeftMotor; + std::shared_ptr topRightMotor; + std::shared_ptr bottomRightMotor; + std::shared_ptr bottomLeftMotor; + std::shared_ptr leftSensor; + std::shared_ptr rightSensor; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncController.hpp new file mode 100644 index 00000000..e0da0da0 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncController.hpp @@ -0,0 +1,24 @@ +/* + * 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 + +#include "okapi/api/control/closedLoopController.hpp" + +namespace okapi { +/** + * Closed-loop controller that steps on its own in another thread and automatically writes to the + * output. + */ +template +class AsyncController : public ClosedLoopController { + public: + /** + * Blocks the current task until the controller has settled. Determining what settling means is + * implementation-dependent. + */ + virtual void waitUntilSettled() = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncLinearMotionProfileController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncLinearMotionProfileController.hpp new file mode 100644 index 00000000..284e10ea --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncLinearMotionProfileController.hpp @@ -0,0 +1,307 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncPositionController.hpp" +#include "okapi/api/control/util/pathfinderUtil.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/units/QAngularSpeed.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include + +extern "C" { +#include "okapi/pathfinder/include/pathfinder.h" +} + +namespace okapi { +class AsyncLinearMotionProfileController : public AsyncPositionController { + public: + /** + * An Async Controller which generates and follows 1D motion profiles. + * + * @param itimeUtil The TimeUtil. + * @param ilimits The default limits. + * @param ioutput The output to write velocity targets to. + * @param idiameter The effective diameter for whatever the motor spins. + * @param ipair The gearset. + * @param ilogger The logger this instance will log to. + */ + AsyncLinearMotionProfileController( + const TimeUtil &itimeUtil, + const PathfinderLimits &ilimits, + const std::shared_ptr> &ioutput, + const QLength &idiameter, + const AbstractMotor::GearsetRatioPair &ipair, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + AsyncLinearMotionProfileController(AsyncLinearMotionProfileController &&other) = delete; + + AsyncLinearMotionProfileController & + operator=(AsyncLinearMotionProfileController &&other) = delete; + + ~AsyncLinearMotionProfileController() override; + + /** + * Generates a path which intersects the given waypoints and saves it internally with a key of + * pathId. Call `executePath()` with the same `pathId` to run it. + * + * If the waypoints form a path which is impossible to achieve, an instance of + * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there + * are no waypoints, no path is generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ipathId A unique identifier to save the path with. + */ + void generatePath(std::initializer_list iwaypoints, const std::string &ipathId); + + /** + * Generates a path which intersects the given waypoints and saves it internally with a key of + * pathId. Call `executePath()` with the same pathId to run it. + * + * If the waypoints form a path which is impossible to achieve, an instance of + * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there + * are no waypoints, no path is generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ipathId A unique identifier to save the path with. + * @param ilimits The limits to use for this path only. + */ + void generatePath(std::initializer_list iwaypoints, + const std::string &ipathId, + const PathfinderLimits &ilimits); + + /** + * Removes a path and frees the memory it used. This function returns `true` if the path was + * either deleted or didn't exist in the first place. It returns `false` if the path could not be + * removed because it is running. + * + * @param ipathId A unique identifier for the path, previously passed to generatePath() + * @return `true` if the path no longer exists + */ + bool removePath(const std::string &ipathId); + + /** + * Gets the identifiers of all paths saved in this `AsyncMotionProfileController`. + * + * @return The identifiers of all paths + */ + std::vector getPaths(); + + /** + * Executes a path with the given ID. If there is no path matching the ID, the method will + * return. Any targets set while a path is being followed will be ignored. + * + * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. + */ + void setTarget(std::string ipathId) override; + + /** + * Executes a path with the given ID. If there is no path matching the ID, the method will + * return. Any targets set while a path is being followed will be ignored. + * + * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. + * @param ibackwards Whether to follow the profile backwards. + */ + void setTarget(std::string ipathId, bool ibackwards); + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. + * + * This just calls `setTarget()`. + */ + void controllerSet(std::string ivalue) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + std::string getTarget() override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + virtual std::string getTarget() const; + + /** + * This is overridden to return the current path. + * + * @return The most recent value of the process variable. + */ + std::string getProcessValue() const override; + + /** + * Blocks the current task until the controller has settled. This controller is settled when + * it has finished following a path. If no path is being followed, it is settled. + */ + void waitUntilSettled() override; + + /** + * Generates a new path from the position (typically the current position) to the target and + * blocks until the controller has settled. Does not save the path which was generated. + * + * @param iposition The starting position. + * @param itarget The target position. + * @param ibackwards Whether to follow the profile backwards. + */ + void moveTo(const QLength &iposition, const QLength &itarget, bool ibackwards = false); + + /** + * Generates a new path from the position (typically the current position) to the target and + * blocks until the controller has settled. Does not save the path which was generated. + * + * @param iposition The starting position. + * @param itarget The target position. + * @param ilimits The limits to use for this path only. + * @param ibackwards Whether to follow the profile backwards. + */ + void moveTo(const QLength &iposition, + const QLength &itarget, + const PathfinderLimits &ilimits, + bool ibackwards = false); + + /** + * Returns the last error of the controller. Does not update when disabled. Returns zero if there + * is no path currently being followed. + * + * @return the last error + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return `true`. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. This implementation also stops movement. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * NOT cause the controller to move to its last set target. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * NOT cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * This implementation does nothing because the API always requires the starting position to be + * specified. + */ + void tarePosition() override; + + /** + * This implementation does nothing because the maximum velocity is configured using + * PathfinderLimits elsewhere. + * + * @param imaxVelocity Ignored. + */ + void setMaxVelocity(std::int32_t imaxVelocity) override; + + /** + * Starts the internal thread. This should not be called by normal users. This method is called + * by the AsyncControllerFactory when making a new instance of this class. + */ + void startThread(); + + /** + * Returns the underlying thread handle. + * + * @return The underlying thread handle. + */ + CrossplatformThread *getThread() const; + + /** + * Attempts to remove a path without stopping execution, then if that fails, disables the + * controller and removes the path. + * + * @param ipathId The path ID that will be removed + */ + void forceRemovePath(const std::string &ipathId); + + protected: + using TrajectoryPtr = std::unique_ptr; + using SegmentPtr = std::unique_ptr; + + struct TrajectoryPair { + SegmentPtr segment; + int length; + }; + + std::shared_ptr logger; + std::map paths{}; + PathfinderLimits limits; + std::shared_ptr> output; + QLength diameter; + AbstractMotor::GearsetRatioPair pair; + double currentProfilePosition{0}; + TimeUtil timeUtil; + + // This must be locked when accessing the current path + CrossplatformMutex currentPathMutex; + + std::string currentPath{""}; + std::atomic_bool isRunning{false}; + std::atomic_int direction{1}; + std::atomic_bool disabled{false}; + std::atomic_bool dtorCalled{false}; + CrossplatformThread *task{nullptr}; + + static void trampoline(void *context); + void loop(); + + /** + * Follow the supplied path. Must follow the disabled lifecycle. + */ + virtual void executeSinglePath(const TrajectoryPair &path, std::unique_ptr rate); + + /** + * Converts linear "chassis" speed to rotational motor speed. + * + * @param linear "chassis" frame speed + * @return motor frame speed + */ + QAngularSpeed convertLinearToRotational(QSpeed linear) const; + + std::string + getPathErrorMessage(const std::vector &points, const std::string &ipathId, int length); + + /** + * Reads the length of the path in a thread-safe manner. + * + * @param path The path to read from. + * @return The length of the path. + */ + int getPathLength(const TrajectoryPair &path); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncMotionProfileController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncMotionProfileController.hpp new file mode 100644 index 00000000..6f42823d --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncMotionProfileController.hpp @@ -0,0 +1,333 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisScales.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/control/async/asyncPositionController.hpp" +#include "okapi/api/control/util/pathfinderUtil.hpp" +#include "okapi/api/units/QAngularSpeed.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include + +extern "C" { +#include "okapi/pathfinder/include/pathfinder.h" +} + +namespace okapi { +class AsyncMotionProfileController : public AsyncPositionController { + public: + /** + * An Async Controller which generates and follows 2D motion profiles. Throws a + * `std::invalid_argument` exception if the gear ratio is zero. + * + * @param itimeUtil The TimeUtil. + * @param ilimits The default limits. + * @param imodel The chassis model to control. + * @param iscales The chassis dimensions. + * @param ipair The gearset. + * @param ilogger The logger this instance will log to. + */ + AsyncMotionProfileController(const TimeUtil &itimeUtil, + const PathfinderLimits &ilimits, + const std::shared_ptr &imodel, + const ChassisScales &iscales, + const AbstractMotor::GearsetRatioPair &ipair, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + AsyncMotionProfileController(AsyncMotionProfileController &&other) = delete; + + AsyncMotionProfileController &operator=(AsyncMotionProfileController &&other) = delete; + + ~AsyncMotionProfileController() override; + + /** + * Generates a path which intersects the given waypoints and saves it internally with a key of + * pathId. Call `executePath()` with the same pathId to run it. + * + * If the waypoints form a path which is impossible to achieve, an instance of + * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there + * are no waypoints, no path is generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ipathId A unique identifier to save the path with. + */ + void generatePath(std::initializer_list iwaypoints, const std::string &ipathId); + + /** + * Generates a path which intersects the given waypoints and saves it internally with a key of + * pathId. Call `executePath()` with the same pathId to run it. + * + * If the waypoints form a path which is impossible to achieve, an instance of + * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there + * are no waypoints, no path is generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ipathId A unique identifier to save the path with. + * @param ilimits The limits to use for this path only. + */ + void generatePath(std::initializer_list iwaypoints, + const std::string &ipathId, + const PathfinderLimits &ilimits); + + /** + * Removes a path and frees the memory it used. This function returns true if the path was either + * deleted or didn't exist in the first place. It returns false if the path could not be removed + * because it is running. + * + * @param ipathId A unique identifier for the path, previously passed to `generatePath()` + * @return True if the path no longer exists + */ + bool removePath(const std::string &ipathId); + + /** + * Gets the identifiers of all paths saved in this `AsyncMotionProfileController`. + * + * @return The identifiers of all paths + */ + std::vector getPaths(); + + /** + * Executes a path with the given ID. If there is no path matching the ID, the method will + * return. Any targets set while a path is being followed will be ignored. + * + * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. + */ + void setTarget(std::string ipathId) override; + + /** + * Executes a path with the given ID. If there is no path matching the ID, the method will + * return. Any targets set while a path is being followed will be ignored. + * + * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. + * @param ibackwards Whether to follow the profile backwards. + * @param imirrored Whether to follow the profile mirrored. + */ + void setTarget(std::string ipathId, bool ibackwards, bool imirrored = false); + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. This just calls `setTarget()`. + */ + void controllerSet(std::string ivalue) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + std::string getTarget() override; + + /** + * This is overridden to return the current path. + * + * @return The most recent value of the process variable. + */ + std::string getProcessValue() const override; + + /** + * Blocks the current task until the controller has settled. This controller is settled when + * it has finished following a path. If no path is being followed, it is settled. + */ + void waitUntilSettled() override; + + /** + * Generates a new path from the position (typically the current position) to the target and + * blocks until the controller has settled. Does not save the path which was generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ibackwards Whether to follow the profile backwards. + * @param imirrored Whether to follow the profile mirrored. + */ + void moveTo(std::initializer_list iwaypoints, + bool ibackwards = false, + bool imirrored = false); + + /** + * Generates a new path from the position (typically the current position) to the target and + * blocks until the controller has settled. Does not save the path which was generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ilimits The limits to use for this path only. + * @param ibackwards Whether to follow the profile backwards. + * @param imirrored Whether to follow the profile mirrored. + */ + void moveTo(std::initializer_list iwaypoints, + const PathfinderLimits &ilimits, + bool ibackwards = false, + bool imirrored = false); + + /** + * Returns the last error of the controller. Does not update when disabled. This implementation + * always returns zero since the robot is assumed to perfectly follow the path. Subclasses can + * override this to be more accurate using odometry information. + * + * @return the last error + */ + PathfinderPoint getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Resets the controller so it can start from 0 again properly. Keeps configuration from + * before. This implementation also stops movement. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * NOT cause the controller to move to its last set target. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * NOT cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * This implementation does nothing because the API always requires the starting position to be + * specified. + */ + void tarePosition() override; + + /** + * This implementation does nothing because the maximum velocity is configured using + * PathfinderLimits elsewhere. + * + * @param imaxVelocity Ignored. + */ + void setMaxVelocity(std::int32_t imaxVelocity) override; + + /** + * Starts the internal thread. This should not be called by normal users. This method is called + * by the `AsyncMotionProfileControllerBuilder` when making a new instance of this class. + */ + void startThread(); + + /** + * @return The underlying thread handle. + */ + CrossplatformThread *getThread() const; + + /** + * Saves a generated path to files. Paths are stored as `..csv`. An SD card + * must be inserted into the brain and the directory must exist. `idirectory` can be prefixed with + * `/usd/`, but it this is not required. + * + * @param idirectory The directory to store the path files in + * @param ipathId The path ID of the generated path + */ + void storePath(const std::string &idirectory, const std::string &ipathId); + + /** + * Loads a path from a directory on the SD card containing path CSV files. `/usd/` is + * automatically prepended to `idirectory` if it is not specified. + * + * @param idirectory The directory that the path files are stored in + * @param ipathId The path ID that the paths are stored under (and will be loaded into) + */ + void loadPath(const std::string &idirectory, const std::string &ipathId); + + /** + * Attempts to remove a path without stopping execution. If that fails, disables the controller + * and removes the path. + * + * @param ipathId The path ID that will be removed + */ + void forceRemovePath(const std::string &ipathId); + + protected: + using TrajectoryPtr = std::unique_ptr; + using SegmentPtr = std::unique_ptr; + + struct TrajectoryPair { + SegmentPtr left; + SegmentPtr right; + int length; + }; + + std::shared_ptr logger; + std::map paths{}; + PathfinderLimits limits; + std::shared_ptr model; + ChassisScales scales; + AbstractMotor::GearsetRatioPair pair; + TimeUtil timeUtil; + + // This must be locked when accessing the current path + CrossplatformMutex currentPathMutex; + + std::string currentPath{""}; + std::atomic_bool isRunning{false}; + std::atomic_int direction{1}; + std::atomic_bool mirrored{false}; + std::atomic_bool disabled{false}; + std::atomic_bool dtorCalled{false}; + CrossplatformThread *task{nullptr}; + + static void trampoline(void *context); + void loop(); + + /** + * Follow the supplied path. Must follow the disabled lifecycle. + */ + virtual void executeSinglePath(const TrajectoryPair &path, std::unique_ptr rate); + + /** + * Converts linear chassis speed to rotational motor speed. + * + * @param linear chassis frame speed + * @return motor frame speed + */ + QAngularSpeed convertLinearToRotational(QSpeed linear) const; + + std::string + getPathErrorMessage(const std::vector &points, const std::string &ipathId, int length); + + /** + * Joins and escapes a directory and file name + * + * @param directory The directory path, separated by forward slashes (/) and with or without a + * trailing slash + * @param filename The file name in the directory + * @return the fully qualified and legal path name + */ + static std::string makeFilePath(const std::string &directory, const std::string &filename); + + void internalStorePath(FILE *leftPathFile, FILE *rightPathFile, const std::string &ipathId); + void internalLoadPath(FILE *leftPathFile, FILE *rightPathFile, const std::string &ipathId); + + /** + * Reads the length of the path in a thread-safe manner. + * + * @param path The path to read from. + * @return The length of the path. + */ + int getPathLength(const TrajectoryPair &path); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncPosIntegratedController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncPosIntegratedController.hpp new file mode 100644 index 00000000..1b479769 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncPosIntegratedController.hpp @@ -0,0 +1,145 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncPositionController.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" + +namespace okapi { +/** + * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are whatever + * units the motor is in. + */ +class AsyncPosIntegratedController : public AsyncPositionController { + public: + /** + * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are + * whatever units the motor is in. Throws a std::invalid_argument exception if the gear ratio is + * zero. + * + * @param imotor The motor to control. + * @param ipair The gearset. + * @param imaxVelocity The maximum velocity after gearing. + * @param itimeUtil The TimeUtil. + * @param ilogger The logger this instance will log to. + */ + AsyncPosIntegratedController(const std::shared_ptr &imotor, + const AbstractMotor::GearsetRatioPair &ipair, + std::int32_t imaxVelocity, + const TimeUtil &itimeUtil, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the target for the controller. + */ + void setTarget(double itarget) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() override; + + /** + * @return The most recent value of the process variable. + */ + double getProcessValue() const override; + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * Blocks the current task until the controller has settled. Determining what settling means is + * implementation-dependent. + */ + void waitUntilSettled() override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be [-1, 1]. + * + * @param ivalue the controller's output in the range [-1, 1] + */ + void controllerSet(double ivalue) override; + + /** + * Sets the "absolute" zero position of the controller to its current position. + */ + void tarePosition() override; + + /** + * Sets a new maximum velocity in motor RPM [0-600]. + * + * @param imaxVelocity The new maximum velocity in motor RPM [0-600]. + */ + void setMaxVelocity(std::int32_t imaxVelocity) override; + + /** + * Stops the motor mid-movement. Does not change the last set target. + */ + virtual void stop(); + + protected: + std::shared_ptr logger; + TimeUtil timeUtil; + std::shared_ptr motor; + AbstractMotor::GearsetRatioPair pair; + std::int32_t maxVelocity; + double lastTarget{0}; + double offset{0}; + bool controllerIsDisabled{false}; + bool hasFirstTarget{false}; + std::unique_ptr settledUtil; + + /** + * Resumes moving after the controller is reset. Should not cause movement if the controller is + * turned off, reset, and turned back on. + */ + virtual void resumeMovement(); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncPosPidController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncPosPidController.hpp new file mode 100644 index 00000000..0621a03e --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncPosPidController.hpp @@ -0,0 +1,100 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncPositionController.hpp" +#include "okapi/api/control/async/asyncWrapper.hpp" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/control/iterative/iterativePosPidController.hpp" +#include "okapi/api/control/offsettableControllerInput.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include + +namespace okapi { +class AsyncPosPIDController : public AsyncWrapper, + public AsyncPositionController { + public: + /** + * An async position PID controller. + * + * @param iinput The controller input. Will be turned into an OffsettableControllerInput. + * @param ioutput The controller output. + * @param itimeUtil The TimeUtil. + * @param ikP The proportional gain. + * @param ikI The integral gain. + * @param ikD The derivative gain. + * @param ikBias The controller bias. + * @param iratio Any external gear ratio. + * @param iderivativeFilter The derivative filter. + */ + AsyncPosPIDController( + const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + const TimeUtil &itimeUtil, + double ikP, + double ikI, + double ikD, + double ikBias = 0, + double iratio = 1, + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * An async position PID controller. + * + * @param iinput The controller input. + * @param ioutput The controller output. + * @param itimeUtil The TimeUtil. + * @param ikP The proportional gain. + * @param ikI The integral gain. + * @param ikD The derivative gain. + * @param ikBias The controller bias. + * @param iratio Any external gear ratio. + * @param iderivativeFilter The derivative filter. + */ + AsyncPosPIDController( + const std::shared_ptr &iinput, + const std::shared_ptr> &ioutput, + const TimeUtil &itimeUtil, + double ikP, + double ikI, + double ikD, + double ikBias = 0, + double iratio = 1, + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the "absolute" zero position of the controller to its current position. + */ + void tarePosition() override; + + /** + * This implementation does not respect the maximum velocity. + * + * @param imaxVelocity Ignored. + */ + void setMaxVelocity(std::int32_t imaxVelocity) override; + + /** + * Set controller gains. + * + * @param igains The new gains. + */ + void setGains(const IterativePosPIDController::Gains &igains); + + /** + * Gets the current gains. + * + * @return The current gains. + */ + IterativePosPIDController::Gains getGains() const; + + protected: + std::shared_ptr offsettableInput; + std::shared_ptr internalController; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncPositionController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncPositionController.hpp new file mode 100644 index 00000000..9ed954f7 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncPositionController.hpp @@ -0,0 +1,28 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncController.hpp" +#include + +namespace okapi { +template +class AsyncPositionController : virtual public AsyncController { + public: + /** + * Sets the "absolute" zero position of the controller to its current position. + */ + virtual void tarePosition() = 0; + + /** + * Sets a new maximum velocity (typically motor RPM [0-600]). The interpretation of the units + * of this velocity and whether it will be respected is implementation-dependent. + * + * @param imaxVelocity The new maximum velocity. + */ + virtual void setMaxVelocity(std::int32_t imaxVelocity) = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncVelIntegratedController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncVelIntegratedController.hpp new file mode 100644 index 00000000..19d3ae17 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncVelIntegratedController.hpp @@ -0,0 +1,124 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncVelocityController.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include + +namespace okapi { +/** + * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are whatever + * units the motor is in. + */ +class AsyncVelIntegratedController : public AsyncVelocityController { + public: + /** + * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are + * whatever units the motor is in. Throws a std::invalid_argument exception if the gear ratio is + * zero. + * + * @param imotor The motor to control. + * @param ipair The gearset. + * @param imaxVelocity The maximum velocity after gearing. + * @param itimeUtil The TimeUtil. + * @param ilogger The logger this instance will log to. + */ + AsyncVelIntegratedController(const std::shared_ptr &imotor, + const AbstractMotor::GearsetRatioPair &ipair, + std::int32_t imaxVelocity, + const TimeUtil &itimeUtil, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the target for the controller. + */ + void setTarget(double itarget) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() override; + + /** + * @return The most recent value of the process variable. + */ + double getProcessValue() const override; + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * Blocks the current task until the controller has settled. Determining what settling means is + * implementation-dependent. + */ + void waitUntilSettled() override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be [-1, 1]. + * + * @param ivalue the controller's output in the range [-1, 1] + */ + void controllerSet(double ivalue) override; + + protected: + std::shared_ptr logger; + TimeUtil timeUtil; + std::shared_ptr motor; + AbstractMotor::GearsetRatioPair pair; + std::int32_t maxVelocity; + double lastTarget = 0; + bool controllerIsDisabled = false; + bool hasFirstTarget = false; + std::unique_ptr settledUtil; + + virtual void resumeMovement(); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncVelPidController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncVelPidController.hpp new file mode 100644 index 00000000..cd19d07c --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncVelPidController.hpp @@ -0,0 +1,64 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncVelocityController.hpp" +#include "okapi/api/control/async/asyncWrapper.hpp" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/control/iterative/iterativeVelPidController.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include + +namespace okapi { +class AsyncVelPIDController : public AsyncWrapper, + public AsyncVelocityController { + public: + /** + * An async velocity PID controller. + * + * @param iinput The controller input. + * @param ioutput The controller output. + * @param itimeUtil The TimeUtil. + * @param ikP The proportional gain. + * @param ikD The derivative gain. + * @param ikF The feed-forward gain. + * @param ikSF A feed-forward gain to counteract static friction. + * @param ivelMath The VelMath used for calculating velocity. + * @param iratio Any external gear ratio. + * @param iderivativeFilter The derivative filter. + */ + AsyncVelPIDController( + const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + const TimeUtil &itimeUtil, + double ikP, + double ikD, + double ikF, + double ikSF, + std::unique_ptr ivelMath, + double iratio = 1, + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Set controller gains. + * + * @param igains The new gains. + */ + void setGains(const IterativeVelPIDController::Gains &igains); + + /** + * Gets the current gains. + * + * @return The current gains. + */ + IterativeVelPIDController::Gains getGains() const; + + protected: + std::shared_ptr internalController; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncVelocityController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncVelocityController.hpp new file mode 100644 index 00000000..10888130 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncVelocityController.hpp @@ -0,0 +1,14 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncController.hpp" +#include + +namespace okapi { +template +class AsyncVelocityController : virtual public AsyncController {}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncWrapper.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncWrapper.hpp new file mode 100644 index 00000000..d53ef452 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/async/asyncWrapper.hpp @@ -0,0 +1,287 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncController.hpp" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/control/iterative/iterativeController.hpp" +#include "okapi/api/control/util/settledUtil.hpp" +#include "okapi/api/coreProsAPI.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/mathUtil.hpp" +#include "okapi/api/util/supplier.hpp" +#include +#include + +namespace okapi { +template +class AsyncWrapper : virtual public AsyncController { + public: + /** + * A wrapper class that transforms an `IterativeController` into an `AsyncController` by running + * it in another task. The input controller will act like an `AsyncController`. + * + * @param iinput controller input, passed to the `IterativeController` + * @param ioutput controller output, written to from the `IterativeController` + * @param icontroller the controller to use + * @param irateSupplier used for rates used in the main loop and in `waitUntilSettled` + * @param iratio Any external gear ratio. + * @param ilogger The logger this instance will log to. + */ + AsyncWrapper(const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + const std::shared_ptr> &icontroller, + const Supplier> &irateSupplier, + const double iratio = 1, + std::shared_ptr ilogger = Logger::getDefaultLogger()) + : logger(std::move(ilogger)), + rateSupplier(irateSupplier), + input(iinput), + output(ioutput), + controller(icontroller), + ratio(iratio) { + } + + AsyncWrapper(AsyncWrapper &&other) = delete; + + AsyncWrapper &operator=(AsyncWrapper &&other) = delete; + + ~AsyncWrapper() override { + dtorCalled.store(true, std::memory_order_release); + delete task; + } + + /** + * Sets the target for the controller. + */ + void setTarget(const Input itarget) override { + LOG_INFO("AsyncWrapper: Set target to " + std::to_string(itarget)); + hasFirstTarget = true; + controller->setTarget(itarget * ratio); + lastTarget = itarget; + } + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. + * + * @param ivalue the controller's output + */ + void controllerSet(const Input ivalue) override { + controller->controllerSet(ivalue); + } + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + Input getTarget() override { + return controller->getTarget(); + } + + /** + * @return The most recent value of the process variable. + */ + Input getProcessValue() const override { + return controller->getProcessValue(); + } + + /** + * Returns the last calculated output of the controller. + */ + Output getOutput() const { + return controller->getOutput(); + } + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + Output getError() const override { + return controller->getError(); + } + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override { + return isDisabled() || controller->isSettled(); + } + + /** + * Set time between loops. + * + * @param isampleTime time between loops + */ + void setSampleTime(const QTime &isampleTime) { + controller->setSampleTime(isampleTime); + } + + /** + * Set controller output bounds. + * + * @param imax max output + * @param imin min output + */ + void setOutputLimits(const Output imax, const Output imin) { + controller->setOutputLimits(imax, imin); + } + + /** + * Sets the (soft) limits for the target range that controllerSet() scales into. The target + * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. + * + * @param itargetMax The new max target for controllerSet(). + * @param itargetMin The new min target for controllerSet(). + */ + void setControllerSetTargetLimits(double itargetMax, double itargetMin) { + controller->setControllerSetTargetLimits(itargetMax, itargetMin); + } + + /** + * Get the upper output bound. + * + * @return the upper output bound + */ + Output getMaxOutput() { + return controller->getMaxOutput(); + } + + /** + * Get the lower output bound. + * + * @return the lower output bound + */ + Output getMinOutput() { + return controller->getMinOutput(); + } + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override { + LOG_INFO_S("AsyncWrapper: Reset"); + controller->reset(); + hasFirstTarget = false; + } + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override { + LOG_INFO("AsyncWrapper: flipDisable " + std::to_string(!controller->isDisabled())); + controller->flipDisable(); + resumeMovement(); + } + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(const bool iisDisabled) override { + LOG_INFO("AsyncWrapper: flipDisable " + std::to_string(iisDisabled)); + controller->flipDisable(iisDisabled); + resumeMovement(); + } + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override { + return controller->isDisabled(); + } + + /** + * Blocks the current task until the controller has settled. Determining what settling means is + * implementation-dependent. + */ + void waitUntilSettled() override { + LOG_INFO_S("AsyncWrapper: Waiting to settle"); + + auto rate = rateSupplier.get(); + while (!isSettled()) { + rate->delayUntil(motorUpdateRate); + } + + LOG_INFO_S("AsyncWrapper: Done waiting to settle"); + } + + /** + * Starts the internal thread. This should not be called by normal users. This method is called + * by the AsyncControllerFactory when making a new instance of this class. + */ + void startThread() { + if (!task) { + task = new CrossplatformThread(trampoline, this, "AsyncWrapper"); + } + } + + /** + * Returns the underlying thread handle. + * + * @return The underlying thread handle. + */ + CrossplatformThread *getThread() const { + return task; + } + + protected: + std::shared_ptr logger; + Supplier> rateSupplier; + std::shared_ptr> input; + std::shared_ptr> output; + std::shared_ptr> controller; + bool hasFirstTarget{false}; + Input lastTarget; + double ratio; + std::atomic_bool dtorCalled{false}; + CrossplatformThread *task{nullptr}; + + static void trampoline(void *context) { + if (context) { + static_cast(context)->loop(); + } + } + + void loop() { + auto rate = rateSupplier.get(); + while (!dtorCalled.load(std::memory_order_acquire) && !task->notifyTake(0)) { + if (!isDisabled()) { + output->controllerSet(controller->step(input->controllerGet())); + } + + rate->delayUntil(controller->getSampleTime()); + } + } + + /** + * Resumes moving after the controller is reset. Should not cause movement if the controller is + * turned off, reset, and turned back on. + */ + virtual void resumeMovement() { + if (isDisabled()) { + // This will grab the output *when disabled* + output->controllerSet(controller->getOutput()); + } else { + if (hasFirstTarget) { + setTarget(lastTarget); + } + } + } +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/closedLoopController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/closedLoopController.hpp new file mode 100644 index 00000000..90ce6c5f --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/closedLoopController.hpp @@ -0,0 +1,86 @@ +/* + * 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 + +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/units/QTime.hpp" + +namespace okapi { +/** + * An abstract closed-loop controller. + * + * @tparam Input The target/input type. + * @tparam Output The error/output type. + */ +template +class ClosedLoopController : public ControllerOutput { + public: + virtual ~ClosedLoopController() = default; + + /** + * Sets the target for the controller. + * + * @param itarget the new target + */ + virtual void setTarget(Input itarget) = 0; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + virtual Input getTarget() = 0; + + /** + * @return The most recent value of the process variable. + */ + virtual Input getProcessValue() const = 0; + + /** + * Returns the last error of the controller. Does not update when disabled. + * + * @return the last error + */ + virtual Output getError() const = 0; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return `true`. + * + * @return whether the controller is settled + */ + virtual bool isSettled() = 0; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + virtual void reset() = 0; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + virtual void flipDisable() = 0; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + virtual void flipDisable(bool iisDisabled) = 0; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + virtual bool isDisabled() const = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/controllerInput.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/controllerInput.hpp new file mode 100644 index 00000000..399ed9e8 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/controllerInput.hpp @@ -0,0 +1,19 @@ +/* + * 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 + +namespace okapi { +template class ControllerInput { + public: + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + virtual T controllerGet() = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/controllerOutput.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/controllerOutput.hpp new file mode 100644 index 00000000..f016f5e1 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/controllerOutput.hpp @@ -0,0 +1,19 @@ +/* + * 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 + +namespace okapi { +template class ControllerOutput { + public: + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be `[-1, 1]`. + * + * @param ivalue the controller's output in the range `[-1, 1]` + */ + virtual void controllerSet(T ivalue) = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativeController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativeController.hpp new file mode 100644 index 00000000..6bf4a077 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativeController.hpp @@ -0,0 +1,79 @@ +/* + * 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 + +#include "okapi/api/control/closedLoopController.hpp" +#include "okapi/api/units/QTime.hpp" + +namespace okapi { +/** + * Closed-loop controller that steps iteratively using the step method below. + * + * `ControllerOutput::controllerSet()` should set the controller's target to the input scaled by + * the output bounds. + */ +template +class IterativeController : public ClosedLoopController { + public: + /** + * Do one iteration of the controller. + * + * @param ireading A new measurement. + * @return The controller output. + */ + virtual Output step(Input ireading) = 0; + + /** + * Returns the last calculated output of the controller. + */ + virtual Output getOutput() const = 0; + + /** + * Set controller output bounds. + * + * @param imax max output + * @param imin min output + */ + virtual void setOutputLimits(Output imax, Output imin) = 0; + + /** + * Sets the (soft) limits for the target range that controllerSet() scales into. The target + * computed by `controllerSet()` is scaled into the range `[-itargetMin, itargetMax]`. + * + * @param itargetMax The new max target for `controllerSet()`. + * @param itargetMin The new min target for `controllerSet()`. + */ + virtual void setControllerSetTargetLimits(Output itargetMax, Output itargetMin) = 0; + + /** + * Get the upper output bound. + * + * @return the upper output bound + */ + virtual Output getMaxOutput() = 0; + + /** + * Get the lower output bound. + * + * @return the lower output bound + */ + virtual Output getMinOutput() = 0; + + /** + * Set time between loops. + * + * @param isampleTime time between loops + */ + virtual void setSampleTime(QTime isampleTime) = 0; + + /** + * Get the last set sample time. + * + * @return sample time + */ + virtual QTime getSampleTime() const = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativeMotorVelocityController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativeMotorVelocityController.hpp new file mode 100644 index 00000000..05e83c9e --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativeMotorVelocityController.hpp @@ -0,0 +1,150 @@ +/* + * 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 + +#include "okapi/api/control/iterative/iterativeVelocityController.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include +#include + +namespace okapi { +class IterativeMotorVelocityController : public IterativeVelocityController { + public: + /** + * Velocity controller that automatically writes to the motor. + */ + IterativeMotorVelocityController( + const std::shared_ptr &imotor, + const std::shared_ptr> &icontroller); + + /** + * Do one iteration of the controller. + * + * @param inewReading new measurement + * @return controller output + */ + double step(double ireading) override; + + /** + * Sets the target for the controller. + */ + void setTarget(double itarget) override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be `[-1, 1]`. + * + * @param ivalue the controller's output in the range `[-1, 1]` + */ + void controllerSet(double ivalue) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() override; + + /** + * @return The most recent value of the process variable. + */ + double getProcessValue() const override; + + /** + * Returns the last calculated output of the controller. + */ + double getOutput() const override; + + /** + * Get the upper output bound. + * + * @return the upper output bound + */ + double getMaxOutput() override; + + /** + * Get the lower output bound. + * + * @return the lower output bound + */ + double getMinOutput() override; + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Set time between loops in ms. + * + * @param isampleTime time between loops in ms + */ + void setSampleTime(QTime isampleTime) override; + + /** + * Set controller output bounds. + * + * @param imax max output + * @param imin min output + */ + void setOutputLimits(double imax, double imin) override; + + /** + * Sets the (soft) limits for the target range that controllerSet() scales into. The target + * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. + * + * @param itargetMax The new max target for controllerSet(). + * @param itargetMin The new min target for controllerSet(). + */ + void setControllerSetTargetLimits(double itargetMax, double itargetMin) override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * Get the last set sample time. + * + * @return sample time + */ + QTime getSampleTime() const override; + + protected: + std::shared_ptr motor; + std::shared_ptr> controller; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativePosPidController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativePosPidController.hpp new file mode 100644 index 00000000..eca96fb0 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativePosPidController.hpp @@ -0,0 +1,276 @@ +/* + * Based on the Arduino PID controller: https://github.com/br3ttb/Arduino-PID-Library + * + * 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 + +#include "okapi/api/control/iterative/iterativePositionController.hpp" +#include "okapi/api/control/util/settledUtil.hpp" +#include "okapi/api/filter/filter.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include + +namespace okapi { +class IterativePosPIDController : public IterativePositionController { + public: + struct Gains { + double kP{0}; + double kI{0}; + double kD{0}; + double kBias{0}; + + bool operator==(const Gains &rhs) const; + bool operator!=(const Gains &rhs) const; + }; + + /** + * Position PID controller. + * + * @param ikP the proportional gain + * @param ikI the integration gain + * @param ikD the derivative gain + * @param ikBias the controller bias + * @param itimeUtil see TimeUtil docs + * @param iderivativeFilter a filter for filtering the derivative term + * @param ilogger The logger this instance will log to. + */ + IterativePosPIDController( + double ikP, + double ikI, + double ikD, + double ikBias, + const TimeUtil &itimeUtil, + std::unique_ptr iderivativeFilter = std::make_unique(), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + /** + * Position PID controller. + * + * @param igains the controller gains + * @param itimeUtil see TimeUtil docs + * @param iderivativeFilter a filter for filtering the derivative term + */ + IterativePosPIDController( + const Gains &igains, + const TimeUtil &itimeUtil, + std::unique_ptr iderivativeFilter = std::make_unique(), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + /** + * Do one iteration of the controller. Returns the reading in the range [-1, 1] unless the + * bounds have been changed with setOutputLimits(). + * + * @param inewReading new measurement + * @return controller output + */ + double step(double inewReading) override; + + /** + * Sets the target for the controller. + * + * @param itarget new target position + */ + void setTarget(double itarget) override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be [-1, 1]. + * + * @param ivalue the controller's output in the range [-1, 1] + */ + void controllerSet(double ivalue) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() const; + + /** + * @return The most recent value of the process variable. + */ + double getProcessValue() const override; + + /** + * Returns the last calculated output of the controller. Output is in the range [-1, 1] + * unless the bounds have been changed with setOutputLimits(). + */ + double getOutput() const override; + + /** + * Get the upper output bound. + * + * @return the upper output bound + */ + double getMaxOutput() override; + + /** + * Get the lower output bound. + * + * @return the lower output bound + */ + double getMinOutput() override; + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Set time between loops in ms. + * + * @param isampleTime time between loops + */ + void setSampleTime(QTime isampleTime) override; + + /** + * Set controller output bounds. Default bounds are [-1, 1]. + * + * @param imax max output + * @param imin min output + */ + void setOutputLimits(double imax, double imin) override; + + /** + * Sets the (soft) limits for the target range that controllerSet() scales into. The target + * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. + * + * @param itargetMax The new max target for controllerSet(). + * @param itargetMin The new min target for controllerSet(). + */ + void setControllerSetTargetLimits(double itargetMax, double itargetMin) override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * Get the last set sample time. + * + * @return sample time + */ + QTime getSampleTime() const override; + + /** + * Set integrator bounds. Default bounds are [-1, 1]. + * + * @param imax max integrator value + * @param imin min integrator value + */ + virtual void setIntegralLimits(double imax, double imin); + + /** + * Set the error sum bounds. Default bounds are [0, std::numeric_limits::max()]. Error + * will only be added to the integral term when its absolute value is between these bounds of + * either side of the target. + * + * @param imax max error value that will be summed + * @param imin min error value that will be summed + */ + virtual void setErrorSumLimits(double imax, double imin); + + /** + * Set whether the integrator should be reset when error is 0 or changes sign. + * + * @param iresetOnZero true to reset + */ + virtual void setIntegratorReset(bool iresetOnZero); + + /** + * Set controller gains. + * + * @param igains The new gains. + */ + virtual void setGains(const Gains &igains); + + /** + * Gets the current gains. + * + * @return The current gains. + */ + Gains getGains() const; + + protected: + std::shared_ptr logger; + double kP, kI, kD, kBias; + QTime sampleTime{10_ms}; + double target{0}; + double lastReading{0}; + double error{0}; + double lastError{0}; + std::unique_ptr derivativeFilter; + + // Integral bounds + double integral{0}; + double integralMax{1}; + double integralMin{-1}; + + // Error will only be added to the integral term within these bounds on either side of the target + double errorSumMin{0}; + double errorSumMax{std::numeric_limits::max()}; + + double derivative{0}; + + // Output bounds + double output{0}; + double outputMax{1}; + double outputMin{-1}; + double controllerSetTargetMax{1}; + double controllerSetTargetMin{-1}; + + // Reset the integrated when the controller crosses 0 or not + bool shouldResetOnCross{true}; + + bool controllerIsDisabled{false}; + + std::unique_ptr loopDtTimer; + std::unique_ptr settledUtil; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativePositionController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativePositionController.hpp new file mode 100644 index 00000000..6da33e6a --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativePositionController.hpp @@ -0,0 +1,13 @@ +/* + * 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 + +#include "okapi/api/control/iterative/iterativeController.hpp" + +namespace okapi { +template +class IterativePositionController : public IterativeController {}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativeVelPidController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativeVelPidController.hpp new file mode 100644 index 00000000..910554f1 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativeVelPidController.hpp @@ -0,0 +1,255 @@ +/* + * 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 + +#include "okapi/api/control/iterative/iterativeVelocityController.hpp" +#include "okapi/api/control/util/settledUtil.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include "okapi/api/filter/velMath.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" + +namespace okapi { +class IterativeVelPIDController : public IterativeVelocityController { + public: + struct Gains { + double kP{0}; + double kD{0}; + double kF{0}; + double kSF{0}; + + bool operator==(const Gains &rhs) const; + bool operator!=(const Gains &rhs) const; + }; + + /** + * Velocity PD controller. + * + * @param ikP the proportional gain + * @param ikD the derivative gain + * @param ikF the feed-forward gain + * @param ikSF a feed-forward gain to counteract static friction + * @param ivelMath The VelMath used for calculating velocity. + * @param itimeUtil see TimeUtil docs + * @param iderivativeFilter a filter for filtering the derivative term + * @param ilogger The logger this instance will log to. + */ + IterativeVelPIDController( + double ikP, + double ikD, + double ikF, + double ikSF, + std::unique_ptr ivelMath, + const TimeUtil &itimeUtil, + std::unique_ptr iderivativeFilter = std::make_unique(), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + /** + * Velocity PD controller. + * + * @param igains The controller gains. + * @param ivelMath The VelMath used for calculating velocity. + * @param itimeUtil see TimeUtil docs + * @param iderivativeFilter a filter for filtering the derivative term + * @param ilogger The logger this instance will log to. + */ + IterativeVelPIDController( + const Gains &igains, + std::unique_ptr ivelMath, + const TimeUtil &itimeUtil, + std::unique_ptr iderivativeFilter = std::make_unique(), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + /** + * Do one iteration of the controller. Returns the reading in the range [-1, 1] unless the + * bounds have been changed with setOutputLimits(). + * + * @param inewReading new measurement + * @return controller output + */ + double step(double inewReading) override; + + /** + * Sets the target for the controller. + * + * @param itarget new target velocity + */ + void setTarget(double itarget) override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be [-1, 1]. + * + * @param ivalue the controller's output in the range [-1, 1] + */ + void controllerSet(double ivalue) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() const; + + /** + * @return The most recent value of the process variable. + */ + double getProcessValue() const override; + + /** + * Returns the last calculated output of the controller. + */ + double getOutput() const override; + + /** + * Get the upper output bound. + * + * @return the upper output bound + */ + double getMaxOutput() override; + + /** + * Get the lower output bound. + * + * @return the lower output bound + */ + double getMinOutput() override; + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Set time between loops in ms. + * + * @param isampleTime time between loops + */ + void setSampleTime(QTime isampleTime) override; + + /** + * Set controller output bounds. Default bounds are [-1, 1]. + * + * @param imax max output + * @param imin min output + */ + void setOutputLimits(double imax, double imin) override; + + /** + * Sets the (soft) limits for the target range that controllerSet() scales into. The target + * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. + * + * @param itargetMax The new max target for controllerSet(). + * @param itargetMin The new min target for controllerSet(). + */ + void setControllerSetTargetLimits(double itargetMax, double itargetMin) override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * Get the last set sample time. + * + * @return sample time + */ + QTime getSampleTime() const override; + + /** + * Do one iteration of velocity calculation. + * + * @param inewReading new measurement + * @return filtered velocity + */ + virtual QAngularSpeed stepVel(double inewReading); + + /** + * Set controller gains. + * + * @param igains The new gains. + */ + virtual void setGains(const Gains &igains); + + /** + * Gets the current gains. + * + * @return The current gains. + */ + Gains getGains() const; + + /** + * Sets the number of encoder ticks per revolution. Default is 1800. + * + * @param tpr number of measured units per revolution + */ + virtual void setTicksPerRev(double tpr); + + /** + * Returns the current velocity. + */ + virtual QAngularSpeed getVel() const; + + protected: + std::shared_ptr logger; + double kP, kD, kF, kSF; + QTime sampleTime{10_ms}; + double error{0}; + double derivative{0}; + double target{0}; + double outputSum{0}; + double output{0}; + double outputMax{1}; + double outputMin{-1}; + double controllerSetTargetMax{1}; + double controllerSetTargetMin{-1}; + bool controllerIsDisabled{false}; + + std::unique_ptr velMath; + std::unique_ptr derivativeFilter; + std::unique_ptr loopDtTimer; + std::unique_ptr settledUtil; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativeVelocityController.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativeVelocityController.hpp new file mode 100644 index 00000000..5e78264d --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/iterative/iterativeVelocityController.hpp @@ -0,0 +1,13 @@ +/* + * 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 + +#include "okapi/api/control/iterative/iterativeController.hpp" + +namespace okapi { +template +class IterativeVelocityController : public IterativeController {}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/offsettableControllerInput.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/offsettableControllerInput.hpp new file mode 100644 index 00000000..8f022019 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/offsettableControllerInput.hpp @@ -0,0 +1,41 @@ +/* + * 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 + +#include "okapi/api/control/controllerInput.hpp" +#include + +namespace okapi { +class OffsetableControllerInput : public ControllerInput { + public: + /** + * A ControllerInput which can be tared to change the zero position. + * + * @param iinput The ControllerInput to reference. + */ + explicit OffsetableControllerInput(const std::shared_ptr> &iinput); + + virtual ~OffsetableControllerInput(); + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or PROS_ERR on a failure. + */ + double controllerGet() override; + + /** + * Sets the "absolute" zero position of this controller input to its current position. This does + * nothing if the underlying controller input returns PROS_ERR. + */ + virtual void tarePosition(); + + protected: + std::shared_ptr> input; + double offset{0}; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/util/controllerRunner.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/util/controllerRunner.hpp new file mode 100644 index 00000000..29a1ebd7 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/util/controllerRunner.hpp @@ -0,0 +1,131 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncController.hpp" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/control/iterative/iterativeController.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include + +namespace okapi { +template class ControllerRunner { + public: + /** + * A utility class that runs a closed-loop controller. + * + * @param itimeUtil The TimeUtil. + * @param ilogger The logger this instance will log to. + */ + explicit ControllerRunner(const TimeUtil &itimeUtil, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()) + : logger(ilogger), rate(itimeUtil.getRate()) { + } + + /** + * Runs the controller until it has settled. + * + * @param itarget the new target + * @param icontroller the controller to run + * @return the error when settled + */ + virtual Output runUntilSettled(const Input itarget, AsyncController &icontroller) { + LOG_INFO("ControllerRunner: runUntilSettled(AsyncController): Set target to " + + std::to_string(itarget)); + icontroller.setTarget(itarget); + + while (!icontroller.isSettled()) { + rate->delayUntil(10_ms); + } + + LOG_INFO("ControllerRunner: runUntilSettled(AsyncController): Done waiting to settle"); + return icontroller.getError(); + } + + /** + * Runs the controller until it has settled. + * + * @param itarget the new target + * @param icontroller the controller to run + * @param ioutput the output to write to + * @return the error when settled + */ + virtual Output runUntilSettled(const Input itarget, + IterativeController &icontroller, + ControllerOutput &ioutput) { + LOG_INFO("ControllerRunner: runUntilSettled(IterativeController): Set target to " + + std::to_string(itarget)); + icontroller.setTarget(itarget); + + while (!icontroller.isSettled()) { + ioutput.controllerSet(icontroller.getOutput()); + rate->delayUntil(10_ms); + } + + LOG_INFO("ControllerRunner: runUntilSettled(IterativeController): Done waiting to settle"); + return icontroller.getError(); + } + + /** + * Runs the controller until it has reached its target, but not necessarily settled. + * + * @param itarget the new target + * @param icontroller the controller to run + * @return the error when settled + */ + virtual Output runUntilAtTarget(const Input itarget, + AsyncController &icontroller) { + LOG_INFO("ControllerRunner: runUntilAtTarget(AsyncController): Set target to " + + std::to_string(itarget)); + icontroller.setTarget(itarget); + + double error = icontroller.getError(); + double lastError = error; + while (error != 0 && std::copysign(1.0, error) == std::copysign(1.0, lastError)) { + lastError = error; + rate->delayUntil(10_ms); + error = icontroller.getError(); + } + + LOG_INFO("ControllerRunner: runUntilAtTarget(AsyncController): Done waiting to settle"); + return icontroller.getError(); + } + + /** + * Runs the controller until it has reached its target, but not necessarily settled. + * + * @param itarget the new target + * @param icontroller the controller to run + * @param ioutput the output to write to + * @return the error when settled + */ + virtual Output runUntilAtTarget(const Input itarget, + IterativeController &icontroller, + ControllerOutput &ioutput) { + LOG_INFO("ControllerRunner: runUntilAtTarget(IterativeController): Set target to " + + std::to_string(itarget)); + icontroller.setTarget(itarget); + + double error = icontroller.getError(); + double lastError = error; + while (error != 0 && std::copysign(1.0, error) == std::copysign(1.0, lastError)) { + ioutput.controllerSet(icontroller.getOutput()); + lastError = error; + rate->delayUntil(10_ms); + error = icontroller.getError(); + } + + LOG_INFO("ControllerRunner: runUntilAtTarget(IterativeController): Done waiting to settle"); + return icontroller.getError(); + } + + protected: + std::shared_ptr logger; + std::unique_ptr rate; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/util/flywheelSimulator.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/util/flywheelSimulator.hpp new file mode 100644 index 00000000..7f82e69d --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/util/flywheelSimulator.hpp @@ -0,0 +1,156 @@ +/* + * 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 + +#include + +namespace okapi { +class FlywheelSimulator { + public: + /** + * A simulator for an inverted pendulum. The center of mass of the system changes as the link + * rotates (by default, you can set a new torque function with setExternalTorqueFunction()). + */ + explicit FlywheelSimulator(double imass = 0.01, + double ilinkLen = 1, + double imuStatic = 0.1, + double imuDynamic = 0.9, + double itimestep = 0.01); + + virtual ~FlywheelSimulator(); + + /** + * Step the simulation by the timestep. + * + * @return the current angle + */ + double step(); + + /** + * Step the simulation by the timestep. + * + * @param itorque new input torque + * @return the current angle + */ + double step(double itorque); + + /** + * Sets the torque function used to calculate the torque due to external forces. This torque gets + * summed with the input torque. + * + * For example, the default torque function has the torque due to gravity vary as the link swings: + * [](double angle, double mass, double linkLength) { + * return (linkLength * std::cos(angle)) * (mass * -1 * gravity); + * } + * + * @param itorqueFunc the torque function. The return value is the torque due to external forces + */ + void setExternalTorqueFunction( + std::function itorqueFunc); + + /** + * Sets the input torque. The input will be bounded by the max torque. + * + * @param itorque new input torque + */ + void setTorque(double itorque); + + /** + * Sets the max torque. The input torque cannot exceed this maximum torque. + * + * @param imaxTorque new maximum torque + */ + void setMaxTorque(double imaxTorque); + + /** + * Sets the current angle. + * + * @param iangle new angle + **/ + void setAngle(double iangle); + + /** + * Sets the mass (kg). + * + * @param imass new mass + */ + void setMass(double imass); + + /** + * Sets the link length (m). + * + * @param ilinkLen new link length + */ + void setLinkLength(double ilinkLen); + + /** + * Sets the static friction (N*m). + * + * @param imuStatic new static friction + */ + void setStaticFriction(double imuStatic); + + /** + * Sets the dynamic friction (N*m). + * + * @param imuDynamic new dynamic friction + */ + void setDynamicFriction(double imuDynamic); + + /** + * Sets the timestep (sec). + * + * @param itimestep new timestep + */ + void setTimestep(double itimestep); + + /** + * Returns the current angle (angle in rad). + * + * @return the current angle + */ + double getAngle() const; + + /** + * Returns the current omgea (angular velocity in rad / sec). + * + * @return the current omega + */ + double getOmega() const; + + /** + * Returns the current acceleration (angular acceleration in rad / sec^2). + * + * @return the current acceleration + */ + double getAcceleration() const; + + /** + * Returns the maximum torque input. + * + * @return the max torque input + */ + double getMaxTorque() const; + + protected: + double inputTorque = 0; // N*m + double maxTorque = 0.5649; // N*m + double angle = 0; // rad + double omega = 0; // rad / sec + double accel = 0; // rad / sec^2 + double mass; // kg + double linkLen; // m + double muStatic; // N*m + double muDynamic; // N*m + double timestep; // sec + double I = 0; // moment of inertia + std::function torqueFunc; + + const double minTimestep = 0.000001; // 1 us + + virtual double stepImpl(); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/util/pathfinderUtil.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/util/pathfinderUtil.hpp new file mode 100644 index 00000000..c356adff --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/util/pathfinderUtil.hpp @@ -0,0 +1,23 @@ +/* + * 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 + +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QLength.hpp" + +namespace okapi { +struct PathfinderPoint { + QLength x; // X coordinate relative to the start of the movement + QLength y; // Y coordinate relative to the start of the movement + QAngle theta; // Exit angle relative to the start of the movement +}; + +struct PathfinderLimits { + double maxVel; // Maximum robot velocity in m/s + double maxAccel; // Maximum robot acceleration in m/s/s + double maxJerk; // Maximum robot jerk in m/s/s/s +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/util/pidTuner.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/util/pidTuner.hpp new file mode 100644 index 00000000..d70c6a01 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/util/pidTuner.hpp @@ -0,0 +1,80 @@ +/* + * 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 + +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/control/iterative/iterativePosPidController.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include + +namespace okapi { +class PIDTuner { + public: + struct Output { + double kP, kI, kD; + }; + + PIDTuner(const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + const TimeUtil &itimeUtil, + QTime itimeout, + std::int32_t igoal, + double ikPMin, + double ikPMax, + double ikIMin, + double ikIMax, + double ikDMin, + double ikDMax, + std::size_t inumIterations = 5, + std::size_t inumParticles = 16, + double ikSettle = 1, + double ikITAE = 2, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + virtual ~PIDTuner(); + + virtual Output autotune(); + + protected: + static constexpr double inertia = 0.5; // Particle inertia + static constexpr double confSelf = 1.1; // Self confidence + static constexpr double confSwarm = 1.2; // Particle swarm confidence + static constexpr int increment = 5; + static constexpr int divisor = 5; + static constexpr QTime loopDelta = 10_ms; // NOLINT + + struct Particle { + double pos, vel, best; + }; + + struct ParticleSet { + Particle kP, kI, kD; + double bestError; + }; + + std::shared_ptr logger; + TimeUtil timeUtil; + std::shared_ptr> input; + std::shared_ptr> output; + + const QTime timeout; + const std::int32_t goal; + const double kPMin; + const double kPMax; + const double kIMin; + const double kIMax; + const double kDMin; + const double kDMax; + const std::size_t numIterations; + const std::size_t numParticles; + const double kSettle; + const double kITAE; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/control/util/settledUtil.hpp b/old-code/v5_hal/firmware/include/okapi/api/control/util/settledUtil.hpp new file mode 100644 index 00000000..9b81ba2f --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/control/util/settledUtil.hpp @@ -0,0 +1,51 @@ +/* + * 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 + +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/util/abstractTimer.hpp" +#include + +namespace okapi { +class SettledUtil { + public: + /** + * A utility class to determine if a control loop has settled based on error. A control loop is + * settled if the error is within `iatTargetError` and `iatTargetDerivative` for `iatTargetTime`. + * + * @param iatTargetTimer A timer used to track `iatTargetTime`. + * @param iatTargetError The minimum error to be considered settled. + * @param iatTargetDerivative The minimum error derivative to be considered settled. + * @param iatTargetTime The minimum time within atTargetError to be considered settled. + */ + explicit SettledUtil(std::unique_ptr iatTargetTimer, + double iatTargetError = 50, + double iatTargetDerivative = 5, + QTime iatTargetTime = 250_ms); + + virtual ~SettledUtil(); + + /** + * Returns whether the controller is settled. + * + * @param ierror The current error. + * @return Whether the controller is settled. + */ + virtual bool isSettled(double ierror); + + /** + * Resets the "at target" timer and clears the previous error. + */ + virtual void reset(); + + protected: + double atTargetError = 50; + double atTargetDerivative = 5; + QTime atTargetTime = 250_ms; + std::unique_ptr atTargetTimer; + double lastError = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/coreProsAPI.hpp b/old-code/v5_hal/firmware/include/okapi/api/coreProsAPI.hpp new file mode 100644 index 00000000..ab1aa694 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/coreProsAPI.hpp @@ -0,0 +1,131 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef THREADS_STD +#include +#define CROSSPLATFORM_THREAD_T std::thread + +#include +#define CROSSPLATFORM_MUTEX_T std::mutex +#else +#include "api.h" +#include "pros/apix.h" +#define CROSSPLATFORM_THREAD_T pros::task_t +#define CROSSPLATFORM_MUTEX_T pros::Mutex +#endif + +#define NOT_INITIALIZE_TASK \ + (strcmp(pros::c::task_get_name(pros::c::task_get_current()), "User Initialization (PROS)") != 0) + +#define NOT_COMP_INITIALIZE_TASK \ + (strcmp(pros::c::task_get_name(pros::c::task_get_current()), "User Comp. Init. (PROS)") != 0) + +class CrossplatformThread { + public: +#ifdef THREADS_STD + CrossplatformThread(void (*ptr)(void *), + void *params, + const char *const = "OkapiLibCrossplatformTask") +#else + CrossplatformThread(void (*ptr)(void *), + void *params, + const char *const name = "OkapiLibCrossplatformTask") +#endif + : +#ifdef THREADS_STD + thread(ptr, params) +#else + thread( + pros::c::task_create(ptr, params, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, name)) +#endif + { + } + + ~CrossplatformThread() { +#ifdef THREADS_STD + thread.join(); +#else + if (pros::c::task_get_state(thread) != pros::E_TASK_STATE_DELETED) { + pros::c::task_delete(thread); + } +#endif + } + +#ifdef THREADS_STD + void notifyWhenDeleting(CrossplatformThread *) { + } +#else + void notifyWhenDeleting(CrossplatformThread *parent) { + pros::c::task_notify_when_deleting(parent->thread, thread, 1, pros::E_NOTIFY_ACTION_INCR); + } +#endif + +#ifdef THREADS_STD + void notifyWhenDeletingRaw(CROSSPLATFORM_THREAD_T *) { + } +#else + void notifyWhenDeletingRaw(CROSSPLATFORM_THREAD_T parent) { + pros::c::task_notify_when_deleting(parent, thread, 1, pros::E_NOTIFY_ACTION_INCR); + } +#endif + +#ifdef THREADS_STD + std::uint32_t notifyTake(const std::uint32_t) { + return 0; + } +#else + std::uint32_t notifyTake(const std::uint32_t itimeout) { + return pros::c::task_notify_take(true, itimeout); + } +#endif + + static std::string getName() { +#ifdef THREADS_STD + std::ostringstream ss; + ss << std::this_thread::get_id(); + return ss.str(); +#else + return std::string(pros::c::task_get_name(NULL)); +#endif + } + + CROSSPLATFORM_THREAD_T thread; +}; + +class CrossplatformMutex { + public: + CrossplatformMutex() = default; + + void lock() { +#ifdef THREADS_STD + mutex.lock(); +#else + while (!mutex.take(1)) { + } +#endif + } + + void unlock() { +#ifdef THREADS_STD + mutex.unlock(); +#else + mutex.give(); +#endif + } + + protected: + CROSSPLATFORM_MUTEX_T mutex; +}; diff --git a/old-code/v5_hal/firmware/include/okapi/api/device/button/abstractButton.hpp b/old-code/v5_hal/firmware/include/okapi/api/device/button/abstractButton.hpp new file mode 100644 index 00000000..4e75f2eb --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/device/button/abstractButton.hpp @@ -0,0 +1,46 @@ +/* + * 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 + +#include "okapi/api/control/controllerInput.hpp" + +namespace okapi { +class AbstractButton : public ControllerInput { + public: + virtual ~AbstractButton(); + + /** + * Return whether the button is currently pressed. + **/ + virtual bool isPressed() = 0; + + /** + * Return whether the state of the button changed since the last time this method was + * called. + **/ + virtual bool changed() = 0; + + /** + * Return whether the state of the button changed to being pressed since the last time this method + * was called. + **/ + virtual bool changedToPressed() = 0; + + /** + * Return whether the state of the button to being not pressed changed since the last time this + * method was called. + **/ + virtual bool changedToReleased() = 0; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value. This is the same as the output of the pressed() method. + */ + virtual bool controllerGet() override; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/device/button/buttonBase.hpp b/old-code/v5_hal/firmware/include/okapi/api/device/button/buttonBase.hpp new file mode 100644 index 00000000..54f1ccd4 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/device/button/buttonBase.hpp @@ -0,0 +1,52 @@ +/* + * 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 + +#include "okapi/api/device/button/abstractButton.hpp" + +namespace okapi { +class ButtonBase : public AbstractButton { + public: + /** + * @param iinverted Whether the button is inverted (`true` meaning default pressed and `false` + * meaning default not pressed). + */ + explicit ButtonBase(bool iinverted = false); + + /** + * Return whether the button is currently pressed. + **/ + bool isPressed() override; + + /** + * Return whether the state of the button changed since the last time this method was called. + **/ + bool changed() override; + + /** + * Return whether the state of the button changed to pressed since the last time this method was + *called. + **/ + bool changedToPressed() override; + + /** + * Return whether the state of the button to not pressed since the last time this method was + *called. + **/ + bool changedToReleased() override; + + protected: + bool inverted{false}; + bool wasPressedLast_c{false}; + bool wasPressedLast_ctp{false}; + bool wasPressedLast_ctr{false}; + + virtual bool currentlyPressed() = 0; + + private: + bool changedImpl(bool &prevState); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/device/motor/abstractMotor.hpp b/old-code/v5_hal/firmware/include/okapi/api/device/motor/abstractMotor.hpp new file mode 100644 index 00000000..ff46fe07 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/device/motor/abstractMotor.hpp @@ -0,0 +1,537 @@ +/* + * 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 + +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" +#include + +namespace okapi { +class AbstractMotor : public ControllerOutput { + public: + /** + * Indicates the 'brake mode' of a motor. + */ + enum class brakeMode { + coast = 0, ///< Motor coasts when stopped, traditional behavior + brake = 1, ///< Motor brakes when stopped + hold = 2, ///< Motor actively holds position when stopped + invalid = INT32_MAX + }; + + /** + * Indicates the units used by the motor encoders. + */ + enum class encoderUnits { + degrees = 0, ///< degrees + rotations = 1, ///< rotations + counts = 2, ///< counts + invalid = INT32_MAX ///< invalid + }; + + /** + * Indicates the internal gear ratio of a motor. + */ + enum class gearset { + red = 100, ///< 36:1, 100 RPM, Red gear set + green = 200, ///< 18:1, 200 RPM, Green gear set + blue = 600, ///< 6:1, 600 RPM, Blue gear set + invalid = INT32_MAX + }; + + /** + * A simple structure representing the full ratio between motor and wheel. + */ + struct GearsetRatioPair { + /** + * A simple structure representing the full ratio between motor and wheel. + * + * The ratio is `motor rotation : wheel rotation`, e.x., if one motor rotation + * corresponds to two wheel rotations, the ratio is `1.0/2.0`. + * + * @param igearset The gearset in the motor. + * @param iratio The ratio of motor rotation to wheel rotation. + */ + GearsetRatioPair(const gearset igearset, const double iratio = 1) + : internalGearset(igearset), ratio(iratio) { + } + + ~GearsetRatioPair() = default; + + gearset internalGearset; + double ratio = 1; + }; + + virtual ~AbstractMotor(); + + /******************************************************************************/ + /** Motor movement functions **/ + /** **/ + /** These functions allow programmers to make motors move **/ + /******************************************************************************/ + + /** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with setZeroPosition(). + * + * @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: + * EACCES - Another resource is currently trying to access the port. + * + * @param iposition The absolute position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t moveAbsolute(double iposition, std::int32_t ivelocity) = 0; + + /** + * Sets the relative target position for the motor to move to. + * + * This movement is relative to the current position of the motor. Providing 10.0 as the position + * parameter would result in the motor moving clockwise 10 units, 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. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param iposition The relative position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t moveRelative(double iposition, std::int32_t ivelocity) = 0; + + /** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the gearset + * used for the motor. This results in a range of +-100 for pros::c::red, + * +-200 for green, and +-600 for blue. The velocity + * is held with PID to ensure consistent speed, as opposed to setting the motor's + * voltage. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's + * gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t moveVelocity(std::int16_t ivelocity) = 0; + + /** + * Sets the voltage for the motor from -12000 to 12000. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ivoltage The new voltage value from -12000 to 12000 + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t moveVoltage(std::int16_t ivoltage) = 0; + + /** + * Changes the output velocity for a profiled movement (moveAbsolute or moveRelative). This will + * have no effect if the motor is not following a profiled movement. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's + * gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t modifyProfiledVelocity(std::int32_t ivelocity) = 0; + + /******************************************************************************/ + /** Motor telemetry functions **/ + /** **/ + /** These functions allow programmers to collect telemetry from motors **/ + /******************************************************************************/ + + /** + * Gets the target position set for the motor by the user. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The target position in its encoder units or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual double getTargetPosition() = 0; + + /** + * Gets the absolute position of the motor in its encoder units. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's absolute position in its encoder units or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double getPosition() = 0; + + /** + * Gets the positional error (target position minus actual position) of the motor in its encoder + * units. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's positional error in its encoder units or PROS_ERR_F if the operation + * failed, setting errno. + */ + double getPositionError(); + + /** + * Sets the "absolute" zero position of the motor to its current position. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t tarePosition() = 0; + + /** + * Gets the velocity commanded to the motor by the user. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The commanded motor velocity from +-100, +-200, or +-600, or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t getTargetVelocity() = 0; + + /** + * Gets the actual velocity of the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's actual velocity in RPM or PROS_ERR_F if the operation failed, setting + * errno. + */ + virtual double getActualVelocity() = 0; + + /** + * Gets the difference between the target velocity of the motor and the actual velocity of the + * motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's velocity error in RPM or PROS_ERR_F if the operation failed, setting + * errno. + */ + double getVelocityError(); + + /** + * Gets the current drawn by the motor in mA. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's current in mA or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t getCurrentDraw() = 0; + + /** + * Gets the direction of movement for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return 1 for moving in the positive direction, -1 for moving in the negative direction, and + * PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t getDirection() = 0; + + /** + * Gets the efficiency of the motor in percent. + * + * 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: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's efficiency in percent or PROS_ERR_F if the operation failed, setting errno. + */ + virtual double getEfficiency() = 0; + + /** + * Checks if the motor is drawing over its current limit. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @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. + */ + virtual std::int32_t isOverCurrent() = 0; + + /** + * Checks if the motor's temperature is above its limit. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return 1 if the temperature limit is exceeded and 0 if the the temperature is below the limit, + * or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t isOverTemp() = 0; + + /** + * Checks if the motor is stopped. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns PROS_ERR with errno set to ENOSYS. + * + * @return 1 if the motor is not moving, 0 if the motor is moving, or PROS_ERR if the operation + * failed, setting errno + */ + virtual std::int32_t isStopped() = 0; + + /** + * Checks if the motor is at its zero position. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns PROS_ERR with errno set to ENOSYS. + * + * @return 1 if the motor is at zero absolute position, 0 if the motor has moved from its absolute + * zero, or PROS_ERR if the operation failed, setting errno + */ + virtual std::int32_t getZeroPositionFlag() = 0; + + /** + * Gets 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: + * EACCES - Another resource is currently trying to access the port. + * + * @return A currently unknown bitfield containing the motor's faults. 0b00000100 = Current Limit + * Hit + */ + virtual uint32_t getFaults() = 0; + + /** + * Gets 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: + * EACCES - Another resource is currently trying to access the port. + * + * @return A currently unknown bitfield containing the motor's flags. These seem to be unrelated + * to the individual get_specific_flag functions + */ + virtual uint32_t getFlags() = 0; + + /** + * Gets 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: + * EACCES - Another resource is currently trying to access the port. + * + * @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 The raw encoder count at the given timestamp or PROS_ERR if the operation failed. + */ + virtual std::int32_t getRawPosition(std::uint32_t *timestamp) = 0; + + /** + * Gets the power drawn by the motor in Watts. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's power draw in Watts or PROS_ERR_F if the operation failed, setting errno. + */ + virtual double getPower() = 0; + + /** + * Gets the temperature of the motor in degrees Celsius. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's temperature in degrees Celsius or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual double getTemperature() = 0; + + /** + * Gets the torque generated by the motor in Newton Metres (Nm). + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's torque in NM or PROS_ERR_F if the operation failed, setting errno. + */ + virtual double getTorque() = 0; + + /** + * Gets the voltage delivered to the motor in millivolts. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's voltage in V or PROS_ERR_F if the operation failed, setting errno. + */ + virtual std::int32_t getVoltage() = 0; + + /******************************************************************************/ + /** Motor configuration functions **/ + /** **/ + /** These functions allow programmers to configure the behavior of motors **/ + /******************************************************************************/ + + /** + * Sets one of brakeMode to the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param imode The new motor brake mode to set for the motor + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setBrakeMode(brakeMode imode) = 0; + + /** + * Gets the brake mode that was set for the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return One of brakeMode, according to what was set for the motor, or brakeMode::invalid if the + * operation failed, setting errno. + */ + virtual brakeMode getBrakeMode() = 0; + + /** + * Sets the current limit for the motor in mA. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ilimit The new current limit in mA + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setCurrentLimit(std::int32_t ilimit) = 0; + + /** + * Gets the current limit for the motor in mA. + * + * The default value is 2500 mA. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's current limit in mA or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t getCurrentLimit() = 0; + + /** + * Sets one of encoderUnits for the motor encoder. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param iunits The new motor encoder units + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setEncoderUnits(encoderUnits iunits) = 0; + + /** + * Gets the encoder units that were set for the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return One of encoderUnits according to what is set for the motor or encoderUnits::invalid if + * the operation failed. + */ + virtual encoderUnits getEncoderUnits() = 0; + + /** + * Sets one of gearset for the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param igearset The new motor gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setGearing(gearset igearset) = 0; + + /** + * Gets the gearset that was set for the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return One of gearset according to what is set for the motor, or gearset::invalid if the + * operation failed. + */ + virtual gearset getGearing() = 0; + + /** + * Sets the reverse flag for the motor. + * + * This will invert its movements and the values returned for its position. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ireverse True reverses the motor, false is default + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setReversed(bool ireverse) = 0; + + /** + * Sets the voltage limit for the motor in Volts. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ilimit The new voltage limit in Volts + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setVoltageLimit(std::int32_t ilimit) = 0; + + /** + * Returns the encoder associated with this motor. + * + * @return the encoder for this motor + */ + virtual std::shared_ptr getEncoder() = 0; +}; + +AbstractMotor::GearsetRatioPair operator*(AbstractMotor::gearset gearset, double ratio); + +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/device/rotarysensor/continuousRotarySensor.hpp b/old-code/v5_hal/firmware/include/okapi/api/device/rotarysensor/continuousRotarySensor.hpp new file mode 100644 index 00000000..4de4cc5e --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/device/rotarysensor/continuousRotarySensor.hpp @@ -0,0 +1,20 @@ +/* + * 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 + +#include "okapi/api/device/rotarysensor/rotarySensor.hpp" + +namespace okapi { +class ContinuousRotarySensor : public RotarySensor { + public: + /** + * Reset the sensor to zero. + * + * @return `1` on success, `PROS_ERR` on fail + */ + virtual std::int32_t reset() = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/device/rotarysensor/rotarySensor.hpp b/old-code/v5_hal/firmware/include/okapi/api/device/rotarysensor/rotarySensor.hpp new file mode 100644 index 00000000..9b010a4b --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/device/rotarysensor/rotarySensor.hpp @@ -0,0 +1,23 @@ +/* + * 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 + +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/coreProsAPI.hpp" + +namespace okapi { +class RotarySensor : public ControllerInput { + public: + virtual ~RotarySensor(); + + /** + * Get the current sensor value. + * + * @return the current sensor value, or `PROS_ERR` on a failure. + */ + virtual double get() const = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/filter/averageFilter.hpp b/old-code/v5_hal/firmware/include/okapi/api/filter/averageFilter.hpp new file mode 100644 index 00000000..c2babd07 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/filter/averageFilter.hpp @@ -0,0 +1,59 @@ +/* + * 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 + +#include "okapi/api/filter/filter.hpp" +#include +#include + +namespace okapi { +/** + * A filter which returns the average of a list of values. + * + * @tparam n number of taps in the filter + */ +template class AverageFilter : public Filter { + public: + /** + * Averaging filter. + */ + AverageFilter() = default; + + /** + * Filters a value, like a sensor reading. + * + * @param ireading new measurement + * @return filtered result + */ + double filter(const double ireading) override { + data[index++] = ireading; + if (index >= n) { + index = 0; + } + + output = 0.0; + for (size_t i = 0; i < n; i++) + output += data[i]; + output /= (double)n; + + return output; + } + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override { + return output; + } + + protected: + std::array data{0}; + std::size_t index = 0; + double output = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/filter/composableFilter.hpp b/old-code/v5_hal/firmware/include/okapi/api/filter/composableFilter.hpp new file mode 100644 index 00000000..be494e95 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/filter/composableFilter.hpp @@ -0,0 +1,50 @@ +/* + * 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 + +#include "okapi/api/filter/filter.hpp" +#include +#include +#include +#include + +namespace okapi { +class ComposableFilter : public Filter { + public: + /** + * A composable filter is a filter that consists of other filters. The input signal is passed + * through each filter in sequence. The final output of this filter is the output of the last + * filter. + * + * @param ilist The filters to use in sequence. + */ + ComposableFilter(const std::initializer_list> &ilist); + + /** + * Filters a value. + * + * @param ireading A new measurement. + * @return The filtered result. + */ + double filter(double ireading) override; + + /** + * @return The previous output from filter. + */ + double getOutput() const override; + + /** + * Adds a filter to the end of the sequence. + * + * @param ifilter The filter to add. + */ + virtual void addFilter(std::shared_ptr ifilter); + + protected: + std::vector> filters; + double output = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/filter/demaFilter.hpp b/old-code/v5_hal/firmware/include/okapi/api/filter/demaFilter.hpp new file mode 100644 index 00000000..c3f4ef31 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/filter/demaFilter.hpp @@ -0,0 +1,52 @@ +/* + * 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 + +#include "okapi/api/filter/filter.hpp" +#include + +namespace okapi { +class DemaFilter : public Filter { + public: + /** + * Double exponential moving average filter. + * + * @param ialpha alpha gain + * @param ibeta beta gain + */ + DemaFilter(double ialpha, double ibeta); + + /** + * Filters a value, like a sensor reading. + * + * @param reading new measurement + * @return filtered result + */ + double filter(double ireading) override; + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override; + + /** + * Set filter gains. + * + * @param ialpha alpha gain + * @param ibeta beta gain + */ + virtual void setGains(double ialpha, double ibeta); + + protected: + double alpha, beta; + double outputS = 0; + double lastOutputS = 0; + double outputB = 0; + double lastOutputB = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/filter/ekfFilter.hpp b/old-code/v5_hal/firmware/include/okapi/api/filter/ekfFilter.hpp new file mode 100644 index 00000000..731ad858 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/filter/ekfFilter.hpp @@ -0,0 +1,71 @@ +/* + * 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 + +#include "okapi/api/filter/filter.hpp" +#include "okapi/api/util/mathUtil.hpp" + +namespace okapi { +class EKFFilter : public Filter { + public: + /** + * One dimensional extended Kalman filter. The default arguments should work fine for most signal + * filtering. It won't hurt to graph your signal and the filtered result, and check if the filter + * is doing its job. + * + * Q is the covariance of the process noise and R is the + * covariance of the observation noise. The default values for Q and R should be a modest balance + * between trust in the sensor and FIR filtering. + * + * Think of R as how noisy your sensor is. Its value can be found mathematically by computing the + * standard deviation of your sensor reading vs. "truth" (of course, "truth" is still an estimate; + * try to calibrate your robot in a controlled setting where you can minimize the error in what + * "truth" is). + * + * Think of Q as how noisy your model is. It decides how much "smoothing" the filter does and how + * far it lags behind the true signal. This parameter is most often used as a "tuning" parameter + * to adjust the response of the filter. + * + * @param iQ process noise covariance + * @param iR measurement noise covariance + */ + explicit EKFFilter(double iQ = 0.0001, double iR = ipow(0.2, 2)); + + /** + * Filters a value, like a sensor reading. Assumes the control input is zero. + * + * @param ireading new measurement + * @return filtered result + */ + double filter(double ireading) override; + + /** + * Filters a reading with a control input. + * + * @param ireading new measurement + * @param icontrol control input + * @return filtered result + */ + virtual double filter(double ireading, double icontrol); + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override; + + protected: + const double Q, R; + double xHat = 0; + double xHatPrev = 0; + double xHatMinus = 0; + double P = 0; + double Pprev = 1; + double Pminus = 0; + double K = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/filter/emaFilter.hpp b/old-code/v5_hal/firmware/include/okapi/api/filter/emaFilter.hpp new file mode 100644 index 00000000..f41611c9 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/filter/emaFilter.hpp @@ -0,0 +1,47 @@ +/* + * 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 + +#include "okapi/api/filter/filter.hpp" + +namespace okapi { +class EmaFilter : public Filter { + public: + /** + * Exponential moving average filter. + * + * @param ialpha alpha gain + */ + explicit EmaFilter(double ialpha); + + /** + * Filters a value, like a sensor reading. + * + * @param reading new measurement + * @return filtered result + */ + double filter(double ireading) override; + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override; + + /** + * Set filter gains. + * + * @param ialpha alpha gain + */ + virtual void setGains(double ialpha); + + protected: + double alpha; + double output = 0; + double lastOutput = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/filter/filter.hpp b/old-code/v5_hal/firmware/include/okapi/api/filter/filter.hpp new file mode 100644 index 00000000..24ca2cf1 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/filter/filter.hpp @@ -0,0 +1,28 @@ +/* + * 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 + +namespace okapi { +class Filter { + public: + virtual ~Filter(); + + /** + * Filters a value, like a sensor reading. + * + * @param ireading new measurement + * @return filtered result + */ + virtual double filter(double ireading) = 0; + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + virtual double getOutput() const = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/filter/filteredControllerInput.hpp b/old-code/v5_hal/firmware/include/okapi/api/filter/filteredControllerInput.hpp new file mode 100644 index 00000000..9257fe6a --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/filter/filteredControllerInput.hpp @@ -0,0 +1,48 @@ +/* + * 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 + +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/filter/filter.hpp" +#include + +namespace okapi { +/** + * A ControllerInput with a filter built in. + * + * @tparam InputType the type of the ControllerInput + * @tparam FilterType the type of the Filter + */ +template +class FilteredControllerInput : public ControllerInput { + public: + /** + * A filtered controller input. Applies a filter to the controller input. Useful if you want to + * place a filter between a control input and a control loop. + * + * @param iinput ControllerInput type + * @param ifilter Filter type + */ + FilteredControllerInput(std::unique_ptr> iinput, + std::unique_ptr ifilter) + : input(std::move(iinput)), filter(std::move(ifilter)) { + } + + /** + * Gets the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current filtered sensor value. + */ + double controllerGet() override { + return filter->filter(input->controllerGet()); + } + + protected: + std::unique_ptr> input; + std::unique_ptr filter; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/filter/medianFilter.hpp b/old-code/v5_hal/firmware/include/okapi/api/filter/medianFilter.hpp new file mode 100644 index 00000000..28792117 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/filter/medianFilter.hpp @@ -0,0 +1,94 @@ +/* + * Uses the median filter algorithm from N. Wirth’s book, implementation by N. Devillard. + * + * 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 + +#include "okapi/api/filter/filter.hpp" +#include +#include +#include + +namespace okapi { +/** + * A filter which returns the median value of list of values. + * + * @tparam n number of taps in the filter + */ +template class MedianFilter : public Filter { + public: + MedianFilter() : middleIndex((((n)&1) ? ((n) / 2) : (((n) / 2) - 1))) { + } + + /** + * Filters a value, like a sensor reading. + * + * @param ireading new measurement + * @return filtered result + */ + double filter(const double ireading) override { + data[index++] = ireading; + if (index >= n) { + index = 0; + } + + output = kth_smallset(); + return output; + } + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override { + return output; + } + + protected: + std::array data{0}; + std::size_t index = 0; + double output = 0; + const size_t middleIndex; + + /** + * Algorithm from N. Wirth’s book, implementation by N. Devillard. + */ + double kth_smallset() { + std::array dataCopy = data; + size_t j, l, m; + l = 0; + m = n - 1; + + while (l < m) { + double x = dataCopy[middleIndex]; + size_t i = l; + j = m; + do { + while (dataCopy[i] < x) { + i++; + } + while (x < dataCopy[j]) { + j--; + } + if (i <= j) { + const double t = dataCopy[i]; + dataCopy[i] = dataCopy[j]; + dataCopy[j] = t; + i++; + j--; + } + } while (i <= j); + if (j < middleIndex) + l = i; + if (middleIndex < i) + m = j; + } + + return dataCopy[middleIndex]; + } +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/filter/passthroughFilter.hpp b/old-code/v5_hal/firmware/include/okapi/api/filter/passthroughFilter.hpp new file mode 100644 index 00000000..543fa317 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/filter/passthroughFilter.hpp @@ -0,0 +1,36 @@ +/* + * 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 + +#include "okapi/api/filter/filter.hpp" + +namespace okapi { +class PassthroughFilter : public Filter { + public: + /** + * A simple filter that does no filtering and just passes the input through. + */ + PassthroughFilter(); + + /** + * Filters a value, like a sensor reading. + * + * @param ireading new measurement + * @return filtered result + */ + double filter(double ireading) override; + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override; + + protected: + double lastOutput = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/filter/velMath.hpp b/old-code/v5_hal/firmware/include/okapi/api/filter/velMath.hpp new file mode 100644 index 00000000..a02dd8f2 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/filter/velMath.hpp @@ -0,0 +1,74 @@ +/* + * 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 + +#include "okapi/api/filter/composableFilter.hpp" +#include "okapi/api/units/QAngularAcceleration.hpp" +#include "okapi/api/units/QAngularSpeed.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/util/abstractTimer.hpp" +#include "okapi/api/util/logging.hpp" +#include + +namespace okapi { +class VelMath { + public: + /** + * Velocity math helper. Calculates filtered velocity. Throws a `std::invalid_argument` exception + * if `iticksPerRev` is zero. + * + * @param iticksPerRev The number of ticks per revolution (or whatever units you are using). + * @param ifilter The filter used for filtering the calculated velocity. + * @param isampleTime The minimum time between velocity measurements. + * @param ilogger The logger this instance will log to. + */ + VelMath(double iticksPerRev, + std::unique_ptr ifilter, + QTime isampleTime, + std::unique_ptr iloopDtTimer, + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + virtual ~VelMath(); + + /** + * Calculates the current velocity and acceleration. Returns the (filtered) velocity. + * + * @param inewPos The new position measurement. + * @return The new velocity estimate. + */ + virtual QAngularSpeed step(double inewPos); + + /** + * Sets ticks per revolution (or whatever units you are using). Throws a `std::invalid_argument` + * exception if iticksPerRev is zero. + * + * @param iTPR The number of ticks per revolution. + */ + virtual void setTicksPerRev(double iTPR); + + /** + * @return The last calculated velocity. + */ + virtual QAngularSpeed getVelocity() const; + + /** + * @return The last calculated acceleration. + */ + virtual QAngularAcceleration getAccel() const; + + protected: + std::shared_ptr logger; + QAngularSpeed vel{0_rpm}; + QAngularSpeed lastVel{0_rpm}; + QAngularAcceleration accel{0.0}; + double lastPos{0}; + double ticksPerRev; + + QTime sampleTime; + std::unique_ptr loopDtTimer; + std::unique_ptr filter; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/odometry/odomMath.hpp b/old-code/v5_hal/firmware/include/okapi/api/odometry/odomMath.hpp new file mode 100644 index 00000000..f32c2cd2 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/odometry/odomMath.hpp @@ -0,0 +1,95 @@ +/* + * 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 + +#include "okapi/api/odometry/odomState.hpp" +#include "okapi/api/odometry/point.hpp" +#include "okapi/api/util/logging.hpp" +#include + +namespace okapi { +class OdomMath { + public: + /** + * Computes the distance from the given Odometry state to the given point. The point and the + * OdomState must be in `StateMode::FRAME_TRANSFORMATION`. + * + * @param ipoint The point. + * @param istate The Odometry state. + * @return The distance between the Odometry state and the point. + */ + static QLength computeDistanceToPoint(const Point &ipoint, const OdomState &istate); + + /** + * Computes the angle from the given Odometry state to the given point. The point and the + * OdomState must be in `StateMode::FRAME_TRANSFORMATION`. + * + * @param ipoint The point. + * @param istate The Odometry state. + * @return The angle between the Odometry state and the point. + */ + static QAngle computeAngleToPoint(const Point &ipoint, const OdomState &istate); + + /** + * Computes the distance and angle from the given Odometry state to the given point. The point and + * the OdomState must be in `StateMode::FRAME_TRANSFORMATION`. + * + * @param ipoint The point. + * @param istate The Odometry state. + * @return The distance and angle between the Odometry state and the point. + */ + static std::pair computeDistanceAndAngleToPoint(const Point &ipoint, + const OdomState &istate); + + /** + * Constraints the angle to [0,360] degrees. + * + * @param angle The input angle. + * @return The angle normalized to [0,360] degrees. + */ + static QAngle constrainAngle360(const QAngle &angle); + + /** + * Constraints the angle to [-180,180) degrees. + * + * @param angle The input angle. + * @return The angle normalized to [-180,180) degrees. + */ + static QAngle constrainAngle180(const QAngle &angle); + + private: + OdomMath(); + ~OdomMath(); + + /** + * Computes the x and y diffs in meters between the points. + * + * @param ipoint The point. + * @param istate The Odometry state. + * @return The diffs in the order `{xDiff, yDiff}`. + */ + static std::pair computeDiffs(const Point &ipoint, const OdomState &istate); + + /** + * Computes the distance between the points. + * + * @param xDiff The x-axis diff in meters. + * @param yDiff The y-axis diff in meters. + * @return The cartesian distance in meters. + */ + static double computeDistance(double xDiff, double yDiff); + + /** + * Compites the angle between the points. + * + * @param xDiff The x-axis diff in meters. + * @param yDiff The y-axis diff in meters. + * @param theta The current robot's theta in radians. + * @return The angle in radians. + */ + static double computeAngle(double xDiff, double yDiff, double theta); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/odometry/odomState.hpp b/old-code/v5_hal/firmware/include/okapi/api/odometry/odomState.hpp new file mode 100644 index 00000000..0ad44554 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/odometry/odomState.hpp @@ -0,0 +1,27 @@ +/* + * 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 + +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QLength.hpp" +#include + +namespace okapi { +struct OdomState { + QLength x{0_m}; + QLength y{0_m}; + QAngle theta{0_deg}; + + /** + * @return A string representing the state. + */ + std::string str() const; + + bool operator==(const OdomState &rhs) const; + + bool operator!=(const OdomState &rhs) const; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/odometry/odometry.hpp b/old-code/v5_hal/firmware/include/okapi/api/odometry/odometry.hpp new file mode 100644 index 00000000..823cf3c2 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/odometry/odometry.hpp @@ -0,0 +1,61 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisScales.hpp" +#include "okapi/api/chassis/model/readOnlyChassisModel.hpp" +#include "okapi/api/odometry/odomState.hpp" +#include "okapi/api/odometry/stateMode.hpp" + +namespace okapi { +class Odometry { + public: + /** + * Odometry. Tracks the movement of the robot and estimates its position in coordinates + * relative to the start (assumed to be (0, 0, 0)). + */ + explicit Odometry() = default; + + virtual ~Odometry() = default; + + /** + * Sets the drive and turn scales. + */ + virtual void setScales(const ChassisScales &ichassisScales) = 0; + + /** + * Do one odometry step. + */ + virtual void step() = 0; + + /** + * Returns the current state. + * + * @param imode The mode to return the state in. + * @return The current state in the given format. + */ + virtual OdomState getState(const StateMode &imode = StateMode::FRAME_TRANSFORMATION) const = 0; + + /** + * Sets a new state to be the current state. + * + * @param istate The new state in the given format. + * @param imode The mode to treat the input state as. + */ + virtual void setState(const OdomState &istate, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION) = 0; + + /** + * @return The internal ChassisModel. + */ + virtual std::shared_ptr getModel() = 0; + + /** + * @return The internal ChassisScales. + */ + virtual ChassisScales getScales() = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/odometry/point.hpp b/old-code/v5_hal/firmware/include/okapi/api/odometry/point.hpp new file mode 100644 index 00000000..c55266b5 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/odometry/point.hpp @@ -0,0 +1,30 @@ +/* + * 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 + +#include "okapi/api/odometry/stateMode.hpp" +#include "okapi/api/units/QLength.hpp" + +namespace okapi { +struct Point { + QLength x{0_m}; + QLength y{0_m}; + + /** + * Computes the value of this point in `StateMode::FRAME_TRANSFORMATION`. + * + * @param imode The StateMode this Point is currently specified in. + * @return This point specified in `StateMode::FRAME_TRANSFORMATION`. + */ + Point inFT(const StateMode &imode) const { + if (imode == StateMode::FRAME_TRANSFORMATION) { + return *this; + } else { + return {y, x}; + } + } +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/odometry/stateMode.hpp b/old-code/v5_hal/firmware/include/okapi/api/odometry/stateMode.hpp new file mode 100644 index 00000000..da2b6bc1 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/odometry/stateMode.hpp @@ -0,0 +1,17 @@ +/* + * 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 + +namespace okapi { +/** + * The mode for the OdomState calculated by Odometry. + */ +enum class StateMode { + FRAME_TRANSFORMATION, ///< +x is forward, +y is right, 0 degrees is along +x + CARTESIAN ///< +x is right, +y is forward, 0 degrees is along +y +}; + +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/odometry/threeEncoderOdometry.hpp b/old-code/v5_hal/firmware/include/okapi/api/odometry/threeEncoderOdometry.hpp new file mode 100644 index 00000000..d4a04010 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/odometry/threeEncoderOdometry.hpp @@ -0,0 +1,43 @@ +/* + * 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 + +#include "okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp" +#include "okapi/api/odometry/twoEncoderOdometry.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include + +namespace okapi { +class ThreeEncoderOdometry : public TwoEncoderOdometry { + public: + /** + * Odometry. Tracks the movement of the robot and estimates its position in coordinates + * relative to the start (assumed to be (0, 0)). + * + * @param itimeUtil The TimeUtil. + * @param imodel The chassis model for reading sensors. + * @param ichassisScales See ChassisScales docs (the middle wheel scale is the third member) + * @param iwheelVelDelta The maximum delta between wheel velocities to consider the robot as + * driving straight. + * @param ilogger The logger this instance will log to. + */ + ThreeEncoderOdometry(const TimeUtil &itimeUtil, + const std::shared_ptr &imodel, + const ChassisScales &ichassisScales, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + protected: + /** + * Does the math, side-effect free, for one odom step. + * + * @param itickDiff The tick difference from the previous step to this step. + * @param ideltaT The time difference from the previous step to this step. + * @return The newly computed OdomState. + */ + OdomState odomMathStep(const std::valarray &itickDiff, + const QTime &ideltaT) override; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/odometry/twoEncoderOdometry.hpp b/old-code/v5_hal/firmware/include/okapi/api/odometry/twoEncoderOdometry.hpp new file mode 100644 index 00000000..c733d450 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/odometry/twoEncoderOdometry.hpp @@ -0,0 +1,93 @@ +/* + * 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 + +#include "okapi/api/odometry/odometry.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include +#include + +namespace okapi { +class TwoEncoderOdometry : public Odometry { + public: + /** + * TwoEncoderOdometry. Tracks the movement of the robot and estimates its position in coordinates + * relative to the start (assumed to be (0, 0, 0)). + * + * @param itimeUtil The TimeUtil. + * @param imodel The chassis model for reading sensors. + * @param ichassisScales The chassis dimensions. + * @param ilogger The logger this instance will log to. + */ + TwoEncoderOdometry(const TimeUtil &itimeUtil, + const std::shared_ptr &imodel, + const ChassisScales &ichassisScales, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + virtual ~TwoEncoderOdometry() = default; + + /** + * Sets the drive and turn scales. + */ + void setScales(const ChassisScales &ichassisScales) override; + + /** + * Do one odometry step. + */ + void step() override; + + /** + * Returns the current state. + * + * @param imode The mode to return the state in. + * @return The current state in the given format. + */ + OdomState getState(const StateMode &imode = StateMode::FRAME_TRANSFORMATION) const override; + + /** + * Sets a new state to be the current state. + * + * @param istate The new state in the given format. + * @param imode The mode to treat the input state as. + */ + void setState(const OdomState &istate, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION) override; + + /** + * @return The internal ChassisModel. + */ + std::shared_ptr getModel() override; + + /** + * @return The internal ChassisScales. + */ + ChassisScales getScales() override; + + protected: + std::shared_ptr logger; + std::unique_ptr rate; + std::unique_ptr timer; + std::shared_ptr model; + ChassisScales chassisScales; + OdomState state; + std::valarray newTicks{0, 0, 0}, tickDiff{0, 0, 0}, lastTicks{0, 0, 0}; + const std::int32_t maximumTickDiff{1000}; + + /** + * Does the math, side-effect free, for one odom step. + * + * @param itickDiff The tick difference from the previous step to this step. + * @param ideltaT The time difference from the previous step to this step. + * @return The newly computed OdomState. + */ + virtual OdomState odomMathStep(const std::valarray &itickDiff, + const QTime &ideltaT); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QAcceleration.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QAcceleration.hpp new file mode 100644 index 00000000..50f7193c --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QAcceleration.hpp @@ -0,0 +1,36 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 1, -2, 0, QAcceleration) + +constexpr QAcceleration mps2 = meter / (second * second); +constexpr QAcceleration G = 9.80665 * mps2; + +inline namespace literals { +constexpr QAcceleration operator"" _mps2(long double x) { + return QAcceleration(x); +} +constexpr QAcceleration operator"" _mps2(unsigned long long int x) { + return QAcceleration(static_cast(x)); +} +constexpr QAcceleration operator"" _G(long double x) { + return static_cast(x) * G; +} +constexpr QAcceleration operator"" _G(unsigned long long int x) { + return static_cast(x) * G; +} +} // namespace literals +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QAngle.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QAngle.hpp new file mode 100644 index 00000000..2e80b4d9 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QAngle.hpp @@ -0,0 +1,35 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/RQuantity.hpp" +#include + +namespace okapi { +QUANTITY_TYPE(0, 0, 0, 1, QAngle) + +constexpr QAngle radian(1.0); +constexpr QAngle degree = static_cast(2_pi / 360.0) * radian; + +inline namespace literals { +constexpr QAngle operator"" _rad(long double x) { + return QAngle(x); +} +constexpr QAngle operator"" _rad(unsigned long long int x) { + return QAngle(static_cast(x)); +} +constexpr QAngle operator"" _deg(long double x) { + return static_cast(x) * degree; +} +constexpr QAngle operator"" _deg(unsigned long long int x) { + return static_cast(x) * degree; +} +} // namespace literals +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QAngularAcceleration.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QAngularAcceleration.hpp new file mode 100644 index 00000000..487acbf8 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QAngularAcceleration.hpp @@ -0,0 +1,16 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 0, -2, 1, QAngularAcceleration) +} diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QAngularJerk.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QAngularJerk.hpp new file mode 100644 index 00000000..c3fd6c7f --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QAngularJerk.hpp @@ -0,0 +1,16 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 0, -3, 1, QAngularJerk) +} diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QAngularSpeed.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QAngularSpeed.hpp new file mode 100644 index 00000000..82d7dae5 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QAngularSpeed.hpp @@ -0,0 +1,38 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QFrequency.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 0, -1, 1, QAngularSpeed) + +constexpr QAngularSpeed radps = radian / second; +constexpr QAngularSpeed rpm = (360 * degree) / minute; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +static QAngularSpeed convertHertzToRadPerSec(QFrequency in) { + return (in.convert(Hz) / 2_pi) * radps; +} +#pragma GCC diagnostic pop + +inline namespace literals { +constexpr QAngularSpeed operator"" _rpm(long double x) { + return x * rpm; +} +constexpr QAngularSpeed operator"" _rpm(unsigned long long int x) { + return static_cast(x) * rpm; +} +} // namespace literals +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QArea.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QArea.hpp new file mode 100644 index 00000000..ed487220 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QArea.hpp @@ -0,0 +1,26 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 2, 0, 0, QArea) + +constexpr QArea kilometer2 = kilometer * kilometer; +constexpr QArea meter2 = meter * meter; +constexpr QArea decimeter2 = decimeter * decimeter; +constexpr QArea centimeter2 = centimeter * centimeter; +constexpr QArea millimeter2 = millimeter * millimeter; +constexpr QArea inch2 = inch * inch; +constexpr QArea foot2 = foot * foot; +constexpr QArea mile2 = mile * mile; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QForce.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QForce.hpp new file mode 100644 index 00000000..8439fb7b --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QForce.hpp @@ -0,0 +1,43 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QAcceleration.hpp" +#include "okapi/api/units/QMass.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(1, 1, -2, 0, QForce) + +constexpr QForce newton = (kg * meter) / (second * second); +constexpr QForce poundforce = pound * G; +constexpr QForce kilopond = kg * G; + +inline namespace literals { +constexpr QForce operator"" _n(long double x) { + return QForce(x); +} +constexpr QForce operator"" _n(unsigned long long int x) { + return QForce(static_cast(x)); +} +constexpr QForce operator"" _lbf(long double x) { + return static_cast(x) * poundforce; +} +constexpr QForce operator"" _lbf(unsigned long long int x) { + return static_cast(x) * poundforce; +} +constexpr QForce operator"" _kp(long double x) { + return static_cast(x) * kilopond; +} +constexpr QForce operator"" _kp(unsigned long long int x) { + return static_cast(x) * kilopond; +} +} // namespace literals +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QFrequency.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QFrequency.hpp new file mode 100644 index 00000000..9cd29911 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QFrequency.hpp @@ -0,0 +1,27 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 0, -1, 0, QFrequency) + +constexpr QFrequency Hz(1.0); + +inline namespace literals { +constexpr QFrequency operator"" _Hz(long double x) { + return QFrequency(x); +} +constexpr QFrequency operator"" _Hz(unsigned long long int x) { + return QFrequency(static_cast(x)); +} +} // namespace literals +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QJerk.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QJerk.hpp new file mode 100644 index 00000000..709df1ed --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QJerk.hpp @@ -0,0 +1,18 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 1, -3, 0, QJerk) +} diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QLength.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QLength.hpp new file mode 100644 index 00000000..ffcd083b --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QLength.hpp @@ -0,0 +1,77 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 1, 0, 0, QLength) + +constexpr QLength meter(1.0); // SI base unit +constexpr QLength decimeter = meter / 10; +constexpr QLength centimeter = meter / 100; +constexpr QLength millimeter = meter / 1000; +constexpr QLength kilometer = 1000 * meter; +constexpr QLength inch = 2.54 * centimeter; +constexpr QLength foot = 12 * inch; +constexpr QLength yard = 3 * foot; +constexpr QLength mile = 5280 * foot; + +inline namespace literals { +constexpr QLength operator"" _mm(long double x) { + return static_cast(x) * millimeter; +} +constexpr QLength operator"" _cm(long double x) { + return static_cast(x) * centimeter; +} +constexpr QLength operator"" _m(long double x) { + return static_cast(x) * meter; +} +constexpr QLength operator"" _km(long double x) { + return static_cast(x) * kilometer; +} +constexpr QLength operator"" _mi(long double x) { + return static_cast(x) * mile; +} +constexpr QLength operator"" _yd(long double x) { + return static_cast(x) * yard; +} +constexpr QLength operator"" _ft(long double x) { + return static_cast(x) * foot; +} +constexpr QLength operator"" _in(long double x) { + return static_cast(x) * inch; +} +constexpr QLength operator"" _mm(unsigned long long int x) { + return static_cast(x) * millimeter; +} +constexpr QLength operator"" _cm(unsigned long long int x) { + return static_cast(x) * centimeter; +} +constexpr QLength operator"" _m(unsigned long long int x) { + return static_cast(x) * meter; +} +constexpr QLength operator"" _km(unsigned long long int x) { + return static_cast(x) * kilometer; +} +constexpr QLength operator"" _mi(unsigned long long int x) { + return static_cast(x) * mile; +} +constexpr QLength operator"" _yd(unsigned long long int x) { + return static_cast(x) * yard; +} +constexpr QLength operator"" _ft(unsigned long long int x) { + return static_cast(x) * foot; +} +constexpr QLength operator"" _in(unsigned long long int x) { + return static_cast(x) * inch; +} +} // namespace literals +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QMass.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QMass.hpp new file mode 100644 index 00000000..0501cbdf --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QMass.hpp @@ -0,0 +1,62 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(1, 0, 0, 0, QMass) + +constexpr QMass kg(1.0); // SI base unit +constexpr QMass gramme = 0.001 * kg; +constexpr QMass tonne = 1000 * kg; +constexpr QMass ounce = 0.028349523125 * kg; +constexpr QMass pound = 16 * ounce; +constexpr QMass stone = 14 * pound; + +inline namespace literals { +constexpr QMass operator"" _kg(long double x) { + return QMass(x); +} +constexpr QMass operator"" _g(long double x) { + return static_cast(x) * gramme; +} +constexpr QMass operator"" _t(long double x) { + return static_cast(x) * tonne; +} +constexpr QMass operator"" _oz(long double x) { + return static_cast(x) * ounce; +} +constexpr QMass operator"" _lb(long double x) { + return static_cast(x) * pound; +} +constexpr QMass operator"" _st(long double x) { + return static_cast(x) * stone; +} +constexpr QMass operator"" _kg(unsigned long long int x) { + return QMass(static_cast(x)); +} +constexpr QMass operator"" _g(unsigned long long int x) { + return static_cast(x) * gramme; +} +constexpr QMass operator"" _t(unsigned long long int x) { + return static_cast(x) * tonne; +} +constexpr QMass operator"" _oz(unsigned long long int x) { + return static_cast(x) * ounce; +} +constexpr QMass operator"" _lb(unsigned long long int x) { + return static_cast(x) * pound; +} +constexpr QMass operator"" _st(unsigned long long int x) { + return static_cast(x) * stone; +} +} // namespace literals +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QPressure.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QPressure.hpp new file mode 100644 index 00000000..23fa384f --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QPressure.hpp @@ -0,0 +1,44 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QAcceleration.hpp" +#include "okapi/api/units/QArea.hpp" +#include "okapi/api/units/QMass.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(1, -1, -2, 0, QPressure) + +constexpr QPressure pascal(1.0); +constexpr QPressure bar = 100000 * pascal; +constexpr QPressure psi = pound * G / inch2; + +inline namespace literals { +constexpr QPressure operator"" _Pa(long double x) { + return QPressure(x); +} +constexpr QPressure operator"" _Pa(unsigned long long int x) { + return QPressure(static_cast(x)); +} +constexpr QPressure operator"" _bar(long double x) { + return static_cast(x) * bar; +} +constexpr QPressure operator"" _bar(unsigned long long int x) { + return static_cast(x) * bar; +} +constexpr QPressure operator"" _psi(long double x) { + return static_cast(x) * psi; +} +constexpr QPressure operator"" _psi(unsigned long long int x) { + return static_cast(x) * psi; +} +} // namespace literals +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QSpeed.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QSpeed.hpp new file mode 100644 index 00000000..d8a19760 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QSpeed.hpp @@ -0,0 +1,43 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 1, -1, 0, QSpeed) + +constexpr QSpeed mps = meter / second; +constexpr QSpeed miph = mile / hour; +constexpr QSpeed kmph = kilometer / hour; + +inline namespace literals { +constexpr QSpeed operator"" _mps(long double x) { + return static_cast(x) * mps; +} +constexpr QSpeed operator"" _miph(long double x) { + return static_cast(x) * mile / hour; +} +constexpr QSpeed operator"" _kmph(long double x) { + return static_cast(x) * kilometer / hour; +} +constexpr QSpeed operator"" _mps(unsigned long long int x) { + return static_cast(x) * mps; +} +constexpr QSpeed operator"" _miph(unsigned long long int x) { + return static_cast(x) * mile / hour; +} +constexpr QSpeed operator"" _kmph(unsigned long long int x) { + return static_cast(x) * kilometer / hour; +} +} // namespace literals +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QTime.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QTime.hpp new file mode 100644 index 00000000..be9d824b --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QTime.hpp @@ -0,0 +1,55 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 0, 1, 0, QTime) + +constexpr QTime second(1.0); // SI base unit +constexpr QTime millisecond = second / 1000; +constexpr QTime minute = 60 * second; +constexpr QTime hour = 60 * minute; +constexpr QTime day = 24 * hour; + +inline namespace literals { +constexpr QTime operator"" _s(long double x) { + return QTime(x); +} +constexpr QTime operator"" _ms(long double x) { + return static_cast(x) * millisecond; +} +constexpr QTime operator"" _min(long double x) { + return static_cast(x) * minute; +} +constexpr QTime operator"" _h(long double x) { + return static_cast(x) * hour; +} +constexpr QTime operator"" _day(long double x) { + return static_cast(x) * day; +} +constexpr QTime operator"" _s(unsigned long long int x) { + return QTime(static_cast(x)); +} +constexpr QTime operator"" _ms(unsigned long long int x) { + return static_cast(x) * millisecond; +} +constexpr QTime operator"" _min(unsigned long long int x) { + return static_cast(x) * minute; +} +constexpr QTime operator"" _h(unsigned long long int x) { + return static_cast(x) * hour; +} +constexpr QTime operator"" _day(unsigned long long int x) { + return static_cast(x) * day; +} +} // namespace literals +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QTorque.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QTorque.hpp new file mode 100644 index 00000000..b7b6c717 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QTorque.hpp @@ -0,0 +1,43 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QForce.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(1, 2, -2, 0, QTorque) + +constexpr QTorque newtonMeter = newton * meter; +constexpr QTorque footPound = 1.355817948 * newtonMeter; +constexpr QTorque inchPound = 0.083333333 * footPound; + +inline namespace literals { +constexpr QTorque operator"" _nM(long double x) { + return QTorque(x); +} +constexpr QTorque operator"" _nM(unsigned long long int x) { + return QTorque(static_cast(x)); +} +constexpr QTorque operator"" _inLb(long double x) { + return static_cast(x) * inchPound; +} +constexpr QTorque operator"" _inLb(unsigned long long int x) { + return static_cast(x) * inchPound; +} +constexpr QTorque operator"" _ftLb(long double x) { + return static_cast(x) * footPound; +} +constexpr QTorque operator"" _ftLb(unsigned long long int x) { + return static_cast(x) * footPound; +} +} // namespace literals +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/QVolume.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/QVolume.hpp new file mode 100644 index 00000000..1c76b9cb --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/QVolume.hpp @@ -0,0 +1,28 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QArea.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 3, 0, 0, QVolume) + +constexpr QVolume kilometer3 = kilometer2 * kilometer; +constexpr QVolume meter3 = meter2 * meter; +constexpr QVolume decimeter3 = decimeter2 * decimeter; +constexpr QVolume centimeter3 = centimeter2 * centimeter; +constexpr QVolume millimeter3 = millimeter2 * millimeter; +constexpr QVolume inch3 = inch2 * inch; +constexpr QVolume foot3 = foot2 * foot; +constexpr QVolume mile3 = mile2 * mile; +constexpr QVolume litre = decimeter3; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/units/RQuantity.hpp b/old-code/v5_hal/firmware/include/okapi/api/units/RQuantity.hpp new file mode 100644 index 00000000..2232ebcc --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/units/RQuantity.hpp @@ -0,0 +1,419 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include +#include + +namespace okapi { +template +class RQuantity { + public: + explicit constexpr RQuantity() : value(0.0) { + } + + explicit constexpr RQuantity(double val) : value(val) { + } + + explicit constexpr RQuantity(long double val) : value(static_cast(val)) { + } + + // The intrinsic operations for a quantity with a unit is addition and subtraction + constexpr RQuantity const &operator+=(const RQuantity &rhs) { + value += rhs.value; + return *this; + } + + constexpr RQuantity const &operator-=(const RQuantity &rhs) { + value -= rhs.value; + return *this; + } + + constexpr RQuantity operator-() { + return RQuantity(value * -1); + } + + constexpr RQuantity const &operator*=(const double rhs) { + value *= rhs; + return *this; + } + + constexpr RQuantity const &operator/=(const double rhs) { + value /= rhs; + return *this; + } + + // Returns the value of the quantity in multiples of the specified unit + constexpr double convert(const RQuantity &rhs) const { + return value / rhs.value; + } + + // returns the raw value of the quantity (should not be used) + constexpr double getValue() const { + return value; + } + + constexpr RQuantity abs() const { + return RQuantity(std::fabs(value)); + } + + constexpr RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>> + sqrt() const { + return RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>>(std::sqrt(value)); + } + + private: + double value; +}; + +// Predefined (physical unit) quantity types: +// ------------------------------------------ +#define QUANTITY_TYPE(_Mdim, _Ldim, _Tdim, _Adim, name) \ + typedef RQuantity, std::ratio<_Ldim>, std::ratio<_Tdim>, std::ratio<_Adim>> \ + name; + +// Unitless +QUANTITY_TYPE(0, 0, 0, 0, Number) +constexpr Number number(1.0); + +// Standard arithmetic operators: +// ------------------------------ +template +constexpr RQuantity operator+(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(lhs.getValue() + rhs.getValue()); +} +template +constexpr RQuantity operator-(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(lhs.getValue() - rhs.getValue()); +} +template +constexpr RQuantity, + std::ratio_add, + std::ratio_add, + std::ratio_add> +operator*(const RQuantity &lhs, const RQuantity &rhs) { + return RQuantity, + std::ratio_add, + std::ratio_add, + std::ratio_add>(lhs.getValue() * rhs.getValue()); +} +template +constexpr RQuantity operator*(const double &lhs, const RQuantity &rhs) { + return RQuantity(lhs * rhs.getValue()); +} +template +constexpr RQuantity operator*(const RQuantity &lhs, const double &rhs) { + return RQuantity(lhs.getValue() * rhs); +} +template +constexpr RQuantity, + std::ratio_subtract, + std::ratio_subtract, + std::ratio_subtract> +operator/(const RQuantity &lhs, const RQuantity &rhs) { + return RQuantity, + std::ratio_subtract, + std::ratio_subtract, + std::ratio_subtract>(lhs.getValue() / rhs.getValue()); +} +template +constexpr RQuantity, M>, + std::ratio_subtract, L>, + std::ratio_subtract, T>, + std::ratio_subtract, A>> +operator/(const double &x, const RQuantity &rhs) { + return RQuantity, M>, + std::ratio_subtract, L>, + std::ratio_subtract, T>, + std::ratio_subtract, A>>(x / rhs.getValue()); +} +template +constexpr RQuantity operator/(const RQuantity &rhs, const double &x) { + return RQuantity(rhs.getValue() / x); +} + +// Comparison operators for quantities: +// ------------------------------------ +template +constexpr bool operator==(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() == rhs.getValue()); +} +template +constexpr bool operator!=(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() != rhs.getValue()); +} +template +constexpr bool operator<=(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() <= rhs.getValue()); +} +template +constexpr bool operator>=(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() >= rhs.getValue()); +} +template +constexpr bool operator<(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() < rhs.getValue()); +} +template +constexpr bool operator>(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() > rhs.getValue()); +} + +// Common math functions: +// ------------------------------ + +template +constexpr RQuantity abs(const RQuantity &rhs) { + return RQuantity(std::abs(rhs.getValue())); +} + +template +constexpr RQuantity, + std::ratio_multiply, + std::ratio_multiply, + std::ratio_multiply> +pow(const RQuantity &lhs) { + return RQuantity, + std::ratio_multiply, + std::ratio_multiply, + std::ratio_multiply>(std::pow(lhs.getValue(), double(R::num) / R::den)); +} + +template +constexpr RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>> +pow(const RQuantity &lhs) { + return RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>>(std::pow(lhs.getValue(), R)); +} + +template +constexpr RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>> +root(const RQuantity &lhs) { + return RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>>(std::pow(lhs.getValue(), 1.0 / R)); +} + +template +constexpr RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>> +sqrt(const RQuantity &rhs) { + return RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>>(std::sqrt(rhs.getValue())); +} + +template +constexpr RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>> +cbrt(const RQuantity &rhs) { + return RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>>(std::cbrt(rhs.getValue())); +} + +template +constexpr RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>> +square(const RQuantity &rhs) { + return RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>>(std::pow(rhs.getValue(), 2)); +} + +template +constexpr RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>> +cube(const RQuantity &rhs) { + return RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>>(std::pow(rhs.getValue(), 3)); +} + +template +constexpr RQuantity hypot(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::hypot(lhs.getValue(), rhs.getValue())); +} + +template +constexpr RQuantity mod(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::fmod(lhs.getValue(), rhs.getValue())); +} + +template +constexpr RQuantity copysign(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::copysign(lhs.getValue(), rhs.getValue())); +} + +template +constexpr RQuantity ceil(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::ceil(lhs.getValue() / rhs.getValue()) * rhs.getValue()); +} + +template +constexpr RQuantity floor(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::floor(lhs.getValue() / rhs.getValue()) * rhs.getValue()); +} + +template +constexpr RQuantity trunc(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::trunc(lhs.getValue() / rhs.getValue()) * rhs.getValue()); +} + +template +constexpr RQuantity round(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::round(lhs.getValue() / rhs.getValue()) * rhs.getValue()); +} + +// Common trig functions: +// ------------------------------ + +constexpr Number +sin(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::sin(rhs.getValue())); +} + +constexpr Number +cos(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::cos(rhs.getValue())); +} + +constexpr Number +tan(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::tan(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +asin(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::asin(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +acos(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::acos(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +atan(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::atan(rhs.getValue())); +} + +constexpr Number +sinh(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::sinh(rhs.getValue())); +} + +constexpr Number +cosh(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::cosh(rhs.getValue())); +} + +constexpr Number +tanh(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::tanh(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +asinh(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::asinh(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +acosh(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::acosh(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +atanh(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::atanh(rhs.getValue())); +} + +template +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +atan2(const RQuantity &lhs, const RQuantity &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::atan2(lhs.getValue(), rhs.getValue())); +} + +inline namespace literals { +constexpr long double operator"" _pi(long double x) { + return static_cast(x) * 3.1415926535897932384626433832795; +} +constexpr long double operator"" _pi(unsigned long long int x) { + return static_cast(x) * 3.1415926535897932384626433832795; +} +} // namespace literals +} // namespace okapi + +// Conversion macro, which utilizes the string literals +#define ConvertTo(_x, _y) (_x).convert(1.0_##_y) diff --git a/old-code/v5_hal/firmware/include/okapi/api/util/abstractRate.hpp b/old-code/v5_hal/firmware/include/okapi/api/util/abstractRate.hpp new file mode 100644 index 00000000..987b3149 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/util/abstractRate.hpp @@ -0,0 +1,41 @@ +/* + * 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 + +#include "okapi/api/coreProsAPI.hpp" +#include "okapi/api/units/QFrequency.hpp" +#include "okapi/api/units/QTime.hpp" + +namespace okapi { +class AbstractRate { + public: + virtual ~AbstractRate(); + + /** + * Delay the current task such that it runs at the given frequency. The first delay will run for + * 1000/(ihz). Subsequent delays will adjust according to the previous runtime of the task. + * + * @param ihz the frequency + */ + virtual void delay(QFrequency ihz) = 0; + + /** + * Delay the current task until itime has passed. This method can be used by periodic tasks to + * ensure a consistent execution frequency. + * + * @param itime the time period + */ + virtual void delayUntil(QTime itime) = 0; + + /** + * Delay the current task until ims milliseconds have passed. This method can be used by + * periodic tasks to ensure a consistent execution frequency. + * + * @param ims the time period + */ + virtual void delayUntil(uint32_t ims) = 0; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/util/abstractTimer.hpp b/old-code/v5_hal/firmware/include/okapi/api/util/abstractTimer.hpp new file mode 100644 index 00000000..db9a488e --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/util/abstractTimer.hpp @@ -0,0 +1,125 @@ +/* + * 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 + +#include "okapi/api/units/QFrequency.hpp" +#include "okapi/api/units/QTime.hpp" + +namespace okapi { +class AbstractTimer { + public: + /** + * A Timer base class which implements its methods in terms of millis(). + * + * @param ifirstCalled the current time + */ + explicit AbstractTimer(QTime ifirstCalled); + + virtual ~AbstractTimer(); + + /** + * Returns the current time in units of QTime. + * + * @return the current time + */ + virtual QTime millis() const = 0; + + /** + * Returns the time passed in ms since the previous call of this function. + * + * @return The time passed in ms since the previous call of this function + */ + virtual QTime getDt(); + + /** + * Returns the time passed in ms since the previous call of getDt(). Does not change the time + * recorded by getDt(). + * + * @return The time passed in ms since the previous call of getDt() + */ + virtual QTime readDt() const; + + /** + * Returns the time the timer was first constructed. + * + * @return The time the timer was first constructed + */ + virtual QTime getStartingTime() const; + + /** + * Returns the time since the timer was first constructed. + * + * @return The time since the timer was first constructed + */ + virtual QTime getDtFromStart() const; + + /** + * Place a time marker. Placing another marker will overwrite the previous one. + */ + virtual void placeMark(); + + /** + * Clears the marker. + * + * @return The old marker + */ + virtual QTime clearMark(); + + /** + * Place a hard time marker. Placing another hard marker will not overwrite the previous one; + * instead, call clearHardMark() and then place another. + */ + virtual void placeHardMark(); + + /** + * Clears the hard marker. + * + * @return The old hard marker + */ + virtual QTime clearHardMark(); + + /** + * Returns the time since the time marker. Returns 0_ms if there is no marker. + * + * @return The time since the time marker + */ + virtual QTime getDtFromMark() const; + + /** + * Returns the time since the hard time marker. Returns 0_ms if there is no hard marker set. + * + * @return The time since the hard time marker + */ + virtual QTime getDtFromHardMark() const; + + /** + * Returns true when the input time period has passed, then resets. Meant to be used in loops + * to run an action every time period without blocking. + * + * @param time time period + * @return true when the input time period has passed, false after reading true until the + * period has passed again + */ + virtual bool repeat(QTime time); + + /** + * Returns true when the input time period has passed, then resets. Meant to be used in loops + * to run an action every time period without blocking. + * + * @param frequency the repeat frequency + * @return true when the input time period has passed, false after reading true until the + * period has passed again + */ + virtual bool repeat(QFrequency frequency); + + protected: + QTime firstCalled; + QTime lastCalled; + QTime mark; + QTime hardMark; + QTime repeatMark; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/util/logging.hpp b/old-code/v5_hal/firmware/include/okapi/api/util/logging.hpp new file mode 100644 index 00000000..b3a6c303 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/util/logging.hpp @@ -0,0 +1,192 @@ +/* + * 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 + +#include "okapi/api/coreProsAPI.hpp" +#include "okapi/api/util/abstractTimer.hpp" +#include "okapi/api/util/mathUtil.hpp" +#include +#include + +#if defined(THREADS_STD) +#else +#include "okapi/impl/util/timer.hpp" +#endif + +#define LOG_DEBUG(msg) logger->debug([=]() { return msg; }) +#define LOG_INFO(msg) logger->info([=]() { return msg; }) +#define LOG_WARN(msg) logger->warn([=]() { return msg; }) +#define LOG_ERROR(msg) logger->error([=]() { return msg; }) + +#define LOG_DEBUG_S(msg) LOG_DEBUG(std::string(msg)) +#define LOG_INFO_S(msg) LOG_INFO(std::string(msg)) +#define LOG_WARN_S(msg) LOG_WARN(std::string(msg)) +#define LOG_ERROR_S(msg) LOG_ERROR(std::string(msg)) + +namespace okapi { +class Logger { + public: + enum class LogLevel { + debug = 4, ///< debug + info = 3, ///< info + warn = 2, ///< warn + error = 1, ///< error + off = 0 ///< off + }; + + /** + * A logger that does nothing. + */ + Logger() noexcept; + + /** + * A logger that opens the input file by name. If the file contains `/ser/`, the file will be + * opened in write mode. Otherwise, the file will be opened in append mode. The file will be + * closed when the logger is destructed. + * + * @param itimer A timer used to get the current time for log statements. + * @param ifileName The name of the log file to open. + * @param ilevel The log level. Log statements more verbose than this level will be disabled. + */ + Logger(std::unique_ptr itimer, + std::string_view ifileName, + const LogLevel &ilevel) noexcept; + + /** + * A logger that uses an existing file handle. The file will be closed when the logger is + * destructed. + * + * @param itimer A timer used to get the current time for log statements. + * @param ifile The log file to open. Will be closed by the logger! + * @param ilevel The log level. Log statements more verbose than this level will be disabled. + */ + Logger(std::unique_ptr itimer, FILE *ifile, const LogLevel &ilevel) noexcept; + + ~Logger(); + + constexpr bool isDebugLevelEnabled() const noexcept { + return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::debug); + } + + template void debug(T ilazyMessage) noexcept { + if (isDebugLevelEnabled() && logfile && timer) { + std::scoped_lock lock(logfileMutex); + fprintf(logfile, + "%ld (%s) DEBUG: %s\n", + static_cast(timer->millis().convert(millisecond)), + CrossplatformThread::getName().c_str(), + ilazyMessage().c_str()); + } + } + + constexpr bool isInfoLevelEnabled() const noexcept { + return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::info); + } + + template void info(T ilazyMessage) noexcept { + if (isInfoLevelEnabled() && logfile && timer) { + std::scoped_lock lock(logfileMutex); + fprintf(logfile, + "%ld (%s) INFO: %s\n", + static_cast(timer->millis().convert(millisecond)), + CrossplatformThread::getName().c_str(), + ilazyMessage().c_str()); + } + } + + constexpr bool isWarnLevelEnabled() const noexcept { + return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::warn); + } + + template void warn(T ilazyMessage) noexcept { + if (isWarnLevelEnabled() && logfile && timer) { + std::scoped_lock lock(logfileMutex); + fprintf(logfile, + "%ld (%s) WARN: %s\n", + static_cast(timer->millis().convert(millisecond)), + CrossplatformThread::getName().c_str(), + ilazyMessage().c_str()); + } + } + + constexpr bool isErrorLevelEnabled() const noexcept { + return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::error); + } + + template void error(T ilazyMessage) noexcept { + if (isErrorLevelEnabled() && logfile && timer) { + std::scoped_lock lock(logfileMutex); + fprintf(logfile, + "%ld (%s) ERROR: %s\n", + static_cast(timer->millis().convert(millisecond)), + CrossplatformThread::getName().c_str(), + ilazyMessage().c_str()); + } + } + + /** + * Closes the connection to the log file. + */ + constexpr void close() noexcept { + if (logfile) { + fclose(logfile); + logfile = nullptr; + } + } + + /** + * @return The default logger. + */ + static std::shared_ptr getDefaultLogger(); + + /** + * Sets a new default logger. OkapiLib classes use the default logger unless given another logger + * in their constructor. + * + * @param ilogger The new logger instance. + */ + static void setDefaultLogger(std::shared_ptr ilogger); + + private: + const std::unique_ptr timer; + const LogLevel logLevel; + FILE *logfile; + CrossplatformMutex logfileMutex; + + static bool isSerialStream(std::string_view filename); +}; + +extern std::shared_ptr defaultLogger; + +struct DefaultLoggerInitializer { + DefaultLoggerInitializer() { + if (count++ == 0) { + init(); + } + } + ~DefaultLoggerInitializer() { + if (--count == 0) { + cleanup(); + } + } + + static int count; + + static void init() { +#if defined(THREADS_STD) + defaultLogger = std::make_shared(); +#else + defaultLogger = + std::make_shared(std::make_unique(), "/ser/sout", Logger::LogLevel::warn); +#endif + } + + static void cleanup() { + } +}; + +static DefaultLoggerInitializer defaultLoggerInitializer; // NOLINT(cert-err58-cpp) +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/util/mathUtil.hpp b/old-code/v5_hal/firmware/include/okapi/api/util/mathUtil.hpp new file mode 100644 index 00000000..5f02afb8 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/util/mathUtil.hpp @@ -0,0 +1,256 @@ +/* + * 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 + +#include "okapi/api/device/motor/abstractMotor.hpp" +#include +#include +#include +#include + +namespace okapi { +/** + * Converts inches to millimeters. + */ +static constexpr double inchToMM = 25.4; + +/** + * Converts millimeters to inches. + */ +static constexpr double mmToInch = 0.0393700787; + +/** + * Converts degrees to radians. + */ +static constexpr double degreeToRadian = 0.01745329252; + +/** + * Converts radians to degrees. + */ +static constexpr double radianToDegree = 57.2957795; + +/** + * The ticks per rotation of the 393 IME with torque gearing. + */ +static constexpr double imeTorqueTPR = 627.2; + +/** + * The ticks per rotation of the 393 IME with speed gearing. + */ +static constexpr std::int32_t imeSpeedTPR = 392; + +/** + * The ticks per rotation of the 393 IME with turbo gearing. + */ +static constexpr double imeTurboTPR = 261.333; + +/** + * The ticks per rotation of the 269 IME. + */ +static constexpr double ime269TPR = 240.448; + +/** + * The ticks per rotation of the V5 motor with a red gearset. + */ +static constexpr std::int32_t imev5RedTPR = 1800; + +/** + * The ticks per rotation of the V5 motor with a green gearset. + */ +static constexpr std::int32_t imev5GreenTPR = 900; + +/** + * The ticks per rotation of the V5 motor with a blue gearset. + */ +static constexpr std::int32_t imev5BlueTPR = 300; + +/** + * The ticks per rotation of the red quadrature encoders. + */ +static constexpr std::int32_t quadEncoderTPR = 360; + +/** + * The value of pi. + */ +static constexpr double pi = 3.1415926535897932; + +/** + * The value of pi divided by 2. + */ +static constexpr double pi2 = 1.5707963267948966; + +/** + * The conventional value of gravity of Earth. + */ +static constexpr double gravity = 9.80665; + +/** + * Same as PROS_ERR. + */ +static constexpr auto OKAPI_PROS_ERR = INT32_MAX; + +/** + * Same as PROS_ERR_F. + */ +static constexpr auto OKAPI_PROS_ERR_F = INFINITY; + +/** + * The maximum voltage that can be sent to V5 motors. + */ +static constexpr double v5MotorMaxVoltage = 12000; + +/** + * The polling frequency of V5 motors in milliseconds. + */ +static constexpr std::int8_t motorUpdateRate = 10; + +/** + * The polling frequency of the ADI ports in milliseconds. + */ +static constexpr std::int8_t adiUpdateRate = 10; + +/** + * Integer power function. Computes `base^expo`. + * + * @param base The base. + * @param expo The exponent. + * @return `base^expo`. + */ +constexpr double ipow(const double base, const int expo) { + return (expo == 0) + ? 1 + : expo == 1 ? base + : expo > 1 ? ((expo & 1) ? base * ipow(base, expo - 1) + : ipow(base, expo / 2) * ipow(base, expo / 2)) + : 1 / ipow(base, -expo); +} + +/** + * Cuts out a range from the number. The new range of the input number will be + * `(-inf, min]U[max, +inf)`. If value sits equally between `min` and `max`, `max` will be returned. + * + * @param value The number to bound. + * @param min The lower bound of range. + * @param max The upper bound of range. + * @return The remapped value. + */ +constexpr double cutRange(const double value, const double min, const double max) { + const double middle = max - ((max - min) / 2); + + if (value > min && value < middle) { + return min; + } else if (value <= max && value >= middle) { + return max; + } + + return value; +} + +/** + * Deadbands a range of the number. Returns the input value, or `0` if it is in the range `[min, + * max]`. + * + * @param value The number to deadband. + * @param min The lower bound of deadband. + * @param max The upper bound of deadband. + * @return The input value or `0` if it is in the range `[min, max]`. + */ +constexpr double deadband(const double value, const double min, const double max) { + return std::clamp(value, min, max) == value ? 0 : value; +} + +/** + * Remap a value in the range `[oldMin, oldMax]` to the range `[newMin, newMax]`. + * + * @param value The value in the old range. + * @param oldMin The old range lower bound. + * @param oldMax The old range upper bound. + * @param newMin The new range lower bound. + * @param newMax The new range upper bound. + * @return The input value in the new range `[newMin, newMax]`. + */ +constexpr double remapRange(const double value, + const double oldMin, + const double oldMax, + const double newMin, + const double newMax) { + return (value - oldMin) * ((newMax - newMin) / (oldMax - oldMin)) + newMin; +} + +/** + * Converts an enum to its value type. + * + * @param e The enum value. + * @return The corresponding value. + */ +template constexpr auto toUnderlyingType(const E e) noexcept { + return static_cast>(e); +} + +/** + * Converts a bool to a sign. + * + * @param b The bool. + * @return True corresponds to `1` and false corresponds to `-1`. + */ +constexpr auto boolToSign(const bool b) noexcept { + return b ? 1 : -1; +} + +/** + * Computes `lhs mod rhs` using Euclidean division. C's `%` symbol computes the remainder, not + * modulus. + * + * @param lhs The left-hand side. + * @param rhs The right-hand side. + * @return `lhs` mod `rhs`. + */ +constexpr long modulus(const long lhs, const long rhs) noexcept { + return ((lhs % rhs) + rhs) % rhs; +} + +/** + * Converts a gearset to its TPR. + * + * @param igearset The gearset. + * @return The corresponding TPR. + */ +constexpr std::int32_t gearsetToTPR(const AbstractMotor::gearset igearset) noexcept { + switch (igearset) { + case AbstractMotor::gearset::red: + return imev5RedTPR; + case AbstractMotor::gearset::green: + return imev5GreenTPR; + case AbstractMotor::gearset::blue: + case AbstractMotor::gearset::invalid: + default: + return imev5BlueTPR; + } +} + +/** + * Maps ADI port numbers/chars to numbers: + * ``` + * when (port) { + * in ['a', 'h'] -> [1, 8] + * in ['A', 'H'] -> [1, 8] + * else -> [1, 8] + * } + * ``` + * + * @param port The ADI port number or char. + * @return An equivalent ADI port number. + */ +constexpr std::int8_t transformADIPort(const std::int8_t port) { + if (port >= 'a' && port <= 'h') { + return port - ('a' - 1); + } else if (port >= 'A' && port <= 'H') { + return port - ('A' - 1); + } else { + return port; + } +} +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/util/supplier.hpp b/old-code/v5_hal/firmware/include/okapi/api/util/supplier.hpp new file mode 100644 index 00000000..9c92ed06 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/util/supplier.hpp @@ -0,0 +1,34 @@ +/* + * 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 + +#include + +namespace okapi { +/** + * A supplier of instances of T. + * + * @tparam T the type to supply + */ +template class Supplier { + public: + explicit Supplier(std::function ifunc) : func(ifunc) { + } + + virtual ~Supplier() = default; + + /** + * Get an instance of type T. This is usually a new instance, but it does not have to be. + * @return an instance of T + */ + T get() const { + return func(); + } + + protected: + std::function func; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/api/util/timeUtil.hpp b/old-code/v5_hal/firmware/include/okapi/api/util/timeUtil.hpp new file mode 100644 index 00000000..a79a7f2c --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/api/util/timeUtil.hpp @@ -0,0 +1,41 @@ +/* + * 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 + +#include "okapi/api/control/util/settledUtil.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/abstractTimer.hpp" +#include "okapi/api/util/supplier.hpp" + +namespace okapi { +/** + * Utility class for holding an AbstractTimer, AbstractRate, and SettledUtil together in one + * class since they are commonly used together. + */ +class TimeUtil { + public: + TimeUtil(const Supplier> &itimerSupplier, + const Supplier> &irateSupplier, + const Supplier> &isettledUtilSupplier); + + std::unique_ptr getTimer() const; + + std::unique_ptr getRate() const; + + std::unique_ptr getSettledUtil() const; + + Supplier> getTimerSupplier() const; + + Supplier> getRateSupplier() const; + + Supplier> getSettledUtilSupplier() const; + + protected: + Supplier> timerSupplier; + Supplier> rateSupplier; + Supplier> settledUtilSupplier; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/chassis/controller/chassisControllerBuilder.hpp b/old-code/v5_hal/firmware/include/okapi/impl/chassis/controller/chassisControllerBuilder.hpp new file mode 100644 index 00000000..f2f9f57f --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/chassis/controller/chassisControllerBuilder.hpp @@ -0,0 +1,484 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisControllerIntegrated.hpp" +#include "okapi/api/chassis/controller/chassisControllerPid.hpp" +#include "okapi/api/chassis/controller/defaultOdomChassisController.hpp" +#include "okapi/api/chassis/model/hDriveModel.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/chassis/model/xDriveModel.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/mathUtil.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/device/rotarysensor/adiEncoder.hpp" +#include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +class ChassisControllerBuilder { + public: + /** + * A builder that creates ChassisControllers. Use this to create your ChassisController. + * + * @param ilogger The logger this instance will log to. + */ + explicit ChassisControllerBuilder( + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the motors using a skid-steer layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const Motor &ileft, const Motor &iright); + + /** + * Sets the motors using a skid-steer layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const MotorGroup &ileft, const MotorGroup &iright); + + /** + * Sets the motors using a skid-steer layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const std::shared_ptr &ileft, + const std::shared_ptr &iright); + + /** + * Sets the motors using an x-drive layout. + * + * @param itopLeft The top left motor. + * @param itopRight The top right motor. + * @param ibottomRight The bottom right motor. + * @param ibottomLeft The bottom left motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const Motor &itopLeft, + const Motor &itopRight, + const Motor &ibottomRight, + const Motor &ibottomLeft); + + /** + * Sets the motors using an x-drive layout. + * + * @param itopLeft The top left motor. + * @param itopRight The top right motor. + * @param ibottomRight The bottom right motor. + * @param ibottomLeft The bottom left motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const MotorGroup &itopLeft, + const MotorGroup &itopRight, + const MotorGroup &ibottomRight, + const MotorGroup &ibottomLeft); + + /** + * Sets the motors using an x-drive layout. + * + * @param itopLeft The top left motor. + * @param itopRight The top right motor. + * @param ibottomRight The bottom right motor. + * @param ibottomLeft The bottom left motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const std::shared_ptr &itopLeft, + const std::shared_ptr &itopRight, + const std::shared_ptr &ibottomRight, + const std::shared_ptr &ibottomLeft); + + /** + * Sets the motors using an h-drive layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @param imiddle The middle motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withMotors(const Motor &ileft, const Motor &iright, const Motor &imiddle); + + /** + * Sets the motors using an h-drive layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @param imiddle The middle motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withMotors(const MotorGroup &ileft, const MotorGroup &iright, const MotorGroup &imiddle); + + /** + * Sets the motors using an h-drive layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @param imiddle The middle motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withMotors(const MotorGroup &ileft, const MotorGroup &iright, const Motor &imiddle); + + /** + * Sets the motors using an h-drive layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @param imiddle The middle motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const std::shared_ptr &ileft, + const std::shared_ptr &iright, + const std::shared_ptr &imiddle); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const ADIEncoder &ileft, const ADIEncoder &iright); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @param imiddle The middle sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withSensors(const ADIEncoder &ileft, const ADIEncoder &iright, const ADIEncoder &imiddle); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const IntegratedEncoder &ileft, + const IntegratedEncoder &iright); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @param imiddle The middle sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const IntegratedEncoder &ileft, + const IntegratedEncoder &iright, + const ADIEncoder &imiddle); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const std::shared_ptr &ileft, + const std::shared_ptr &iright); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @param imiddle The middle sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const std::shared_ptr &ileft, + const std::shared_ptr &iright, + const std::shared_ptr &imiddle); + + /** + * Sets the PID controller gains, causing the builder to generate a ChassisControllerPID. Uses the + * turn controller's gains for the angle controller's gains. + * + * @param idistanceGains The distance controller's gains. + * @param iturnGains The turn controller's gains. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withGains(const IterativePosPIDController::Gains &idistanceGains, + const IterativePosPIDController::Gains &iturnGains); + + /** + * Sets the PID controller gains, causing the builder to generate a ChassisControllerPID. + * + * @param idistanceGains The distance controller's gains. + * @param iturnGains The turn controller's gains. + * @param iangleGains The angle controller's gains. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withGains(const IterativePosPIDController::Gains &idistanceGains, + const IterativePosPIDController::Gains &iturnGains, + const IterativePosPIDController::Gains &iangleGains); + + /** + * Sets the odometry information, causing the builder to generate an Odometry variant. + * + * @param imode The new default StateMode used to interpret target points and query the Odometry + * state. + * @param imoveThreshold The minimum length movement. + * @param iturnThreshold The minimum angle turn. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withOdometry(const StateMode &imode = StateMode::FRAME_TRANSFORMATION, + const QLength &imoveThreshold = 0_mm, + const QAngle &iturnThreshold = 0_deg); + + /** + * Sets the odometry information, causing the builder to generate an Odometry variant. + * + * @param iodomScales The ChassisScales used just for odometry (if they are different than those + * for the drive). + * @param imode The new default StateMode used to interpret target points and query the Odometry + * state. + * @param imoveThreshold The minimum length movement. + * @param iturnThreshold The minimum angle turn. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withOdometry(const ChassisScales &iodomScales, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION, + const QLength &imoveThreshold = 0_mm, + const QAngle &iturnThreshold = 0_deg); + + /** + * Sets the odometry information, causing the builder to generate an Odometry variant. + * + * @param iodometry The odometry object. + * @param imode The new default StateMode used to interpret target points and query the Odometry + * state. + * @param imoveThreshold The minimum length movement. + * @param iturnThreshold The minimum angle turn. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withOdometry(std::shared_ptr iodometry, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION, + const QLength &imoveThreshold = 0_mm, + const QAngle &iturnThreshold = 0_deg); + + /** + * Sets the derivative filters. Uses a PassthroughFilter by default. + * + * @param idistanceFilter The distance controller's filter. + * @param iturnFilter The turn controller's filter. + * @param iangleFilter The angle controller's filter. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withDerivativeFilters( + std::unique_ptr idistanceFilter, + std::unique_ptr iturnFilter = std::make_unique(), + std::unique_ptr iangleFilter = std::make_unique()); + + /** + * Sets the chassis dimensions. + * + * @param igearset The gearset in the drive motors. + * @param iscales The ChassisScales for the base. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withDimensions(const AbstractMotor::gearset &igearset, + const ChassisScales &iscales); + + /** + * Sets the max velocity. Overrides the max velocity of the gearset. + * + * @param imaxVelocity The max velocity. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMaxVelocity(double imaxVelocity); + + /** + * Sets the max voltage. The default is `12000`. + * + * @param imaxVoltage The max voltage. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMaxVoltage(double imaxVoltage); + + /** + * Sets the TimeUtilFactory used when building a ChassisController. This instance will be given + * to the ChassisController (not to controllers it uses). The default is the static + * TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withChassisControllerTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Sets the TimeUtilFactory used when building a ClosedLoopController. This instance will be given + * to any ClosedLoopController instances. The default is the static TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withClosedLoopControllerTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Creates a new ConfigurableTimeUtilFactory with the given parameters. Given to any + * ClosedLoopController instances. + * + * @param iatTargetError The minimum error to be considered settled. + * @param iatTargetDerivative The minimum error derivative to be considered settled. + * @param iatTargetTime The minimum time within atTargetError to be considered settled. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withClosedLoopControllerTimeUtil(double iatTargetError = 50, + double iatTargetDerivative = 5, + const QTime &iatTargetTime = 250_ms); + + /** + * Sets the TimeUtilFactory used when building an Odometry. The default is the static + * TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withOdometryTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Sets the logger used for the ChassisController and ClosedLoopControllers. + * + * @param ilogger The logger. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withLogger(const std::shared_ptr &ilogger); + + /** + * Parents the internal tasks started by this builder to the current task, meaning they will be + * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks + * are never parented to. This is the default behavior. + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + ChassisControllerBuilder &parentedToCurrentTask(); + + /** + * Prevents parenting the internal tasks started by this builder to the current task, meaning they + * will not be deleted once the current task is deleted. This can cause runaway tasks, but is + * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and + * then again in `opcontrol`). + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + ChassisControllerBuilder ¬ParentedToCurrentTask(); + + /** + * Builds the ChassisController. Throws a std::runtime_exception if no motors were set or if no + * dimensions were set. + * + * @return A fully built ChassisController. + */ + std::shared_ptr build(); + + /** + * Builds the OdomChassisController. Throws a std::runtime_exception if no motors were set, if no + * dimensions were set, or if no odometry information was passed. + * + * @return A fully built OdomChassisController. + */ + std::shared_ptr buildOdometry(); + + private: + std::shared_ptr logger; + + struct SkidSteerMotors { + std::shared_ptr left; + std::shared_ptr right; + }; + + struct XDriveMotors { + std::shared_ptr topLeft; + std::shared_ptr topRight; + std::shared_ptr bottomRight; + std::shared_ptr bottomLeft; + }; + + struct HDriveMotors { + std::shared_ptr left; + std::shared_ptr right; + std::shared_ptr middle; + }; + + enum class DriveMode { SkidSteer, XDrive, HDrive }; + + bool hasMotors{false}; // Used to verify motors were passed + DriveMode driveMode{DriveMode::SkidSteer}; + SkidSteerMotors skidSteerMotors; + XDriveMotors xDriveMotors; + HDriveMotors hDriveMotors; + + bool sensorsSetByUser{false}; // Used so motors don't overwrite sensors set manually + std::shared_ptr leftSensor{nullptr}; + std::shared_ptr rightSensor{nullptr}; + std::shared_ptr middleSensor{nullptr}; + + bool hasGains{false}; // Whether gains were passed, no gains means CCI + IterativePosPIDController::Gains distanceGains; + std::unique_ptr distanceFilter = std::make_unique(); + IterativePosPIDController::Gains angleGains; + std::unique_ptr angleFilter = std::make_unique(); + IterativePosPIDController::Gains turnGains; + std::unique_ptr turnFilter = std::make_unique(); + TimeUtilFactory chassisControllerTimeUtilFactory = TimeUtilFactory(); + TimeUtilFactory closedLoopControllerTimeUtilFactory = TimeUtilFactory(); + TimeUtilFactory odometryTimeUtilFactory = TimeUtilFactory(); + + AbstractMotor::GearsetRatioPair gearset{AbstractMotor::gearset::invalid}; + ChassisScales driveScales{{1, 1}, imev5GreenTPR}; + bool differentOdomScales{false}; + ChassisScales odomScales{{1, 1}, imev5GreenTPR}; + std::shared_ptr controllerLogger = Logger::getDefaultLogger(); + + bool hasOdom{false}; // Whether odometry was passed + std::shared_ptr odometry; + StateMode stateMode; + QLength moveThreshold; + QAngle turnThreshold; + + bool maxVelSetByUser{false}; // Used so motors don't overwrite maxVelocity + double maxVelocity{600}; + + double maxVoltage{12000}; + + bool isParentedToCurrentTask{true}; + + std::shared_ptr buildCCPID(); + std::shared_ptr buildCCI(); + std::shared_ptr + buildDOCC(std::shared_ptr chassisController); + + std::shared_ptr makeChassisModel(); + std::shared_ptr makeSkidSteerModel(); + std::shared_ptr makeXDriveModel(); + std::shared_ptr makeHDriveModel(); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp b/old-code/v5_hal/firmware/include/okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp new file mode 100644 index 00000000..7faf8271 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp @@ -0,0 +1,177 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisController.hpp" +#include "okapi/api/control/async/asyncLinearMotionProfileController.hpp" +#include "okapi/api/control/async/asyncMotionProfileController.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +class AsyncMotionProfileControllerBuilder { + public: + /** + * A builder that creates async motion profile controllers. Use this to build an + * AsyncMotionProfileController or an AsyncLinearMotionProfileController. + * + * @param ilogger The logger this instance will log to. + */ + explicit AsyncMotionProfileControllerBuilder( + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the output. This must be used with buildLinearMotionProfileController(). + * + * @param ioutput The output. + * @param idiameter The diameter of the mechanical part the motor spins. + * @param ipair The gearset. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withOutput(const Motor &ioutput, + const QLength &idiameter, + const AbstractMotor::GearsetRatioPair &ipair); + + /** + * Sets the output. This must be used with buildLinearMotionProfileController(). + * + * @param ioutput The output. + * @param idiameter The diameter of the mechanical part the motor spins. + * @param ipair The gearset. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withOutput(const MotorGroup &ioutput, + const QLength &idiameter, + const AbstractMotor::GearsetRatioPair &ipair); + + /** + * Sets the output. This must be used with buildLinearMotionProfileController(). + * + * @param ioutput The output. + * @param idiameter The diameter of the mechanical part the motor spins. + * @param ipair The gearset. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder & + withOutput(const std::shared_ptr> &ioutput, + const QLength &idiameter, + const AbstractMotor::GearsetRatioPair &ipair); + + /** + * Sets the output. This must be used with buildMotionProfileController(). + * + * @param icontroller The chassis controller to use. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withOutput(ChassisController &icontroller); + + /** + * Sets the output. This must be used with buildMotionProfileController(). + * + * @param icontroller The chassis controller to use. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder & + withOutput(const std::shared_ptr &icontroller); + + /** + * Sets the output. This must be used with buildMotionProfileController(). + * + * @param imodel The chassis model to use. + * @param iscales The chassis dimensions. + * @param ipair The gearset. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withOutput(const std::shared_ptr &imodel, + const ChassisScales &iscales, + const AbstractMotor::GearsetRatioPair &ipair); + + /** + * Sets the limits. + * + * @param ilimits The limits. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withLimits(const PathfinderLimits &ilimits); + + /** + * Sets the TimeUtilFactory used when building the controller. The default is the static + * TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Sets the logger. + * + * @param ilogger The logger. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withLogger(const std::shared_ptr &ilogger); + + /** + * Parents the internal tasks started by this builder to the current task, meaning they will be + * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks + * are never parented to. This is the default behavior. + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &parentedToCurrentTask(); + + /** + * Prevents parenting the internal tasks started by this builder to the current task, meaning they + * will not be deleted once the current task is deleted. This can cause runaway tasks, but is + * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and + * then again in `opcontrol`). + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder ¬ParentedToCurrentTask(); + + /** + * Builds the AsyncLinearMotionProfileController. + * + * @return A fully built AsyncLinearMotionProfileController. + */ + std::shared_ptr buildLinearMotionProfileController(); + + /** + * Builds the AsyncMotionProfileController. + * + * @return A fully built AsyncMotionProfileController. + */ + std::shared_ptr buildMotionProfileController(); + + private: + std::shared_ptr logger; + + bool hasLimits{false}; + PathfinderLimits limits; + + bool hasOutput{false}; + std::shared_ptr> output; + QLength diameter; + + bool hasModel{false}; + std::shared_ptr model; + ChassisScales scales{{1, 1}, imev5GreenTPR}; + AbstractMotor::GearsetRatioPair pair{AbstractMotor::gearset::invalid}; + TimeUtilFactory timeUtilFactory = TimeUtilFactory(); + std::shared_ptr controllerLogger = Logger::getDefaultLogger(); + + bool isParentedToCurrentTask{true}; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/control/async/asyncPosControllerBuilder.hpp b/old-code/v5_hal/firmware/include/okapi/impl/control/async/asyncPosControllerBuilder.hpp new file mode 100644 index 00000000..124558b3 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/control/async/asyncPosControllerBuilder.hpp @@ -0,0 +1,190 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncPosIntegratedController.hpp" +#include "okapi/api/control/async/asyncPosPidController.hpp" +#include "okapi/api/control/async/asyncPositionController.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/device/rotarysensor/adiEncoder.hpp" +#include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +class AsyncPosControllerBuilder { + public: + /** + * A builder that creates async position controllers. Use this to create an + * AsyncPosIntegratedController or an AsyncPosPIDController. + * + * @param ilogger The logger this instance will log to. + */ + explicit AsyncPosControllerBuilder( + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withMotor(const Motor &imotor); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withMotor(const MotorGroup &imotor); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withMotor(const std::shared_ptr &imotor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withSensor(const ADIEncoder &isensor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withSensor(const IntegratedEncoder &isensor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withSensor(const std::shared_ptr &isensor); + + /** + * Sets the controller gains, causing the builder to generate an AsyncPosPIDController. This does + * not set the integrated control's gains. + * + * @param igains The gains. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withGains(const IterativePosPIDController::Gains &igains); + + /** + * Sets the derivative filter which filters the derivative term before it is scaled by kD. The + * filter is ignored when using integrated control. The default derivative filter is a + * PassthroughFilter. + * + * @param iderivativeFilter The derivative filter. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withDerivativeFilter(std::unique_ptr iderivativeFilter); + + /** + * Sets the gearset. The default gearset is derived from the motor's. + * + * @param igearset The gearset. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withGearset(const AbstractMotor::GearsetRatioPair &igearset); + + /** + * Sets the maximum velocity. The default maximum velocity is derived from the motor's gearset. + * This parameter is ignored when using an AsyncPosPIDController. + * + * @param imaxVelocity The maximum velocity. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withMaxVelocity(double imaxVelocity); + + /** + * Sets the TimeUtilFactory used when building the controller. The default is the static + * TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Sets the logger. + * + * @param ilogger The logger. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withLogger(const std::shared_ptr &ilogger); + + /** + * Parents the internal tasks started by this builder to the current task, meaning they will be + * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks + * are never parented to. This is the default behavior. + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &parentedToCurrentTask(); + + /** + * Prevents parenting the internal tasks started by this builder to the current task, meaning they + * will not be deleted once the current task is deleted. This can cause runaway tasks, but is + * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and + * then again in `opcontrol`). + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncPosControllerBuilder ¬ParentedToCurrentTask(); + + /** + * Builds the AsyncPositionController. Throws a std::runtime_exception is no motors were set. + * + * @return A fully built AsyncPositionController. + */ + std::shared_ptr> build(); + + private: + std::shared_ptr logger; + + bool hasMotors{false}; // Used to verify motors were passed + std::shared_ptr motor; + + bool sensorsSetByUser{false}; // Used so motors don't overwrite sensors set manually + std::shared_ptr sensor; + + bool hasGains{false}; // Whether gains were passed, no gains means integrated control + IterativePosPIDController::Gains gains; + std::unique_ptr derivativeFilter = std::make_unique(); + + bool gearsetSetByUser{false}; // Used so motor's don't overwrite a gearset set manually + AbstractMotor::GearsetRatioPair pair{AbstractMotor::gearset::invalid}; + + bool maxVelSetByUser{false}; // Used so motors don't overwrite maxVelocity + double maxVelocity{600}; + + TimeUtilFactory timeUtilFactory = TimeUtilFactory(); + std::shared_ptr controllerLogger = Logger::getDefaultLogger(); + + bool isParentedToCurrentTask{true}; + + std::shared_ptr buildAPIC(); + std::shared_ptr buildAPPC(); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/control/async/asyncVelControllerBuilder.hpp b/old-code/v5_hal/firmware/include/okapi/impl/control/async/asyncVelControllerBuilder.hpp new file mode 100644 index 00000000..8643e892 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/control/async/asyncVelControllerBuilder.hpp @@ -0,0 +1,203 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncVelIntegratedController.hpp" +#include "okapi/api/control/async/asyncVelPidController.hpp" +#include "okapi/api/control/async/asyncVelocityController.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/device/rotarysensor/adiEncoder.hpp" +#include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +class AsyncVelControllerBuilder { + public: + /** + * A builder that creates async velocity controllers. Use this to create an + * AsyncVelIntegratedController or an AsyncVelPIDController. + * + * @param ilogger The logger this instance will log to. + */ + explicit AsyncVelControllerBuilder( + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withMotor(const Motor &imotor); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withMotor(const MotorGroup &imotor); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withMotor(const std::shared_ptr &imotor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withSensor(const ADIEncoder &isensor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withSensor(const IntegratedEncoder &isensor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withSensor(const std::shared_ptr &isensor); + + /** + * Sets the controller gains, causing the builder to generate an AsyncVelPIDController. This does + * not set the integrated control's gains. + * + * @param igains The gains. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withGains(const IterativeVelPIDController::Gains &igains); + + /** + * Sets the VelMath which calculates and filters velocity. This is ignored when using integrated + * controller. If using a PID controller (by setting the gains), this is required. + * + * @param ivelMath The VelMath. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withVelMath(std::unique_ptr ivelMath); + + /** + * Sets the derivative filter which filters the derivative term before it is scaled by kD. The + * filter is ignored when using integrated control. The default derivative filter is a + * PassthroughFilter. + * + * @param iderivativeFilter The derivative filter. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withDerivativeFilter(std::unique_ptr iderivativeFilter); + + /** + * Sets the gearset. The default gearset is derived from the motor's. + * + * @param igearset The gearset. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withGearset(const AbstractMotor::GearsetRatioPair &igearset); + + /** + * Sets the maximum velocity. The default maximum velocity is derived from the motor's gearset. + * This parameter is ignored when using an AsyncVelPIDController. + * + * @param imaxVelocity The maximum velocity. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withMaxVelocity(double imaxVelocity); + + /** + * Sets the TimeUtilFactory used when building the controller. The default is the static + * TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Sets the logger. + * + * @param ilogger The logger. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withLogger(const std::shared_ptr &ilogger); + + /** + * Parents the internal tasks started by this builder to the current task, meaning they will be + * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks + * are never parented to. This is the default behavior. + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &parentedToCurrentTask(); + + /** + * Prevents parenting the internal tasks started by this builder to the current task, meaning they + * will not be deleted once the current task is deleted. This can cause runaway tasks, but is + * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and + * then again in `opcontrol`). + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncVelControllerBuilder ¬ParentedToCurrentTask(); + + /** + * Builds the AsyncVelocityController. Throws a std::runtime_exception is no motors were set. + * + * @return A fully built AsyncVelocityController. + */ + std::shared_ptr> build(); + + private: + std::shared_ptr logger; + + bool hasMotors{false}; // Used to verify motors were passed + std::shared_ptr motor; + + bool sensorsSetByUser{false}; // Used so motors don't overwrite sensors set manually + std::shared_ptr sensor; + + bool hasGains{false}; // Whether gains were passed, no gains means integrated control + IterativeVelPIDController::Gains gains; + + bool hasVelMath{false}; // Used to verify velMath was passed + std::unique_ptr velMath; + + std::unique_ptr derivativeFilter = std::make_unique(); + + bool gearsetSetByUser{false}; // Used so motor's don't overwrite a gearset set manually + AbstractMotor::GearsetRatioPair pair{AbstractMotor::gearset::invalid}; + + bool maxVelSetByUser{false}; // Used so motors don't overwrite maxVelocity + double maxVelocity{600}; + + TimeUtilFactory timeUtilFactory = TimeUtilFactory(); + std::shared_ptr controllerLogger = Logger::getDefaultLogger(); + + bool isParentedToCurrentTask{true}; + + std::shared_ptr buildAVIC(); + std::shared_ptr buildAVPC(); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/control/iterative/iterativeControllerFactory.hpp b/old-code/v5_hal/firmware/include/okapi/impl/control/iterative/iterativeControllerFactory.hpp new file mode 100644 index 00000000..85b05a58 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/control/iterative/iterativeControllerFactory.hpp @@ -0,0 +1,120 @@ +/* + * 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 + +#include "okapi/api/control/iterative/iterativeMotorVelocityController.hpp" +#include "okapi/api/control/iterative/iterativePosPidController.hpp" +#include "okapi/api/control/iterative/iterativeVelPidController.hpp" +#include "okapi/api/util/mathUtil.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/filter/velMathFactory.hpp" + +namespace okapi { +class IterativeControllerFactory { + public: + /** + * Position PID controller. + * + * @param ikP proportional gain + * @param ikI integral gain + * @param ikD derivative gain + * @param ikBias controller bias (constant offset added to the output) + * @param iderivativeFilter A filter for filtering the derivative term. + * @param ilogger The logger this instance will log to. + */ + static IterativePosPIDController + posPID(double ikP, + double ikI, + double ikD, + double ikBias = 0, + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity PD controller. + * + * @param ikP proportional gain + * @param ikD derivative gain + * @param ikF feed-forward gain + * @param ikSF a feed-forward gain to counteract static friction + * @param iderivativeFilter A filter for filtering the derivative term. + * @param ilogger The logger this instance will log to. + */ + static IterativeVelPIDController + velPID(double ikP, + double ikD, + double ikF = 0, + double ikSF = 0, + std::unique_ptr ivelMath = VelMathFactory::createPtr(imev5GreenTPR), + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity PD controller that automatically writes to the motor. + * + * @param imotor output motor + * @param ikP proportional gain + * @param ikD derivative gain + * @param ikF feed-forward gain + * @param ikSF a feed-forward gain to counteract static friction + * @param ivelMath The VelMath. + * @param iderivativeFilter A filter for filtering the derivative term. + * @param ilogger The logger this instance will log to. + */ + static IterativeMotorVelocityController + motorVelocity(Motor imotor, + double ikP, + double ikD, + double ikF = 0, + double ikSF = 0, + std::unique_ptr ivelMath = VelMathFactory::createPtr(imev5GreenTPR), + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity PD controller that automatically writes to the motor. + * + * @param imotor output motor + * @param ikP proportional gain + * @param ikD derivative gain + * @param ikF feed-forward gain + * @param ikSF a feed-forward gain to counteract static friction + * @param ivelMath The VelMath. + * @param iderivativeFilter A filter for filtering the derivative term. + * @param ilogger The logger this instance will log to. + */ + static IterativeMotorVelocityController + motorVelocity(MotorGroup imotor, + double ikP, + double ikD, + double ikF = 0, + double ikSF = 0, + std::unique_ptr ivelMath = VelMathFactory::createPtr(imev5GreenTPR), + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity PD controller that automatically writes to the motor. + * + * @param imotor output motor + * @param icontroller controller to use + */ + static IterativeMotorVelocityController + motorVelocity(Motor imotor, + std::shared_ptr> icontroller); + + /** + * Velocity PD controller that automatically writes to the motor. + * + * @param imotor output motor + * @param icontroller controller to use + */ + static IterativeMotorVelocityController + motorVelocity(MotorGroup imotor, + std::shared_ptr> icontroller); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/control/util/controllerRunnerFactory.hpp b/old-code/v5_hal/firmware/include/okapi/impl/control/util/controllerRunnerFactory.hpp new file mode 100644 index 00000000..16ab592f --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/control/util/controllerRunnerFactory.hpp @@ -0,0 +1,25 @@ +/* + * 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 + +#include "okapi/api/control/util/controllerRunner.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +template class ControllerRunnerFactory { + public: + /** + * A utility class that runs a closed-loop controller. + * + * @param ilogger The logger this instance will log to. + * @return + */ + static ControllerRunner + create(const std::shared_ptr &ilogger = Logger::getDefaultLogger()) { + return ControllerRunner(TimeUtilFactory::createDefault(), ilogger); + } +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/control/util/pidTunerFactory.hpp b/old-code/v5_hal/firmware/include/okapi/impl/control/util/pidTunerFactory.hpp new file mode 100644 index 00000000..332b55fc --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/control/util/pidTunerFactory.hpp @@ -0,0 +1,47 @@ +/* + * 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 + +#include "okapi/api/control/util/pidTuner.hpp" +#include + +namespace okapi { +class PIDTunerFactory { + public: + static PIDTuner create(const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + QTime itimeout, + std::int32_t igoal, + double ikPMin, + double ikPMax, + double ikIMin, + double ikIMax, + double ikDMin, + double ikDMax, + std::int32_t inumIterations = 5, + std::int32_t inumParticles = 16, + double ikSettle = 1, + double ikITAE = 2, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + static std::unique_ptr + createPtr(const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + QTime itimeout, + std::int32_t igoal, + double ikPMin, + double ikPMax, + double ikIMin, + double ikIMax, + double ikDMin, + double ikDMax, + std::int32_t inumIterations = 5, + std::int32_t inumParticles = 16, + double ikSettle = 1, + double ikITAE = 2, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/device/adiUltrasonic.hpp b/old-code/v5_hal/firmware/include/okapi/impl/device/adiUltrasonic.hpp new file mode 100644 index 00000000..6a525f4d --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/device/adiUltrasonic.hpp @@ -0,0 +1,71 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include + +namespace okapi { +class ADIUltrasonic : public ControllerInput { + public: + /** + * An ultrasonic sensor in the ADI (3-wire) ports. + * + * ```cpp + * auto ultra = ADIUltrasonic('A', 'B'); + * auto filteredUltra = ADIUltrasonic('A', 'B', std::make_unique>()); + * ``` + * + * @param iportPing The port connected to the orange OUTPUT cable. This must be in port ``1``, + * ``3``, ``5``, or ``7`` (``A``, ``C``, ``E``, or ``G``). + * @param iportEcho The port connected to the yellow INPUT cable. This must be in the next highest + * port following iportPing. + * @param ifilter The filter to use for filtering the distance measurements. + */ + ADIUltrasonic(std::uint8_t iportPing, + std::uint8_t iportEcho, + std::unique_ptr ifilter = std::make_unique()); + + /** + * An ultrasonic sensor in the ADI (3-wire) ports. + * + * ```cpp + * auto ultra = ADIUltrasonic({1, 'A', 'B'}); + * auto filteredUltra = ADIUltrasonic({1, 'A', 'B'}, std::make_unique>()); + * ``` + * + * @param iports The ports the ultrasonic is plugged in to in the order ``{smart port, ping port, + * echo port}``. The smart port is the smart port number (``[1, 21]``). The ping port is the port + * connected to the orange OUTPUT cable. This must be in port ``1``, ``3``, ``5``, or ``7`` + * (``A``, ``C``, ``E``, or ``G``). The echo port is the port connected to the yellow INPUT cable. + * This must be in the next highest port following the ping port. + * @param ifilter The filter to use for filtering the distance measurements. + */ + ADIUltrasonic(std::tuple iports, + std::unique_ptr ifilter = std::make_unique()); + + virtual ~ADIUltrasonic(); + + /** + * Returns the current filtered sensor value. + * + * @return current value + */ + virtual double get(); + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. Calls get(). + */ + virtual double controllerGet() override; + + protected: + pros::c::ext_adi_ultrasonic_t ultra; + std::unique_ptr filter; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/device/button/adiButton.hpp b/old-code/v5_hal/firmware/include/okapi/impl/device/button/adiButton.hpp new file mode 100644 index 00000000..32e59a8a --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/device/button/adiButton.hpp @@ -0,0 +1,50 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/device/button/buttonBase.hpp" + +namespace okapi { +class ADIButton : public ButtonBase { + public: + /** + * A button in an ADI port. + * + * ```cpp + * auto btn = ADIButton('A', false); + * auto invertedBtn = ADIButton('A', true); + * ``` + * + * @param iport The ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). + * @param iinverted Whether the button is inverted (``true`` meaning default pressed and ``false`` + * meaning default not pressed). + */ + ADIButton(std::uint8_t iport, bool iinverted = false); + + /** + * A button in an ADI port. + * + * ```cpp + * auto btn = ADIButton({1, 'A'}, false); + * auto invertedBtn = ADIButton({1, 'A'}, true); + * ``` + * + * @param iports The ports the button is plugged in to in the order ``{smart port, button port}``. + * The smart port is the smart port number (``[1, 21]``). The button port is the ADI port number + * (``[1, 8]``, ``[a, h]``, ``[A, H]``). + * @param iinverted Whether the button is inverted (``true`` meaning default pressed and ``false`` + * meaning default not pressed). + */ + ADIButton(std::pair iports, bool iinverted = false); + + protected: + std::uint8_t smartPort; + std::uint8_t port; + + virtual bool currentlyPressed() override; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/device/button/controllerButton.hpp b/old-code/v5_hal/firmware/include/okapi/impl/device/button/controllerButton.hpp new file mode 100644 index 00000000..3d7e5e58 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/device/button/controllerButton.hpp @@ -0,0 +1,38 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/device/button/buttonBase.hpp" +#include "okapi/impl/device/controllerUtil.hpp" + +namespace okapi { +class ControllerButton : public ButtonBase { + public: + /** + * A button on a Controller. + * + * @param ibtn The button id. + * @param iinverted Whether the button is inverted (default pressed instead of default released). + */ + ControllerButton(ControllerDigital ibtn, bool iinverted = false); + + /** + * A button on a Controller. + * + * @param icontroller The Controller the button is on. + * @param ibtn The button id. + * @param iinverted Whether the button is inverted (default pressed instead of default released). + */ + ControllerButton(ControllerId icontroller, ControllerDigital ibtn, bool iinverted = false); + + protected: + pros::controller_id_e_t id; + pros::controller_digital_e_t btn; + + virtual bool currentlyPressed() override; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/device/controller.hpp b/old-code/v5_hal/firmware/include/okapi/impl/device/controller.hpp new file mode 100644 index 00000000..81f92298 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/device/controller.hpp @@ -0,0 +1,118 @@ +/* + * 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 + +#include "api.h" +#include "okapi/impl/device/button/controllerButton.hpp" +#include "okapi/impl/device/controllerUtil.hpp" +#include + +namespace okapi { +class Controller { + public: + Controller(ControllerId iid = ControllerId::master); + + virtual ~Controller(); + + /** + * Returns whether the controller is connected. + * + * @return true if the controller is connected + */ + virtual bool isConnected(); + + /** + * Returns the current analog reading for the channel in the range [-1, 1]. Returns 0 if the + * controller is not connected. + * + * @param ichannel the channel to read + * @return the value of that channel in the range [-1, 1] + */ + virtual float getAnalog(ControllerAnalog ichannel); + + /** + * Returns whether the digital button is currently pressed. Returns false if the controller is + * not connected. + * + * @param ibutton the button to check + * @return true if the button is pressed, false if the controller is not connected + */ + virtual bool getDigital(ControllerDigital ibutton); + + /** + * Returns a ControllerButton for the given button on this controller. + * + * @param ibtn the button + * @return a ControllerButton on this controller + */ + virtual ControllerButton &operator[](ControllerDigital ibtn); + + /** + * Sets text to the controller LCD screen. + * + * @param iline the line number in the range [0-2] at which the text will be displayed + * @param icol the column number in the range [0-14] at which the text will be displayed + * @param itext the string to display + * @return 1 if the operation was successful, PROS_ERR otherwise + */ + virtual std::int32_t setText(std::uint8_t iline, std::uint8_t icol, std::string itext); + + /** + * Clears all of the lines of the controller screen. On vexOS version 1.0.0 this function will + * block for 110ms. + * + * @return 1 if the operation was successful, PROS_ERR otherwise + */ + virtual std::int32_t clear(); + + /** + * Clears an individual line of the controller screen. + * + * @param iline the line number to clear in the range [0, 2]. + * @return 1 if the operation was successful, PROS_ERR otherwise + */ + virtual std::int32_t clearLine(std::uint8_t iline); + + /** + * Rumble the controller. + * + * Controller rumble activation is currently in beta, so continuous, fast + * updates will not work well. + * + * @param irumblePattern A string consisting of the characters '.', '-', and ' ', where dots are + * short rumbles, dashes are long rumbles, and spaces are pauses. Maximum supported length is 8 + * characters. + * + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t rumble(std::string irumblePattern); + + /** + * Gets the battery capacity of the given controller. + * + * 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. + * + * @return the controller's battery capacity + */ + virtual std::int32_t getBatteryCapacity(); + + /** + * Gets the battery level of the given controller. + * + * 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. + * + * @return the controller's battery level + */ + virtual std::int32_t getBatteryLevel(); + + protected: + ControllerId okapiId; + pros::controller_id_e_t prosId; + std::array buttonArray{}; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/device/controllerUtil.hpp b/old-code/v5_hal/firmware/include/okapi/impl/device/controllerUtil.hpp new file mode 100644 index 00000000..d62df3ab --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/device/controllerUtil.hpp @@ -0,0 +1,64 @@ +/* + * 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 + +#include "api.h" + +namespace okapi { +/** + * Which controller role this has. + */ +enum class ControllerId { + master = 0, ///< master + partner = 1 ///< partner +}; + +/** + * The analog sticks. + */ +enum class ControllerAnalog { + leftX = 0, ///< leftX + leftY = 1, ///< leftY + rightX = 2, ///< rightX + rightY = 3 ///< rightY +}; + +/** + * Various buttons. + */ +enum class ControllerDigital { + L1 = 6, ///< L1 + L2 = 7, ///< L2 + R1 = 8, ///< R1 + R2 = 9, ///< R2 + up = 10, ///< up + down = 11, ///< down + left = 12, ///< left + right = 13, ///< right + X = 14, ///< X + B = 15, ///< B + Y = 16, ///< Y + A = 17 ///< A +}; + +class ControllerUtil { + public: + /** + * Maps an `id` to the PROS enum equivalent. + */ + static pros::controller_id_e_t idToProsEnum(ControllerId in); + + /** + * Maps an `analog` to the PROS enum equivalent. + */ + static pros::controller_analog_e_t analogToProsEnum(ControllerAnalog in); + + /** + * Maps a `digital` to the PROS enum equivalent. + */ + static pros::controller_digital_e_t digitalToProsEnum(ControllerDigital in); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/device/motor/adiMotor.hpp b/old-code/v5_hal/firmware/include/okapi/impl/device/motor/adiMotor.hpp new file mode 100644 index 00000000..f39bd417 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/device/motor/adiMotor.hpp @@ -0,0 +1,69 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/util/logging.hpp" + +namespace okapi { +class ADIMotor : public ControllerOutput { + public: + /** + * A motor in an ADI port. + * + * ```cpp + * auto mtr = ADIMotor('A'); + * auto reversedMtr = ADIMotor('A', true); + * ``` + * + * @param iport The ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). + * @param ireverse Whether the motor is reversed. + * @param logger The logger that initialization warnings will be logged to. + */ + ADIMotor(std::uint8_t iport, + bool ireverse = false, + const std::shared_ptr &logger = Logger::getDefaultLogger()); + + /** + * A motor in an ADI port. + * + * ```cpp + * auto mtr = ADIMotor({1, 'A'}, false); + * auto reversedMtr = ADIMotor({1, 'A'}, true); + * ``` + * + * @param iports The ports the motor is plugged in to in the order ``{smart port, motor port}``. + * The smart port is the smart port number (``[1, 21]``). The motor port is the ADI port number + * (``[1, 8]``, ``[a, h]``, ``[A, H]``). + * @param ireverse Whether the motor is reversed. + * @param logger The logger that initialization warnings will be logged to. + */ + ADIMotor(std::pair iports, + bool ireverse = false, + const std::shared_ptr &logger = Logger::getDefaultLogger()); + + /** + * Set the voltage to the motor. + * + * @param ivoltage voltage in the range [-127, 127]. + */ + virtual void moveVoltage(std::int8_t ivoltage) const; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be [-1, 1]. + * + * @param ivalue the controller's output in the range [-1, 1] + */ + void controllerSet(double ivalue) override; + + protected: + std::uint8_t smartPort; + std::uint8_t port; + std::int8_t reversed; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/device/motor/motor.hpp b/old-code/v5_hal/firmware/include/okapi/impl/device/motor/motor.hpp new file mode 100644 index 00000000..78c5b3b0 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/device/motor/motor.hpp @@ -0,0 +1,457 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/util/logging.hpp" + +namespace okapi { +class Motor : public AbstractMotor { + public: + /** + * A V5 motor. + * + * @param iport The port number in the range ``[1, 21]``. A negative port number is shorthand for + * reversing the motor. + */ + Motor(std::int8_t iport); + + /** + * A V5 motor. + * + * @param iport The port number in the range [1, 21]. + * @param ireverse Whether the motor is reversed (this setting is not written to the motor, it is + * maintained by okapi::Motor instead). + * @param igearset The internal gearset to set in the motor. + * @param iencoderUnits The encoder units to set in the motor. + * @param logger The logger that initialization warnings will be logged to. + */ + Motor(std::uint8_t iport, + bool ireverse, + AbstractMotor::gearset igearset, + AbstractMotor::encoderUnits iencoderUnits, + const std::shared_ptr &logger = Logger::getDefaultLogger()); + + /******************************************************************************/ + /** Motor movement functions **/ + /** **/ + /** These functions allow programmers to make motors move **/ + /******************************************************************************/ + + /** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with setZeroPosition(). + * + * @note This function simply sets the target for the motor, it does not block program execution + * until the movement finishes. + * + * @param iposition The absolute position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t moveAbsolute(double iposition, std::int32_t ivelocity) override; + + /** + * Sets the relative target position for the motor to move to. + * + * This movement is relative to the current position of the motor. Providing 10.0 as the position + * parameter would result in the motor moving clockwise 10 units, 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. + * + * @param iposition The relative position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t moveRelative(double iposition, std::int32_t ivelocity) override; + + /** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the gearset + * used for the motor. This results in a range of +-100 for pros::c::red, + * +-200 for green, and +-600 for blue. The velocity + * is held with PID to ensure consistent speed, as opposed to setting the motor's + * voltage. + * + * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's + * gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t moveVelocity(std::int16_t ivelocity) override; + + /** + * Sets the voltage for the motor from -12000 to 12000. + * + * @param ivoltage The new voltage value from -12000 to 12000. + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t moveVoltage(std::int16_t ivoltage) override; + + /** + * Changes the output velocity for a profiled movement (moveAbsolute or moveRelative). This will + * have no effect if the motor is not following a profiled movement. + * + * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's + * gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t modifyProfiledVelocity(std::int32_t ivelocity) override; + + /******************************************************************************/ + /** Motor telemetry functions **/ + /** **/ + /** These functions allow programmers to collect telemetry from motors **/ + /******************************************************************************/ + + /** + * Gets the target position set for the motor by the user. + * + * @return The target position in its encoder units or PROS_ERR_F if the operation failed, + * setting errno. + */ + double getTargetPosition() override; + + /** + * Gets the absolute position of the motor in its encoder units. + * + * @return The motor's absolute position in its encoder units or PROS_ERR_F if the operation + * failed, setting errno. + */ + double getPosition() override; + + /** + * Sets the "absolute" zero position of the motor to its current position. + * + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t tarePosition() override; + + /** + * Gets the velocity commanded to the motor by the user. + * + * @return The commanded motor velocity from +-100, +-200, or +-600, or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t getTargetVelocity() override; + + /** + * Gets the actual velocity of the motor. + * + * @return The motor's actual velocity in RPM or PROS_ERR_F if the operation failed, setting + * errno. + */ + double getActualVelocity() override; + + /** + * Gets the current drawn by the motor in mA. + * + * @return The motor's current in mA or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t getCurrentDraw() override; + + /** + * Gets the direction of movement for the motor. + * + * @return 1 for moving in the positive direction, -1 for moving in the negative direction, and + * PROS_ERR if the operation failed, setting errno. + */ + std::int32_t getDirection() override; + + /** + * Gets the efficiency of the motor in percent. + * + * 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. + * + * @return The motor's efficiency in percent or PROS_ERR_F if the operation failed, setting errno. + */ + double getEfficiency() override; + + /** + * Checks if the motor is drawing over its current limit. + * + * @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. + */ + std::int32_t isOverCurrent() override; + + /** + * Checks if the motor's temperature is above its limit. + * + * @return 1 if the temperature limit is exceeded and 0 if the the temperature is below the limit, + * or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t isOverTemp() override; + + /** + * Checks if the motor is stopped. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns PROS_ERR with errno set to ENOSYS. + * + * @return 1 if the motor is not moving, 0 if the motor is moving, or PROS_ERR if the operation + * failed, setting errno + */ + std::int32_t isStopped() override; + + /** + * Checks if the motor is at its zero position. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns PROS_ERR with errno set to ENOSYS. + * + * @return 1 if the motor is at zero absolute position, 0 if the motor has moved from its absolute + * zero, or PROS_ERR if the operation failed, setting errno + */ + std::int32_t getZeroPositionFlag() override; + + /** + * Gets the faults experienced by the motor. Compare this bitfield to the bitmasks in + * pros::motor_fault_e_t. + * + * @return A currently unknown bitfield containing the motor's faults. 0b00000100 = Current Limit + * Hit + */ + uint32_t getFaults() override; + + /** + * Gets the flags set by the motor's operation. Compare this bitfield to the bitmasks in + * pros::motor_flag_e_t. + * + * @return A currently unknown bitfield containing the motor's flags. These seem to be unrelated + * to the individual get_specific_flag functions + */ + uint32_t getFlags() override; + + /** + * Gets the raw encoder count of the motor at a given timestamp. + * + * @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 The raw encoder count at the given timestamp or PROS_ERR if the operation failed. + */ + std::int32_t getRawPosition(std::uint32_t *timestamp) override; + + /** + * Gets the power drawn by the motor in Watts. + * + * @return The motor's power draw in Watts or PROS_ERR_F if the operation failed, setting errno. + */ + double getPower() override; + + /** + * Gets the temperature of the motor in degrees Celsius. + * + * @return The motor's temperature in degrees Celsius or PROS_ERR_F if the operation failed, + * setting errno. + */ + double getTemperature() override; + + /** + * Gets the torque generated by the motor in Newton Metres (Nm). + * + * @return The motor's torque in NM or PROS_ERR_F if the operation failed, setting errno. + */ + double getTorque() override; + + /** + * Gets the voltage delivered to the motor in millivolts. + * + * @return The motor's voltage in V or PROS_ERR_F if the operation failed, setting errno. + */ + std::int32_t getVoltage() override; + + /******************************************************************************/ + /** Motor configuration functions **/ + /** **/ + /** These functions allow programmers to configure the behavior of motors **/ + /******************************************************************************/ + + /** + * Sets one of AbstractMotor::brakeMode to the motor. + * + * @param imode The new motor brake mode to set for the motor + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setBrakeMode(AbstractMotor::brakeMode imode) override; + + /** + * Gets the brake mode that was set for the motor. + * + * @return One of brakeMode, according to what was set for the motor, or brakeMode::invalid if the + * operation failed, setting errno. + */ + brakeMode getBrakeMode() override; + + /** + * Sets the current limit for the motor in mA. + * + * @param ilimit The new current limit in mA + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setCurrentLimit(std::int32_t ilimit) override; + + /** + * Gets the current limit for the motor in mA. The default value is 2500 mA. + * + * @return The motor's current limit in mA or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t getCurrentLimit() override; + + /** + * Sets one of AbstractMotor::encoderUnits for the motor encoder. + * + * @param iunits The new motor encoder units + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setEncoderUnits(AbstractMotor::encoderUnits iunits) override; + + /** + * Gets the encoder units that were set for the motor. + * + * @return One of encoderUnits according to what is set for the motor or encoderUnits::invalid if + * the operation failed. + */ + encoderUnits getEncoderUnits() override; + + /** + * Sets one of AbstractMotor::gearset for the motor. + * + * @param igearset The new motor gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setGearing(AbstractMotor::gearset igearset) override; + + /** + * Gets the gearset that was set for the motor. + * + * @return One of gearset according to what is set for the motor, or gearset::invalid if the + * operation failed. + */ + gearset getGearing() override; + + /** + * Sets the reverse flag for the motor. This will invert its movements and the values returned for + * its position. + * + * @param ireverse True reverses the motor, false is default + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setReversed(bool ireverse) override; + + /** + * Sets the voltage limit for the motor in Volts. + * + * @param ilimit The new voltage limit in Volts + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setVoltageLimit(std::int32_t ilimit) override; + + /** + * Sets new PID constants. + * + * @param ikF the feed-forward constant + * @param ikP the proportional constant + * @param ikI the integral constant + * @param ikD the derivative constant + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setPosPID(double ikF, double ikP, double ikI, double ikD); + + /** + * Sets new PID constants. + * + * @param ikF the feed-forward constant + * @param ikP the proportional constant + * @param ikI the integral constant + * @param ikD the derivative constant + * @param ifilter a constant used for filtering the profile acceleration + * @param ilimit the integral limit + * @param ithreshold the threshold for determining if a position movement has reached its goal + * @param iloopSpeed the rate at which the PID computation is run (in ms) + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setPosPIDFull(double ikF, + double ikP, + double ikI, + double ikD, + double ifilter, + double ilimit, + double ithreshold, + double iloopSpeed); + + /** + * Sets new PID constants. + * + * @param ikF the feed-forward constant + * @param ikP the proportional constant + * @param ikI the integral constant + * @param ikD the derivative constant + * @return `1` if the operation was successful or `PROS_ERR` if the operation failed, setting + * errno. + */ + virtual std::int32_t setVelPID(double ikF, double ikP, double ikI, double ikD); + + /** + * Sets new PID constants. + * + * @param ikF the feed-forward constant + * @param ikP the proportional constant + * @param ikI the integral constant + * @param ikD the derivative constant + * @param ifilter a constant used for filtering the profile acceleration + * @param ilimit the integral limit + * @param ithreshold the threshold for determining if a position movement has reached its goal + * @param iloopSpeed the rate at which the PID computation is run (in ms) + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setVelPIDFull(double ikF, + double ikP, + double ikI, + double ikD, + double ifilter, + double ilimit, + double ithreshold, + double iloopSpeed); + + /** + * Get the encoder associated with this motor. + * + * @return The encoder for this motor. + */ + std::shared_ptr getEncoder() override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be `[-1, 1]`. + * + * @param ivalue The controller's output in the range `[-1, 1]`. + */ + void controllerSet(double ivalue) override; + + /** + * @return The port number. + */ + std::uint8_t getPort() const; + + /** + * @return Whether this motor is reversed. + */ + bool isReversed() const; + + protected: + std::uint8_t port; + std::int8_t reversed{1}; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/device/motor/motorGroup.hpp b/old-code/v5_hal/firmware/include/okapi/impl/device/motor/motorGroup.hpp new file mode 100644 index 00000000..35469622 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/device/motor/motorGroup.hpp @@ -0,0 +1,393 @@ +/* + * 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 + +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include +#include + +namespace okapi { +class MotorGroup : public AbstractMotor { + public: + /** + * A group of V5 motors which act as one motor (i.e. they are mechanically linked). A MotorGroup + * requires at least one motor. If no motors are supplied, a `std::invalid_argument` exception is + * thrown. + * + * @param imotors The motors in this group. + * @param ilogger The logger this instance will log initialization warnings to. + */ + MotorGroup(const std::initializer_list &imotors, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * A group of V5 motors which act as one motor (i.e. they are mechanically linked). A MotorGroup + * requires at least one motor. If no motors are supplied, a `std::invalid_argument` exception is + * thrown. + * + * @param imotors The motors in this group. + * @param ilogger The logger this instance will log initialization warnings to. + */ + MotorGroup(const std::initializer_list> &imotors, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /******************************************************************************/ + /** Motor movement functions **/ + /** **/ + /** These functions allow programmers to make motors move **/ + /******************************************************************************/ + + /** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with setZeroPosition(). + * + * @note This function simply sets the target for the motor, it does not block program execution + * until the movement finishes. + * + * @param iposition The absolute position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t moveAbsolute(double iposition, std::int32_t ivelocity) override; + + /** + * Sets the relative target position for the motor to move to. + * + * This movement is relative to the current position of the motor. Providing 10.0 as the position + * parameter would result in the motor moving clockwise 10 units, 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. + * + * @param iposition The relative position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t moveRelative(double iposition, std::int32_t ivelocity) override; + + /** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the gearset + * used for the motor. This results in a range of +-100 for pros::c::red, + * +-200 for green, and +-600 for blue. The velocity + * is held with PID to ensure consistent speed, as opposed to setting the motor's + * voltage. + * + * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's + * gearset + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t moveVelocity(std::int16_t ivelocity) override; + + /** + * Sets the voltage for the motor from `-12000` to `12000`. + * + * @param ivoltage The new voltage value from `-12000` to `12000`. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t moveVoltage(std::int16_t ivoltage) override; + + /** + * Changes the output velocity for a profiled movement (moveAbsolute or moveRelative). This will + * have no effect if the motor is not following a profiled movement. + * + * @param ivelocity The new motor velocity from `+-100`, `+-200`, or `+-600` depending on the + * motor's gearset. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t modifyProfiledVelocity(std::int32_t ivelocity) override; + + /******************************************************************************/ + /** Motor telemetry functions **/ + /** **/ + /** These functions allow programmers to collect telemetry from motors **/ + /******************************************************************************/ + + /** + * Gets the target position set for the motor by the user. + * + * @return The target position in its encoder units or `PROS_ERR_F` if the operation failed, + * setting errno. + */ + double getTargetPosition() override; + + /** + * Gets the absolute position of the motor in its encoder units. + * + * @return The motor's absolute position in its encoder units or `PROS_ERR_F` if the operation + * failed, setting errno. + */ + double getPosition() override; + + /** + * Sets the "absolute" zero position of the motor to its current position. + * + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t tarePosition() override; + + /** + * Gets the velocity commanded to the motor by the user. + * + * @return The commanded motor velocity from +-100, +-200, or +-600, or `PROS_ERR` if the + * operation failed, setting errno. + */ + std::int32_t getTargetVelocity() override; + + /** + * Gets the actual velocity of the motor. + * + * @return The motor's actual velocity in RPM or `PROS_ERR_F` if the operation failed, setting + * errno. + */ + double getActualVelocity() override; + + /** + * Gets the current drawn by the motor in mA. + * + * @return The motor's current in mA or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t getCurrentDraw() override; + + /** + * Gets the direction of movement for the motor. + * + * @return 1 for moving in the positive direction, -1 for moving in the negative direction, and + * `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t getDirection() override; + + /** + * Gets the efficiency of the motor in percent. + * + * 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. + * + * @return The motor's efficiency in percent or `PROS_ERR_F` if the operation failed, setting + * errno. + */ + double getEfficiency() override; + + /** + * Checks if the motor is drawing over its current limit. + * + * @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. + */ + std::int32_t isOverCurrent() override; + + /** + * Checks if the motor's temperature is above its limit. + * + * @return 1 if the temperature limit is exceeded and 0 if the the temperature is below the limit, + * or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t isOverTemp() override; + + /** + * Checks if the motor is stopped. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns `PROS_ERR` with errno set to `ENOSYS`. + * + * @return 1 if the motor is not moving, 0 if the motor is moving, or `PROS_ERR` if the operation + * failed, setting errno + */ + std::int32_t isStopped() override; + + /** + * Checks if the motor is at its zero position. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns `PROS_ERR` with errno set to `ENOSYS`. + * + * @return 1 if the motor is at zero absolute position, `0` if the motor has moved from its + * absolute zero, or `PROS_ERR` if the operation failed, setting errno + */ + std::int32_t getZeroPositionFlag() override; + + /** + * Gets the faults experienced by the motor. Compare this bitfield to the bitmasks in + * pros::motor_fault_e_t. + * + * @return A currently unknown bitfield containing the motor's faults. `0b00000100` = Current + * Limit Hit + */ + uint32_t getFaults() override; + + /** + * Gets the flags set by the motor's operation. Compare this bitfield to the bitmasks in + * pros::motor_flag_e_t. + * + * @return A currently unknown bitfield containing the motor's flags. These seem to be unrelated + * to the individual get_specific_flag functions + */ + uint32_t getFlags() override; + + /** + * Gets the raw encoder count of the motor at a given timestamp. + * + * @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 The raw encoder count at the given timestamp or `PROS_ERR` if the operation failed. + */ + std::int32_t getRawPosition(std::uint32_t *timestamp) override; + + /** + * Gets the power drawn by the motor in Watts. + * + * @return The motor's power draw in Watts or `PROS_ERR_F` if the operation failed, setting errno. + */ + double getPower() override; + + /** + * Gets the temperature of the motor in degrees Celsius. + * + * @return The motor's temperature in degrees Celsius or `PROS_ERR_F` if the operation failed, + * setting errno. + */ + double getTemperature() override; + + /** + * Gets the torque generated by the motor in Newton Metres (Nm). + * + * @return The motor's torque in NM or `PROS_ERR_F` if the operation failed, setting errno. + */ + double getTorque() override; + + /** + * Gets the voltage delivered to the motor in millivolts. + * + * @return The motor's voltage in V or `PROS_ERR_F` if the operation failed, setting errno. + */ + std::int32_t getVoltage() override; + + /******************************************************************************/ + /** Motor configuration functions **/ + /** **/ + /** These functions allow programmers to configure the behavior of motors **/ + /******************************************************************************/ + + /** + * Sets one of AbstractMotor::brakeMode to the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param imode The new motor brake mode to set for the motor. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setBrakeMode(AbstractMotor::brakeMode imode) override; + + /** + * Gets the brake mode that was set for the motor. + * + * @return One of brakeMode, according to what was set for the motor, or brakeMode::invalid if the + * operation failed, setting errno. + */ + brakeMode getBrakeMode() override; + + /** + * Sets the current limit for the motor in mA. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ilimit The new current limit in mA. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setCurrentLimit(std::int32_t ilimit) override; + + /** + * Gets the current limit for the motor in mA. The default value is `2500` mA. + * + * @return The motor's current limit in mA or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t getCurrentLimit() override; + + /** + * Sets one of AbstractMotor::encoderUnits for the motor encoder. + * + * @param iunits The new motor encoder units. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setEncoderUnits(AbstractMotor::encoderUnits iunits) override; + + /** + * Gets the encoder units that were set for the motor. + * + * @return One of encoderUnits according to what is set for the motor or encoderUnits::invalid if + * the operation failed. + */ + encoderUnits getEncoderUnits() override; + + /** + * Sets one of AbstractMotor::gearset for the motor. + * + * @param igearset The new motor gearset. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setGearing(AbstractMotor::gearset igearset) override; + + /** + * Gets the gearset that was set for the motor. + * + * @return One of gearset according to what is set for the motor, or `gearset::invalid` if the + * operation failed. + */ + gearset getGearing() override; + + /** + * Sets the reverse flag for the motor. This will invert its movements and the values returned for + * its position. + * + * @param ireverse True reverses the motor, false is default. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setReversed(bool ireverse) override; + + /** + * Sets the voltage limit for the motor in Volts. + * + * @param ilimit The new voltage limit in Volts. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setVoltageLimit(std::int32_t ilimit) override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be `[-1, 1]`. + * + * @param ivalue the controller's output in the range `[-1, 1]` + */ + void controllerSet(double ivalue) override; + + /** + * Get the encoder associated with the first motor in this group. + * + * @return The encoder for the motor at index `0`. + */ + std::shared_ptr getEncoder() override; + + /** + * Get the encoder associated with this motor. + * + * @param index The index in `motors` to get the encoder from. + * @return The encoder for the motor at `index`. + */ + virtual std::shared_ptr getEncoder(std::size_t index); + + protected: + std::vector> motors; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/device/rotarysensor/IMU.hpp b/old-code/v5_hal/firmware/include/okapi/impl/device/rotarysensor/IMU.hpp new file mode 100644 index 00000000..462190e2 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/device/rotarysensor/IMU.hpp @@ -0,0 +1,99 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +enum class IMUAxes { + z, ///< Yaw Axis + y, ///< Pitch Axis + x ///< Roll Axis +}; + +class IMU : public ContinuousRotarySensor { + public: + /** + * An inertial sensor on the given port. The IMU returns an angle about the selected axis in + * degrees. + * + * ```cpp + * auto imuZ = IMU(1); + * auto imuX = IMU(1, IMUAxes::x); + * ``` + * + * @param iport The port number in the range ``[1, 21]``. + * @param iaxis The axis of the inertial sensor to measure, default `IMUAxes::z`. + */ + IMU(std::uint8_t iport, IMUAxes iaxis = IMUAxes::z); + + /** + * Get the current rotation about the configured axis. + * + * @return The current sensor value or ``PROS_ERR``. + */ + double get() const override; + + /** + * Get the current sensor value remapped into the target range (``[-1800, 1800]`` by default). + * + * @param iupperBound The upper bound of the range. + * @param ilowerBound The lower bound of the range. + * @return The remapped sensor value. + */ + double getRemapped(double iupperBound = 1800, double ilowerBound = -1800) const; + + /** + * Get the current acceleration along the configured axis. + * + * @return The current sensor value or ``PROS_ERR``. + */ + double getAcceleration() const; + + /** + * Reset the rotation value to zero. + * + * @return ``1`` or ``PROS_ERR``. + */ + std::int32_t reset() override; + + /** + * Calibrate the IMU. Resets the rotation value to zero. Calibration is expected to take two + * seconds, but is bounded to five seconds. + * + * @return ``1`` or ``PROS_ERR``. + */ + std::int32_t calibrate(); + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return The current sensor value or ``PROS_ERR``. + */ + double controllerGet() override; + + /** + * @return Whether the IMU is calibrating. + */ + bool isCalibrating() const; + + protected: + std::uint8_t port; + IMUAxes axis; + double offset = 0; + + /** + * Get the current rotation about the configured axis. The internal offset is not accounted for + * or modified. This just reads from the sensor. + * + * @return The current sensor value or ``PROS_ERR``. + */ + double readAngle() const; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/device/rotarysensor/adiEncoder.hpp b/old-code/v5_hal/firmware/include/okapi/impl/device/rotarysensor/adiEncoder.hpp new file mode 100644 index 00000000..da2eb3bd --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/device/rotarysensor/adiEncoder.hpp @@ -0,0 +1,73 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +class ADIEncoder : public ContinuousRotarySensor { + public: + /** + * An encoder in an ADI port. + * + * ```cpp + * auto enc = ADIEncoder('A', 'B', false); + * auto reversedEnc = ADIEncoder('A', 'B', true); + * ``` + * + * @param iportTop The "top" wire from the encoder with the removable cover side up. This must be + * in port ``1``, ``3``, ``5``, or ``7`` (``A``, ``C``, ``E``, or ``G``). + * @param iportBottom The "bottom" wire from the encoder. This must be in port ``2``, ``4``, + * ``6``, or ``8`` (``B``, ``D``, ``F``, or ``H``). + * @param ireversed Whether the encoder is reversed. + */ + ADIEncoder(std::uint8_t iportTop, std::uint8_t iportBottom, bool ireversed = false); + + /** + * An encoder in an ADI port. + * + * ```cpp + * auto enc = ADIEncoder({1, 'A', 'B'}, false); + * auto reversedEnc = ADIEncoder({1, 'A', 'B'}, true); + * ``` + * + * @param iports The ports the encoder is plugged in to in the order ``{smart port, top port, + * bottom port}``. The smart port is the smart port number (``[1, 21]``). The top port is the + * "top" wire from the encoder with the removable cover side up. This must be in port ``1``, + * ``3``, ``5``, or + * ``7`` (``A``, ``C``, ``E``, or ``G``). The bottom port is the "bottom" wire from the encoder. + * This must be in port ``2``, ``4``, ``6``, or ``8`` (``B``, ``D``, ``F``, or ``H``). + * @param ireversed Whether the encoder is reversed. + */ + ADIEncoder(std::tuple iports, bool ireversed = false); + + /** + * Get the current sensor value. + * + * @return the current sensor value, or `PROS_ERR` on a failure. + */ + virtual double get() const override; + + /** + * Reset the sensor to zero. + * + * @return `1` on success, `PROS_ERR` on fail + */ + virtual std::int32_t reset() override; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or `PROS_ERR` on a failure. + */ + virtual double controllerGet() override; + + protected: + pros::c::ext_adi_encoder_t enc; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/device/rotarysensor/adiGyro.hpp b/old-code/v5_hal/firmware/include/okapi/impl/device/rotarysensor/adiGyro.hpp new file mode 100644 index 00000000..f8a34a76 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/device/rotarysensor/adiGyro.hpp @@ -0,0 +1,82 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +class ADIGyro : public ContinuousRotarySensor { + public: + /** + * A gyroscope on the given ADI port. If the port has not previously been configured as a gyro, + * then the constructor will block for 1 second for calibration. The gyro measures in tenths of a + * degree, so there are ``3600`` measurement points per revolution. + * + * ```cpp + * auto gyro = ADIGyro('A'); + * ``` + * + * @param iport The ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). + * @param imultiplier A value multiplied by the gyro heading value. + */ + ADIGyro(std::uint8_t iport, double imultiplier = 1); + + /** + * A gyroscope on the given ADI port. If the port has not previously been configured as a gyro, + * then the constructor will block for 1 second for calibration. The gyro measures in tenths of a + * degree, so there are 3600 measurement points per revolution. + * + * ```cpp + * auto gyro = ADIGyro({1, 'A'}, 1); + * ``` + * + * Note to developers: Keep the default value on imultiplier so that users get an error if they do + * ADIGyro({1, 'A'}). Without it, this calls the non-ext-adi constructor. + * + * @param iports The ports the gyro is plugged in to in the order ``{smart port, gyro port}``. The + * smart port is the smart port number (``[1, 21]``). The gyro port is the ADI port number (``[1, + * 8]``, ``[a, h]``, ``[A, H]``). + * @param imultiplier A value multiplied by the gyro heading value. + */ + ADIGyro(std::pair iports, double imultiplier = 1); + + /** + * Get the current sensor value. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + double get() const override; + + /** + * Get the current sensor value remapped into the target range (``[-1800, 1800]`` by default). + * + * @param iupperBound the upper bound of the range. + * @param ilowerBound the lower bound of the range. + * @return the remapped sensor value. + */ + double getRemapped(double iupperBound = 1800, double ilowerBound = -1800) const; + + /** + * Reset the sensor to zero. + * + * @return `1` on success, `PROS_ERR` on fail + */ + std::int32_t reset() override; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + double controllerGet() override; + + protected: + pros::c::ext_adi_gyro_t gyro; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/device/rotarysensor/integratedEncoder.hpp b/old-code/v5_hal/firmware/include/okapi/impl/device/rotarysensor/integratedEncoder.hpp new file mode 100644 index 00000000..8b3473b5 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/device/rotarysensor/integratedEncoder.hpp @@ -0,0 +1,56 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" +#include "okapi/impl/device/motor/motor.hpp" + +namespace okapi { +class IntegratedEncoder : public ContinuousRotarySensor { + public: + /** + * Integrated motor encoder. Uses the encoder inside the V5 motor. + * + * @param imotor The motor to use the encoder from. + */ + IntegratedEncoder(const okapi::Motor &imotor); + + /** + * Integrated motor encoder. Uses the encoder inside the V5 motor. + * + * @param iport The motor's port number in the range [1, 21]. + * @param ireversed Whether the encoder is reversed. + */ + IntegratedEncoder(std::int8_t iport, bool ireversed = false); + + /** + * Get the current sensor value. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + virtual double get() const override; + + /** + * Reset the sensor to zero. + * + * @return `1` on success, `PROS_ERR` on fail + */ + virtual std::int32_t reset() override; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + virtual double controllerGet() override; + + protected: + std::uint8_t port; + std::int8_t reversed{1}; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/device/rotarysensor/potentiometer.hpp b/old-code/v5_hal/firmware/include/okapi/impl/device/rotarysensor/potentiometer.hpp new file mode 100644 index 00000000..7842c3f3 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/device/rotarysensor/potentiometer.hpp @@ -0,0 +1,57 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/device/rotarysensor/rotarySensor.hpp" + +namespace okapi { +class Potentiometer : public RotarySensor { + public: + /** + * A potentiometer in an ADI port. + * + * ```cpp + * auto pot = Potentiometer('A'); + * ``` + * + * @param iport The ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). + */ + Potentiometer(std::uint8_t iport); + + /** + * A potentiometer in an ADI port. + * + * ```cpp + * auto pot = Potentiometer({1, 'A'}); + * ``` + * + * @param iports The ports the potentiometer is plugged in to in the order ``{smart port, + * potentiometer port}``. The smart port is the smart port number (``[1, 21]``). The potentiometer + * port is the ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). + */ + Potentiometer(std::pair iports); + + /** + * Get the current sensor value. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + virtual double get() const override; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + virtual double controllerGet() override; + + protected: + std::uint8_t smartPort; + std::uint8_t port; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/filter/velMathFactory.hpp b/old-code/v5_hal/firmware/include/okapi/impl/filter/velMathFactory.hpp new file mode 100644 index 00000000..af223d44 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/filter/velMathFactory.hpp @@ -0,0 +1,68 @@ +/* + * 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 + +#include "okapi/api/filter/velMath.hpp" +#include + +namespace okapi { +class VelMathFactory { + public: + /** + * Velocity math helper. Calculates filtered velocity. Throws a std::invalid_argument exception + * if iticksPerRev is zero. Averages the last two readings. + * + * @param iticksPerRev The number of ticks per revolution. + * @param isampleTime The minimum time between samples. + * @param ilogger The logger this instance will log to. + */ + static VelMath create(double iticksPerRev, + QTime isampleTime = 0_ms, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity math helper. Calculates filtered velocity. Throws a std::invalid_argument exception + * if iticksPerRev is zero. Averages the last two readings. + * + * @param iticksPerRev The number of ticks per revolution. + * @param isampleTime The minimum time between samples. + * @param ilogger The logger this instance will log to. + */ + static std::unique_ptr + createPtr(double iticksPerRev, + QTime isampleTime = 0_ms, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity math helper. Calculates filtered velocity. Throws a std::invalid_argument exception + * if iticksPerRev is zero. + * + * @param iticksPerRev The number of ticks per revolution. + * @param ifilter The filter used for filtering the calculated velocity. + * @param isampleTime The minimum time between samples. + * @param ilogger The logger this instance will log to. + */ + static VelMath create(double iticksPerRev, + std::unique_ptr ifilter, + QTime isampleTime = 0_ms, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity math helper. Calculates filtered velocity. Throws a std::invalid_argument exception + * if iticksPerRev is zero. + * + * @param iticksPerRev The number of ticks per revolution. + * @param ifilter The filter used for filtering the calculated velocity. + * @param isampleTime The minimum time between samples. + * @param ilogger The logger this instance will log to. + */ + static std::unique_ptr + createPtr(double iticksPerRev, + std::unique_ptr ifilter, + QTime isampleTime = 0_ms, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/util/configurableTimeUtilFactory.hpp b/old-code/v5_hal/firmware/include/okapi/impl/util/configurableTimeUtilFactory.hpp new file mode 100644 index 00000000..3775460f --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/util/configurableTimeUtilFactory.hpp @@ -0,0 +1,34 @@ +/* + * 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 + +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +/** + * A TimeUtilFactory that supplies the SettledUtil parameters passed in the constructor to every + * new TimeUtil instance. + */ +class ConfigurableTimeUtilFactory : public TimeUtilFactory { + public: + ConfigurableTimeUtilFactory(double iatTargetError = 50, + double iatTargetDerivative = 5, + const QTime &iatTargetTime = 250_ms); + + /** + * Creates a TimeUtil with the SettledUtil parameters specified in the constructor by + * delegating to TimeUtilFactory::withSettledUtilParams. + * + * @return A TimeUtil with the SettledUtil parameters specified in the constructor. + */ + TimeUtil create() override; + + private: + double atTargetError; + double atTargetDerivative; + QTime atTargetTime; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/util/rate.hpp b/old-code/v5_hal/firmware/include/okapi/impl/util/rate.hpp new file mode 100644 index 00000000..b76be723 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/util/rate.hpp @@ -0,0 +1,42 @@ +/* + * 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 + +#include "okapi/api/util/abstractRate.hpp" + +namespace okapi { +class Rate : public AbstractRate { + public: + Rate(); + + /** + * Delay the current task such that it runs at the given frequency. The first delay will run for + * 1000/(ihz). Subsequent delays will adjust according to the previous runtime of the task. + * + * @param ihz the frequency + */ + void delay(QFrequency ihz) override; + + /** + * Delay the current task until itime has passed. This method can be used by periodic tasks to + * ensure a consistent execution frequency. + * + * @param itime the time period + */ + void delayUntil(QTime itime) override; + + /** + * Delay the current task until ims milliseconds have passed. This method can be used by + * periodic tasks to ensure a consistent execution frequency. + * + * @param ims the time period + */ + void delayUntil(uint32_t ims) override; + + protected: + std::uint32_t lastTime{0}; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/util/timeUtilFactory.hpp b/old-code/v5_hal/firmware/include/okapi/impl/util/timeUtilFactory.hpp new file mode 100644 index 00000000..5d4f116c --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/util/timeUtilFactory.hpp @@ -0,0 +1,32 @@ +/* + * 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 + +#include "okapi/api/util/timeUtil.hpp" + +namespace okapi { +class TimeUtilFactory { + public: + virtual ~TimeUtilFactory() = default; + + /** + * Creates a default TimeUtil. + */ + virtual TimeUtil create(); + + /** + * Creates a default TimeUtil. + */ + static TimeUtil createDefault(); + + /** + * Creates a TimeUtil with custom SettledUtil params. See SettledUtil docs. + */ + static TimeUtil withSettledUtilParams(double iatTargetError = 50, + double iatTargetDerivative = 5, + const QTime &iatTargetTime = 250_ms); +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/impl/util/timer.hpp b/old-code/v5_hal/firmware/include/okapi/impl/util/timer.hpp new file mode 100644 index 00000000..13d77c92 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/impl/util/timer.hpp @@ -0,0 +1,22 @@ +/* + * 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 + +#include "okapi/api/util/abstractTimer.hpp" + +namespace okapi { +class Timer : public AbstractTimer { + public: + Timer(); + + /** + * Returns the current time in units of QTime. + * + * @return the current time + */ + QTime millis() const override; +}; +} // namespace okapi diff --git a/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder.h b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder.h new file mode 100644 index 00000000..8db9223f --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder.h @@ -0,0 +1,19 @@ +#ifndef PATHFINDER_H_DEF +#define PATHFINDER_H_DEF + +#include "okapi/pathfinder/include/pathfinder/mathutil.h" +#include "okapi/pathfinder/include/pathfinder/structs.h" + +#include "okapi/pathfinder/include/pathfinder/fit.h" +#include "okapi/pathfinder/include/pathfinder/spline.h" +#include "okapi/pathfinder/include/pathfinder/trajectory.h" + +#include "okapi/pathfinder/include/pathfinder/modifiers/tank.h" +#include "okapi/pathfinder/include/pathfinder/modifiers/swerve.h" + +#include "okapi/pathfinder/include/pathfinder/followers/encoder.h" +#include "okapi/pathfinder/include/pathfinder/followers/distance.h" + +#include "okapi/pathfinder/include/pathfinder/io.h" + +#endif \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/fit.h b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/fit.h new file mode 100644 index 00000000..39eea48f --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/fit.h @@ -0,0 +1,23 @@ +#ifndef PATHFINDER_FIT_H_DEF +#define PATHFINDER_FIT_H_DEF + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "okapi/pathfinder/include/pathfinder/lib.h" +#include "okapi/pathfinder/include/pathfinder/structs.h" + +CAPI void pf_fit_hermite_pre(Waypoint a, Waypoint b, Spline *s); +CAPI void pf_fit_hermite_cubic(Waypoint a, Waypoint b, Spline *s); +CAPI void pf_fit_hermite_quintic(Waypoint a, Waypoint b, Spline *s); + +#define FIT_HERMITE_CUBIC &pf_fit_hermite_cubic +#define FIT_HERMITE_QUINTIC &pf_fit_hermite_quintic + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/followers/distance.h b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/followers/distance.h new file mode 100644 index 00000000..21c6e6e6 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/followers/distance.h @@ -0,0 +1,29 @@ +#ifndef PATHFINDER_FOL_DISTANCE_H_DEF +#define PATHFINDER_FOL_DISTANCE_H_DEF + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "okapi/pathfinder/include/pathfinder/lib.h" +#include "okapi/pathfinder/include/pathfinder/structs.h" + +CAPI typedef struct { + double kp, ki, kd, kv, ka; +} FollowerConfig; + +CAPI typedef struct { + double last_error, heading, output; + int segment, finished; +} DistanceFollower; + +CAPI double pathfinder_follow_distance(FollowerConfig c, DistanceFollower *follower, Segment *trajectory, int trajectory_length, double distance); + +CAPI double pathfinder_follow_distance2(FollowerConfig c, DistanceFollower *follower, Segment segment, int trajectory_length, double distance); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/followers/encoder.h b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/followers/encoder.h new file mode 100644 index 00000000..c1d9cfd9 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/followers/encoder.h @@ -0,0 +1,31 @@ +#ifndef PATHFINDER_FOL_ENCODER_H_DEF +#define PATHFINDER_FOL_ENCODER_H_DEF + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "okapi/pathfinder/include/pathfinder/structs.h" + +typedef struct { + int initial_position, ticks_per_revolution; + double wheel_circumference; + double kp, ki, kd, kv, ka; +} EncoderConfig; + +typedef struct { + double last_error, heading, output; + int segment, finished; +} EncoderFollower; + + +double pathfinder_follow_encoder(EncoderConfig c, EncoderFollower *follower, Segment *trajectory, int trajectory_length, int encoder_tick); + +double pathfinder_follow_encoder2(EncoderConfig c, EncoderFollower *follower, Segment segment, int trajectory_length, int encoder_tick); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/io.h b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/io.h new file mode 100644 index 00000000..210bb269 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/io.h @@ -0,0 +1,37 @@ +#ifndef PATHFINDER_IO_H_DEF +#define PATHFINDER_IO_H_DEF + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "okapi/pathfinder/include/pathfinder/structs.h" +#include "okapi/pathfinder/include/pathfinder/lib.h" + +#define CSV_LEADING_STRING "dt,x,y,position,velocity,acceleration,jerk,heading\n" + +CAPI void intToBytes(int n, char *bytes); +CAPI int bytesToInt(char *bytes); +CAPI void longToBytes(unsigned long long n, char *bytes); +CAPI unsigned long long bytesToLong(char *bytes); +CAPI double longToDouble(unsigned long long l); +CAPI unsigned long long doubleToLong(double d); +CAPI void doubleToBytes(double n, char *bytes); +CAPI double bytesToDouble(char *bytes); + +CAPI void pathfinder_serialize(FILE *fp, Segment *trajectory, int trajectory_length); +CAPI int pathfinder_deserialize(FILE *fp, Segment *target); + +CAPI void pathfinder_serialize_csv(FILE *fp, Segment *trajectory, int trajectory_length); +CAPI int pathfinder_deserialize_csv(FILE *fp, Segment *target); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/lib.h b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/lib.h new file mode 100644 index 00000000..0ba47afe --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/lib.h @@ -0,0 +1,10 @@ +#ifndef PATHFINDER_LIB_H_DEF +#define PATHFINDER_LIB_H_DEF + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) + #define CAPI __declspec(dllexport) +#else + #define CAPI +#endif + +#endif \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/mathutil.h b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/mathutil.h new file mode 100644 index 00000000..db3ebcbc --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/mathutil.h @@ -0,0 +1,29 @@ +#include + +#ifndef PATHFINDER_MATH_UTIL_H_DEF +#define PATHFINDER_MATH_UTIL_H_DEF + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "okapi/pathfinder/include/pathfinder/lib.h" + +#define PI 3.14159265358979323846 +#define TAU PI*2 + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +CAPI double bound_radians(double angle); + +CAPI double r2d(double angleInRads); + +CAPI double d2r(double angleInDegrees); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/modifiers/swerve.h b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/modifiers/swerve.h new file mode 100644 index 00000000..60be7500 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/modifiers/swerve.h @@ -0,0 +1,23 @@ +#ifndef PATHFINDER_MOD_SWERVE_H_DEF +#define PATHFINDER_MOD_SWERVE_H_DEF + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "okapi/pathfinder/include/pathfinder/lib.h" +#include "okapi/pathfinder/include/pathfinder/structs.h" + +CAPI typedef enum { + SWERVE_DEFAULT +} SWERVE_MODE; + +CAPI void pathfinder_modify_swerve(Segment *original, int length, Segment *front_left, Segment *front_right, + Segment *back_left, Segment *back_right, double wheelbase_width, double wheelbase_depth, SWERVE_MODE mode); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/modifiers/tank.h b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/modifiers/tank.h new file mode 100644 index 00000000..f72db638 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/modifiers/tank.h @@ -0,0 +1,18 @@ +#ifndef PATHFINDER_MOD_TANK_H_DEF +#define PATHFINDER_MOD_TANK_H_DEF + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "okapi/pathfinder/include/pathfinder/lib.h" +#include "okapi/pathfinder/include/pathfinder/structs.h" + +CAPI void pathfinder_modify_tank(Segment *original, int length, Segment *left, Segment *right, double wheelbase_width); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/spline.h b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/spline.h new file mode 100644 index 00000000..8c68ae12 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/spline.h @@ -0,0 +1,19 @@ +#ifndef PATHFINDER_SPLINE_H_DEF +#define PATHFINDER_SPLINE_H_DEF + +#include "okapi/pathfinder/include/pathfinder/lib.h" +#include "okapi/pathfinder/include/pathfinder/structs.h" + +#define PATHFINDER_SAMPLES_FAST (int)1000 +#define PATHFINDER_SAMPLES_LOW (int)PATHFINDER_SAMPLES_FAST*10 +#define PATHFINDER_SAMPLES_HIGH (int)PATHFINDER_SAMPLES_LOW*10 + +CAPI Coord pf_spline_coords(Spline s, double percentage); +CAPI double pf_spline_deriv(Spline s, double percentage); +CAPI double pf_spline_deriv_2(double a, double b, double c, double d, double e, double k, double p); +CAPI double pf_spline_angle(Spline s, double percentage); + +CAPI double pf_spline_distance(Spline *s, int sample_count); +CAPI double pf_spline_progress_for_distance(Spline s, double distance, int sample_count); + +#endif \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/structs.h b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/structs.h new file mode 100644 index 00000000..5c424d39 --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/structs.h @@ -0,0 +1,43 @@ +#ifndef PATHFINDER_STRUCT_H_DEF +#define PATHFINDER_STRUCT_H_DEF + +#include "okapi/pathfinder/include/pathfinder/lib.h" + +CAPI typedef struct { + double x, y, angle; +} Waypoint; + +CAPI typedef struct { + double a, b, c, d, e; + double x_offset, y_offset, angle_offset, knot_distance, arc_length; +} Spline; + +CAPI typedef struct { + double x, y; +} Coord; + +CAPI typedef struct { + double dt, x, y, position, velocity, acceleration, jerk, heading; +} Segment; + +CAPI typedef struct { + double dt, max_v, max_a, max_j, src_v, src_theta, dest_pos, dest_v, dest_theta; + int sample_count; +} TrajectoryConfig; + +CAPI typedef struct { + int filter1, filter2, length; + double dt, u, v, impulse; +} TrajectoryInfo; + +CAPI typedef struct { + Spline *saptr; + double *laptr; + double totalLength; + int length; + int path_length; + TrajectoryInfo info; + TrajectoryConfig config; +} TrajectoryCandidate; + +#endif \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/trajectory.h b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/trajectory.h new file mode 100644 index 00000000..fb9a410f --- /dev/null +++ b/old-code/v5_hal/firmware/include/okapi/pathfinder/include/pathfinder/trajectory.h @@ -0,0 +1,27 @@ +#ifndef PATHFINDER_TRAJECTORY_H_DEF +#define PATHFINDER_TRAJECTORY_H_DEF + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "okapi/pathfinder/include/pathfinder/lib.h" +#include "okapi/pathfinder/include/pathfinder/structs.h" + +CAPI int pathfinder_prepare(Waypoint *path, int path_length, void (*fit)(Waypoint,Waypoint,Spline*), int sample_count, double dt, + double max_velocity, double max_acceleration, double max_jerk, TrajectoryCandidate *cand); +CAPI int pathfinder_generate(TrajectoryCandidate *c, Segment *segments); + +CAPI void pf_trajectory_copy(Segment *src, Segment *dest, int length); + +CAPI TrajectoryInfo pf_trajectory_prepare(TrajectoryConfig c); +CAPI int pf_trajectory_create(TrajectoryInfo info, TrajectoryConfig c, Segment *seg); +CAPI int pf_trajectory_fromSecondOrderFilter(int filter_1_l, int filter_2_l, + double dt, double u, double v, double impulse, int len, Segment *t); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/pathing/Path.h b/old-code/v5_hal/firmware/include/pathing/Path.h new file mode 100644 index 00000000..d4fa0717 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pathing/Path.h @@ -0,0 +1,26 @@ +#pragma once + +#include "eigen/Eigen/Dense" +#include "pathing/PathPoint.h" +#include "math/Pose.h" +#include + +using namespace std; + +class Path { +public: + Path(); + + Path(vector pathPoints); + + Pose update(float time); + + vector getPathPoints(); + + bool isComplete(); + +private: + vector m_pathPoints; + PathPoint m_last_point; + bool m_is_complete; +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/pathing/PathManager.h b/old-code/v5_hal/firmware/include/pathing/PathManager.h new file mode 100644 index 00000000..7029c551 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pathing/PathManager.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include +#include +#include "pathing/Path.h" +#include "pathing/PathPoint.h" +#include "3rdparty/json.hpp" +#include "math/Math.h" +#include "util/Logger.h" + +using namespace nlohmann; +using namespace std; + +class PathManager { +public: + static PathManager* GetInstance(); + + bool LoadPathsText(string text); + bool LoadPaths(json pathJson); + bool LoadPathsFile(string filePath); + + int NumPaths(); + + unordered_map GetPaths(); + + Path GetPath(string name); + +private: + PathManager() = default; + unordered_map m_paths; + static PathManager* m_instance; +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/pathing/PathPoint.h b/old-code/v5_hal/firmware/include/pathing/PathPoint.h new file mode 100644 index 00000000..d3d89e45 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pathing/PathPoint.h @@ -0,0 +1,27 @@ +#pragma once + +#include "eigen/Eigen/Dense" +#include "math/Pose.h" +// #include "util/Logger.h" + +class PathPoint { +public: + PathPoint(float time, Pose pose, Vector2d linear_velocity, float rotational_velocity); + + float getTime(); + + Pose getPose(); + + Vector2d getLinearVelocity(); + + float getRotationalVelocity(); + + PathPoint interpolateTo(PathPoint other, float time); + + bool equals(PathPoint* that); +private: + Pose m_pose; + float m_time; + Vector2d m_linear_velocity; + float m_rotational_velocity; +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/pathing/Waypoint.h b/old-code/v5_hal/firmware/include/pathing/Waypoint.h new file mode 100644 index 00000000..8b7a05ac --- /dev/null +++ b/old-code/v5_hal/firmware/include/pathing/Waypoint.h @@ -0,0 +1,21 @@ +#pragma once + +#include "api.h" +#include "eigen/Eigen/Dense" +#include "math/Pose.h" + +class Waypoint { +private: + Pose m_position; + Vector2d m_velocity; + float m_time; + +public: + Waypoint(Pose position, Vector2d velocity, float time); + + Pose getPosition(); + + Vector2d getVelocity(); + + float getTime(); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/pros/adi.h b/old-code/v5_hal/firmware/include/pros/adi.h new file mode 100644 index 00000000..b850fc0a --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/adi.h @@ -0,0 +1,698 @@ +/** + * \file pros/adi.h + * + * Contains prototypes for interfacing with the ADI. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/adi.html to learn more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_ADI_H_ +#define _PROS_ADI_H_ + +#include +#include +#ifndef PROS_ERR +#define PROS_ERR (INT32_MAX) +#endif + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +/** + * Represents the port type for an ADI port. + */ +typedef enum adi_port_config_e { + E_ADI_ANALOG_IN = 0, + E_ADI_ANALOG_OUT = 1, + E_ADI_DIGITAL_IN = 2, + E_ADI_DIGITAL_OUT = 3, + +#ifdef _INTELLISENSE +#define _DEPRECATE_DIGITAL_IN = E_ADI_DIGITAL_IN +#define _DEPRECATE_ANALOG_IN = E_ADI_ANALOG_IN +#else +#define _DEPRECATE_DIGITAL_IN __attribute__((deprecated("use E_ADI_DIGITAL_IN instead"))) = E_ADI_DIGITAL_IN +#define _DEPRECATE_ANALOG_IN __attribute__((deprecated("use E_ADI_ANALOG_IN instead"))) = E_ADI_ANALOG_IN +#endif + + E_ADI_SMART_BUTTON _DEPRECATE_DIGITAL_IN, + E_ADI_SMART_POT _DEPRECATE_ANALOG_IN, + + E_ADI_LEGACY_BUTTON _DEPRECATE_DIGITAL_IN, + E_ADI_LEGACY_POT _DEPRECATE_ANALOG_IN, + E_ADI_LEGACY_LINE_SENSOR _DEPRECATE_ANALOG_IN, + E_ADI_LEGACY_LIGHT_SENSOR _DEPRECATE_ANALOG_IN, + E_ADI_LEGACY_GYRO = 10, + E_ADI_LEGACY_ACCELEROMETER _DEPRECATE_ANALOG_IN, + +#undef _DEPRECATE_DIGITAL_IN +#undef _DEPRECATE_ANALOG_IN + + E_ADI_LEGACY_SERVO = 12, + E_ADI_LEGACY_PWM = 13, + + E_ADI_LEGACY_ENCODER = 14, + E_ADI_LEGACY_ULTRASONIC = 15, + + E_ADI_TYPE_UNDEFINED = 255, + E_ADI_ERR = PROS_ERR +} adi_port_config_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define ADI_ANALOG_IN pros::E_ADI_ANALOG_IN +#define ADI_ANALOG_OUT pros::E_ADI_ANALOG_OUT +#define ADI_DIGITAL_IN pros::E_ADI_DIGITAL_IN +#define ADI_DIGITAL_OUT pros::E_ADI_DIGITAL_OUT +#define ADI_SMART_BUTTON pros::E_ADI_SMART_BUTTON +#define ADI_SMART_POT pros::E_ADI_SMART_POT +#define ADI_LEGACY_BUTTON pros::E_ADI_LEGACY_BUTTON +#define ADI_LEGACY_POT pros::E_ADI_LEGACY_POT +#define ADI_LEGACY_LINE_SENSOR pros::E_ADI_LEGACY_LINE_SENSOR +#define ADI_LEGACY_LIGHT_SENSOR pros::E_ADI_LEGACY_LIGHT_SENSOR +#define ADI_LEGACY_GYRO pros::E_ADI_LEGACY_GYRO +#define ADI_LEGACY_ACCELEROMETER pros::E_ADI_LEGACY_ACCELEROMETER +#define ADI_LEGACY_SERVO pros::E_ADI_LEGACY_SERVO +#define ADI_LEGACY_PWM pros::E_ADI_LEGACY_PWM +#define ADI_LEGACY_ENCODER pros::E_ADI_LEGACY_ENCODER +#define ADI_LEGACY_ULTRASONIC pros::E_ADI_LEGACY_ULTRASONIC +#define ADI_TYPE_UNDEFINED pros::E_ADI_TYPE_UNDEFINED +#define ADI_ERR pros::E_ADI_ERR +#else +#define ADI_ANALOG_IN E_ADI_ANALOG_IN +#define ADI_ANALOG_OUT E_ADI_ANALOG_OUT +#define ADI_DIGITAL_IN E_ADI_DIGITAL_IN +#define ADI_DIGITAL_OUT E_ADI_DIGITAL_OUT +#define ADI_SMART_BUTTON E_ADI_SMART_BUTTON +#define ADI_SMART_POT E_ADI_SMART_POT +#define ADI_LEGACY_BUTTON E_ADI_LEGACY_BUTTON +#define ADI_LEGACY_POT E_ADI_LEGACY_POT +#define ADI_LEGACY_LINE_SENSOR E_ADI_LEGACY_LINE_SENSOR +#define ADI_LEGACY_LIGHT_SENSOR E_ADI_LEGACY_LIGHT_SENSOR +#define ADI_LEGACY_GYRO E_ADI_LEGACY_GYRO +#define ADI_LEGACY_ACCELEROMETER E_ADI_LEGACY_ACCELEROMETER +#define ADI_LEGACY_SERVO E_ADI_LEGACY_SERVO +#define ADI_LEGACY_PWM E_ADI_LEGACY_PWM +#define ADI_LEGACY_ENCODER E_ADI_LEGACY_ENCODER +#define ADI_LEGACY_ULTRASONIC E_ADI_LEGACY_ULTRASONIC +#define ADI_TYPE_UNDEFINED E_ADI_TYPE_UNDEFINED +#define ADI_ERR E_ADI_ERR +#endif +#endif + +#define INTERNAL_ADI_PORT 22 +#define NUM_ADI_PORTS 8 + +#ifdef __cplusplus +namespace c { +#endif + +/******************************************************************************/ +/** General ADI Use Functions **/ +/** **/ +/** These functions allow for interaction with any ADI port type **/ +/******************************************************************************/ + +/** + * Gets the configuration for the given ADI 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 port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which to return + * the configuration + * + * \return The ADI configuration for the given port + */ +adi_port_config_e_t adi_port_get_config(uint8_t port); + +/** + * Gets the value for the given ADI 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 port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which the value + * will be returned + * + * \return The value stored for the given port + */ +int32_t adi_port_get_value(uint8_t port); + +/** + * Configures an ADI port to act as a given sensor type. + * + * 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 + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param type + * The configuration type for the port + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_port_set_config(uint8_t port, adi_port_config_e_t type); + +/** + * Sets the value for the given ADI port. + * + * This only works on ports configured as outputs, and the behavior will change + * depending on the configuration of the 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 port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which the value + * will be set + * \param value + * The value to set the ADI port to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_port_set_value(uint8_t port, int32_t value); + +/******************************************************************************/ +/** PROS 2 Compatibility Functions **/ +/** **/ +/** These functions provide similar functionality to the PROS 2 API **/ +/******************************************************************************/ + +/** + * Used for adi_digital_write() to specify a logic HIGH state to output. + * + * In reality, using any non-zero expression or "true" will work to set a pin to + * HIGH. + */ +#define HIGH 1 +/** + * Used for adi_digital_write() to specify a logic LOW state to output. + * + * In reality, using a zero expression or "false" will work to set a pin to LOW. + */ +#define LOW 0 + +/** + * adi_pin_mode() state for a digital input. + */ +#define INPUT 0x00 +/** + * adi_pin_mode() state for a digital output. + */ +#define OUTPUT 0x01 +/** + * adi_pin_mode() state for an analog input. + */ +#define INPUT_ANALOG 0x02 + +/** + * adi_pin_mode() state for an analog output. + */ +#define OUTPUT_ANALOG 0x03 + +/** + * Calibrates the analog sensor on the specified port and returns the new + * calibration value. + * + * This method assumes that the true sensor value is not actively changing at + * this time and computes an average from approximately 500 samples, 1 ms apart, + * for a 0.5 s period of calibration. The average value thus calculated is + * returned and stored for later calls to the adi_analog_read_calibrated() and + * adi_analog_read_calibrated_HR() functions. These functions will return + * the difference between this value and the current sensor value when called. + * + * Do not use this function when the sensor value might be unstable + * (gyro rotation, accelerometer movement). + * + * 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 + * The ADI port to calibrate (from 1-8, 'a'-'h', 'A'-'H') + * + * \return The average sensor value computed by this function + */ +int32_t adi_analog_calibrate(uint8_t port); + +/** + * Gets the 12-bit value of the specified port. + * + * The value returned is undefined if the analog pin has been switched to a + * different mode. + * + * 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 + * EADDRINUSE - The port is not configured as an analog input + * + * \param port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \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 + */ +int32_t adi_analog_read(uint8_t port); + +/** + * Gets the 12 bit calibrated value of an analog input port. + * + * The adi_analog_calibrate() function must be run first. This function is + * inappropriate for sensor values intended for integration, as round-off error + * can accumulate causing drift over time. Use adi_analog_read_calibrated_HR() + * instead. + * + * 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 + * EADDRINUSE - The port is not configured as an analog input + * + * \param port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \return The difference of the sensor value from its calibrated default from + * -4095 to 4095 + */ +int32_t adi_analog_read_calibrated(uint8_t port); + +/** + * Gets the 16 bit calibrated value of an analog input port. + * + * The adi_analog_calibrate() function must be run first. This is intended for + * integrated sensor values such as gyros and accelerometers to reduce drift due + * to round-off, and should not be used on a sensor such as a line tracker + * or potentiometer. + * + * The value returned actually has 16 bits of "precision", even though the ADC + * only reads 12 bits, so that error induced by the average value being between + * two values when integrated over time is trivial. Think of the value as the + * true value times 16. + * + * 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 + * EADDRINUSE - The port is not configured as an analog input + * + * \param port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \return The difference of the sensor value from its calibrated default from + * -16384 to 16384 + */ +int32_t adi_analog_read_calibrated_HR(uint8_t port); + +/** + * Gets the digital value (1 or 0) of a port configured as a digital input. + * + * If the port is configured as some other mode, the digital value which + * reflects the current state of the port is returned, which may or may not + * differ from the currently set value. The return value is undefined for ports + * configured as any mode other than a Digital Input. + * + * 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 + * EADDRINUSE - The port is not configured as a digital input + * + * \param port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * + * \return True if the pin is HIGH, or false if it is LOW + */ +int32_t adi_digital_read(uint8_t port); + +/** + * Gets a rising-edge case for a digital 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 + * presses, and not in any other tasks. + * + * 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 + * EADDRINUSE - The port is not configured as a digital input + * + * \param port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * + * \return 1 if the button is pressed and had not been pressed + * the last time this function was called, 0 otherwise. + */ +int32_t adi_digital_get_new_press(uint8_t port); + +/** + * Sets the digital value (1 or 0) of a port configured as a digital output. + * + * If the port is configured as some other mode, behavior 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 ADI Ports + * EADDRINUSE - The port is not configured as a digital output + * + * \param port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * \param value + * An expression evaluating to "true" or "false" to set the output to + * HIGH or LOW respectively, or the constants HIGH or LOW themselves + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_digital_write(uint8_t port, bool value); + +/** + * Configures the port as an input or output with a variety of settings. + * + * 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 + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * \param mode + * One of INPUT, INPUT_ANALOG, INPUT_FLOATING, OUTPUT, or OUTPUT_OD + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_pin_mode(uint8_t port, uint8_t mode); + +/** + * Sets the speed of the motor 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 ADI Ports + * EADDRINUSE - The port is not configured as an motor + * + * \param port + * The ADI port to set (from 1-8, 'a'-'h', 'A'-'H') + * \param speed + * The new signed speed; -127 is full reverse and 127 is full forward, + * with 0 being off + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_motor_set(uint8_t port, int8_t speed); + +/** + * Gets the last set speed of the motor 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 ADI Ports + * EADDRINUSE - The port is not configured as an motor + * + * \param port + * The ADI port to get (from 1-8, 'a'-'h', 'A'-'H') + * + * \return The last set speed of the motor on the given port + */ +int32_t adi_motor_get(uint8_t port); + +/** + * Stops the motor 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 ADI Ports + * EADDRINUSE - The port is not configured as an motor + * + * \param port + * The ADI port to set (from 1-8, 'a'-'h', 'A'-'H') + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_motor_stop(uint8_t port); + +/** + * Reference type for an initialized encoder. + * + * This merely contains the port number for the encoder, unlike its use as an + * object to store encoder data in PROS 2. + */ +typedef int32_t adi_encoder_t; + +/** + * Gets the number of ticks recorded by the encoder. + * + * There are 360 ticks in one revolution. + * + * 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 + * EADDRINUSE - The port is not configured as an encoder + + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to read + * + * \return The signed and cumulative number of counts since the last start or + * reset + */ +int32_t adi_encoder_get(adi_encoder_t enc); + +/** + * Creates an encoder object and configures the specified ports accordingly. + * + * 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 + * EADDRINUSE - The port is not configured as an encoder + + * + * \param port_top + * The "top" wire from the encoder sensor with the removable cover side + * up. This should be in port 1, 3, 5, or 7 ('A', 'C', 'E', or 'G'). + * \param port_bottom + * The "bottom" wire from the encoder sensor + * \param reverse + * If "true", the sensor will count in the opposite direction + * + * \return An adi_encoder_t object to be stored and used for later calls to + * encoder functions + */ +adi_encoder_t adi_encoder_init(uint8_t port_top, uint8_t port_bottom, bool reverse); + +/** + * Sets the encoder value to zero. + * + * It is safe to use this method while an encoder is enabled. It is not + * necessary to call this method before stopping or starting an encoder. + * + * 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 + * EADDRINUSE - The port is not configured as an encoder + + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to reset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_encoder_reset(adi_encoder_t enc); + +/** + * Disables the encoder and voids the configuration on its ports. + * + * 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 + * EADDRINUSE - The port is not configured as an encoder + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to stop + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_encoder_shutdown(adi_encoder_t enc); + +/** + * Reference type for an initialized ultrasonic. + * + * This merely contains the port number for the ultrasonic, unlike its use as an + * object to store ultrasonic data in PROS 2. + */ +typedef int32_t adi_ultrasonic_t; + +/** + * Gets the current ultrasonic sensor value in centimeters. + * + * If no object was found, zero is returned. If the ultrasonic sensor was never + * started, the return value is undefined. Round and fluffy objects can cause + * inaccurate values to be returned. + * + * 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 + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param ult + * The adi_ultrasonic_t object from adi_ultrasonic_init() to read + * + * \return The distance to the nearest object in m^-4 (10000 indicates 1 meter), + * measured from the sensor's mounting points. + */ +int32_t adi_ultrasonic_get(adi_ultrasonic_t ult); + +/** + * Creates an ultrasonic object and configures the specified ports accordingly. + * + * 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 + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param port_ping + * The port connected to the orange OUTPUT cable. This should be in port + * 1, 3, 5, or 7 ('A', 'C', 'E', 'G'). + * \param port_echo + * The port connected to the yellow INPUT cable. This should be in the + * next highest port following port_ping. + * + * \return An adi_ultrasonic_t object to be stored and used for later calls to + * ultrasonic functions + */ +adi_ultrasonic_t adi_ultrasonic_init(uint8_t port_ping, uint8_t port_echo); + +/** + * Disables the ultrasonic sensor and voids the configuration on its ports. + * + * 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 + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param ult + * The adi_ultrasonic_t object from adi_ultrasonic_init() to stop + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_ultrasonic_shutdown(adi_ultrasonic_t ult); + +/** + * Reference type for an initialized gyroscope. + * + * This merely contains the port number for the gyroscope, unlike its use as an + * object to store gyro data in PROS 2. + */ +typedef int32_t adi_gyro_t; + +/** + * 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 + * the number of degrees of rotation times 10. + * + * There are 360 degrees in a circle, thus the gyro will return 3600 for one + * whole rotation. + * + * 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 + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object for which the angle will be returned + * + * \return The gyro angle in degrees. + */ +double adi_gyro_get(adi_gyro_t gyro); + +/** + * Initializes a gyroscope on the given port. If the given port has not + * previously been configured as a gyro, then this function starts a 1300 ms + * calibration period. + * + * It is highly recommended that this function be called from initialize() when + * the robot is stationary to ensure proper calibration. + * + * 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 + * EADDRINUSE - The port is not configured as a gyro + * + * \param 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 ADI + * + * \return An adi_gyro_t object containing the given port, or PROS_ERR if the + * initialization failed. + */ +adi_gyro_t adi_gyro_init(uint8_t port, double multiplier); + +/** + * Resets the gyroscope value to zero. + * + * 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 + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object for which the angle will be returned + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_gyro_reset(adi_gyro_t gyro); + +/** + * Disables the gyro and voids the configuration on its 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 + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object to be shut down + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_gyro_shutdown(adi_gyro_t gyro); + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_ADI_H_ diff --git a/old-code/v5_hal/firmware/include/pros/adi.hpp b/old-code/v5_hal/firmware/include/pros/adi.hpp new file mode 100644 index 00000000..30548054 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/adi.hpp @@ -0,0 +1,663 @@ +/** + * \file pros/adi.hpp + * + * Contains prototypes for interfacing with the ADI. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/adi.html to learn more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_ADI_HPP_ +#define _PROS_ADI_HPP_ + +#include +#include +#include + +#include "pros/adi.h" + +namespace pros { + +/** 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; + +class ADIPort { + public: + /** + * Configures an ADI port to act as a given sensor type. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param type + * The configuration type for the port + */ + explicit ADIPort(std::uint8_t adi_port, adi_port_config_e_t type = E_ADI_TYPE_UNDEFINED); + + /** + * Configures an ADI port on an adi expander to act as a given sensor type. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + * \param type + * The configuration type for the port + */ + ADIPort(ext_adi_port_pair_t port_pair, adi_port_config_e_t type = E_ADI_TYPE_UNDEFINED); + + /** + * Gets the configuration for the given ADI port. + * + * \return The ADI configuration for the given port + */ + std::int32_t get_config() const; + + /** + * Gets the value for the given ADI port. + * + * \return The value stored for the given port + */ + std::int32_t get_value() const; + + /** + * Configures an ADI port to act as a given sensor type. + * + * \param type + * The configuration type for the port + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_config(adi_port_config_e_t type) const; + + /** + * Sets the value for the given ADI port. + * + * This only works on ports configured as outputs, and the behavior will + * change depending on the configuration of the port. + * + * \param value + * The value to set the ADI port to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_value(std::int32_t value) const; + + protected: + std::uint8_t _smart_port; + std::uint8_t _adi_port; +}; + +class ADIAnalogIn : private ADIPort { + public: + /** + * Configures an ADI port to act as an Analog Input. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + explicit ADIAnalogIn(std::uint8_t adi_port); + + /** + * Configures an ADI port on an adi expander to act as an Analog Input. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + ADIAnalogIn(ext_adi_port_pair_t port_pair); + + /** + * Calibrates the analog sensor on the specified port and returns the new + * calibration value. + * + * This method assumes that the true sensor value is not actively changing at + * this time and computes an average from approximately 500 samples, 1 ms + * apart, for a 0.5 s period of calibration. The average value thus calculated + * is returned and stored for later calls to the + * pros::ADIAnalogIn::get_value_calibrated() and + * pros::ADIAnalogIn::get_value_calibrated_HR() functions. These functions + * will return the difference between this value and the current sensor value + * when called. + * + * Do not use this function when the sensor value might be unstable (gyro + * rotation, accelerometer movement). + * + * 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 + */ + std::int32_t calibrate() const; + + /** + * Gets the 12 bit calibrated value of an analog input port. + * + * The pros::ADIAnalogIn::calibrate() function must be run first. This + * function is inappropriate for sensor values intended for integration, as + * round-off error can accumulate causing drift over time. Use + * pros::ADIAnalogIn::get_value_calibrated_HR() instead. + * + * 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 difference of the sensor value from its calibrated default from + * -4095 to 4095 + */ + std::int32_t get_value_calibrated() const; + + /** + * Gets the 16 bit calibrated value of an analog input port. + * + * The pros::ADIAnalogIn::calibrate() function must be run first. This is + * intended for integrated sensor values such as gyros and accelerometers to + * reduce drift due to round-off, and should not be used on a sensor such as a + * line tracker or potentiometer. + * + * The value returned actually has 16 bits of "precision", even though the ADC + * only reads 12 bits, so that error induced by the average value being + * between two values when integrated over time is trivial. Think of the value + * as the true value times 16. + * + * 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 difference of the sensor value from its calibrated default from + * -16384 to 16384 + */ + std::int32_t get_value_calibrated_HR() const; + + /** + * Gets the 12-bit value of the specified port. + * + * The value returned is undefined if the analog pin has been switched to a + * different mode. + * + * 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 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 + */ + using ADIPort::get_value; +}; + +using ADIPotentiometer = ADIAnalogIn; +using ADILineSensor = ADIAnalogIn; +using ADILightSensor = ADIAnalogIn; +using ADIAccelerometer = ADIAnalogIn; + +class ADIAnalogOut : private ADIPort { + public: + /** + * Configures an ADI port to act as an Analog Output. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + */ + explicit ADIAnalogOut(std::uint8_t adi_port); + + /** + * Configures an ADI port on an adi_expander to act as an Analog Output. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + * + */ + ADIAnalogOut(ext_adi_port_pair_t port_pair); + + /** + * Sets the value for the given ADI port. + * + * This only works on ports configured as outputs, and the behavior will + * change depending on the configuration of the port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as an analog output + * + * \param value + * The value to set the ADI port to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + using ADIPort::set_value; +}; + +class ADIDigitalOut : private ADIPort { + public: + /** + * Configures an ADI port to act as a Digital Output. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param init_state + * The initial state for the port + */ + explicit ADIDigitalOut(std::uint8_t adi_port, bool init_state = LOW); + + /** + * Configures an ADI port on an adi_expander to act as a Digital Output. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + * \param init_state + * The initial state for the port + */ + ADIDigitalOut(ext_adi_port_pair_t port_pair, bool init_state = LOW); + + /** + * Sets the value for the given ADI port. + * + * This only works on ports configured as outputs, and the behavior will + * change depending on the configuration of the port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a digital output + * + * \param value + * The value to set the ADI port to + * + * \return if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + using ADIPort::set_value; +}; + +class ADIDigitalIn : private ADIPort { + public: + /** + * Configures an ADI port to act as a Digital Input. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + */ + explicit ADIDigitalIn(std::uint8_t adi_port); + + /** + * Configures an ADI port on an adi_expander to act as a Digital Input. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + */ + ADIDigitalIn(ext_adi_port_pair_t port_pair); + + /** + * Gets a rising-edge case for a digital 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 presses, and not in any other tasks. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a digital input + * + * \return 1 if the button is pressed and had not been pressed the last time + * this function was called, 0 otherwise. + */ + std::int32_t get_new_press() const; + + /** + * Gets the value for the given ADI port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a digital input + * + * \return The value stored for the given port + */ + using ADIPort::get_value; +}; + +using ADIButton = ADIDigitalIn; + +class ADIMotor : private ADIPort { + public: + /** + * Configures an ADI port to act as a Motor. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + */ + explicit ADIMotor(std::uint8_t adi_port); + + /** + * Configures an ADI port on an adi_expander to act as a Motor. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + */ + ADIMotor(ext_adi_port_pair_t port_pair); + + /** + * Stops the motor on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t stop() const; + + /** + * Sets the speed of the motor on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a motor + * + * \param value + * The new signed speed; -127 is full reverse and 127 is full forward, + * with 0 being off + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + using ADIPort::set_value; + + /** + * Gets the last set speed of the motor on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a motor + * + * \return The last set speed of the motor on the given port + */ + using ADIPort::get_value; +}; + +class ADIEncoder : private ADIPort { + public: + /** + * Configures a set of ADI ports to act as an Encoder. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port_top + * The "top" wire from the encoder sensor with the removable cover side up + * \param adi_port_bottom + * The "bottom" wire from the encoder sensor + * \param reverse + * If "true", the sensor will count in the opposite direction + */ + ADIEncoder(std::uint8_t adi_port_top, std::uint8_t adi_port_bottom, bool reversed = false); + + /** + * Configures a set of ADI ports on an adi_expander to act as an Encoder. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_tuple + * The tuple of the smart port number, the "top" wire from the encoder + * sensor with the removable cover side up, and the "bottom" wire from + * the encoder sensor + * \param reverse + * If "true", the sensor will count in theopposite direction + */ + ADIEncoder(ext_adi_port_tuple_t port_tuple, bool reversed = false); + + /** + * Sets the encoder value to zero. + * + * It is safe to use this method while an encoder is enabled. It is not + * necessary to call this method before stopping or starting an encoder. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t reset() const; + + /** + * Gets the number of ticks recorded by the encoder. + * + * There are 360 ticks in one revolution. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a motor + * + * \return The signed and cumulative number of counts since the last start or + * reset + */ + std::int32_t get_value() const; +}; + +class ADIUltrasonic : private ADIPort { + public: + /** + * Configures a set of ADI ports to act as an Ultrasonic sensor. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_ping + * The port connected to the orange OUTPUT cable. This should be in port + * 1, 3, 5, or 7 ('A', 'C', 'E', 'G'). + * \param port_echo + * The port connected to the yellow INPUT cable. This should be in the + * next highest port following port_ping. + */ + ADIUltrasonic(std::uint8_t adi_port_ping, std::uint8_t adi_port_echo); + + /** + * Configures a set of ADI ports on an adi_expander to act as an Ultrasonic sensor. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_tuple + * The tuple of the smart port number, the port connected to the orange + * 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). + */ + ADIUltrasonic(ext_adi_port_tuple_t port_tuple); + + /** + * Gets the current ultrasonic sensor value in centimeters. + * + * If no object was found, zero is returned. If the ultrasonic sensor was + * never started, the return value is undefined. Round and fluffy objects can + * cause inaccurate values to be returned. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as an ultrasonic + * + * \return The distance to the nearest object in m^-4 (10000 indicates 1 + * meter), measured from the sensor's mounting points. + */ + std::int32_t get_value() const; +}; + +class ADIGyro : private ADIPort { + public: + /** + * Initializes a gyroscope on the given port. If the given port has not + * previously been configured as a gyro, then this function starts a 1300ms + * calibration period. + * + * It is highly recommended that an ADIGyro object be created in initialize() + * when the robot is stationary to ensure proper calibration. If an ADIGyro + * object is declared at the global scope, a hardcoded 1300ms delay at the + * beginning of initialize will be necessary to ensure that the gyro's + * returned values are correct at the beginning of autonomous/opcontrol. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_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 ADI + */ + explicit ADIGyro(std::uint8_t adi_port, double multiplier = 1); + + /** + * Initializes a gyroscope on the given port of an adi expander. If the given + * port has not previously been configured as a gyro, then this function starts + * a 1300ms calibration period. + * + * It is highly recommended that an ADIGyro object be created in initialize() + * when the robot is stationary to ensure proper calibration. If an ADIGyro + * object is declared at the global scope, a hardcoded 1300ms delay at the + * beginning of initialize will be necessary to ensure that the gyro's + * returned values are correct at the beginning of autonomous/opcontrol. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + * \param multiplier + * A scalar value that will be multiplied by the gyro heading value + * supplied by the ADI + */ + ADIGyro(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 + * the number of degrees of rotation times 10. + * + * There are 360 degrees in a circle, thus the gyro will return 3600 for one + * whole rotation. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a gyro + * + * \return The gyro angle in degrees. + */ + double get_value() const; + + /** + * Resets the gyroscope value to zero. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a gyro + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t reset() const; +}; +} // namespace pros + +#endif // _PROS_ADI_HPP_ diff --git a/old-code/v5_hal/firmware/include/pros/api_legacy.h b/old-code/v5_hal/firmware/include/pros/api_legacy.h new file mode 100644 index 00000000..8768b515 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/api_legacy.h @@ -0,0 +1,108 @@ +/** + * \file pros/api_legacy.h + * + * PROS 2 Legacy API header + * + * Contains declarations for functions that are name-compatible with the PROS 2 + * API. Some functions from the PROS 2 API are not useful or cannot be + * implemented in PROS 3, but most common functions are available. + * + * 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. + * 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/. + */ + +#ifndef _PROS_API_LEGACY_H_ +#define _PROS_API_LEGACY_H_ + +#include "api.h" + +#ifdef __cplusplus +#define _NAMESPACE pros:: +#define _CNAMESPACE pros::c:: +#else +#define _NAMESPACE +#define _CNAMESPACE +#endif + +/** + * From adi.h + */ +#define analogCalibrate(port) adi_analog_calibrate(port) +#define analogRead(port) adi_analog_read(port) +#define analogReadCalibrated(port) adi_analog_read_calibrated(port) +#define analogReadCalibratedHR(port) adi_analog_read_calibrated_HR(port) +#define digitalRead(port) adi_digital_read(port) +#define digitalWrite(port, value) adi_digital_write(port, value) +#define pinMode(port, mode) adi_pin_mode(port, mode) +#define adiMotorSet(port, speed) adi_motor_set(port, speed) +#define adiMotorGet(port) adi_motor_get(port) +#define adiMotorStop(port) adi_motor_stop(port) +#define encoderGet(enc) adi_encoder_get(enc) +#define encoderInit(portTop, portBottom, reverse) adi_encoder_init(portTop, portBottom, reverse) +#define encoderShutdown(enc) adi_encoder_shutdown(enc) +#define ultrasonicGet(ult) adi_ultrasonic_get(ult) +#define ultrasonicInit(portEcho, portPing) adi_ultrasonic_init(portEcho, portPing) +#define ultrasonicShutdown(ult) adi_ultrasonic_shutdown(ult) + +typedef _CNAMESPACE adi_encoder_t Encoder; +typedef _CNAMESPACE adi_ultrasonic_t Ultrasonic; + +/** + * From llemu.h + */ +#define lcdInit lcd_initialize +#define lcdReadButtons lcd_read_buttons +#define lcdClear lcd_clear +#define lcdClearLine lcd_clear_line +#define lcdShutdown lcd_shutdown +#define lcdPrint(line, fmt, ...) lcd_print(line, fmt, __VA_ARGS__) +#define lcdSetText(line, text) lcd_set_text(line, text) + +/** + * From misc.h + */ +#define isEnabled() (!competition_is_disabled()) +#define isAutonomous competition_is_autonomous +#define isOnline competition_is_connected +#define isJoystickConnected(id) controller_is_connected(id) +#define joystickGetAnalog(id, channel) controller_get_analog(id, channel) + +/** + * From rtos.h + */ +#define taskCreate(taskCode, stackDepth, parameters, priority) \ + task_create(taskCode, parameters, priority, stackDepth, "") +#define taskDelete(task) task_delete(task) +#define taskDelay task_delay +#define taskDelayUntil(previousWakeTime, cycleTime) task_delay_until(previousWakeTime, cycleTime) +#define taskPriorityGet(task) task_get_priority(task) +#define taskPrioritySet(task, newPriority) task_priority_set(task, newPriority) +#define taskGetState(task) task_get_state(task) +#define taskSuspend(task) task_suspend(task) +#define taskResume(task) task_resume(task) +#define taskGetCount task_get_count +#define mutexCreate mutex_create +#define mutexTake(mutex, blockTime) mutex_take(mutex, blockTime) +#define mutexGive(mutex) mutex_give(mutex) + +typedef _NAMESPACE task_t TaskHandle; +typedef _NAMESPACE mutex_t Mutex; + +/** + * From motors.h + */ +#define motorSet(port, speed) motor_move(port, speed) +#define motorGet(port) motor_get_voltage(port) +#define motorStop(port) motor_move(port, 0) + +#undef _NAMESPACE +#undef _CNAMESPACE + +#endif // _PROS_API_LEGACY_H_ diff --git a/old-code/v5_hal/firmware/include/pros/apix.h b/old-code/v5_hal/firmware/include/pros/apix.h new file mode 100644 index 00000000..71146ada --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/apix.h @@ -0,0 +1,561 @@ +/** + * \file pros/apix.h + * + * PROS Extended API header + * + * Contains additional declarations for use by advaned users of PROS. These + * functions do not typically have as much error handling or require deeper + * knowledge of real time operating systems. + * + * Visit https://pros.cs.purdue.edu/v5/extended/api.html to learn more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_API_EXTENDED_H_ +#define _PROS_API_EXTENDED_H_ + +#include "api.h" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wall" +#include "display/lvgl.h" +#pragma GCC diagnostic pop +#include "pros/serial.h" + +#ifdef __cplusplus +#include "pros/serial.hpp" +namespace pros::c { +extern "C" { +#endif + +/******************************************************************************/ +/** RTOS FACILITIES **/ +/** **/ +/** **/ +/**See https://pros.cs.purdue.edu/v5/extended/multitasking.html to learn more**/ +/******************************************************************************/ + +typedef void* queue_t; +typedef void* sem_t; + +/** + * Unblocks a task in the Blocked state (e.g. waiting for a delay, on a + * semaphore, etc.). + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#abort_delay for + * details. + */ +bool task_abort_delay(task_t task); + +/** + * Notify a task when a target task is being deleted. + * + * This function will configure the PROS kernel to call + * task_notify_ext(task_to_notify, value, action, NULL) when target_task is + * deleted. + * + * + * \param target_task + * The task being watched for deletion + * \param task_to_notify + * The task to notify when target_task is deleted + * \param value + * The value to supply to task_notify_ext + * \param notify_action + * The action to supply to task_notify_ext + */ +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. + * + * See + * https://pros.cs.purdue.edu/v5/extended/multitasking.html#recursive_mutexes + * for details. + * + * \return A newly created recursive mutex. + */ +mutex_t mutex_recursive_create(void); + +/** + * Takes a recursive mutex. + * + * See + * https://pros.cs.purdue.edu/v5/extended/multitasking.html#recursive_mutexes + * for details. + * + * \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 + */ +bool mutex_recursive_take(mutex_t mutex, uint32_t timeout); + +/** + * Gives a recursive mutex. + * + * See + * https://pros.cs.purdue.edu/v5/extended/multitasking.html#recursive_mutexes + * for details. + * + * \param mutex + * A mutex handle created by mutex_recursive_create + * + * \return 1 if the mutex was obtained, 0 otherwise + */ +bool mutex_recursive_give(mutex_t mutex); + +/** + * Returns a handle to the current owner of a mutex. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#extra for + * details. + * + * \param mutex + * A mutex handle + * + * \return A handle to the current task that owns the mutex, or NULL if the + * mutex isn't owned. + */ +task_t mutex_get_owner(mutex_t mutex); + +/** + * Creates a counting sempahore. + * + * See https://pros.cs.purdue.edu/v5/tutorials/multitasking.html#semaphores for + *details. + * + * \param max_count + * The maximum count value that can be reached. + * \param init_count + * The initial count value assigned to the new semaphore. + * + * \return A newly created semaphore. If an error occurred, NULL will be + * returned and errno can be checked for hints as to why sem_create failed. + */ +sem_t sem_create(uint32_t max_count, uint32_t init_count); + +/** + * Deletes a semaphore (or binary semaphore) + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#semaphores for + * details. + * + * \param sem + * Semaphore to delete + */ +void sem_delete(sem_t sem); + +/** + * Creates a binary semaphore. + * + * See + * https://pros.cs.purdue.edu/v5/extended/multitasking#.htmlbinary_semaphores + * for details. + * + * \return A newly created semaphore. + */ +sem_t sem_binary_create(void); + +/** + * Waits for the semaphore's value to be greater than 0. If the value is already + * greater than 0, this function immediately returns. + * + * See https://pros.cs.purdue.edu/v5/tutorials/multitasking.html#semaphores for + * details. + * + * \param sem + * Semaphore to wait on + * \param timeout + * Time to wait before the semaphore's becomes available. A timeout of 0 + * can be used to poll the sempahore. TIMEOUT_MAX can be used to block + * indefinitely. + * + * \return True if the semaphore was successfully take, false otherwise. If + * false is returned, then errno is set with a hint about why the sempahore + * couldn't be taken. + */ +bool sem_wait(sem_t sem, uint32_t timeout); + +/** + * Increments a semaphore's value. + * + * See https://pros.cs.purdue.edu/v5/tutorials/multitasking.html#semaphores for + * details. + * + * \param sem + * Semaphore to post + * + * \return True if the value was incremented, false otherwise. If false is + * returned, then errno is set with a hint about why the semaphore couldn't be + * taken. + */ +bool sem_post(sem_t sem); + +/** + * Returns the current value of the semaphore. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#extra for + * details. + * + * \param sem + * A semaphore handle + * + * \return The current value of the semaphore (e.g. the number of resources + * available) + */ +uint32_t sem_get_count(sem_t sem); + +/** + * Creates a queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param length + * The maximum number of items that the queue can contain. + * \param item_size + * The number of bytes each item in the queue will require. + * + * \return A handle to a newly created queue, or NULL if the queue cannot be + * created. + */ +queue_t queue_create(uint32_t length, uint32_t item_size); + +/** + * Posts an item to the front of a queue. The item is queued by copy, not by + * reference. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * The queue handle + * \param item + * A pointer to the item that will be placed on the queue. + * \param timeout + * Time to wait for space to become available. A timeout of 0 can be used + * to attempt to post without blocking. TIMEOUT_MAX can be used to block + * indefinitely. + * + * \return True if the item was preprended, false otherwise. + */ +bool queue_prepend(queue_t queue, const void* item, uint32_t timeout); + +/** + * Posts an item to the end of a queue. The item is queued by copy, not by + * reference. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * The queue handle + * \param item + * A pointer to the item that will be placed on the queue. + * \param timeout + * Time to wait for space to become available. A timeout of 0 can be used + * to attempt to post without blocking. TIMEOUT_MAX can be used to block + * indefinitely. + * + * \return True if the item was preprended, false otherwise. + */ +bool queue_append(queue_t queue, const void* item, uint32_t timeout); + +/** + * Receive an item from a queue without removing the item from the queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * The queue handle + * \param buffer + * Pointer to a buffer to which the received item will be copied + * \param timeout + * The maximum amount of time the task should block waiting for an item to receive should the queue be empty at + * the time of the call. TIMEOUT_MAX can be used to block indefinitely. + * + * \return True if an item was copied into the buffer, false otherwise. + */ +bool queue_peek(queue_t queue, void* const buffer, uint32_t timeout); + +/** + * Receive an item from the queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * The queue handle + * \param buffer + * Pointer to a buffer to which the received item will be copied + * \param timeout + * The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. queue_recv() will return immediately if timeout + * is zero and the queue is empty. + * + * \return True if an item was copied into the buffer, false otherwise. + */ +bool queue_recv(queue_t queue, void* const buffer, uint32_t timeout); + +/** + * Return the number of messages stored in a queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * The queue handle. + * + * \return The number of messages available in the queue. + */ +uint32_t queue_get_waiting(const queue_t queue); + +/** + * Return the number of spaces left in a queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * The queue handle. + * + * \return The number of spaces available in the queue. + */ +uint32_t queue_get_available(const queue_t queue); + +/** + * Delete a queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * Queue handle to delete + */ +void queue_delete(queue_t queue); + +/** + * Resets a queue to an empty state + * + * \param queue + * Queue handle to reset + */ +void queue_reset(queue_t queue); + +/******************************************************************************/ +/** Device Registration **/ +/******************************************************************************/ + +/* + * List of possible v5 devices + * + * This list contains all current V5 Devices, and mirrors V5_DeviceType from the + * api. + */ +typedef enum v5_device_e { + E_DEVICE_NONE = 0, + E_DEVICE_MOTOR = 2, + E_DEVICE_ROTATION = 4, + E_DEVICE_IMU = 6, + E_DEVICE_DISTANCE = 7, + E_DEVICE_RADIO = 8, + E_DEVICE_VISION = 11, + E_DEVICE_ADI = 12, + E_DEVICE_OPTICAL = 16, + E_DEVICE_GENERIC = 129, + E_DEVICE_UNDEFINED = 255 +} v5_device_e_t; + +/* + * Registers a device in the given port + * + * Registers a device of the given type in the given port into the registry, if + * that type of device is detected to be plugged in to that 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), or a + * a different device than specified is plugged in. + * EADDRINUSE - The port is already registered to another device. + * + * \param port + * The port number to register the device + * \param device + * The type of device to register + * + * \return 1 upon success, PROS_ERR upon failure + */ +int registry_bind_port(uint8_t port, v5_device_e_t device_type); + +/* + * Deregisters a devices from the given port + * + * Removes the device registed in the given port, if there is one. + * + * 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). + * + * \param port + * The port number to deregister + * + * \return 1 upon success, PROS_ERR upon failure + */ +int registry_unbind_port(uint8_t port); + +/******************************************************************************/ +/** Filesystem **/ +/******************************************************************************/ +/** + * Control settings of the serial driver. + * + * \param action + * An action to perform on the serial driver. See the SERCTL_* macros for + * details on the different actions. + * \param extra_arg + * An argument to pass in based on the action + */ +int32_t serctl(const uint32_t action, void* const extra_arg); + +/** + * Control settings of the microSD card driver. + * + * \param action + * An action to perform on the microSD card driver. See the USDCTL_* macros + * for details on the different actions. + * \param extra_arg + * An argument to pass in based on the action + */ +// Not yet implemented +// int32_t usdctl(const uint32_t action, void* const extra_arg); + +/** + * Control settings of the way the file's driver treats the file + * + * \param file + * A valid file descriptor number + * \param action + * An action to perform on the file's driver. See the *CTL_* macros for + * details on the different actions. Note that the action passed in must + * match the correct driver (e.g. don't perform a SERCTL_* action on a + * microSD card file) + * \param extra_arg + * An argument to pass in based on the action + */ +int32_t fdctl(int file, const uint32_t action, void* const extra_arg); + +/** + * Action macro to pass into serctl or fdctl that activates the stream + * identifier. + * + * When used with serctl, the extra argument must be the little endian + * representation of the stream identifier (e.g. "sout" -> 0x74756f73) + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#define SERCTL_ACTIVATE 10 + +/** + * Action macro to pass into serctl or fdctl that deactivates the stream + * identifier. + * + * When used with serctl, the extra argument must be the little endian + * representation of the stream identifier (e.g. "sout" -> 0x74756f73) + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#define SERCTL_DEACTIVATE 11 + +/** + * Action macro to pass into fdctl that enables blocking writes for the file + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#define SERCTL_BLKWRITE 12 + +/** + * Action macro to pass into fdctl that makes writes non-blocking for the file + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#define SERCTL_NOBLKWRITE 13 + +/** + * Action macro to pass into serctl that enables advanced stream multiplexing + * capabilities + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#define SERCTL_ENABLE_COBS 14 + +/** + * Action macro to pass into serctl that disables advanced stream multiplexing + * capabilities + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#define SERCTL_DISABLE_COBS 15 + +/** + * Action macro to check if there is data available from the Generic Serial + * Device + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + */ +#define DEVCTL_FIONREAD 16 + +/** + * Action macro to check if there is space available in the Generic Serial + * Device's output buffer + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + */ +#define DEVCTL_FIONWRITE 18 + +/** + * Action macro to set the Generic Serial Device's baudrate. + * + * The extra argument is the baudrate. + */ +#define DEVCTL_SET_BAUDRATE 17 + +#ifdef __cplusplus +} +} +#endif + +#endif // _PROS_API_EXTENDED_H_ diff --git a/old-code/v5_hal/firmware/include/pros/colors.h b/old-code/v5_hal/firmware/include/pros/colors.h new file mode 100644 index 00000000..0f5e3b93 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/colors.h @@ -0,0 +1,171 @@ +/* + * \file pros/colors.h + * + * Contains macro definitions of colors (as `uint32_t`) + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_COLORS_H_ +#define _PROS_COLORS_H_ + +#define RGB2COLOR(R, G, B) ((R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff)) +#define COLOR2R(COLOR) ((COLOR >> 16) & 0xff) +#define COLOR2G(COLOR) ((COLOR >> 8) && 0xff) +#define COLOR2B(COLOR) (COLOR & 0xff) + +#define COLOR_ALICE_BLUE 0x00F0F8FF +#define COLOR_ANTIQUE_WHITE 0x00FAEBD7 +#define COLOR_AQUA 0x0000FFFF +#define COLOR_AQUAMARINE 0x007FFFD4 +#define COLOR_AZURE 0x00F0FFFF +#define COLOR_BEIGE 0x00F5F5DC +#define COLOR_BISQUE 0x00FFE4C4 +#define COLOR_BLACK 0x00000000 +#define COLOR_BLANCHED_ALMOND 0x00FFEBCD +#define COLOR_BLUE 0x000000FF +#define COLOR_BLUE_VIOLET 0x008A2BE2 +#define COLOR_BROWN 0x00A52A2A +#define COLOR_BURLY_WOOD 0x00DEB887 +#define COLOR_CADET_BLUE 0x005F9EA0 +#define COLOR_CHARTREUSE 0x007FFF00 +#define COLOR_CHOCOLATE 0x00D2691E +#define COLOR_CORAL 0x00FF7F50 +#define COLOR_CORNFLOWER_BLUE 0x006495ED +#define COLOR_CORNSILK 0x00FFF8DC +#define COLOR_CRIMSON 0x00DC143C +#define COLOR_CYAN 0x0000FFFF +#define COLOR_DARK_BLUE 0x0000008B +#define COLOR_DARK_CYAN 0x00008B8B +#define COLOR_DARK_GOLDENROD 0x00B8860B +#define COLOR_DARK_GRAY 0x00A9A9A9 +#define COLOR_DARK_GREEN 0x00006400 +#define COLOR_DARK_KHAKI 0x00BDB76B +#define COLOR_DARK_MAGENTA 0x008B008B +#define COLOR_DARK_OLIVE_GREEN 0x00556B2F +#define COLOR_DARK_ORANGE 0x00FF8C00 +#define COLOR_DARK_ORCHID 0x009932CC +#define COLOR_DARK_RED 0x008B0000 +#define COLOR_DARK_SALMON 0x00E9967A +#define COLOR_DARK_SEA_GREEN 0x008FBC8F +#define COLOR_DARK_SLATE_GRAY 0x002F4F4F +#define COLOR_DARK_TURQUOISE 0x0000CED1 +#define COLOR_DARK_VIOLET 0x009400D3 +#define COLOR_DEEP_PINK 0x00FF1493 +#define COLOR_DEEP_SKY_BLUE 0x0000BFFF +#define COLOR_DIM_GRAY 0x00696969 +#define COLOR_DODGER_BLUE 0x001E90FF +#define COLOR_FIRE_BRICK 0x00B22222 +#define COLOR_FLORAL_WHITE 0x00FFFAF0 +#define COLOR_FOREST_GREEN 0x00228B22 +#define COLOR_FUCHSIA 0x00FF00FF +#define COLOR_GAINSBORO 0x00DCDCDC +#define COLOR_GHOST_WHITE 0x00F8F8FF +#define COLOR_GOLD 0x00FFD700 +#define COLOR_GOLDENROD 0x00DAA520 +#define COLOR_GRAY 0x00808080 +#define COLOR_GREEN 0x00008000 +#define COLOR_GREEN_YELLOW 0x00ADFF2F +#define COLOR_HONEYDEW 0x00F0FFF0 +#define COLOR_HOT_PINK 0x00FF69B4 +#define COLOR_INDIAN_RED 0x00CD5C5C +#define COLOR_INDIGO 0x004B0082 +#define COLOR_IVORY 0x00FFFFF0 +#define COLOR_KHAKI 0x00F0E68C +#define COLOR_LAVENDER 0x00E6E6FA +#define COLOR_LAVENDER_BLUSH 0x00FFF0F5 +#define COLOR_LAWN_GREEN 0x007CFC00 +#define COLOR_LEMON_CHIFFON 0x00FFFACD +#define COLOR_LIGHT_BLUE 0x00ADD8E6 +#define COLOR_LIGHT_CORAL 0x00F08080 +#define COLOR_LIGHT_CYAN 0x00E0FFFF +#define COLOR_LIGHT_GOLDENROD_YELLOW 0x00FAFAD2 +#define COLOR_LIGHT_GREEN 0x0090EE90 +#define COLOR_LIGHT_GRAY 0x00D3D3D3 +#define COLOR_LIGHT_PINK 0x00FFB6C1 +#define COLOR_LIGHT_SALMON 0x00FFA07A +#define COLOR_LIGHT_SEA_GREEN 0x0020B2AA +#define COLOR_LIGHT_SKY_BLUE 0x0087CEFA +#define COLOR_LIGHT_SLATE_GRAY 0x00778899 +#define COLOR_LIGHT_STEEL_BLUE 0x00B0C4DE +#define COLOR_LIGHT_YELLOW 0x00FFFFE0 +#define COLOR_LIME 0x0000FF00 +#define COLOR_LIME_GREEN 0x0032CD32 +#define COLOR_LINEN 0x00FAF0E6 +#define COLOR_MAGENTA 0x00FF00FF +#define COLOR_MAROON 0x00800000 +#define COLOR_MEDIUM_AQUAMARINE 0x0066CDAA +#define COLOR_MEDIUM_BLUE 0x000000CD +#define COLOR_MEDIUM_ORCHID 0x00BA55D3 +#define COLOR_MEDIUM_PURPLE 0x009370DB +#define COLOR_MEDIUM_SEA_GREEN 0x003CB371 +#define COLOR_MEDIUM_SLATE_BLUE 0x007B68EE +#define COLOR_MEDIUM_SPRING_GREEN 0x0000FA9A +#define COLOR_MEDIUM_TURQUOISE 0x0048D1CC +#define COLOR_MEDIUM_VIOLET_RED 0x00C71585 +#define COLOR_MIDNIGHT_BLUE 0x00191970 +#define COLOR_MINT_CREAM 0x00F5FFFA +#define COLOR_MISTY_ROSE 0x00FFE4E1 +#define COLOR_MOCCASIN 0x00FFE4B5 +#define COLOR_NAVAJO_WHITE 0x00FFDEAD +#define COLOR_NAVY 0x00000080 +#define COLOR_OLD_LACE 0x00FDF5E6 +#define COLOR_OLIVE 0x00808000 +#define COLOR_OLIVE_DRAB 0x006B8E23 +#define COLOR_ORANGE 0x00FFA500 +#define COLOR_ORANGE_RED 0x00FF4500 +#define COLOR_ORCHID 0x00DA70D6 +#define COLOR_PALE_GOLDENROD 0x00EEE8AA +#define COLOR_PALE_GREEN 0x0098FB98 +#define COLOR_PALE_TURQUOISE 0x00AFEEEE +#define COLOR_PALE_VIOLET_RED 0x00DB7093 +#define COLOR_PAPAY_WHIP 0x00FFEFD5 +#define COLOR_PEACH_PUFF 0x00FFDAB9 +#define COLOR_PERU 0x00CD853F +#define COLOR_PINK 0x00FFC0CB +#define COLOR_PLUM 0x00DDA0DD +#define COLOR_POWDER_BLUE 0x00B0E0E6 +#define COLOR_PURPLE 0x00800080 +#define COLOR_RED 0x00FF0000 +#define COLOR_ROSY_BROWN 0x00BC8F8F +#define COLOR_ROYAL_BLUE 0x004169E1 +#define COLOR_SADDLE_BROWN 0x008B4513 +#define COLOR_SALMON 0x00FA8072 +#define COLOR_SANDY_BROWN 0x00F4A460 +#define COLOR_SEA_GREEN 0x002E8B57 +#define COLOR_SEASHELL 0x00FFF5EE +#define COLOR_SIENNA 0x00A0522D +#define COLOR_SILVER 0x00C0C0C0 +#define COLOR_SKY_BLUE 0x0087CEEB +#define COLOR_SLATE_BLUE 0x006A5ACD +#define COLOR_SLATE_GRAY 0x00708090 +#define COLOR_SNOW 0x00FFFAFA +#define COLOR_SPRING_GREEN 0x0000FF7F +#define COLOR_STEEL_BLUE 0x004682B4 +#define COLOR_TAN 0x00D2B48C +#define COLOR_TEAL 0x00008080 +#define COLOR_THISTLE 0x00D8BFD8 +#define COLOR_TOMATO 0x00FF6347 +#define COLOR_TURQUOISE 0x0040E0D0 +#define COLOR_VIOLET 0x00EE82EE +#define COLOR_WHEAT 0x00F5DEB3 +#define COLOR_WHITE 0x00FFFFFF +#define COLOR_WHITE_SMOKE 0x00F5F5F5 +#define COLOR_YELLOW 0x00FFFF00 +#define COLOR_YELLOW_GREEN 0x009ACD32 +#define COLOR_DARK_GREY COLOR_DARK_GRAY +#define COLOR_DARK_SLATE_GREY COLOR_DARK_SLATE_GRAY +#define COLOR_DIM_GREY COLOR_DIM_GRAY +#define COLOR_GREY COLOR_GRAY +#define COLOR_LIGHT_GREY COLOR_LIGHT_GRAY +#define COLOR_LIGHT_SLATE_GREY COLOR_LIGHT_SLATE_GRAY +#define COLOR_SLATE_GREY COLOR_SLATE_GRAY + +#endif // _PROS_COLORS_H_ diff --git a/old-code/v5_hal/firmware/include/pros/distance.h b/old-code/v5_hal/firmware/include/pros/distance.h new file mode 100644 index 00000000..115cf2ad --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/distance.h @@ -0,0 +1,101 @@ +/** + * \file pros/distance.h + * + * Contains prototypes for functions related to the VEX Distance sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/distance.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_DISTANCE_H_ +#define _PROS_DISTANCE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/** + * Get the currently measured distance from the sensor in mm + * + * 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 + * + * \param port The V5 Distance Sensor port number from 1-21 + * \return The distance value or PROS_ERR if the operation failed, setting + * errno. + */ +int32_t distance_get(uint8_t port); + +/** + * Get the confidence in the distance reading + * + * This is a value that has a range of 0 to 63. 63 means high confidence, + * lower values imply less confidence. Confidence is only available + * when distance is > 200mm (the value 10 is returned in this scenario). + * + * 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 + * + * \param port The V5 Distance Sensor port number from 1-21 + * \return The confidence value or PROS_ERR if the operation failed, setting + * errno. + */ +int32_t distance_get_confidence(uint8_t port); + +/** + * Get the current guess at relative object size + * + * This is a value that has a range of 0 to 400. + * A 18" x 30" grey card will return a value of approximately 75 + * in typical room lighting. + * + * 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 + * + * \param port The V5 Distance Sensor port number from 1-21 + * \return The size value or PROS_ERR if the operation failed, setting + * errno. + */ +int32_t distance_get_object_size(uint8_t port); + +/** + * Get the object velocity in m/s + * + * 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 + * + * \param port The V5 Distance Sensor port number from 1-21 + * \return The velocity value or PROS_ERR if the operation failed, setting + * errno. + */ +double distance_get_object_velocity(uint8_t port); + +#ifdef __cplusplus +} +} +} +#endif + +#endif diff --git a/old-code/v5_hal/firmware/include/pros/distance.hpp b/old-code/v5_hal/firmware/include/pros/distance.hpp new file mode 100644 index 00000000..b584966a --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/distance.hpp @@ -0,0 +1,114 @@ +/** + * \file pros/distance.hpp + * + * Contains prototypes for the V5 Distance Sensor-related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/distance.html to learn + * more. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2018, 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/. + */ + +#ifndef _PROS_DISTANCE_HPP_ +#define _PROS_DISTANCE_HPP_ + +#include + +#include "pros/distance.h" + +namespace pros { +class Distance { + public: + /** + * Creates a Distance Sensor 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). + * ENODEV - The port cannot be configured as a Distance Sensor + * + * \param port + * The V5 port number from 1-21 + */ + explicit Distance(const std::uint8_t port); + + /** + * Get the currently measured distance from the sensor in mm + * + * 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. + */ + virtual std::int32_t get(); + + /** + * Get the confidence in the distance reading + * + * This is a value that has a range of 0 to 63. 63 means high confidence, + * lower values imply less confidence. Confidence is only available + * when distance is > 200mm. + * + * 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 confidence value or PROS_ERR if the operation failed, setting + * errno. + */ + virtual std::int32_t get_confidence(); + + /** + * Get the current guess at relative object size + * + * This is a value that has a range of 0 to 400. + * A 18" x 30" grey card will return a value of approximately 75 + * in typical room lighting. + * + * 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 size value or PROS_ERR if the operation failed, setting + * errno. + */ + virtual std::int32_t get_object_size(); + + /** + * Get the object velocity in m/s + * + * 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 velocity value or PROS_ERR if the operation failed, setting + * errno. + */ + virtual double get_object_velocity(); + + /** + * Gets the port number of the distance sensor. + * + * \return The distance sensor's port number. + */ + std::uint8_t get_port(); + + private: + const std::uint8_t _port; +}; +} // namespace pros + +#endif diff --git a/old-code/v5_hal/firmware/include/pros/ext_adi.h b/old-code/v5_hal/firmware/include/pros/ext_adi.h new file mode 100644 index 00000000..391617f4 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/ext_adi.h @@ -0,0 +1,639 @@ +/** + * \file pros/ext_adi.h + * + * Contains prototypes for interfacing with the 3-Wire Expander. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/adi.html to learn more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_EXT_ADI_H_ +#define _PROS_EXT_ADI_H_ + +#include +#include + +#include "adi.h" +#include "pros/adi.h" +#ifndef PROS_ERR +#define PROS_ERR (INT32_MAX) +#endif + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +#ifdef __cplusplus +namespace c { +#endif + +/******************************************************************************/ +/** General ADI Use Functions **/ +/** **/ +/** These functions allow for interaction with any ADI port type **/ +/******************************************************************************/ + +/** + * Gets the configuration for the given ADI port. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which to return + * the configuration + * + * \return The ADI configuration for the given port + */ +adi_port_config_e_t ext_adi_port_get_config(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets the value for the given ADI port. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which to return + * the configuration + * + * \return The value stored for the given port + */ +int32_t ext_adi_port_get_value(uint8_t smart_port, uint8_t adi_port); + +/** + * Configures an ADI port to act as a given sensor type. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param type + * The configuration type for the port + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_port_set_config(uint8_t smart_port, uint8_t adi_port, adi_port_config_e_t type); + +/** + * Sets the value for the given ADI port. + * + * This only works on ports configured as outputs, and the behavior will change + * depending on the configuration of the port. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which the value + * will be set + * \param value + * The value to set the ADI port to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_port_set_value(uint8_t smart_port, uint8_t adi_port, int32_t value); + +/** + * Calibrates the analog sensor on the specified port and returns the new + * calibration value. + * + * This method assumes that the true sensor value is not actively changing at + * this time and computes an average from approximately 500 samples, 1 ms apart, + * for a 0.5 s period of calibration. The average value thus calculated is + * returned and stored for later calls to the adi_analog_read_calibrated() and + * adi_analog_read_calibrated_HR() functions. These functions will return + * the difference between this value and the current sensor value when called. + * + * Do not use this function when the sensor value might be unstable + * (gyro rotation, accelerometer movement). + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to calibrate (from 1-8, 'a'-'h', 'A'-'H') + * + * \return The average sensor value computed by this function + */ +int32_t ext_adi_analog_calibrate(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets the 12-bit value of the specified port. + * + * The value returned is undefined if the analog pin has been switched to a + * different mode. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an analog input + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \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 + */ +int32_t ext_adi_analog_read(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets the 12 bit calibrated value of an analog input port. + * + * The adi_analog_calibrate() function must be run first. This function is + * inappropriate for sensor values intended for integration, as round-off error + * can accumulate causing drift over time. Use adi_analog_read_calibrated_HR() + * instead. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an analog input + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \return The difference of the sensor value from its calibrated default from + * -4095 to 4095 + */ +int32_t ext_adi_analog_read_calibrated(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets the 16 bit calibrated value of an analog input port. + * + * The adi_analog_calibrate() function must be run first. This is intended for + * integrated sensor values such as gyros and accelerometers to reduce drift due + * to round-off, and should not be used on a sensor such as a line tracker + * or potentiometer. + * + * The value returned actually has 16 bits of "precision", even though the ADC + * only reads 12 bits, so that error induced by the average value being between + * two values when integrated over time is trivial. Think of the value as the + * true value times 16. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an analog input + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \return The difference of the sensor value from its calibrated default from + * -16384 to 16384 + */ +int32_t ext_adi_analog_read_calibrated_HR(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets the digital value (1 or 0) of a port configured as a digital input. + * + * If the port is configured as some other mode, the digital value which + * reflects the current state of the port is returned, which may or may not + * differ from the currently set value. The return value is undefined for ports + * configured as any mode other than a Digital Input. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a digital input + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * + * \return True if the pin is HIGH, or false if it is LOW + */ +int32_t ext_adi_digital_read(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets a rising-edge case for a digital 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 + * presses, and not in any other tasks. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a digital input + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * + * \return 1 if the button is pressed and had not been pressed + * the last time this function was called, 0 otherwise. + */ +int32_t ext_adi_digital_get_new_press(uint8_t smart_port, uint8_t adi_port); + +/** + * Sets the digital value (1 or 0) of a port configured as a digital output. + * + * If the port is configured as some other mode, behavior is undefined. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a digital output + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param value + * An expression evaluating to "true" or "false" to set the output to + * HIGH or LOW respectively, or the constants HIGH or LOW themselves + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_digital_write(uint8_t smart_port, uint8_t adi_port, bool value); + +/** + * Configures the port as an input or output with a variety of settings. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param mode + * One of INPUT, INPUT_ANALOG, INPUT_FLOATING, OUTPUT, or OUTPUT_OD + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_pin_mode(uint8_t smart_port, uint8_t adi_port, uint8_t mode); + +/** + * Sets the speed of the motor on the given port. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an motor + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param speed + * The new signed speed; -127 is full reverse and 127 is full forward, + * with 0 being off + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_motor_set(uint8_t smart_port, uint8_t adi_port, int8_t speed); + +/** + * Gets the last set speed of the motor on the given port. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an motor + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to get (from 1-8, 'a'-'h', 'A'-'H') + * + * \return The last set speed of the motor on the given port + */ +int32_t ext_adi_motor_get(uint8_t smart_port, uint8_t adi_port); + +/** + * Stops the motor on the given port. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an motor + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to set (from 1-8, 'a'-'h', 'A'-'H') + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_motor_stop(uint8_t smart_port, uint8_t adi_port); + +/** + * Reference type for an initialized encoder. + * + * This merely contains the port number for the encoder, unlike its use as an + * object to store encoder data in PROS 2. + */ +typedef int32_t ext_adi_encoder_t; + +/** + * Gets the number of ticks recorded by the encoder. + * + * There are 360 ticks in one revolution. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an encoder + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to read + * + * \return The signed and cumulative number of counts since the last start or + * reset + */ +int32_t ext_adi_encoder_get(ext_adi_encoder_t enc); + +/** + * Creates an encoder object and configures the specified ports accordingly. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an encoder + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port_top + * The "top" wire from the encoder sensor with the removable cover side + * up. This should be in port 1, 3, 5, or 7 ('A', 'C', 'E', or 'G'). + * \param adi_port_bottom + * The "bottom" wire from the encoder sensor + * \param reverse + * If "true", the sensor will count in the opposite direction + * + * \return An adi_encoder_t object to be stored and used for later calls to + * encoder functions + */ +ext_adi_encoder_t ext_adi_encoder_init(uint8_t smart_port, uint8_t adi_port_top, uint8_t adi_port_bottom, bool reverse); + +/** + * Sets the encoder value to zero. + * + * It is safe to use this method while an encoder is enabled. It is not + * necessary to call this method before stopping or starting an encoder. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an encoder + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to reset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_encoder_reset(ext_adi_encoder_t enc); + +/** + * Disables the encoder and voids the configuration on its ports. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an encoder + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to stop + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_encoder_shutdown(ext_adi_encoder_t enc); + +/** + * Reference type for an initialized ultrasonic. + * + * This merely contains the port number for the ultrasonic, unlike its use as an + * object to store encoder data in PROS 2. + */ +typedef int32_t ext_adi_ultrasonic_t; + +/** + * Gets the current ultrasonic sensor value in centimeters. + * + * If no object was found, zero is returned. If the ultrasonic sensor was never + * started, the return value is undefined. Round and fluffy objects can cause + * inaccurate values to be returned. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param ult + * The adi_ultrasonic_t object from adi_ultrasonic_init() to read + * + * \return The distance to the nearest object in m^-4 (10000 indicates 1 meter), + * measured from the sensor's mounting points. + */ +int32_t ext_adi_ultrasonic_get(ext_adi_ultrasonic_t ult); + +/** + * Creates an ultrasonic object and configures the specified ports accordingly. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port_ping + * The port connected to the orange OUTPUT cable. This should be in port + * 1, 3, 5, or 7 ('A', 'C', 'E', 'G'). + * \param adi_port_echo + * The port connected to the yellow INPUT cable. This should be in the + * next highest port following port_ping. + * + * \return An adi_ultrasonic_t object to be stored and used for later calls to + * ultrasonic functions + */ +ext_adi_ultrasonic_t ext_adi_ultrasonic_init(uint8_t smart_port, uint8_t adi_port_ping, uint8_t adi_port_echo); + +/** + * Disables the ultrasonic sensor and voids the configuration on its ports. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param ult + * The adi_ultrasonic_t object from adi_ultrasonic_init() to stop + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_ultrasonic_shutdown(ext_adi_ultrasonic_t ult); + +/** + * Reference type for an initialized gyroscope. + * + * This merely contains the port number for the gyroscope, unlike its use as an + * object to store gyro data in PROS 2. + * + * (Might Be useless with the wire expander.) + */ +typedef int32_t ext_adi_gyro_t; + +/** + * 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 + * the number of degrees of rotation times 10. + * + * There are 360 degrees in a circle, thus the gyro will return 3600 for one + * whole rotation. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object for which the angle will be returned + * + * \return The gyro angle in degrees. + */ +double ext_adi_gyro_get(ext_adi_gyro_t gyro); + +/** + * Initializes a gyroscope on the given port. If the given port has not + * previously been configured as a gyro, then this function starts a 1300 ms + * calibration period. + * + * It is highly recommended that this function be called from initialize() when + * the robot is stationary to ensure proper calibration. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a gyro + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_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 ADI + * + * \return An adi_gyro_t object containing the given port, or PROS_ERR if the + * initialization failed. + */ +ext_adi_gyro_t ext_adi_gyro_init(uint8_t smart_port, uint8_t adi_port, double multiplier); + +/** + * Resets the gyroscope value to zero. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object for which the angle will be returned + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_gyro_reset(ext_adi_gyro_t gyro); + +/** + * Disables the gyro and voids the configuration on its port. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object to be shut down + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_gyro_shutdown(ext_adi_gyro_t gyro); + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_ADI_H_ diff --git a/old-code/v5_hal/firmware/include/pros/imu.h b/old-code/v5_hal/firmware/include/pros/imu.h new file mode 100644 index 00000000..0caf6843 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/imu.h @@ -0,0 +1,285 @@ +/** + * \file pros/imu.h + * + * Contains prototypes for functions related to the VEX Inertial sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/imu.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_IMU_H_ +#define _PROS_IMU_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +typedef enum imu_status_e { + E_IMU_STATUS_CALIBRATING = 0x01, + E_IMU_STATUS_ERROR = 0xFF, // NOTE: used for returning an error from the get_status function, not that the IMU is + // necessarily in an error state +} imu_status_e_t; + +typedef struct __attribute__((__packed__)) quaternion_s { + double x; + double y; + double z; + double w; +} quaternion_s_t; + +struct imu_raw_s { + double x; + double y; + double z; +}; + +typedef struct imu_raw_s imu_gyro_s_t; +typedef struct imu_raw_s imu_accel_s_t; + +typedef struct __attribute__((__packed__)) euler_s { + double pitch; + double roll; + double yaw; +} euler_s_t; + +#define IMU_MINIMUM_DATA_RATE 5 + +/** + * Calibrate IMU + * + * This takes approximately 2 seconds, and is a non-blocking operation. + * + * 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 + * EAGAIN - The sensor is already calibrating + * + * \param port + * 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. + */ +int32_t imu_reset(uint8_t port); + + +/** + * Set the Inertial Sensor's refresh interval in milliseconds. + * + * The rate may be specified in increments of 5ms, and will be rounded down to + * the nearest increment. The minimum allowable refresh rate is 5ms. The default + * rate is 10ms. + * + * As values are copied into the shared memory buffer only at 10ms intervals, + * setting this value to less than 10ms does not mean that you can poll the + * sensor's values any faster. However, it will guarantee that the data is as + * recent as possible. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param rate The data refresh interval in milliseconds + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t imu_set_data_rate(uint8_t port, uint32_t rate); + +/** + * Get the total number of degrees the Inertial Sensor has spun about the z-axis + * + * This value is theoretically unbounded. Clockwise rotations are represented + * with positive degree values, while counterclockwise rotations are represented + * with negative ones. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The degree value or PROS_ERR_F if the operation failed, setting + * errno. + */ +double imu_get_rotation(uint8_t port); + +/** + * Get the Inertial Sensor's heading relative to the initial direction of its + * x-axis + * + * This value is bounded by (-360,360). Clockwise rotations are represented with + * positive degree values, while counterclockwise rotations are represented with + * negative ones. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The degree value or PROS_ERR_F if the operation failed, setting + * errno. + */ +double imu_get_heading(uint8_t port); + +/** + * Get a quaternion representing the Inertial Sensor's 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \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. + */ +quaternion_s_t imu_get_quaternion(uint8_t port); + +/** + * Get the Euler angles representing the Inertial Sensor's 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \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. + */ +euler_s_t imu_get_euler(uint8_t port); + +/** + * Get the Inertial Sensor's pitch angle + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The pitch angle, or PROS_ERR_F if the operation failed, setting + * errno. + */ +double imu_get_pitch(uint8_t port); + +/** + * Get the Inertial Sensor's roll angle + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \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. + */ +double imu_get_roll(uint8_t port); + +/** + * Get the Inertial Sensor's yaw angle + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \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. + */ +double imu_get_yaw(uint8_t port); + +/** + * Get the Inertial Sensor's raw gyroscope values + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ +imu_gyro_s_t imu_get_gyro_rate(uint8_t port); + +/** + * Get the Inertial Sensor's raw acceleroneter values + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ +imu_accel_s_t imu_get_accel(uint8_t port); + +/** + * Get the Inertial Sensor's 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ +imu_status_e_t imu_get_status(uint8_t port); + +// NOTE: not used +// void imu_set_mode(uint8_t port, uint32_t mode); +// uint32_t imu_get_mode(uint8_t port); + +#ifdef __cplusplus +} +} +} +#endif + +#endif diff --git a/old-code/v5_hal/firmware/include/pros/imu.hpp b/old-code/v5_hal/firmware/include/pros/imu.hpp new file mode 100644 index 00000000..07159f52 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/imu.hpp @@ -0,0 +1,238 @@ +/** + * \file pros/imu.hpp + * + * Contains prototypes for functions related to the VEX Inertial sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/imu.html to learn + * more. + * + * 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. + * + * 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/. + */ +#ifndef _PROS_IMU_HPP_ +#define _PROS_IMU_HPP_ + +#include +#include "pros/imu.h" + +namespace pros { +class Imu { + const std::uint8_t _port; + + public: + Imu(const std::uint8_t port) : _port(port){}; + + /** + * Calibrate IMU + * + * This takes approximately 2 seconds, and is a non-blocking operation. + * + * 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 + * EAGAIN - The sensor is already calibrating + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t reset() const; + /** + * Set the Inertial Sensor's refresh interval in milliseconds. + * + * The rate may be specified in increments of 5ms, and will be rounded down to + * the nearest increment. The minimum allowable refresh rate is 5ms. The default + * rate is 10ms. + * + * As values are copied into the shared memory buffer only at 10ms intervals, + * setting this value to less than 10ms does not mean that you can poll the + * sensor's values any faster. However, it will guarantee that the data is as + * recent as possible. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param rate The data refresh interval in milliseconds + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_data_rate(std::uint32_t rate) const; + /** + * Get the total number of degrees the Inertial Sensor has spun about the z-axis + * + * This value is theoretically unbounded. Clockwise rotations are represented + * with positive degree values, while counterclockwise rotations are represented + * with negative ones. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The degree value or PROS_ERR_F if the operation failed, setting + * errno. + */ + virtual double get_rotation() const; + /** + * Get the Inertial Sensor's heading relative to the initial direction of its + * x-axis + * + * This value is bounded by (-360,360). Clockwise rotations are represented with + * positive degree values, while counterclockwise rotations are represented with + * negative ones. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The degree value or PROS_ERR_F if the operation failed, setting + * errno. + */ + virtual double get_heading() const; + /** + * Get a quaternion representing the Inertial Sensor's 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \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. + */ + virtual pros::c::quaternion_s_t get_quaternion() const; + /** + * Get the Euler angles representing the Inertial Sensor's 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \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. + */ + virtual pros::c::euler_s_t get_euler() const; + /** + * Get the Inertial Sensor's pitch angle + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The pitch angle, or PROS_ERR_F if the operation failed, setting + * errno. + */ + virtual double get_pitch() const; + /** + * Get the Inertial Sensor's roll angle + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \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. + */ + virtual double get_roll() const; + /** + * Get the Inertial Sensor's yaw angle + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \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. + */ + virtual double get_yaw() const; + /** + * Get the Inertial Sensor's raw gyroscope values + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ + virtual pros::c::imu_gyro_s_t get_gyro_rate() const; + /** + * Get the Inertial Sensor's raw acceleroneter values + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ + virtual pros::c::imu_accel_s_t get_accel() const; + /** + * Get the Inertial Sensor's 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ + virtual pros::c::imu_status_e_t get_status() const; + /** + * Check whether the IMU is calibrating + * + * \return true if the V5 Inertial Sensor is calibrating or false + * false if it is not. + */ + virtual bool is_calibrating() const; +}; +} // namespace pros + +#endif diff --git a/old-code/v5_hal/firmware/include/pros/llemu.h b/old-code/v5_hal/firmware/include/pros/llemu.h new file mode 100644 index 00000000..aef90d6f --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/llemu.h @@ -0,0 +1,233 @@ +/* + * \file pros/llemu.h + * + * Legacy LCD Emulator + * + * This file defines a high-level API for emulating the three-button, UART-based + * VEX LCD, containing a set of functions that facilitate the use of a software- + * emulated version of the classic VEX LCD module. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/llemu.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_LLEMU_H_ +#define _PROS_LLEMU_H_ + +#include +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#include "display/lvgl.h" +#pragma GCC diagnostic pop + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +typedef void (*lcd_btn_cb_fn_t)(void); + +#define LCD_BTN_LEFT 4 +#define LCD_BTN_CENTER 2 +#define LCD_BTN_RIGHT 1 + +typedef struct lcd_s { + lv_obj_t* frame; + lv_obj_t* screen; + lv_obj_t* lcd_text[8]; + lv_obj_t* btn_container; + lv_obj_t* btns[3]; // < 0 => left; 1 => center; 2 => right + lcd_btn_cb_fn_t callbacks[3]; // < 0 => left; 1 => center; 2 => right + volatile uint8_t touch_bits; // < 4 => left; 2 => center; 1 => right (no + // multitouch support) +} lcd_s_t; + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Checks whether the emulated three-button LCD has already been initialized. + * + * \return True if the LCD has been initialized or false if not. + */ +bool lcd_is_initialized(void); + +/** + * Creates an emulation of the three-button, UART-based VEX LCD on the display. + * + * \return True if the LCD was successfully initialized, or false if it has + * already been initialized. + */ +bool lcd_initialize(void); + +/** + * Turns off the Legacy LCD Emulator. + * + * Calling this function will clear the entire display, and you will not be able + * to call any further LLEMU functions until another call to lcd_initialize. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_shutdown(void); + +/** + * Displays a formatted string on the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line on which to display the text [0-7] + * \param fmt + * Format string + * \param ... + * Optional list of arguments for the format string + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_print(int16_t line, const char* fmt, ...); + +/** + * Displays a string on the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line on which to display the text [0-7] + * \param text + * The text to display + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_set_text(int16_t line, const char* text); + +/** + * Clears the contents of the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_clear(void); + +/** + * Clears the contents of a line of the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line to clear + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_clear_line(int16_t line); + +/** + * Registers a callback function for the leftmost button. + * + * When the leftmost button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t (void (*cb)(void)) + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_register_btn0_cb(lcd_btn_cb_fn_t cb); + +/** + * Registers a callback function for the center button. + * + * When the center button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t (void (*cb)(void)) + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_register_btn1_cb(lcd_btn_cb_fn_t cb); + +/** + * Registers a callback function for the rightmost button. + * + * When the rightmost button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t (void (*cb)(void)) + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_register_btn2_cb(lcd_btn_cb_fn_t cb); + +/** + * Gets the button status from the emulated three-button LCD. + * + * The value returned is a 3-bit integer where 1 0 0 indicates the left button + * is pressed, 0 1 0 indicates the center button is pressed, and 0 0 1 + * indicates the right button is pressed. 0 is returned if no buttons are + * currently being pressed. + * + * Note that this function is provided for legacy API compatibility purposes, + * with the caveat that the V5 touch screen does not actually support pressing + * multiple points on the screen at the same time. + * + * \return The buttons pressed as a bit mask + */ +uint8_t lcd_read_buttons(void); + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif +#endif // _PROS_LLEMU_H_ diff --git a/old-code/v5_hal/firmware/include/pros/llemu.hpp b/old-code/v5_hal/firmware/include/pros/llemu.hpp new file mode 100644 index 00000000..a7eaa372 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/llemu.hpp @@ -0,0 +1,199 @@ +/* + * \file pros/llemu.hpp + * + * Legacy LCD Emulator + * + * This file defines a high-level API for emulating the three-button, UART-based + * VEX LCD, containing a set of functions that facilitate the use of a software- + * emulated version of the classic VEX LCD module. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/llemu.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_LLEMU_HPP_ +#define _PROS_LLEMU_HPP_ + +#include +#include + +#include "pros/llemu.h" + +namespace pros { +namespace lcd { +/** + * Checks whether the emulated three-button LCD has already been initialized. + * + * \return True if the LCD has been initialized or false if not. + */ +bool is_initialized(void); + +/** + * Creates an emulation of the three-button, UART-based VEX LCD on the display. + * + * \return True if the LCD was successfully initialized, or false if it has + * already been initialized. + */ +bool initialize(void); + +/** + * Turns off the Legacy LCD Emulator. + * + * Calling this function will clear the entire display, and you will not be able + * to call any further LLEMU functions until another call to lcd_initialize. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool shutdown(void); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +namespace { +template +T convert_args(T arg) { + return arg; +} +const char* convert_args(const std::string& arg) { + return arg.c_str(); +} +} // namespace +#pragma GCC diagnostic pop + +/** + * Displays a formatted string on the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line on which to display the text [0-7] + * \param fmt + * Format string + * \param ... + * Optional list of arguments for the format string + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +template +bool print(std::int16_t line, const char* fmt, Params... args) { + return pros::c::lcd_print(line, fmt, convert_args(args)...); +} + +/** + * Displays a string on the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line on which to display the text [0-7] + * \param text + * The text to display + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool set_text(std::int16_t line, std::string text); + +/** + * Clears the contents of the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool clear(void); + +/** + * Clears the contents of a line of the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line to clear + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool clear_line(std::int16_t line); + +using lcd_btn_cb_fn_t = void (*)(void); + +/** + * Registers a callback function for the leftmost button. + * + * When the leftmost button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t(void (*cb)(void)) + */ +void register_btn0_cb(lcd_btn_cb_fn_t cb); + +/** + * Registers a callback function for the center button. + * + * When the center button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t(void (*cb)(void)) + */ +void register_btn1_cb(lcd_btn_cb_fn_t cb); + +/** + * Registers a callback function for the rightmost button. + * + * When the rightmost button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t(void (*cb)(void)) + */ +void register_btn2_cb(lcd_btn_cb_fn_t cb); + +/** + * Gets the button status from the emulated three-button LCD. + * + * The value returned is a 3-bit integer where 1 0 0 indicates the left button + * is pressed, 0 1 0 indicates the center button is pressed, and 0 0 1 + * indicates the right button is pressed. 0 is returned if no buttons are + * currently being pressed. + * + * Note that this function is provided for legacy API compatibility purposes, + * with the caveat that the V5 touch screen does not actually support pressing + * multiple points on the screen at the same time. + * + * \return The buttons pressed as a bit mask + */ +std::uint8_t read_buttons(void); +} // namespace lcd +} // namespace pros + +#endif // _PROS_LLEMU_HPP_ diff --git a/old-code/v5_hal/firmware/include/pros/misc.h b/old-code/v5_hal/firmware/include/pros/misc.h new file mode 100644 index 00000000..7bdb00f5 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/misc.h @@ -0,0 +1,464 @@ +/** + * \file pros/misc.h + * + * Contains prototypes for miscellaneous functions pertaining to the controller, + * battery, and competition control. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/controller.html to + * learn more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_MISC_H_ +#define _PROS_MISC_H_ + +#include + +#define NUM_V5_PORTS (22) + +/******************************************************************************/ +/** V5 Competition **/ +/******************************************************************************/ +#define COMPETITION_DISABLED (1 << 0) +#define COMPETITION_AUTONOMOUS (1 << 1) +#define COMPETITION_CONNECTED (1 << 2) + +/** + * Get the current status of the competition control. + * + * \return The competition control status as a mask of bits with + * COMPETITION_{ENABLED,AUTONOMOUS,CONNECTED}. + */ +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif +uint8_t competition_get_status(void); +#ifdef __cplusplus +} +} +} +#endif +#define competition_is_disabled() ((competition_get_status() & COMPETITION_DISABLED) != 0) +#define competition_is_connected() ((competition_get_status() & COMPETITION_CONNECTED) != 0) +#define competition_is_autonomous() ((competition_get_status() & COMPETITION_AUTONOMOUS) != 0) + +/******************************************************************************/ +/** V5 Controller **/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +typedef enum { E_CONTROLLER_MASTER = 0, E_CONTROLLER_PARTNER } controller_id_e_t; + +typedef enum { + E_CONTROLLER_ANALOG_LEFT_X = 0, + E_CONTROLLER_ANALOG_LEFT_Y, + E_CONTROLLER_ANALOG_RIGHT_X, + E_CONTROLLER_ANALOG_RIGHT_Y +} controller_analog_e_t; + +typedef enum { + E_CONTROLLER_DIGITAL_L1 = 6, + E_CONTROLLER_DIGITAL_L2, + E_CONTROLLER_DIGITAL_R1, + E_CONTROLLER_DIGITAL_R2, + E_CONTROLLER_DIGITAL_UP, + E_CONTROLLER_DIGITAL_DOWN, + E_CONTROLLER_DIGITAL_LEFT, + E_CONTROLLER_DIGITAL_RIGHT, + E_CONTROLLER_DIGITAL_X, + E_CONTROLLER_DIGITAL_B, + E_CONTROLLER_DIGITAL_Y, + E_CONTROLLER_DIGITAL_A +} controller_digital_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define CONTROLLER_MASTER pros::E_CONTROLLER_MASTER +#define CONTROLLER_PARTNER pros::E_CONTROLLER_PARTNER +#define ANALOG_LEFT_X pros::E_CONTROLLER_ANALOG_LEFT_X +#define ANALOG_LEFT_Y pros::E_CONTROLLER_ANALOG_LEFT_Y +#define ANALOG_RIGHT_X pros::E_CONTROLLER_ANALOG_RIGHT_X +#define ANALOG_RIGHT_Y pros::E_CONTROLLER_ANALOG_RIGHT_Y +#define DIGITAL_L1 pros::E_CONTROLLER_DIGITAL_L1 +#define DIGITAL_L2 pros::E_CONTROLLER_DIGITAL_L2 +#define DIGITAL_R1 pros::E_CONTROLLER_DIGITAL_R1 +#define DIGITAL_R2 pros::E_CONTROLLER_DIGITAL_R2 +#define DIGITAL_UP pros::E_CONTROLLER_DIGITAL_UP +#define DIGITAL_DOWN pros::E_CONTROLLER_DIGITAL_DOWN +#define DIGITAL_LEFT pros::E_CONTROLLER_DIGITAL_LEFT +#define DIGITAL_RIGHT pros::E_CONTROLLER_DIGITAL_RIGHT +#define DIGITAL_X pros::E_CONTROLLER_DIGITAL_X +#define DIGITAL_B pros::E_CONTROLLER_DIGITAL_B +#define DIGITAL_Y pros::E_CONTROLLER_DIGITAL_Y +#define DIGITAL_A pros::E_CONTROLLER_DIGITAL_A +#else +#define CONTROLLER_MASTER E_CONTROLLER_MASTER +#define CONTROLLER_PARTNER E_CONTROLLER_PARTNER +#define ANALOG_LEFT_X E_CONTROLLER_ANALOG_LEFT_X +#define ANALOG_LEFT_Y E_CONTROLLER_ANALOG_LEFT_Y +#define ANALOG_RIGHT_X E_CONTROLLER_ANALOG_RIGHT_X +#define ANALOG_RIGHT_Y E_CONTROLLER_ANALOG_RIGHT_Y +#define DIGITAL_L1 E_CONTROLLER_DIGITAL_L1 +#define DIGITAL_L2 E_CONTROLLER_DIGITAL_L2 +#define DIGITAL_R1 E_CONTROLLER_DIGITAL_R1 +#define DIGITAL_R2 E_CONTROLLER_DIGITAL_R2 +#define DIGITAL_UP E_CONTROLLER_DIGITAL_UP +#define DIGITAL_DOWN E_CONTROLLER_DIGITAL_DOWN +#define DIGITAL_LEFT E_CONTROLLER_DIGITAL_LEFT +#define DIGITAL_RIGHT E_CONTROLLER_DIGITAL_RIGHT +#define DIGITAL_X E_CONTROLLER_DIGITAL_X +#define DIGITAL_B E_CONTROLLER_DIGITAL_B +#define DIGITAL_Y E_CONTROLLER_DIGITAL_Y +#define DIGITAL_A E_CONTROLLER_DIGITAL_A +#endif +#endif + +/* +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; \ + } \ + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Checks if the controller is connected. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * + * \return 1 if the controller is connected, 0 otherwise + */ +int32_t controller_is_connected(controller_id_e_t id); + +/** + * Gets the value of an analog channel (joystick) on a controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param channel + * The analog channel to get. + * Must be one of ANALOG_LEFT_X, ANALOG_LEFT_Y, ANALOG_RIGHT_X, + * ANALOG_RIGHT_Y + * + * \return The current reading of the analog channel: [-127, 127]. + * If the controller was not connected, then 0 is returned + */ +int32_t controller_get_analog(controller_id_e_t id, controller_analog_e_t channel); + +/** + * Gets the battery capacity of the given controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER + * + * \return The controller's battery capacity + */ +int32_t controller_get_battery_capacity(controller_id_e_t id); + +/** + * Gets the battery level of the given controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER + * + * \return The controller's battery level + */ +int32_t controller_get_battery_level(controller_id_e_t id); + +/** + * Checks if a digital channel (button) on the controller is currently pressed. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \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 pressed. + * If the controller was not connected, then 0 is returned + */ +int32_t controller_get_digital(controller_id_e_t id, controller_digital_e_t button); + +/** + * Returns a rising-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 + * presses, and not in any other tasks. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \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 pressed and had not been pressed + * the last time this function was called, 0 otherwise. + */ +int32_t controller_get_digital_new_press(controller_id_e_t id, controller_digital_e_t button); + +/** + * Sets text to the controller LCD screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param line + * The line number at which the text will be displayed [0-2] + * \param col + * The column number at which the text will be displayed [0-14] + * \param fmt + * The format string to print to the controller + * \param ... + * The argument list for the format string + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t controller_print(controller_id_e_t id, uint8_t line, uint8_t col, const char* fmt, ...); + +/** + * Sets text to the controller LCD screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param line + * The line number at which the text will be displayed [0-2] + * \param col + * The column number at which the text will be displayed [0-14] + * \param str + * The pre-formatted string to print to the controller + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t controller_set_text(controller_id_e_t id, uint8_t line, uint8_t col, const char* str); + +/** + * Clears an individual line of the controller screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param line + * The line number to clear [0-2] + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t controller_clear_line(controller_id_e_t id, uint8_t line); + +/** + * Clears all of the lines on the controller screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. On vexOS version 1.0.0 this function will block + * for 110ms. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t controller_clear(controller_id_e_t id); + +/** + * Rumble the controller. + * + * \note Controller rumble activation is currently in beta, so continuous, fast + * updates will not work well. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param rumble_pattern + * A string consisting of the characters '.', '-', and ' ', where dots + * are short rumbles, dashes are long rumbles, and spaces are pauses. + * Maximum supported length is 8 characters. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t controller_rumble(controller_id_e_t id, const char* rumble_pattern); + +/** + * Gets the current voltage of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current voltage of the battery + */ +int32_t battery_get_voltage(void); + +/** + * Gets the current current of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current current of the battery + */ +int32_t battery_get_current(void); + +/** + * Gets the current temperature of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current temperature of the battery + */ +double battery_get_temperature(void); + +/** + * Gets the current capacity of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current capacity of the battery + */ +double battery_get_capacity(void); + +/** + * Checks if the SD card is installed. + * + * \return 1 if the SD card is installed, 0 otherwise + */ +int32_t usd_is_installed(void); + +#ifdef __cplusplus +} +} +} +#endif + +#endif // _PROS_MISC_H_ diff --git a/old-code/v5_hal/firmware/include/pros/misc.hpp b/old-code/v5_hal/firmware/include/pros/misc.hpp new file mode 100644 index 00000000..72a689af --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/misc.hpp @@ -0,0 +1,331 @@ +/** + * \file pros/misc.hpp + * + * Contains prototypes for miscellaneous functions pertaining to the controller, + * battery, and competition control. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/controller.html to + * learn more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_MISC_HPP_ +#define _PROS_MISC_HPP_ + +#include "pros/misc.h" + +#include +#include + +namespace pros { +class Controller { + public: + /** + * Creates a controller object for the given controller id. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + */ + Controller(controller_id_e_t id); + + /** + * Checks if the controller is connected. + * + * 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. + * + * \return 1 if the controller is connected, 0 otherwise + */ + std::int32_t is_connected(void); + + /** + * Gets the value of an analog channel (joystick) on a controller. + * + * 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 channel + * The analog channel to get. + * Must be one of ANALOG_LEFT_X, ANALOG_LEFT_Y, ANALOG_RIGHT_X, + * ANALOG_RIGHT_Y + * + * \return The current reading of the analog channel: [-127, 127]. + * If the controller was not connected, then 0 is returned + */ + std::int32_t get_analog(controller_analog_e_t channel); + + /** + * Gets the battery capacity of the controller. + * + * 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. + * + * \return The controller's battery capacity + */ + std::int32_t get_battery_capacity(void); + + /** + * Gets the battery level of the controller. + * + * 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. + * + * \return The controller's battery level + */ + std::int32_t get_battery_level(void); + + /** + * Checks if a digital channel (button) on the controller is currently + * pressed. + * + * 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 pressed. + * If the controller was not connected, then 0 is returned + */ + std::int32_t get_digital(controller_digital_e_t button); + + /** + * Returns a rising-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 presses, 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 pressed and had not been + * pressed the last time this function was called, 0 otherwise. + */ + std::int32_t get_digital_new_press(controller_digital_e_t button); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" + template + T convert_args(T arg) { + return arg; + } + const char* convert_args(const std::string& arg) { + return arg.c_str(); + } +#pragma GCC diagnostic pop + + /** + * Sets text to the controller LCD screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * 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 line + * The line number at which the text will be displayed [0-2] + * \param col + * The column number at which the text will be displayed [0-14] + * \param fmt + * The format string to print to the controller + * \param ... + * The argument list for the format string + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + template + std::int32_t print(std::uint8_t line, std::uint8_t col, const char* fmt, Params... args) { + return pros::c::controller_print(_id, line, col, fmt, convert_args(args)...); + } + + /** + * Sets text to the controller LCD screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * 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 line + * The line number at which the text will be displayed [0-2] + * \param col + * The column number at which the text will be displayed [0-14] + * \param str + * The pre-formatted string to print to the controller + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + 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); + + /** + * Clears an individual line of the controller screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * 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 line + * The line number to clear [0-2] + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t clear_line(std::uint8_t line); + + /** + * Rumble the controller. + * + * \note Controller rumble activation is currently in beta, so continuous, fast + * updates will not work well. + * + * 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 rumble_pattern + * A string consisting of the characters '.', '-', and ' ', where dots + * are short rumbles, dashes are long rumbles, and spaces are pauses. + * Maximum supported length is 8 characters. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t rumble(const char* rumble_pattern); + + /** + * Clears all of the lines on the controller screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. On vexOS version 1.0.0 this function will + * block for 110ms. + * + * 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. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t clear(void); + + private: + controller_id_e_t _id; +}; + +namespace battery { +/** + * Gets the current voltage of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current voltage of the battery + */ +double get_capacity(void); + +/** + * Gets the current current of the battery in milliamps, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current current of the battery + */ +int32_t get_current(void); + +/** + * Gets the current temperature of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current temperature of the battery + */ +double get_temperature(void); + +/** + * Gets the current capacity of the battery in millivolts, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current capacity of the battery + */ +int32_t get_voltage(void); +} // namespace battery + +namespace competition { +/** + * Get the current status of the competition control. + * + * \return The competition control status as a mask of bits with + * COMPETITION_{ENABLED,AUTONOMOUS,CONNECTED}. + */ +std::uint8_t get_status(void); +std::uint8_t is_autonomous(void); +std::uint8_t is_connected(void); +std::uint8_t is_disabled(void); +} // namespace competition + +namespace usd { +/** + * Checks if the SD card is installed. + * + * \return 1 if the SD card is installed, 0 otherwise + */ +std::int32_t is_installed(void); +} // namespace usd +} // namespace pros + +#endif // _PROS_MISC_HPP_ diff --git a/old-code/v5_hal/firmware/include/pros/motors.h b/old-code/v5_hal/firmware/include/pros/motors.h new file mode 100644 index 00000000..35ef6e45 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/motors.h @@ -0,0 +1,1101 @@ +/** + * \file pros/motors.h + * + * Contains prototypes for the V5 Motor-related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/motors.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_MOTORS_H_ +#define _PROS_MOTORS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/******************************************************************************/ +/** Motor movement functions **/ +/** **/ +/** 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 motor_move_voltage(), or motorSet() from the PROS 2 API. + * + * 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-21 + * \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. + */ +int32_t motor_move(uint8_t port, int32_t voltage); + +/** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with motor_set_zero_position(). + * + * \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: + * 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-21 + * \param position + * The absolute position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_move_absolute(uint8_t port, const double position, const int32_t velocity); + +/** + * Sets the relative target position for the motor to move to. + * + * This movement is relative to the current position of the motor as given in + * motor_get_position(). Providing 10.0 as the position parameter would result + * in the motor moving clockwise 10 units, 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. + * + * 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-21 + * \param position + * The relative position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_move_relative(uint8_t port, const double position, const int32_t velocity); + +/** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the gearset + * used for the motor. This results in a range of +-100 for E_MOTOR_GEARSET_36, + * +-200 for E_MOTOR_GEARSET_18, and +-600 for E_MOTOR_GEARSET_6. The velocity + * is held with PID to ensure consistent speed, as opposed to setting the + * motor's voltage. + * + * 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-21 + * \param velocity + * The new motor velocity from +-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_move_velocity(uint8_t port, const int32_t velocity); + +/** + * Sets the output voltage for the motor from -12000 to 12000 in millivolts + * + * 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-21 + * \param voltage + * The new voltage value from -12000 to 12000 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_move_voltage(uint8_t port, const int32_t voltage); + +/** + * Changes the output velocity for a profiled movement (motor_move_absolute or + * motor_move_relative). This will have no effect if the motor is not following + * a profiled movement. + * + * 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-21 + * \param velocity + * The new motor velocity from +-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_modify_profiled_velocity(uint8_t port, const int32_t velocity); + +/** + * Gets the target position set for the motor by the user. + * + * 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-21 + * + * \return The target position in its encoder units or PROS_ERR_F if the + * operation failed, setting errno. + */ +double motor_get_target_position(uint8_t port); + +/** + * Gets the velocity commanded to the motor by the user. + * + * 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-21 + * + * \return The commanded motor velocity from +-100, +-200, or +-600, or PROS_ERR + * if the operation failed, setting errno. + */ +int32_t motor_get_target_velocity(uint8_t port); + +/******************************************************************************/ +/** Motor telemetry functions **/ +/** **/ +/** These functions allow programmers to collect telemetry from motors **/ +/******************************************************************************/ + +/** + * Gets the actual velocity 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-21 + * + * \return The motor's actual velocity in RPM or PROS_ERR_F if the operation + * failed, setting errno. + */ +double motor_get_actual_velocity(uint8_t port); + +/** + * Gets the current drawn by the motor in mA. + * + * 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-21 + * + * \return The motor's current in mA or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t motor_get_current_draw(uint8_t port); + +/** + * Gets the direction of movement for 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-21 + * + * \return 1 for moving in the positive direction, -1 for moving in the + * negative direction, or PROS_ERR if the operation failed, setting errno. + */ +int32_t motor_get_direction(uint8_t port); + +/** + * Gets the efficiency of the motor in percent. + * + * 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: + * 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-21 + * + * \return The motor's efficiency in percent or PROS_ERR_F if the operation + * failed, setting errno. + */ +double motor_get_efficiency(uint8_t port); + +/** + * Checks if the motor is drawing over its current limit. + * + * 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-21 + * + * \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. + */ +int32_t motor_is_over_current(uint8_t port); + +/** + * Checks if the motor's temperature is above its limit. + * + * 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-21 + * + * \return 1 if the temperature limit is exceeded and 0 if the the temperature + * is below the limit, or PROS_ERR if the operation failed, setting errno. + */ +int32_t motor_is_over_temp(uint8_t port); + +/** + * Checks if the motor is stopped. + * + * \note Although this function forwards data from the motor, the motor + * presently does not provide any value. This function returns PROS_ERR with + * errno set to ENOSYS. + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the motor is not moving, 0 if the motor is moving, or PROS_ERR + * if the operation failed, setting errno + */ +int32_t motor_is_stopped(uint8_t port); + +/** + * Checks if the motor is at its zero position. + * + * \note Although this function forwards data from the motor, the motor + * presently does not provide any value. This function returns PROS_ERR with + * errno set to ENOSYS. + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the motor is at zero absolute position, 0 if the motor has + * moved from its absolute zero, or PROS_ERR if the operation failed, + * setting errno + */ +int32_t motor_get_zero_position_flag(uint8_t port); + +#ifdef __cplusplus +} // namespace c +#endif + +typedef enum motor_fault_e { + E_MOTOR_FAULT_NO_FAULTS = 0x00, + E_MOTOR_FAULT_MOTOR_OVER_TEMP = 0x01, // Analogous to motor_is_over_temp() + E_MOTOR_FAULT_DRIVER_FAULT = 0x02, // Indicates a motor h-bridge fault + E_MOTOR_FAULT_OVER_CURRENT = 0x04, // Analogous to motor_is_over_current() + E_MOTOR_FAULT_DRV_OVER_CURRENT = 0x08 // Indicates an h-bridge over current +} motor_fault_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define MOTOR_FAULT_NO_FAULTS pros::E_MOTOR_FAULT_NO_FAULTS +#define MOTOR_FAULT_MOTOR_OVER_TEMP pros::E_MOTOR_FAULT_MOTOR_OVER_TEMP +#define MOTOR_FAULT_DRIVER_FAULT pros::E_MOTOR_FAULT_DRIVER_FAULT +#define MOTOR_FAULT_OVER_CURRENT pros::E_MOTOR_FAULT_DRV_OVER_CURRENT +#define MOTOR_FAULT_DRV_OVER_CURRENT pros::E_MOTOR_FAULT_DRV_OVER_CURRENT +#else +#define MOTOR_FAULT_NO_FAULTS E_MOTOR_FAULT_NO_FAULTS +#define MOTOR_FAULT_MOTOR_OVER_TEMP E_MOTOR_FAULT_MOTOR_OVER_TEMP +#define MOTOR_FAULT_DRIVER_FAULT E_MOTOR_FAULT_DRIVER_FAULT +#define MOTOR_FAULT_OVER_CURRENT E_MOTOR_FAULT_DRV_OVER_CURRENT +#define MOTOR_FAULT_DRV_OVER_CURRENT E_MOTOR_FAULT_DRV_OVER_CURRENT +#endif +#endif + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Gets the faults experienced by the motor. + * + * Compare this bitfield to the bitmasks in motor_fault_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 motor + * + * \param port + * The V5 port number from 1-21 + * + * \return A bitfield containing the motor's faults. + */ +uint32_t motor_get_faults(uint8_t port); + +#ifdef __cplusplus +} // namespace c +#endif + +typedef enum motor_flag_e { + E_MOTOR_FLAGS_NONE = 0x00, + E_MOTOR_FLAGS_BUSY = 0x01, // Cannot currently communicate to the motor + E_MOTOR_FLAGS_ZERO_VELOCITY = 0x02, // Analogous to motor_is_stopped() + E_MOTOR_FLAGS_ZERO_POSITION = 0x04 // Analogous to motor_get_zero_position_flag() +} motor_flag_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define MOTOR_FLAGS_NONE pros::E_MOTOR_FLAGS_NONE +#define MOTOR_FLAGS_BUSY pros::E_MOTOR_FLAGS_BUSY +#define MOTOR_FLAGS_ZERO_VELOCITY pros::E_MOTOR_FLAGS_ZERO_VELOCITY +#define MOTOR_FLAGS_ZERO_POSITION pros::E_MOTOR_FLAGS_ZERO_POSITION +#else +#define MOTOR_FLAGS_NONE E_MOTOR_FLAGS_NONE +#define MOTOR_FLAGS_BUSY E_MOTOR_FLAGS_BUSY +#define MOTOR_FLAGS_ZERO_VELOCITY E_MOTOR_FLAGS_ZERO_VELOCITY +#define MOTOR_FLAGS_ZERO_POSITION E_MOTOR_FLAGS_ZERO_POSITION +#endif +#endif + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Gets the flags set by the motor's operation. + * + * Compare this bitfield to the bitmasks in motor_flag_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 motor + * + * \param port + * The V5 port number from 1-21 + * + * \return A bitfield containing the motor's flags. + */ +uint32_t motor_get_flags(uint8_t port); + +/** + * Gets 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: + * 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-21 + * \param[in] 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 The raw encoder count at the given timestamp or PROS_ERR if the + * operation failed. + */ +int32_t motor_get_raw_position(uint8_t port, uint32_t* const timestamp); + +/** + * Gets the absolute position of the motor in its encoder units. + * + * 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-21 + * + * \return The motor's absolute position in its encoder units or PROS_ERR_F + * if the operation failed, setting errno. + */ +double motor_get_position(uint8_t port); + +/** + * Gets the power drawn by the motor in Watts. + * + * 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-21 + * + * \return The motor's power draw in Watts or PROS_ERR_F if the operation + * failed, setting errno. + */ +double motor_get_power(uint8_t port); + +/** + * Gets the temperature of the motor 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 motor + * + * \param port + * The V5 port number from 1-21 + * + * \return The motor's temperature in degrees Celsius or PROS_ERR_F if the + * operation failed, setting errno. + */ +double motor_get_temperature(uint8_t port); + +/** + * Gets the torque generated by the motor in Newton Meters (Nm). + * + * 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-21 + * + * \return The motor's torque in Nm or PROS_ERR_F if the operation failed, + * setting errno. + */ +double motor_get_torque(uint8_t port); + +/** + * Gets the voltage delivered to the motor in millivolts. + * + * 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-21 + * + * \return The motor's voltage in mV or PROS_ERR_F if the operation failed, + * setting errno. + */ +int32_t motor_get_voltage(uint8_t port); + +/******************************************************************************/ +/** Motor configuration functions **/ +/** **/ +/** These functions allow programmers to configure the behavior of motors **/ +/******************************************************************************/ + +#ifdef __cplusplus +} // namespace c +#endif + +/** + * Indicates the current 'brake mode' of a motor. + */ +typedef enum motor_brake_mode_e { + E_MOTOR_BRAKE_COAST = 0, // Motor coasts when stopped, traditional behavior + E_MOTOR_BRAKE_BRAKE = 1, // Motor brakes when stopped + E_MOTOR_BRAKE_HOLD = 2, // Motor actively holds position when stopped + E_MOTOR_BRAKE_INVALID = INT32_MAX +} motor_brake_mode_e_t; + +/** + * Indicates the units used by the motor encoders. + */ +typedef enum motor_encoder_units_e { + E_MOTOR_ENCODER_DEGREES = 0, // Position is recorded as angle in degrees + // as a floating point number + E_MOTOR_ENCODER_ROTATIONS = 1, // Position is recorded as angle in rotations + // as a floating point number + E_MOTOR_ENCODER_COUNTS = 2, // Position is recorded as raw encoder ticks + // as a whole number + E_MOTOR_ENCODER_INVALID = INT32_MAX +} motor_encoder_units_e_t; + +/** + * Indicates the current internal gear ratio of a motor. + */ +typedef enum motor_gearset_e { + E_MOTOR_GEARSET_36 = 0, // 36:1, 100 RPM, Red gear set + E_MOTOR_GEARSET_18 = 1, // 18:1, 200 RPM, Green gear set + E_MOTOR_GEARSET_06 = 2, // 6:1, 600 RPM, Blue gear set + E_MOTOR_GEARSET_INVALID = INT32_MAX +} motor_gearset_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define MOTOR_BRAKE_COAST pros::E_MOTOR_BRAKE_COAST +#define MOTOR_BRAKE_BRAKE pros::E_MOTOR_BRAKE_BRAKE +#define MOTOR_BRAKE_HOLD pros::E_MOTOR_BRAKE_HOLD +#define MOTOR_BRAKE_INVALID pros::E_MOTOR_BRAKE_INVALID +#define MOTOR_ENCODER_DEGREES pros::E_MOTOR_ENCODER_DEGREES +#define MOTOR_ENCODER_ROTATIONS pros::E_MOTOR_ENCODER_ROTATIONS +#define MOTOR_ENCODER_COUNTS pros::E_MOTOR_ENCODER_COUNTS +#define MOTOR_ENCODER_INVALID pros::E_MOTOR_ENCODER_INVALID +#define MOTOR_GEARSET_36 pros::E_MOTOR_GEARSET_36 +#define MOTOR_GEARSET_18 pros::E_MOTOR_GEARSET_18 +#define MOTOR_GEARSET_06 pros::E_MOTOR_GEARSET_06 +#define MOTOR_GEARSET_6 pros::E_MOTOR_GEARSET_06 +#define MOTOR_GEARSET_INVALID pros::E_MOTOR_GEARSET_INVALID +#else +#define MOTOR_BRAKE_COAST E_MOTOR_BRAKE_COAST +#define MOTOR_BRAKE_BRAKE E_MOTOR_BRAKE_BRAKE +#define MOTOR_BRAKE_HOLD E_MOTOR_BRAKE_HOLD +#define MOTOR_BRAKE_INVALID E_MOTOR_BRAKE_INVALID +#define MOTOR_ENCODER_DEGREES E_MOTOR_ENCODER_DEGREES +#define MOTOR_ENCODER_ROTATIONS E_MOTOR_ENCODER_ROTATIONS +#define MOTOR_ENCODER_COUNTS E_MOTOR_ENCODER_COUNTS +#define MOTOR_ENCODER_INVALID E_MOTOR_ENCODER_INVALID +#define MOTOR_GEARSET_36 E_MOTOR_GEARSET_36 +#define MOTOR_GEARSET_18 E_MOTOR_GEARSET_18 +#define MOTOR_GEARSET_06 E_MOTOR_GEARSET_06 +#define MOTOR_GEARSET_6 E_MOTOR_GEARSET_06 +#define MOTOR_GEARSET_INVALID E_MOTOR_GEARSET_INVALID +#endif +#endif + +/** + * Holds the information about a Motor's position or velocity PID controls. + * + * These values are in 4.4 format, meaning that a value of 0x20 represents 2.0, + * 0x21 represents 2.0625, 0x22 represents 2.125, etc. + */ +typedef struct motor_pid_full_s { + uint8_t kf; // The feedforward constant + uint8_t kp; // The proportional constant + uint8_t ki; // The integral constants + uint8_t kd; // The derivative constant + uint8_t filter; // A constant used for filtering the profile acceleration + uint16_t limit; // The integral limit + uint8_t threshold; // The threshold for determining if a position movement has + // reached its goal. This has no effect for velocity PID + // calculations. + uint8_t loopspeed; // The rate at which the PID computation is run in ms +} motor_pid_full_s_t; + +/** + * Holds just the constants for a Motor's position or velocity PID controls. + * + * These values are in 4.4 format, meaning that a value of 0x20 represents 2.0, + * 0x21 represents 2.0625, 0x22 represents 2.125, etc. + */ +typedef struct motor_pid_s { + uint8_t kf; // The feedforward constant + uint8_t kp; // The proportional constant + uint8_t ki; // The integral constants + uint8_t kd; // The derivative constant +} motor_pid_s_t; + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Sets the position for the motor in its encoder units. + * + * This will be the future reference point for the motor's "absolute" 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 motor + * + * \param port + * The V5 port number from 1-21 + * \param position + * The new reference position in its encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_zero_position(uint8_t port, const double position); + +/** + * Sets the "absolute" zero position of the motor to its current 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 motor + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_tare_position(uint8_t port); + +/** + * Sets one of motor_brake_mode_e_t to 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-21 + * \param mode + * The motor_brake_mode_e_t to set for the motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_brake_mode(uint8_t port, const motor_brake_mode_e_t mode); + +/** + * Sets the current limit for the motor in mA. + * + * 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-21 + * \param limit + * The new current limit in mA + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_current_limit(uint8_t port, const int32_t limit); + +/** + * Sets one of motor_encoder_units_e_t for the motor encoder. + * + * 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-21 + * \param units + * The new motor encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_encoder_units(uint8_t port, const motor_encoder_units_e_t units); + +/** + * Sets one of motor_gearset_e_t for 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-21 + * \param gearset + * The new motor gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_gearing(uint8_t port, const motor_gearset_e_t gearset); + +/** + * Takes in floating point values and returns a properly formatted pid struct. + * The motor_pid_s_t struct is in 4.4 format, i.e. 0x20 is 2.0, 0x21 is 2.0625, + * etc. + * This function will convert the floating point values to the nearest 4.4 + * value. + * + * 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 kf + * The feedforward constant + * \param kp + * The proportional constant + * \param ki + * The integral constant + * \param kd + * The derivative constant + * + * \return A motor_pid_s_t struct formatted properly in 4.4. + */ +motor_pid_s_t motor_convert_pid(double kf, double kp, double ki, double kd); + +/** + * Takes in floating point values and returns a properly formatted pid struct. + * The motor_pid_s_t struct is in 4.4 format, i.e. 0x20 is 2.0, 0x21 is 2.0625, + * etc. + * This function will convert the floating point values to the nearest 4.4 + * value. + * + * 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 kf + * The feedforward constant + * \param kp + * The proportional constant + * \param ki + * The integral constant + * \param kd + * The derivative constant + * \param filter + * A constant used for filtering the profile acceleration + * \param limit + * The integral limit + * \param threshold + * The threshold for determining if a position movement has reached its + * goal. This has no effect for velocity PID calculations. + * \param loopspeed + * The rate at which the PID computation is run in ms + * + * \return A motor_pid_s_t struct formatted properly in 4.4. + */ +motor_pid_full_s_t motor_convert_pid_full(double kf, double kp, double ki, double kd, double filter, double limit, + double threshold, double loopspeed); + +/** + * Sets one of motor_pid_s_t for the motor. This intended to just modify the + * main PID constants. + * + * Only non-zero values of the struct will change the existing motor constants. + * + * \note This feature is in beta, it is advised to use caution when modifying + * the PID values. The motor could be damaged by particularly large constants. + * + * 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-21 + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_pos_pid(uint8_t port, const motor_pid_s_t pid); + +/** + * Sets one of motor_pid_full_s_t for the motor. + * + * Only non-zero values of the struct will change the existing motor constants. + * + * \note This feature is in beta, it is advised to use caution when modifying + * the PID values. The motor could be damaged by particularly large constants. + * + * 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-21 + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_pos_pid_full(uint8_t port, const motor_pid_full_s_t pid); + +/** + * Sets one of motor_pid_s_t for the motor. This intended to just modify the + * main PID constants. + * + * Only non-zero values of the struct will change the existing motor constants. + * + * \note This feature is in beta, it is advised to use caution when modifying + * the PID values. The motor could be damaged by particularly large constants. + * + * 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-21 + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_vel_pid(uint8_t port, const motor_pid_s_t pid); + +/** + * Sets one of motor_pid_full_s_t for the motor. + * + * Only non-zero values of the struct will change the existing motor constants. + * + * \note This feature is in beta, it is advised to use caution when modifying + * the PID values. The motor could be damaged by particularly large constants. + * + * 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-21 + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_vel_pid_full(uint8_t port, const motor_pid_full_s_t pid); + +/** + * Sets the reverse flag for the motor. + * + * This will invert its movements and the values returned for its 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 motor + * + * \param port + * The V5 port number from 1-21 + * \param reverse + * True reverses the motor, false is default + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_reversed(uint8_t port, const bool reverse); + +/** + * Sets the voltage limit for the motor in Volts. + * + * 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-21 + * \param limit + * The new voltage limit in Volts + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_voltage_limit(uint8_t port, const int32_t limit); + +/** + * Gets the brake mode that was set for 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-21 + * + * \return One of motor_brake_mode_e_t, according to what was set for the motor, + * or E_MOTOR_BRAKE_INVALID if the operation failed, setting errno. + */ +motor_brake_mode_e_t motor_get_brake_mode(uint8_t port); + +/** + * Gets the current limit for the motor in mA. + * + * The default value is 2500 mA. + * + * 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-21 + * + * \return The motor's current limit in mA or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t motor_get_current_limit(uint8_t port); + +/** + * Gets the encoder units that were set for 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-21 + * + * \return One of motor_encoder_units_e_t according to what is set for the motor + * or E_MOTOR_ENCODER_INVALID if the operation failed. + */ +motor_encoder_units_e_t motor_get_encoder_units(uint8_t port); + +/** + * Gets the gearset that was set for 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-21 + * + * \return One of motor_gearset_e_t according to what is set for the motor, + * or E_GEARSET_INVALID if the operation failed. + */ +motor_gearset_e_t motor_get_gearing(uint8_t port); + +/** + * Gets the position PID that was set for the motor. This function will return + * zero for all of the parameters if the motor_set_pos_pid() or + * motor_set_pos_pid_full() functions have not been used. + * + * 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 + * + * Additionally, in an error state all values of the returned struct are set + * to their negative maximum values. + * + * \param port + * The V5 port number from 1-21 + * + * \return A motor_pid_full_s_t containing the position PID constants last set + * to the given motor + */ +motor_pid_full_s_t motor_get_pos_pid(uint8_t port); + +/** + * Gets the velocity PID that was set for the motor. This function will return + * zero for all of the parameters if the motor_set_vel_pid() or + * motor_set_vel_pid_full() functions have not been used. + * + * 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 + * + * Additionally, in an error state all values of the returned struct are set + * to their negative maximum values. + * + * \param port + * The V5 port number from 1-21 + * + * \return A motor_pid_full_s_t containing the velocity PID constants last set + * to the given motor + */ +motor_pid_full_s_t motor_get_vel_pid(uint8_t port); + +/** + * Gets the operation direction of the motor as set by the user. + * + * 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-21 + * + * \return 1 if the motor has been reversed and 0 if the motor was not reversed, + * or PROS_ERR if the operation failed, setting errno. + */ +int32_t motor_is_reversed(uint8_t port); + +/** + * Gets the voltage limit set by the user. + * + * Default value is 0V, which means that there is no software limitation imposed + * on the voltage. + * + * 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-21 + * + * \return The motor's voltage limit in V or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t motor_get_voltage_limit(uint8_t port); + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_MOTORS_H_ diff --git a/old-code/v5_hal/firmware/include/pros/motors.hpp b/old-code/v5_hal/firmware/include/pros/motors.hpp new file mode 100644 index 00000000..adcce8ad --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/motors.hpp @@ -0,0 +1,833 @@ +/** + * \file pros/motors.hpp + * + * Contains prototypes for the V5 Motor-related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/motors.html to learn + * more. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2018, 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/. + */ + +#ifndef _PROS_MOTORS_HPP_ +#define _PROS_MOTORS_HPP_ + +#include +#include "pros/motors.h" + +namespace pros { +class Motor { + public: + /** + * Creates a Motor object for the given port and specifications. + * + * 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-21 + * \param gearset + * The motor's gearset + * \param reverse + * True reverses the motor, false is default + * \param encoder_units + * The motor's encoder units + */ + explicit Motor(const std::uint8_t port, const motor_gearset_e_t gearset, const bool reverse, + const motor_encoder_units_e_t encoder_units); + + explicit Motor(const std::uint8_t port, const motor_gearset_e_t gearset, const bool reverse); + + explicit Motor(const std::uint8_t port, const motor_gearset_e_t gearset); + + explicit Motor(const std::uint8_t port, const bool reverse); + + explicit Motor(const std::uint8_t port); + + /****************************************************************************/ + /** 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(), or motorSet from the PROS 2 API. + * + * 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; + + /** + * 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 motor_move(), or motorSet() from the PROS 2 API. + * + * 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 move(std::int32_t voltage) const; + + /** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with + * pros::Motor::set_zero_position(). + * + * \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: + * ENODEV - The port cannot be configured as a motor + * + * \param position + * The absolute position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t move_absolute(const double position, const std::int32_t velocity) const; + + /** + * Sets the relative target position for the motor to move to. + * + * 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, 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. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param position + * The relative position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t move_relative(const double position, const std::int32_t velocity) const; + + /** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the + * gearset used for the motor. This results in a range of +-100 for + * E_MOTOR_GEARSET_36, +-200 for E_MOTOR_GEARSET_18, and +-600 for + * E_MOTOR_GEARSET_6. The velocity is held with PID to ensure consistent + * speed, as opposed to setting the motor's voltage. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param velocity + * The new motor velocity from -+-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t move_velocity(const std::int32_t velocity) const; + + /** + * Sets the output voltage for the motor from -12000 to 12000 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 + * + * \param port + * The V5 port number from 1-21 + * \param voltage + * The new voltage value from -12000 to 12000 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t move_voltage(const std::int32_t voltage) const; + + /** + * Changes the output velocity for a profiled movement (motor_move_absolute() + * or motor_move_relative()). This will have no effect if the motor is not + * following a profiled movement. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param velocity + * The new motor velocity from +-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t modify_profiled_velocity(const std::int32_t velocity) const; + + /** + * Gets the target position set for 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 + * + * \return The target position in its encoder units or PROS_ERR_F if the + * operation failed, setting errno. + */ + virtual double get_target_position(void) const; + + /** + * Gets 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 + * + * \return The commanded motor velocity from +-100, +-200, or +-600, or + * PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t get_target_velocity(void) const; + + /****************************************************************************/ + /** Motor telemetry functions **/ + /** **/ + /** These functions allow programmers to collect telemetry from motors **/ + /****************************************************************************/ + + /** + * Gets the actual velocity 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 The motor's actual velocity in RPM or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double get_actual_velocity(void) const; + + /** + * Gets 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 The motor's current in mA or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t get_current_draw(void) const; + + /** + * Gets 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 1 for moving in the positive direction, -1 for moving in the + * negative direction, and PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t get_direction(void) const; + + /** + * Gets the efficiency of the motor in percent. + * + * 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 The motor's efficiency in percent or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double get_efficiency(void) const; + + /** + * Checks if the motor is drawing over its current limit. + * + * 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 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. + */ + virtual std::int32_t is_over_current(void) const; + + /** + * Checks if the motor is stopped. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \note Although this function forwards data from the motor, the motor + * presently does not provide any value. This function returns PROS_ERR with + * errno set to ENOSYS. + * + * \return 1 if the motor is not moving, 0 if the motor is moving, or PROS_ERR + * if the operation failed, setting errno + */ + virtual std::int32_t is_stopped(void) const; + + /** + * Checks if the motor is at its zero position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \note Although this function forwards data from the motor, the motor + * presently does not provide any value. This function returns PROS_ERR with + * errno set to ENOSYS. + * + * \return 1 if the motor is at zero absolute position, 0 if the motor has + * moved from its absolute zero, or PROS_ERR if the operation failed, setting + * errno + */ + virtual std::int32_t get_zero_position_flag(void) const; + + /** + * Gets 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 + * + * \param port + * The V5 port number from 1-21 + * + * \return A bitfield containing the motor's faults. + */ + virtual std::uint32_t get_faults(void) const; + + /** + * Gets 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 + * + * \param port + * The V5 port number from 1-21 + * + * \return A bitfield containing the motor's flags. + */ + virtual std::uint32_t get_flags(void) const; + + /** + * Gets 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[in] 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 The raw encoder count at the given timestamp or PROS_ERR if the + * operation failed. + */ + virtual std::int32_t get_raw_position(std::uint32_t* const timestamp) 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 + * + * \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. + */ + virtual std::int32_t is_over_temp(void) const; + + /** + * Gets 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 The motor's absolute position in its encoder units or PROS_ERR_F + * if the operation failed, setting errno. + */ + virtual double get_position(void) const; + + /** + * Gets 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 The motor's power draw in Watts or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double get_power(void) const; + + /** + * Gets the temperature of the motor in degrees Celsius. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return The motor's temperature in degrees Celsius or PROS_ERR_F if the + * operation failed, setting errno. + */ + virtual double get_temperature(void) const; + + /** + * Gets the torque generated by the motor in Newton Meters (Nm). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return The motor's torque in Nm or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual double get_torque(void) const; + + /** + * Gets 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 The motor's voltage in mV or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual std::int32_t get_voltage(void) const; + + /****************************************************************************/ + /** Motor configuration functions **/ + /** **/ + /** These functions allow programmers to configure the behavior of motors **/ + /****************************************************************************/ + + /** + * Sets the position for the motor in its encoder units. + * + * This will be the future reference point for the motor's "absolute" + * position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param position + * The new reference position in its encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_zero_position(const double position) const; + + /** + * Sets the "absolute" zero position of the motor to its current position. + * + * 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. + */ + virtual std::int32_t tare_position(void) const; + + /** + * Sets one of motor_brake_mode_e_t to 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 mode + * The motor_brake_mode_e_t to set for the motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_brake_mode(const motor_brake_mode_e_t mode) const; + + /** + * Sets the current limit for 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 + * + * \param limit + * The new current limit in mA + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_current_limit(const std::int32_t limit) const; + + /** + * Sets one of motor_encoder_units_e_t for the motor encoder. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param units + * The new motor encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_encoder_units(const motor_encoder_units_e_t units) const; + + /** + * Sets one of motor_gearset_e_t 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 + * + * \param gearset + * The new motor gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_gearing(const motor_gearset_e_t gearset) const; + + /** + * Takes in floating point values and returns a properly formatted pid struct. + * The motor_pid_s_t struct is in 4.4 format, i.e. 0x20 is 2.0, 0x21 is + * 2.0625, etc. + * This function will convert the floating point values to the nearest 4.4 + * value. + * + * \param kf + * The feedforward constant + * \param kp + * The proportional constant + * \param ki + * The integral constant + * \param kd + * The derivative constant + * + * \return A motor_pid_s_t struct formatted properly in 4.4. + */ + static motor_pid_s_t convert_pid(double kf, double kp, double ki, double kd); + + /** + * Takes in floating point values and returns a properly formatted pid struct. + * The motor_pid_s_t struct is in 4.4 format, i.e. 0x20 is 2.0, 0x21 is + * 2.0625, etc. + * This function will convert the floating point values to the nearest 4.4 + * value. + * + * \param kf + * The feedforward constant + * \param kp + * The proportional constant + * \param ki + * The integral constant + * \param kd + * The derivative constant + * \param filter + * A constant used for filtering the profile acceleration + * \param limit + * The integral limit + * \param threshold + * The threshold for determining if a position movement has reached its + * goal. This has no effect for velocity PID calculations. + * \param loopspeed + * The rate at which the PID computation is run in ms + * + * \return A motor_pid_s_t struct formatted properly in 4.4. + */ + static motor_pid_full_s_t convert_pid_full(double kf, double kp, double ki, double kd, double filter, double limit, + double threshold, double loopspeed); + + /** + * Sets one of motor_pid_s_t for the motor. This intended to just modify the + * main PID constants. + * + * Only non-zero values of the struct will change the existing motor + * constants. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_pos_pid(const motor_pid_s_t pid) const; + + /** + * Sets one of motor_pid_full_s_t for the motor. + * + * Only non-zero values of the struct will change the existing motor + * constants. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_pos_pid_full(const motor_pid_full_s_t pid) const; + + /** + * Sets one of motor_pid_s_t for the motor. This intended to just modify the + * main PID constants. + * + * Only non-zero values of the struct will change the existing motor + * constants. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_vel_pid(const motor_pid_s_t pid) const; + + /** + * Sets one of motor_pid_full_s_t for the motor. + * + * Only non-zero values of the struct will change the existing motor + * constants. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_vel_pid_full(const motor_pid_full_s_t pid) const; + + /** + * Sets the reverse flag for the motor. + * + * This will invert its movements and the values returned for its position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param reverse + * True reverses the motor, false is default + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_reversed(const bool reverse) const; + + /** + * Sets the voltage limit for the motor in Volts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param limit + * The new voltage limit in Volts + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_voltage_limit(const std::int32_t limit) const; + + /** + * Gets the brake mode that was set 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 One of motor_brake_mode_e_t, according to what was set for the + * motor, or E_MOTOR_BRAKE_INVALID if the operation failed, setting errno. + */ + virtual motor_brake_mode_e_t get_brake_mode(void) const; + + /** + * Gets the current limit for the motor in mA. + * + * The default value is 2500 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 The motor's current limit in mA or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t get_current_limit(void) const; + + /** + * Gets the encoder units that were set 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 One of motor_encoder_units_e_t according to what is set for the + * motor or E_MOTOR_ENCODER_INVALID if the operation failed. + */ + virtual motor_encoder_units_e_t get_encoder_units(void) const; + + /** + * Gets the gearset that was set 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 One of motor_gearset_e_t according to what is set for the motor, + * or E_GEARSET_INVALID if the operation failed. + */ + virtual motor_gearset_e_t get_gearing(void) const; + + /** + * Gets the position PID that was set for the motor. This function will return + * zero for all of the parameters if the motor_set_pos_pid() or + * motor_set_pos_pid_full() functions have not been used. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * Additionally, in an error state all values of the returned struct are set + * to their negative maximum values. + * + * \return A motor_pid_full_s_t containing the position PID constants last set + * to the given motor + */ + virtual motor_pid_full_s_t get_pos_pid(void) const; + + /** + * Gets the velocity PID that was set for the motor. This function will return + * zero for all of the parameters if the motor_set_vel_pid() or + * motor_set_vel_pid_full() functions have not been used. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * Additionally, in an error state all values of the returned struct are set + * to their negative maximum values. + * + * \return A motor_pid_full_s_t containing the velocity PID constants last set + * to the given motor + */ + virtual motor_pid_full_s_t get_vel_pid(void) const; + + /** + * Gets the operation direction of the motor as set 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 + * + * \return 1 if the motor has been reversed and 0 if the motor was not + * reversed, or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t is_reversed(void) const; + + /** + * Gets the voltage limit set by the user. + * + * Default value is 0V, which means that there is no software limitation + * imposed on the voltage. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return The motor's voltage limit in V or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t get_voltage_limit(void) const; + + /** + * Gets the port number of the motor. + * + * \return The motor's port number. + */ + virtual std::uint8_t get_port(void) const; + + private: + const std::uint8_t _port; +}; + +namespace literals { +const pros::Motor operator"" _mtr(const unsigned long long int m); +const pros::Motor operator"" _rmtr(const unsigned long long int m); +} // namespace literals +} // namespace pros +#endif // _PROS_MOTORS_HPP_ diff --git a/old-code/v5_hal/firmware/include/pros/optical.h b/old-code/v5_hal/firmware/include/pros/optical.h new file mode 100644 index 00000000..18bacff7 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/optical.h @@ -0,0 +1,267 @@ +/** + * \file pros/optical.h + * + * Contains prototypes for functions related to the VEX Optical sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/imu.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_OPTICAL_H_ +#define _PROS_OPTICAL_H_ + +#include +#include +#include "api.h" + +#define OPT_GESTURE_ERR (INT8_MAX) +#define OPT_COUNT_ERR (INT16_MAX) +#define OPT_TIME_ERR PROS_ERR + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + + +typedef enum optical_direction_e { NO_GESTURE = 0, UP = 1, DOWN = 2, RIGHT = 3, LEFT = 4, ERROR = PROS_ERR } optical_direction_e_t; + +typedef struct optical_rgb_s { + double red; + double green; + double blue; + double brightness; +} optical_rgb_s_t; + +typedef struct optical_raw_s { + uint32_t clear; + uint32_t red; + uint32_t green; + uint32_t blue; +} optical_raw_s_t; + +typedef struct optical_gesture_s { + uint8_t udata; + uint8_t ddata; + uint8_t ldata; + uint8_t rdata; + uint8_t type; + uint8_t pad; + uint16_t count; + uint32_t time; +} optical_gesture_s_t; + +/** + * Get the detected color hue + * + * This is not available if gestures are being detected. Hue has a + * range of 0 to 359.999 + * + * 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 hue value if the operation was successful or PROS_ERR_F if the operation + * failed, setting errno. + */ +double optical_get_hue(uint8_t port); + +/** + * Get the detected color saturation + * + * This is not available if gestures are being detected. Saturation has a + * range of 0 to 1.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 an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return saturation value if the operation was successful or PROS_ERR_F if + * the operation failed, setting errno. + */ +double optical_get_saturation(uint8_t port); + +/** + * Get the detected color brightness + * + * This is not available if gestures are being detected. Brightness has a + * range of 0 to 1.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 an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return brightness value if the operation was successful or PROS_ERR_F if + * the operation failed, setting errno. + */ +double optical_get_brightness(uint8_t port); + +/** + * Get the detected proximity value + * + * This is not available if gestures are being detected. proximity has + * a range of 0 to 255. + * + * 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 poximity value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + */ +int32_t optical_get_proximity(uint8_t port); + +/** + * Set the pwm value of the White LED + * + * value that ranges from 0 to 100 + * + * 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 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t optical_set_led_pwm(uint8_t port, uint8_t value); + +/** + * Get the pwm value of the White LED + * + * + * 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 LED pwm value that ranges from 0 to 100 if the operation was + * successful or PROS_ERR if the operation failed, setting errno. + */ +int32_t optical_get_led_pwm(uint8_t port); + +/** + * Get the processed RGBC data from the 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 an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \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. + */ +optical_rgb_s_t optical_get_rgb(uint8_t port); + +/** + * Get the raw, unprocessed RGBC data from the 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 an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \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. + */ +optical_raw_s_t optical_get_raw(uint8_t port); + +/** + * Get the most recent gesture data from the sensor + * + * Gestures will be cleared after 500mS + * + * 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 gesture value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + */ +optical_direction_e_t optical_get_gesture(uint8_t port); + +/** + * Get the most recent raw gesture data from the 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 an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \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. + */ +optical_gesture_s_t optical_get_gesture_raw(uint8_t port); + +/** + * Enable gesture detection on the 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 an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t optical_enable_gesture(uint8_t port); + +/** + * Disable gesture detection on the 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 an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t optical_disable_gesture(uint8_t port); + +#ifdef __cplusplus +} +} +} +#endif + +#endif diff --git a/old-code/v5_hal/firmware/include/pros/optical.hpp b/old-code/v5_hal/firmware/include/pros/optical.hpp new file mode 100644 index 00000000..4b3c39da --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/optical.hpp @@ -0,0 +1,234 @@ +/** + * \file pros/optical.hpp + * + * Contains prototypes for functions related to the VEX Optical sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/imu.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_OPTICAL_HPP_ +#define _PROS_OPTICAL_HPP_ + +#include + +#include + +#include "pros/optical.h" + +namespace pros { +class Optical { + public: + /** + * Creates an Optical Sensor 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). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \param port + * The V5 port number from 1-21 + */ + explicit Optical(const std::uint8_t port); + + /** + * Get the detected color hue + * + * This is not available if gestures are being detected. Hue has a + * range of 0 to 359.999 + * + * 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 hue value if the operation was successful or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double get_hue(); + + /** + * Get the detected color saturation + * + * This is not available if gestures are being detected. Saturation has a + * range of 0 to 1.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 an Optical Sensor + * + * \return saturation value if the operation was successful or PROS_ERR_F if + * the operation failed, setting errno. + */ + virtual double get_saturation(); + + /** + * Get the detected color brightness + * + * This is not available if gestures are being detected. Brightness has a + * range of 0 to 1.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 an Optical Sensor + * + * \return brightness value if the operation was successful or PROS_ERR_F if + * the operation failed, setting errno. + */ + virtual double get_brightness(); + + /** + * Get the detected proximity value + * + * This is not available if gestures are being detected. proximity has + * a range of 0 to 255. + * + * 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 poximity value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + */ + virtual std::int32_t get_proximity(); + + /** + * Set the pwm value of the White LED on the sensor + * + * value that ranges from 0 to 100 + * + * 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 The Error code encountered + */ + virtual std::int32_t set_led_pwm(uint8_t value); + + /** + * Get the pwm value of the White LED on the sensor + * + * value that ranges from 0 to 100 + * + * 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 LED pwm value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + */ + virtual std::int32_t get_led_pwm(); + + /** + * Get the processed RGBC data from the 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 an Optical Sensor + * + * \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. + */ + virtual pros::c::optical_rgb_s_t get_rgb(); + + /** + * Get the raw un-processed RGBC data from the 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 an Optical Sensor + * + * \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. + */ + virtual pros::c::optical_raw_s_t get_raw(); + + /** + * 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 + * 4 = left + * + * 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 gesture value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + */ + virtual pros::c::optical_direction_e_t get_gesture(); + + /** + * Get the most recent raw gesture data from the 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 an Optical Sensor + * + * \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. + */ + virtual pros::c::optical_gesture_s_t get_gesture_raw(); + + /** + * Enable gesture detection on the 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 an Optical Sensor + * + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t enable_gesture(); + + /** + * Disable gesture detection on the 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 an Optical Sensor + * + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t disable_gesture(); + + /** + * Gets the port number of the Optical Sensor. + * + * \return The Optical Sensor's port number. + */ + virtual std::uint8_t get_port(); + + private: + const std::uint8_t _port; +}; +} // namespace pros + +#endif diff --git a/old-code/v5_hal/firmware/include/pros/rotation.h b/old-code/v5_hal/firmware/include/pros/rotation.h new file mode 100644 index 00000000..28c8e558 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/rotation.h @@ -0,0 +1,183 @@ +/** + * \file pros/rotation.h + * + * Contains prototypes for functions related to the VEX Rotation Sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/rotation.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_ROTATION_H_ +#define _PROS_ROTATION_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/** + * Reset Rotation Sensor + * + * Reset the current absolute position to be the same as the + * Rotation Sensor angle. + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t rotation_reset(uint8_t port); + +/** + * Set the Rotation Sensor position reading to a desired rotation value + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \param position + * The position in terms of ticks + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t rotation_set_position(uint8_t port, uint32_t position); + +/** + * Reset the Rotation Sensor position to 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 an Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t rotation_reset_position(uint8_t port); + +/** + * Get the Rotation Sensor's current position in centidegrees + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \return The position value or PROS_ERR_F if the operation failed, setting + * errno. + */ +int32_t rotation_get_position(uint8_t port); + +/** + * Get the Rotation Sensor's current velocity in centidegrees per second + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \return The velocity value or PROS_ERR_F if the operation failed, setting + * errno. + */ +int32_t rotation_get_velocity(uint8_t port); + +/** + * Get the Rotation Sensor's current position in centidegrees + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \return The angle value or PROS_ERR_F if the operation failed, setting + * errno. + */ +int32_t rotation_get_angle(uint8_t port); + +/** + * Set the Rotation Sensor's direction reversed flag + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \param value + * Determines if the direction of the Rotation Sensor is reversed or not. + * + * \return 1 if operation succeeded or PROS_ERR if the operation failed, setting + * errno. + */ +int32_t rotation_set_reversed(uint8_t port, bool value); + +/** + * Reverse the Rotation Sensor's direction + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t rotation_reverse(uint8_t port); + +/** + * Get the Rotation Sensor's reversed flag + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * + * \return Boolean value of if the Rotation Sensor's direction is reversed or not + * or PROS_ERR if the operation failed, setting errno. + */ +int32_t rotation_get_reversed(uint8_t port); + +#ifdef __cplusplus +} //namespace C +} //namespace pros +} //extern "C" +#endif + +#endif diff --git a/old-code/v5_hal/firmware/include/pros/rotation.hpp b/old-code/v5_hal/firmware/include/pros/rotation.hpp new file mode 100644 index 00000000..58595f59 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/rotation.hpp @@ -0,0 +1,165 @@ +/** + * \file pros/rotation.hpp + * + * Contains prototypes for functions related to the VEX Rotation Sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/rotation.html to learn + * more. + * + * 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. + * + * 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/. + */ +#ifndef _PROS_ROTATION_HPP_ +#define _PROS_ROTATION_HPP_ + +#include + +#include "pros/rotation.h" + +namespace pros { +class Rotation { + const std::uint8_t _port; + + public: + Rotation(const std::uint8_t port) : _port(port){}; + + /** + * Reset the Rotation Sensor + * + * Reset the current absolute position to be the same as the + * Rotation Sensor angle. + * + * 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 Rotation Sensor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t reset(); + + /** + * Set the Rotation Sensor position reading to a desired rotation value + * + * 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 Rotation Sensor + * + * \param position + * The position in terms of ticks + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_position(std::uint32_t position); + + /** + * Reset the Rotation Sensor to a desired rotation value + * + * 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 Rotation Sensor + * + * \param position + * The position in terms of ticks + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t reset_position(void); + + /** + * Get the Rotation Sensor's current position in centidegrees + * + * 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 Rotation Sensor + * + * \return The position value or PROS_ERR if the operation failed, setting + * errno. + */ + virtual std::int32_t get_position(); + + /** + * Get the Rotation Sensor's current velocity in centidegrees per second + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \return The + value or PROS_ERR_F if the operation failed, setting + * errno. + */ + virtual std::int32_t get_velocity(); + + /** + * Get the Rotation Sensor's current position in centidegrees + * + * 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 Rotation Sensor + * + * \return The angle value or PROS_ERR if the operation failed, setting + * errno. + */ + virtual std::int32_t get_angle(); + + /** + * Set the Rotation Sensor's direction reversed flag + * + * 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 Rotation Sensor + * + * \param value + * Determines if the direction of the rotational sensor is + * reversed or not. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_reversed(bool value); + + /** + * Reverse the Rotation Sensor's direction. + * + * 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 Rotation Sensor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t reverse(); + + /** + * Get the Rotation Sensor's reversed flag + * + * 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 Rotation Sensor + * + * \return Reversed value or PROS_ERR if the operation failed, setting + * errno. + */ + virtual std::int32_t get_reversed(); +}; +} // namespace pros + +#endif diff --git a/old-code/v5_hal/firmware/include/pros/rtos.h b/old-code/v5_hal/firmware/include/pros/rtos.h new file mode 100644 index 00000000..23cfc7c2 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/rtos.h @@ -0,0 +1,420 @@ +/** + * \file pros/rtos.h + * + * Contains declarations for the PROS RTOS kernel for use by typical VEX + * programmers. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html to + * learn more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_RTOS_H_ +#define _PROS_RTOS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +// The highest priority that can be assigned to a task. Beware of deadlock. +#define TASK_PRIORITY_MAX 16 + +// The lowest priority that can be assigned to a task. +// This may cause severe performance problems and is generally not recommended. +#define TASK_PRIORITY_MIN 1 + +// The default task priority, which should be used for most tasks. +// Default tasks such as autonomous() inherit this priority. +#define TASK_PRIORITY_DEFAULT 8 + +// The recommended stack size for a new task. This stack size is used for +// default tasks such as autonomous(). This equates to 32,768 bytes, or 128 +// times the default stack size for a task in PROS 2. +#define TASK_STACK_DEPTH_DEFAULT 0x2000 + +// The minimal stack size for a task. This equates to 2048 bytes, or 8 times the +// default stack size for a task in PROS 2. +#define TASK_STACK_DEPTH_MIN 0x200 + +// The maximum number of characters allowed in a task's name. +#define TASK_NAME_MAX_LEN 32 + +// The maximum timeout value that can be given to, for instance, a mutex grab. +#define TIMEOUT_MAX ((uint32_t)0xffffffffUL) + +typedef void* task_t; +typedef void (*task_fn_t)(void*); + +typedef enum { + E_TASK_STATE_RUNNING = 0, + E_TASK_STATE_READY, + E_TASK_STATE_BLOCKED, + E_TASK_STATE_SUSPENDED, + E_TASK_STATE_DELETED, + E_TASK_STATE_INVALID +} task_state_e_t; + +typedef enum { + E_NOTIFY_ACTION_NONE, + E_NOTIFY_ACTION_BITS, + E_NOTIFY_ACTION_INCR, + E_NOTIFY_ACTION_OWRITE, + E_NOTIFY_ACTION_NO_OWRITE +} notify_action_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define TASK_STATE_RUNNING pros::E_TASK_STATE_RUNNING +#define TASK_STATE_READY pros::E_TASK_STATE_READY +#define TASK_STATE_BLOCKED pros::E_TASK_STATE_BLOCKED +#define TASK_STATE_SUSPENDED pros::E_TASK_STATE_SUSPENDED +#define TASK_STATE_DELETED pros::E_TASK_STATE_DELETED +#define TASK_STATE_INVALID pros::E_TASK_STATE_INVALID +#define NOTIFY_ACTION_NONE pros::E_NOTIFY_ACTION_NONE +#define NOTIFY_ACTION_BITS pros::E_NOTIFY_ACTION_BITS +#define NOTIFY_ACTION_INCR pros::E_NOTIFY_ACTION_INCR +#define NOTIFY_ACTION_OWRITE pros::E_NOTIFY_ACTION_OWRITE +#define NOTIFY_ACTION_NO_OWRITE pros::E_NOTIFY_ACTION_NO_OWRITE +#else +#define TASK_STATE_RUNNING E_TASK_STATE_RUNNING +#define TASK_STATE_READY E_TASK_STATE_READY +#define TASK_STATE_BLOCKED E_TASK_STATE_BLOCKED +#define TASK_STATE_SUSPENDED E_TASK_STATE_SUSPENDED +#define TASK_STATE_DELETED E_TASK_STATE_DELETED +#define TASK_STATE_INVALID E_TASK_STATE_INVALID +#define NOTIFY_ACTION_NONE E_NOTIFY_ACTION_NONE +#define NOTIFY_ACTION_BITS E_NOTIFY_ACTION_BITS +#define NOTIFY_ACTION_INCR E_NOTIFY_ACTION_INCR +#define NOTIFY_ACTION_OWRITE E_NOTIFY_ACTION_OWRITE +#define NOTIFY_ACTION_NO_OWRITE E_NOTIFY_ACTION_NO_OWRITE +#endif +#endif + +typedef void* mutex_t; + +/** + * Refers to the current task handle + */ +#ifdef __cplusplus +#define CURRENT_TASK ((pros::task_t)NULL) +#else +#define CURRENT_TASK ((task_t)NULL) +#endif + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Gets the number of milliseconds since PROS initialized. + * + * \return The number of milliseconds since PROS initialized + */ +uint32_t millis(void); + +/** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Pointer to the task entry function + * \param parameters + * Pointer to memory that will be used as a parameter for the task being + * created. This memory should not typically come from stack, but rather + * from dynamically (i.e., malloc'd) or statically allocated memory. + * \param prio + * The priority at which the task should run. + * TASK_PRIO_DEFAULT plus/minus 1 or 2 is typically used. + * \param stack_depth + * The number of words (i.e. 4 * stack_depth) available on the task's + * stack. TASK_STACK_DEPTH_DEFAULT is typically sufficienct. + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + * \return A handle by which the newly created task can be referenced. If an + * error occurred, NULL will be returned and errno can be checked for hints as + * to why task_create failed. + */ +task_t task_create(task_fn_t function, void* const parameters, uint32_t prio, const uint16_t stack_depth, + const char* const name); + +/** + * Removes a task from the RTOS real time kernel's management. The task being + * deleted will be removed from all ready, blocked, suspended and event lists. + * + * Memory dynamically allocated by the task is not automatically freed, and + * should be freed before the task is deleted. + * + * \param task + * The handle of the task to be deleted. Passing NULL will cause the + * calling task to be deleted. + */ +void task_delete(task_t task); + +/** + * Delays a task for a given number of milliseconds. + * + * This is not the best method to have a task execute code at predefined + * intervals, as the delay time is measured from when the delay is requested. + * To delay cyclically, use task_delay_until(). + * + * \param milliseconds + * The number of milliseconds to wait (1000 milliseconds per second) + */ +void task_delay(const uint32_t milliseconds); + +void delay(const uint32_t milliseconds); + +/** + * Delays a task until a specified time. This function can be used by periodic + * tasks to ensure a constant execution frequency. + * + * The task will be woken up at the time *prev_time + delta, and *prev_time will + * be updated to reflect the time at which the task will unblock. + * + * \param prev_time + * A pointer to the location storing the setpoint time. This should + * typically be initialized to the return value of millis(). + * \param delta + * The number of milliseconds to wait (1000 milliseconds per second) + */ +void task_delay_until(uint32_t* const prev_time, const uint32_t delta); + +/** + * Gets the priority of the specified task. + * + * \param task + * The task to check + * + * \return The priority of the task + */ +uint32_t task_get_priority(task_t task); + +/** + * Sets the priority of the specified task. + * + * If the specified task's state is available to be scheduled (e.g. not blocked) + * and new priority is higher than the currently running task, a context switch + * may occur. + * + * \param task + * The task to set + * \param prio + * The new priority of the task + */ +void task_set_priority(task_t task, uint32_t prio); + +/** + * Gets the state of the specified task. + * + * \param task + * The task to check + * + * \return The state of the task + */ +task_state_e_t task_get_state(task_t task); + +/** + * Suspends the specified task, making it ineligible to be scheduled. + * + * \param task + * The task to suspend + */ +void task_suspend(task_t task); + +/** + * Resumes the specified task, making it eligible to be scheduled. + * + * \param task + * The task to resume + */ +void task_resume(task_t task); + +/** + * Gets the number of tasks the kernel is currently managing, including all + * ready, blocked, or suspended tasks. A task that has been deleted, but not yet + * reaped by the idle task will also be included in the count. Tasks recently + * created may take one context switch to be counted. + * + * \return The number of tasks that are currently being managed by the kernel. + */ +uint32_t task_get_count(void); + +/** + * Gets the name of the specified task. + * + * \param task + * The task to check + * + * \return A pointer to the name of the task + */ +char* task_get_name(task_t task); + +/** + * Gets a task handle from the specified name + * + * The operation takes a relatively long time and should be used sparingly. + * + * \param name + * The name to query + * + * \return A task handle with a matching name, or NULL if none were found. + */ +task_t task_get_by_name(const char* name); + +/** + * Get the currently running task handle. This could be useful if a task + * wants to tell another task about itself. + * + * \return The currently running task handle. + */ +task_t task_get_current(); + +/** + * Sends a simple notification to task and increments the notification counter. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param task + * The task to notify + * + * \return Always returns true. + */ +uint32_t task_notify(task_t task); + +/** + * Sends a notification to a task, optionally performing some action. Will also + * retrieve the value of the notification in the target task before modifying + * the notification value. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param task + * The task to notify + * \param value + * The value used in performing the action + * \param action + * An action to optionally perform on the receiving task's notification + * value + * \param prev_value + * A pointer to store the previous value of the target task's + * notification, may be NULL + * + * \return Dependent on the notification action. + * For NOTIFY_ACTION_NO_WRITE: return 0 if the value could be written without + * needing to overwrite, 1 otherwise. + * For all other NOTIFY_ACTION values: always return 0 + */ +uint32_t task_notify_ext(task_t task, uint32_t value, notify_action_e_t action, uint32_t* prev_value); + +/** + * Waits for a notification to be nonzero. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param clear_on_exit + * If true (1), then the notification value is cleared. + * If false (0), then the notification value is decremented. + * \param timeout + * Specifies the amount of time to be spent waiting for a notification + * to occur. + * + * \return The value of the task's notification value before it is decremented + * or cleared + */ +uint32_t task_notify_take(bool clear_on_exit, uint32_t timeout); + +/** + * Clears the notification for a task. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param task + * The task to clear + * + * \return False if there was not a notification waiting, true if there was + */ +bool task_notify_clear(task_t task); + +/** + * Creates a mutex. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes + * for details. + * + * \return A handle to a newly created mutex. If an error occurred, NULL will be + * returned and errno can be checked for hints as to why mutex_create failed. + */ +mutex_t mutex_create(void); + +/** + * 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 mutex + * Mutex to attempt to lock. + * \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. + */ +bool mutex_take(mutex_t mutex, uint32_t timeout); + +/** + * Unlocks a mutex. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes + * for details. + * + * \param mutex + * Mutex to unlock. + * + * \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. + */ +bool mutex_give(mutex_t mutex); + +/** + * Deletes a mutex + * + * \param mutex + * Mutex to unlock. + */ +void mutex_delete(mutex_t mutex); + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_RTOS_H_ diff --git a/old-code/v5_hal/firmware/include/pros/rtos.hpp b/old-code/v5_hal/firmware/include/pros/rtos.hpp new file mode 100644 index 00000000..c44f322a --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/rtos.hpp @@ -0,0 +1,383 @@ +/** + * \file pros/rtos.hpp + * + * Contains declarations for the PROS RTOS kernel for use by typical VEX + * programmers. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html to + * learn more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_RTOS_HPP_ +#define _PROS_RTOS_HPP_ + +#include "pros/rtos.h" +#undef delay +#include +#include +#include +#include +#include + +namespace pros { +class Task { + public: + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Pointer to the task entry function + * \param parameters + * Pointer to memory that will be used as a parameter for the task + * being created. This memory should not typically come from stack, + * but rather from dynamically (i.e., malloc'd) or statically + * allocated memory. + * \param prio + * The priority at which the task should run. + * TASK_PRIO_DEFAULT plus/minus 1 or 2 is typically used. + * \param stack_depth + * The number of words (i.e. 4 * stack_depth) available on the task's + * stack. TASK_STACK_DEPTH_DEFAULT is typically sufficienct. + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + */ + Task(task_fn_t function, void* parameters = NULL, std::uint32_t prio = TASK_PRIORITY_DEFAULT, + std::uint16_t stack_depth = TASK_STACK_DEPTH_DEFAULT, const char* name = ""); + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Pointer to the task entry function + * \param parameters + * Pointer to memory that will be used as a parameter for the task + * being created. This memory should not typically come from stack, + * but rather from dynamically (i.e., malloc'd) or statically + * allocated memory. + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + */ + Task(task_fn_t function, void* parameters, const char* name); + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Callable object to use as entry function + * \param prio + * The priority at which the task should run. + * TASK_PRIO_DEFAULT plus/minus 1 or 2 is typically used. + * \param stack_depth + * The number of words (i.e. 4 * stack_depth) available on the task's + * stack. TASK_STACK_DEPTH_DEFAULT is typically sufficienct. + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + */ + template + Task(F&& function, std::uint32_t prio = TASK_PRIORITY_DEFAULT, std::uint16_t stack_depth = TASK_STACK_DEPTH_DEFAULT, + const char* name = "") + : Task( + [](void* parameters) { + std::unique_ptr> ptr{static_cast*>(parameters)}; + (*ptr)(); + }, + new std::function(std::forward(function)), prio, stack_depth, name) { + static_assert(std::is_invocable_r_v); + } + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Callable object to use as entry function + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + */ + template + Task(F&& function, const char* name) + : Task(std::forward(function), TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, name) {} + + /** + * Create a C++ task object from a task handle + * + * \param task + * A task handle from task_create() for which to create a pros::Task + * object. + */ + Task(task_t task); + + /** + * Get the currently running Task + */ + static Task current(); + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * \param in + * A task handle from task_create() for which to create a pros::Task + * object. + */ + Task& operator=(task_t in); + + /** + * Removes the Task from the RTOS real time kernel's management. This task + * will be removed from all ready, blocked, suspended and event lists. + * + * Memory dynamically allocated by the task is not automatically freed, and + * should be freed before the task is deleted. + */ + void remove(); + + /** + * Gets the priority of the specified task. + * + * \return The priority of the task + */ + std::uint32_t get_priority(void); + + /** + * Sets the priority of the specified task. + * + * If the specified task's state is available to be scheduled (e.g. not + * blocked) and new priority is higher than the currently running task, + * a context switch may occur. + * + * \param prio + * The new priority of the task + */ + void set_priority(std::uint32_t prio); + + /** + * Gets the state of the specified task. + * + * \return The state of the task + */ + std::uint32_t get_state(void); + + /** + * Suspends the specified task, making it ineligible to be scheduled. + */ + void suspend(void); + + /** + * Resumes the specified task, making it eligible to be scheduled. + * + * \param task + * The task to resume + */ + void resume(void); + + /** + * Gets the name of the specified task. + * + * \return A pointer to the name of the task + */ + const char* get_name(void); + + /** + * Convert this object to a C task_t handle + */ + operator task_t() { + return task; + } + + /** + * Sends a simple notification to task and increments the notification + * counter. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \return Always returns true. + */ + std::uint32_t notify(void); + + /** + * Sends a notification to a task, optionally performing some action. Will + * also retrieve the value of the notification in the target task before + * modifying the notification value. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param value + * The value used in performing the action + * \param action + * An action to optionally perform on the receiving task's notification + * value + * \param prev_value + * A pointer to store the previous value of the target task's + * notification, may be NULL + * + * \return Dependent on the notification action. + * For NOTIFY_ACTION_NO_WRITE: return 0 if the value could be written without + * needing to overwrite, 1 otherwise. + * For all other NOTIFY_ACTION values: always return 0 + */ + std::uint32_t notify_ext(std::uint32_t value, notify_action_e_t action, std::uint32_t* prev_value); + + /** + * Waits for a notification to be nonzero. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param clear_on_exit + * If true (1), then the notification value is cleared. + * If false (0), then the notification value is decremented. + * \param timeout + * Specifies the amount of time to be spent waiting for a notification + * to occur. + * + * \return The value of the task's notification value before it is decremented + * or cleared + */ + static std::uint32_t notify_take(bool clear_on_exit, std::uint32_t timeout); + + /** + * Clears the notification for a task. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \return False if there was not a notification waiting, true if there was + */ + bool notify_clear(void); + + /** + * Delays a task for a given number of milliseconds. + * + * This is not the best method to have a task execute code at predefined + * intervals, as the delay time is measured from when the delay is requested. + * To delay cyclically, use task_delay_until(). + * + * \param milliseconds + * The number of milliseconds to wait (1000 milliseconds per second) + */ + static void delay(const std::uint32_t milliseconds); + + /** + * Delays a task until a specified time. This function can be used by + * periodic tasks to ensure a constant execution frequency. + * + * The task will be woken up at the time *prev_time + delta, and *prev_time + * will be updated to reflect the time at which the task will unblock. + * + * \param prev_time + * A pointer to the location storing the setpoint time. This should + * typically be initialized to the return value from pros::millis(). + * \param delta + * The number of milliseconds to wait (1000 milliseconds per second) + */ + static void delay_until(std::uint32_t* const prev_time, const std::uint32_t delta); + + /** + * Gets the number of tasks the kernel is currently managing, including all + * ready, blocked, or suspended tasks. A task that has been deleted, but not + * yet reaped by the idle task will also be included in the count. + * Tasks recently created may take one context switch to be counted. + * + * \return The number of tasks that are currently being managed by the kernel. + */ + static std::uint32_t get_count(void); + + private: + task_t task; +}; + +class Mutex { + public: + Mutex(void); + + /** + * 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. + */ + 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. + */ + bool give(void); + + private: + std::shared_ptr> mutex; +}; + +/** + * Gets the number of milliseconds since PROS initialized. + * + * \return The number of milliseconds since PROS initialized + */ +using pros::c::millis; + +/** + * Delays a task for a given number of milliseconds. + * + * This is not the best method to have a task execute code at predefined + * intervals, as the delay time is measured from when the delay is requested. + * To delay cyclically, use task_delay_until(). + * + * \param milliseconds + * The number of milliseconds to wait (1000 milliseconds per second) + */ +using pros::c::delay; +} // namespace pros + +#endif // _PROS_RTOS_HPP_s diff --git a/old-code/v5_hal/firmware/include/pros/serial.h b/old-code/v5_hal/firmware/include/pros/serial.h new file mode 100644 index 00000000..81de139f --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/serial.h @@ -0,0 +1,247 @@ +/** + * \file pros/serial.h + * + * Contains prototypes for the V5 Generic Serial related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/serial.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_SERIAL_H_ +#define _PROS_SERIAL_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/******************************************************************************/ +/** Serial communication functions **/ +/** **/ +/** These functions allow programmers to communicate using UART over RS485 **/ +/******************************************************************************/ + +/** + * Enables generic serial on the given port. + * + * \note This function must be called before any of the generic serial + * functions will work. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t serial_enable(uint8_t port); + +/** + * Sets the baudrate for the serial port to operate at. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * \param baudrate + * The baudrate to operate at + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t serial_set_baudrate(uint8_t port, int32_t baudrate); + +/** + * Clears the internal input and output FIFO buffers. + * + * This can be useful to reset state and remove old, potentially unneeded data + * from the input FIFO buffer or to cancel sending any data in the output FIFO + * buffer. + * + * \note This function does not cause the data in the output buffer to be + * written, it simply clears the internal buffers. Unlike stdout, generic + * serial does not use buffered IO (the FIFO buffers are written as soon + * as possible). + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t serial_flush(uint8_t port); + +/** + * Returns the number of bytes available to be read in the the port's FIFO + * input buffer. + * + * \note This function does not actually read any bytes, is simply returns the + * number of bytes available to be read. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return The number of bytes avaliable to be read or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t serial_get_read_avail(uint8_t port); + +/** + * Returns the number of bytes free in the port's FIFO output buffer. + * + * \note This function does not actually write any bytes, is simply returns the + * number of bytes free in the port's buffer. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return The number of bytes free or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t serial_get_write_free(uint8_t port); + +/** + * Reads the next byte avaliable in the port's input buffer without removing it. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return The next byte avaliable to be read, -1 if none are available, or + * PROS_ERR if the operation failed, setting errno. + */ +int32_t serial_peek_byte(uint8_t port); + +/** + * Reads the next byte avaliable in the port's input buffer. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return The next byte avaliable to be read, -1 if none are available, or + * PROS_ERR if the operation failed, setting errno. + */ +int32_t serial_read_byte(uint8_t port); + +/** + * Reads up to the next length bytes from the port's input buffer and places + * them in the user supplied buffer. + * + * \note This function will only return bytes that are currently avaliable to be + * read and will not block waiting for any to arrive. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * \param buffer + * The location to place the data read + * \param length + * The maximum number of bytes to read + * + * \return The number of bytes read or PROS_ERR if the operation failed, setting + * errno. + */ +int32_t serial_read(uint8_t port, uint8_t* buffer, int32_t length); + +/** + * Write the given byte to the port's output buffer. + * + * \note Data in the port's output buffer is written to the serial port as soon + * as possible on a FIFO basis and can not be done manually by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * EIO - Serious internal write error. + * + * \param port + * The V5 port number from 1-21 + * \param buffer + * The byte to write + * + * \return The number of bytes written or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t serial_write_byte(uint8_t port, uint8_t buffer); + +/** + * Writes up to length bytes from the user supplied buffer to the port's output + * buffer. + * + * \note Data in the port's output buffer is written to the serial port as soon + * as possible on a FIFO basis and can not be done manually by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * EIO - Serious internal write error. + * + * \param port + * The V5 port number from 1-21 + * \param buffer + * The data to write + * \param length + * The maximum number of bytes to write + * + * \return The number of bytes written or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t serial_write(uint8_t port, uint8_t* buffer, int32_t length); + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_SERIAL_H_ \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/pros/serial.hpp b/old-code/v5_hal/firmware/include/pros/serial.hpp new file mode 100644 index 00000000..07378e95 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/serial.hpp @@ -0,0 +1,228 @@ +/** + * \file pros/serial.hpp + * + * Contains prototypes for the V5 Generic Serial related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/serial.html to learn + * more. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2018, 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/. + */ + +#ifndef _PROS_SERIAL_HPP_ +#define _PROS_SERIAL_HPP_ + +#include +#include "pros/serial.h" + +namespace pros { +class Serial { + public: + /** + * Creates a Serial object for the given port and specifications. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * \param baudrate + * The baudrate to run the port at + */ + explicit Serial(std::uint8_t port, std::int32_t baudrate); + + explicit Serial(std::uint8_t port); + + /******************************************************************************/ + /** Serial communication functions **/ + /** **/ + /** These functions allow programmers to communicate using UART over RS485 **/ + /******************************************************************************/ + + /** + * Sets the baudrate for the serial port to operate at. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param baudrate + * The baudrate to operate at + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_baudrate(std::int32_t baudrate) const; + + /** + * Clears the internal input and output FIFO buffers. + * + * This can be useful to reset state and remove old, potentially unneeded data + * from the input FIFO buffer or to cancel sending any data in the output FIFO + * buffer. + * + * \note This function does not cause the data in the output buffer to be + * written, it simply clears the internal buffers. Unlike stdout, generic + * serial does not use buffered IO (the FIFO buffers are written as soon + * as possible). + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t flush() const; + + /** + * Returns the number of bytes available to be read in the the port's FIFO + * input buffer. + * + * \note This function does not actually read any bytes, is simply returns the + * number of bytes available to be read. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \return The number of bytes avaliable to be read or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t get_read_avail() const; + + /** + * Returns the number of bytes free in the port's FIFO output buffer. + * + * \note This function does not actually write any bytes, is simply returns the + * number of bytes free in the port's buffer. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \return The number of bytes free or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t get_write_free() const; + + /** + * Gets the port number of the serial port. + * + * \return The serial port's port number. + */ + std::uint8_t get_port() const; + + /** + * Reads the next byte avaliable in the port's input buffer without removing it. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \return The next byte avaliable to be read, -1 if none are available, or + * PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t peek_byte() const; + + /** + * Reads the next byte avaliable in the port's input buffer. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \return The next byte avaliable to be read, -1 if none are available, or + * PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t read_byte() const; + + /** + * Reads up to the next length bytes from the port's input buffer and places + * them in the user supplied buffer. + * + * \note This function will only return bytes that are currently avaliable to be + * read and will not block waiting for any to arrive. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param buffer + * The location to place the data read + * \param length + * The maximum number of bytes to read + * + * \return The number of bytes read or PROS_ERR if the operation failed, setting + * errno. + */ + virtual std::int32_t read(std::uint8_t* buffer, std::int32_t length) const; + + /** + * Write the given byte to the port's output buffer. + * + * \note Data in the port's output buffer is written to the serial port as soon + * as possible on a FIFO basis and can not be done manually by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * EIO - Serious internal write error. + * + * \param buffer + * The byte to write + * + * \return The number of bytes written or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t write_byte(std::uint8_t buffer) const; + + /** + * Writes up to length bytes from the user supplied buffer to the port's output + * buffer. + * + * \note Data in the port's output buffer is written to the serial port as soon + * as possible on a FIFO basis and can not be done manually by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * EIO - Serious internal write error. + * + * \param buffer + * The data to write + * \param length + * The maximum number of bytes to write + * + * \return The number of bytes written or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t write(std::uint8_t* buffer, std::int32_t length) const; + + private: + const std::uint8_t _port; +}; + +namespace literals { +const pros::Serial operator"" _ser(const unsigned long long int m); +} // namespace literals +} // namespace pros +#endif // _PROS_SERIAL_HPP_ diff --git a/old-code/v5_hal/firmware/include/pros/vision.h b/old-code/v5_hal/firmware/include/pros/vision.h new file mode 100644 index 00000000..a21db2d1 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/vision.h @@ -0,0 +1,557 @@ +/** + * \file pros/vision.h + * + * Contains prototypes for the VEX Vision Sensor-related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html to learn + * more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_VISION_H_ +#define _PROS_VISION_H_ + +#define VISION_OBJECT_ERR_SIG 255 +// Parameters given by VEX +#define VISION_FOV_WIDTH 316 +#define VISION_FOV_HEIGHT 212 + +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif +/** + * This enumeration defines the different types of objects + * that can be detected by the Vision Sensor + */ +typedef enum vision_object_type { + E_VISION_OBJECT_NORMAL = 0, + E_VISION_OBJECT_COLOR_CODE = 1, + E_VISION_OBJECT_LINE = 2 +} vision_object_type_e_t; + +/** + * This structure contains the parameters used by the Vision Sensor + * to detect objects. + */ +typedef struct __attribute__((__packed__)) vision_signature { + uint8_t id; + uint8_t _pad[3]; + float range; + int32_t u_min; + int32_t u_max; + int32_t u_mean; + int32_t v_min; + int32_t v_max; + int32_t v_mean; + uint32_t rgb; + uint32_t type; +} vision_signature_s_t; + +/** + * Color codes are just signatures with multiple IDs and a different type. + */ +typedef uint16_t vision_color_code_t; + +/** + * This structure contains a descriptor of an object detected + * by the Vision Sensor + */ +typedef struct __attribute__((__packed__)) vision_object { + // Object signature + uint16_t signature; + // Object type, e.g. normal, color code, or line detection + vision_object_type_e_t type; + // left boundary coordinate of the object + int16_t left_coord; + // top boundary coordinate of the object + int16_t top_coord; + // width of the object + int16_t width; + // height of the object + int16_t height; + // Angle of a color code object in 0.1 degree units (e.g. 10 -> 1 degree, 155 + // -> 15.5 degrees) + uint16_t angle; + + // coordinates of the middle of the object (computed from the values above) + int16_t x_middle_coord; + int16_t y_middle_coord; +} vision_object_s_t; + +typedef enum vision_zero { + E_VISION_ZERO_TOPLEFT = 0, // (0,0) coordinate is the top left of the FOV + E_VISION_ZERO_CENTER = 1 // (0,0) coordinate is the center of the FOV +} vision_zero_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define VISION_OBJECT_NORMAL pros::E_VISION_OBJECT_NORMAL +#define VISION_OBJECT_COLOR_CODE pros::E_VISION_OBJECT_COLOR_CODE +#define VISION_OBJECT_LINE pros::E_VISION_OBJECT_LINE +#define VISION_ZERO_TOPLEFT pros::E_VISION_ZERO_TOPLEFT +#define VISION_ZERO_CENTER pros::E_VISION_ZERO_CENTER +#else +#define VISION_OBJECT_NORMAL E_VISION_OBJECT_NORMAL +#define VISION_OBJECT_COLOR_CODE E_VISION_OBJECT_COLOR_CODE +#define VISION_OBJECT_LINE E_VISION_OBJECT_LINE +#define VISION_ZERO_TOPLEFT E_VISION_ZERO_TOPLEFT +#define VISION_ZERO_CENTER E_VISION_ZERO_CENTER +#endif +#endif + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Clears the vision sensor LED color, reseting it back to its default behavior, + * displaying the most prominent object signature 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 V5 ports (1-21). + * ENODEV - The port cannot be configured as a vision sensor + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t vision_clear_led(uint8_t port); + +/** + * Creates a signature from the vision sensor utility + * + * \param id + * The signature ID + * \param u_min + * Minimum value on U axis + * \param u_max + * Maximum value on U axis + * \param u_mean + * Mean value on U axis + * \param v_min + * Minimum value on V axis + * \param v_max + * Maximum value on V axis + * \param v_mean + * Mean value on V axis + * \param range + * Scale factor + * \param type + * Signature type + * + * \return A vision_signature_s_t that can be set using vision_set_signature + */ +vision_signature_s_t vision_signature_from_utility(const int32_t id, const int32_t u_min, const int32_t u_max, + const int32_t u_mean, const int32_t v_min, const int32_t v_max, + const int32_t v_mean, const float range, const int32_t type); + +/** + * Creates a color code that represents a combination of the given signature + * IDs. If fewer than 5 signatures are to be a part of the color code, pass 0 + * for the additional function parameters. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - Fewer than two signatures have been provided or one of the + * signatures is out of its [1-7] range (or 0 when omitted). + * + * \param port + * The V5 port number from 1-21 + * \param sig_id1 + * The first signature id [1-7] to add to the color code + * \param sig_id2 + * The second signature id [1-7] to add to the color code + * \param sig_id3 + * The third signature id [1-7] to add to the color code + * \param sig_id4 + * The fourth signature id [1-7] to add to the color code + * \param sig_id5 + * The fifth signature id [1-7] to add to the color code + * + * \return A vision_color_code_t object containing the color code information. + */ +vision_color_code_t vision_create_color_code(uint8_t port, const uint32_t sig_id1, const uint32_t sig_id2, + const uint32_t sig_id3, const uint32_t sig_id4, const uint32_t sig_id5); + +/** + * Gets the nth largest object according to size_id. + * + * 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 + * EDOM - size_id is greater than the number of available objects. + * EHOSTDOWN - Reading the vision sensor failed for an unknown reason. + * + * \param port + * The V5 port number from 1-21 + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * + * \return The vision_object_s_t object corresponding to the given size id, or + * PROS_ERR if an error occurred. + */ +vision_object_s_t vision_get_by_size(uint8_t port, const uint32_t size_id); + +/** + * Gets the nth largest object of the given signature according to size_id. + * + * 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 + * EINVAL - sig_id is outside the range [1-8] + * EDOM - size_id is greater than the number of available objects. + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param port + * The V5 port number from 1-21 + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param signature + * The signature ID [1-7] for which an object will be returned. + * + * \return The vision_object_s_t object corresponding to the given signature and + * size_id, or PROS_ERR if an error occurred. + */ +vision_object_s_t vision_get_by_sig(uint8_t port, const uint32_t size_id, const uint32_t sig_id); + +/** + * Gets the nth largest object of the given color code according to size_id. + * + * 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 + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param port + * The V5 port number from 1-21 + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param color_code + * The vision_color_code_t for which an object will be returned + * + * \return The vision_object_s_t object corresponding to the given color code + * and size_id, or PROS_ERR if an error occurred. + */ +vision_object_s_t vision_get_by_code(uint8_t port, const uint32_t size_id, const vision_color_code_t color_code); + +/** + * Gets the exposure parameter of the Vision Sensor. See + * https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html#exposure-setting + * for more detials. + * + * 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 current exposure setting from [0,150], PROS_ERR if an error + * occurred + */ +int32_t vision_get_exposure(uint8_t port); + +/** + * Gets the number of objects currently detected by the 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 detected on the specified vision sensor. + * Returns PROS_ERR if the port was invalid or an error occurred. + */ +int32_t vision_get_object_count(uint8_t port); + +/** + * Get the white balance parameter of the 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 current RGB white balance setting of the sensor + */ +int32_t vision_get_white_balance(uint8_t port); + +/** + * Prints the contents of the signature as an initializer list to the terminal. + * + * \param sig + * The signature for which the contents will be printed + * + * \return 1 if no errors occured, PROS_ERR otherwise + */ +int32_t vision_print_signature(const vision_signature_s_t sig); + +/** + * Reads up to object_count object descriptors into object_arr. + * + * 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), or + * fewer than object_count number of objects were found. + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * + * \param port + * The V5 port number from 1-21 + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param object_count + * The number of objects to read + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * 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. + */ +int32_t vision_read_by_size(uint8_t port, const uint32_t size_id, const uint32_t object_count, + vision_object_s_t* const object_arr); + +/** + * Reads up to object_count object descriptors into object_arr. + * + * 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), or + * fewer than object_count number of objects were found. + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * + * \param port + * The V5 port number from 1-21 + * \param object_count + * The number of objects to read + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param signature + * The signature ID [1-7] for which objects will be returned. + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * 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. + */ +int32_t vision_read_by_sig(uint8_t port, const uint32_t size_id, const uint32_t sig_id, const uint32_t object_count, + vision_object_s_t* const object_arr); + +/** + * Reads up to object_count object descriptors into object_arr. + * + * 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), or + * fewer than object_count number of objects were found. + * ENODEV - The port cannot be configured as a vision sensor + * + * \param port + * The V5 port number from 1-21 + * \param object_count + * The number of objects to read + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param color_code + * The vision_color_code_t for which objects will be returned + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * 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. + */ +int32_t vision_read_by_code(uint8_t port, const uint32_t size_id, const vision_color_code_t color_code, + const uint32_t object_count, vision_object_s_t* const object_arr); + +/** + * Gets the object detection signature with the given id number. + * + * \param port + * The V5 port number from 1-21 + * \param signature_id + * The signature id to read + * + * \return A vision_signature_s_t containing information about the signature. + */ +vision_signature_s_t vision_get_signature(uint8_t port, const uint8_t signature_id); + +/** + * Stores the supplied object detection signature onto the vision sensor. + * + * NOTE: This saves the signature in volatile memory, and the signature will be + * lost as soon as the sensor is powered down. + * + * \param port + * The V5 port number from 1-21 + * \param signature_id + * The signature id to store into + * \param[in] signature_ptr + * A pointer to the signature to save + * + * \return 1 if no errors occured, PROS_ERR otherwise + */ +int32_t vision_set_signature(uint8_t port, const uint8_t signature_id, vision_signature_s_t* const signature_ptr); + +/** + * Enables/disables auto white-balancing on the 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 + * EINVAL - enable was not 0 or 1 + * + * \param port + * The V5 port number from 1-21 + * \param enabled + * Pass 0 to disable, 1 to enable + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t vision_set_auto_white_balance(uint8_t port, const uint8_t enable); + +/** + * Sets the exposure parameter of the Vision Sensor. See + * https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html#exposure-setting + * for more detials. + * + * 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 percent + * The new exposure setting from [0,150] + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t vision_set_exposure(uint8_t port, const uint8_t exposure); + +/** + * Sets the vision sensor LED color, overriding the automatic behavior. + * + * 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 rgb + * An RGB code to set the LED to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t vision_set_led(uint8_t port, const int32_t rgb); + +/** + * Sets the white balance parameter of the 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 + * \param rgb + * The new RGB white balance setting of the sensor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t vision_set_white_balance(uint8_t port, const int32_t rgb); + +/** + * Sets the (0,0) coordinate for the Field of View. + * + * This will affect the coordinates returned for each request for a + * vision_object_s_t from the sensor, so it is recommended that this function + * only be used to configure the sensor at the beginning of its use. + * + * 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 zero_point + * One of vision_zero_e_t to set the (0,0) coordinate for the FOV + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t vision_set_zero_point(uint8_t port, vision_zero_e_t zero_point); + +/** + * Sets the Wi-Fi mode of the Vision sensor + * + * This functions uses the following values of errno when an error state is + * reached: + * ENXIO - The given port is not within the range of V5 ports (1-21) + * EACCESS - Anothe resources is currently trying to access the port + * + * \param port + * The V5 port number from 1-21 + * \param enable + * Disable Wi-Fi on the Vision sensor if 0, enable otherwise (e.g. 1) + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t vision_set_wifi_mode(uint8_t port, const uint8_t enable); + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_VISION_H_ diff --git a/old-code/v5_hal/firmware/include/pros/vision.hpp b/old-code/v5_hal/firmware/include/pros/vision.hpp new file mode 100644 index 00000000..edcc5a3c --- /dev/null +++ b/old-code/v5_hal/firmware/include/pros/vision.hpp @@ -0,0 +1,445 @@ +/** + * \file pros/vision.hpp + * + * Contains prototypes for the VEX Vision Sensor-related functions in C++. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html to learn + * more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_VISION_HPP_ +#define _PROS_VISION_HPP_ + +#include "pros/vision.h" + +#include + +namespace pros { +class Vision { + public: + /** + * Create a 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 a vision sensor + * + * \param port + * 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 + */ + Vision(std::uint8_t port, vision_zero_e_t zero_point = E_VISION_ZERO_TOPLEFT); + + /** + * Clears the vision sensor LED color, reseting it back to its default + * behavior, displaying the most prominent object signature color. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t clear_led(void) const; + + /** + * Creates a signature from the vision sensor utility + * + * \param id + * The signature ID + * \param u_min + * Minimum value on U axis + * \param u_max + * Maximum value on U axis + * \param u_mean + * Mean value on U axis + * \param v_min + * Minimum value on V axis + * \param v_max + * Maximum value on V axis + * \param v_mean + * Mean value on V axis + * \param rgb + * Scale factor + * \param type + * Signature type + * + * \return A vision_signature_s_t that can be set using Vision::set_signature + */ + 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, + const std::int32_t v_min, const std::int32_t v_max, + const std::int32_t v_mean, const float range, + const std::int32_t type); + + /** + * Creates a color code that represents a combination of the given signature + * IDs. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - Fewer than two signatures have been provided or one of the + * signatures is out of its [1-7] range (or 0 when omitted). + * + * \param sig_id1 + * The first signature id [1-7] to add to the color code + * \param sig_id2 + * The second signature id [1-7] to add to the color code + * \param sig_id3 + * The third signature id [1-7] to add to the color code + * \param sig_id4 + * The fourth signature id [1-7] to add to the color code + * \param sig_id5 + * The fifth signature id [1-7] to add to the color code + * + * \return A vision_color_code_t object containing the color code information. + */ + 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 the nth largest object according to size_id. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * + * \return The vision_object_s_t object corresponding to the given size id, or + * PROS_ERR if an error occurred. + */ + vision_object_s_t get_by_size(const std::uint32_t size_id) const; + + /** + * Gets the nth largest object of the given signature according to size_id. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * EINVAL - sig_id is outside the range [1-8] + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param signature + * The vision_signature_s_t signature for which an object will be + * returned. + * + * \return The vision_object_s_t object corresponding to the given signature + * and size_id, or PROS_ERR if an error occurred. + */ + vision_object_s_t get_by_sig(const std::uint32_t size_id, const std::uint32_t sig_id) const; + + /** + * Gets the nth largest object of the given color code according to size_id. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EAGAIN - Reading the Vision Sensor failed for an unknown reason. + * + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param color_code + * The vision_color_code_t for which an object will be returned + * + * \return The vision_object_s_t object corresponding to the given color code + * and size_id, or PROS_ERR if an error occurred. + */ + 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. See + * https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html#exposure-setting + * for more detials. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \return The current exposure parameter from [0,150], + * PROS_ERR if an error occurred + */ + std::int32_t get_exposure(void) const; + + /** + * Gets the number of objects currently detected by the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \return The number of objects detected on the specified vision sensor. + * Returns PROS_ERR if the port was invalid or an error occurred. + */ + std::int32_t get_object_count(void) const; + + /** + * Gets the object detection signature with the given id number. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param signature_id + * The signature id to read + * + * \return A vision_signature_s_t containing information about the signature. + */ + vision_signature_s_t get_signature(const std::uint8_t signature_id) const; + + /** + * Get the white balance parameter of the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \return The current RGB white balance setting of the sensor + */ + std::int32_t get_white_balance(void) const; + + /** + * Gets the port number of the Vision Sensor. + * + * \return The vision sensor's port number. + */ + std::uint8_t get_port(void) const; + + /** + * Reads up to object_count object descriptors into object_arr. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param object_count + * The number of objects to read + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * 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. + */ + 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; + + /** + * Reads up to object_count object descriptors into object_arr. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * EINVAL - sig_id is outside the range [1-8] + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param object_count + * The number of objects to read + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param signature + * The vision_signature_s_t signature for which an object will be + * returned. + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * 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. + */ + std::int32_t read_by_sig(const std::uint32_t size_id, const std::uint32_t sig_id, const std::uint32_t object_count, + vision_object_s_t* const object_arr) const; + + /** + * Reads up to object_count object descriptors into object_arr. + * + * This function uses the following values of errno when an error state is + * reached: + * EDOM - size_id is greater than the number of available objects. + * ENODEV - The port cannot be configured as a vision sensor + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param object_count + * The number of objects to read + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param color_code + * The vision_color_code_t for which objects will be returned + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * 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. + */ + int32_t read_by_code(const std::uint32_t size_id, const vision_color_code_t color_code, + const std::uint32_t object_count, vision_object_s_t* const object_arr) const; + + /** + * Prints the contents of the signature as an initializer list to the terminal. + * + * \param sig + * The signature for which the contents will be printed + * + * \return 1 if no errors occured, PROS_ERR otherwise + */ + static std::int32_t print_signature(const vision_signature_s_t sig); + + /** + * Enables/disables auto white-balancing on the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param enabled + * Pass 0 to disable, 1 to enable + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_auto_white_balance(const std::uint8_t enable) const; + + /** + * Sets the exposure parameter of the Vision Sensor. See + * https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html#exposure-setting + * for more detials. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param percent + * The new exposure setting from [0,150]. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_exposure(const std::uint8_t exposure) const; + + /** + * Sets the vision sensor LED color, overriding the automatic behavior. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param rgb + * An RGB code to set the LED to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_led(const std::int32_t rgb) const; + + /** + * Stores the supplied object detection signature onto the vision sensor. + * + * NOTE: This saves the signature in volatile memory, and the signature will be + * lost as soon as the sensor is powered down. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EINVAL - sig_id is outside the range [1-8] + * + * \param signature_id + * The signature id to store into + * \param[in] signature_ptr + * A pointer to the signature to save + * + * \return 1 if no errors occured, PROS_ERR otherwise + */ + std::int32_t set_signature(const std::uint8_t signature_id, vision_signature_s_t* const signature_ptr) const; + + /** + * Sets the white balance parameter of the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param rgb + * The new RGB white balance setting of the sensor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_white_balance(const std::int32_t rgb) const; + + /** + * Sets the (0,0) coordinate for the Field of View. + * + * This will affect the coordinates returned for each request for a + * vision_object_s_t from the sensor, so it is recommended that this function + * only be used to configure the sensor at the beginning of its use. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param zero_point + * One of vision_zero_e_t to set the (0,0) coordinate for the FOV + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_zero_point(vision_zero_e_t zero_point) const; + + /** + * Sets the Wi-Fi mode of the Vision sensor + * + * This functions uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param enable + * Disable Wi-Fi on the Vision sensor if 0, enable otherwise (e.g. 1) + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_wifi_mode(const std::uint8_t enable) const; + + private: + std::uint8_t _port; +}; +} // namespace pros +#endif // _PROS_VISION_HPP_ diff --git a/old-code/v5_hal/firmware/include/pursuit/adaptive_pursuit/Position2d.h b/old-code/v5_hal/firmware/include/pursuit/adaptive_pursuit/Position2d.h new file mode 100644 index 00000000..57ba4e91 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pursuit/adaptive_pursuit/Position2d.h @@ -0,0 +1,38 @@ +#pragma once + +#include "Trans2d.h" + +class Position2d{ +public: + struct Delta{ + double dx, dy, dtheta; + + Delta(double x, double y, double t); + }; + +protected: + Trans2d m_translation; + Rotation2d m_rotation; + +public: + Position2d(); + Position2d(Trans2d tran, Rotation2d rot); + Position2d(const Position2d& other); + + static Position2d fromTranslation(Trans2d tran); + static Position2d fromRotation(Rotation2d rot); + static Position2d fromVelocity(Delta delta); + + Trans2d getTranslation(); + void setTranslation(Trans2d tran); + Rotation2d getRotation(); + void setRotation(Rotation2d rot); + + Position2d transformBy(Position2d other); + + Position2d inverse(); + + Position2d interpolate(Position2d other, double x); + + +}; diff --git a/old-code/v5_hal/firmware/include/pursuit/adaptive_pursuit/Rotation2d.h b/old-code/v5_hal/firmware/include/pursuit/adaptive_pursuit/Rotation2d.h new file mode 100644 index 00000000..a1e7ba3b --- /dev/null +++ b/old-code/v5_hal/firmware/include/pursuit/adaptive_pursuit/Rotation2d.h @@ -0,0 +1,30 @@ +#pragma once + +#include "math/Math.h" + +class Rotation2d{ +protected: + double m_cos, m_sin; + +public: + Rotation2d(); + Rotation2d(double x, double y, bool doNormalize); + Rotation2d(const Rotation2d& other); + + static Rotation2d fromRadians(double radians); + static Rotation2d fromDegrees(double degrees); + + void normalize(); + + double getCos(); + double getSin(); + + double getRadians(); + double getDegrees(); + + Rotation2d rotateBy(Rotation2d other); + Rotation2d inverse(); + Rotation2d opposite(); + + Rotation2d interpolate(Rotation2d other, double x); +}; diff --git a/old-code/v5_hal/firmware/include/pursuit/adaptive_pursuit/Trans2d.h b/old-code/v5_hal/firmware/include/pursuit/adaptive_pursuit/Trans2d.h new file mode 100644 index 00000000..8a52631d --- /dev/null +++ b/old-code/v5_hal/firmware/include/pursuit/adaptive_pursuit/Trans2d.h @@ -0,0 +1,41 @@ +#pragma once + +#include "Rotation2d.h" + +class Trans2d{ +protected: + double m_x, m_y; + +public: + Trans2d(); + + Trans2d(double x, double y); + + double norm(); + + double getX(); + + double getY(); + + void setX(double x); + + void setY(double y); + + Trans2d translateBy(Trans2d other); + + Trans2d rotateBy(Rotation2d rotation); + + Trans2d inverse(); + + Trans2d interpolate(Trans2d other, double x); + + Trans2d extrapolate(Trans2d other, double x); + + Trans2d flipX(); + Trans2d flipY(); + + double getSin(); + double getCos(); + + +}; diff --git a/old-code/v5_hal/firmware/include/pursuit/holonomic_pursuit/HolonomicPosePursuit.h b/old-code/v5_hal/firmware/include/pursuit/holonomic_pursuit/HolonomicPosePursuit.h new file mode 100644 index 00000000..bda1aea9 --- /dev/null +++ b/old-code/v5_hal/firmware/include/pursuit/holonomic_pursuit/HolonomicPosePursuit.h @@ -0,0 +1,36 @@ +#pragma once + +#include "api.h" +#include "eigen/Eigen/Dense" +#include "pathing/Path.h" +#include "util/Timer.h" +#include "util/PID.h" +#include "util/Constants.h" +#include "math/Pose.h" + +using namespace Eigen; + +class HolonomicPosePursuit { +private: + Pose m_target_pose; + Timer m_timer; + float m_previous_time; + PID m_x_pid; + PID m_y_pid; + PID m_theta_pid; + +public: + struct TargetVelocity { + Vector2d linear_velocity; + float rotational_velocity; + bool is_within_end_tolerance; + }; + + HolonomicPosePursuit(Pose target_pose, Timer timer=Timer()); + + void startPursuit(); + + TargetVelocity getTargetVelocity(Pose current_pose); + + ~HolonomicPosePursuit(); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/pursuit/holonomic_pursuit/HolonomicPursuit.h b/old-code/v5_hal/firmware/include/pursuit/holonomic_pursuit/HolonomicPursuit.h new file mode 100644 index 00000000..bbf6eb0c --- /dev/null +++ b/old-code/v5_hal/firmware/include/pursuit/holonomic_pursuit/HolonomicPursuit.h @@ -0,0 +1,36 @@ +#pragma once + +#include "api.h" +#include "eigen/Eigen/Dense" +#include "pathing/Path.h" +#include "util/Timer.h" +#include "util/PID.h" +#include "util/Constants.h" +#include "math/Pose.h" +#include "util/Logger.h" + +using namespace Eigen; + +class HolonomicPursuit { +private: + Path m_path; + Timer m_timer; + PID m_x_pid; + PID m_y_pid; + PID m_theta_pid; + +public: + struct TargetVelocity { + Vector2d linear_velocity; + float rotational_velocity; + bool end_of_path; + }; + + HolonomicPursuit(Path path, Timer timer=Timer()); + + void startPursuit(); + + TargetVelocity getTargetVelocity(Pose current_pose); + + ~HolonomicPursuit(); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/swerve/SwerveController.h b/old-code/v5_hal/firmware/include/swerve/SwerveController.h new file mode 100644 index 00000000..29ea4ba8 --- /dev/null +++ b/old-code/v5_hal/firmware/include/swerve/SwerveController.h @@ -0,0 +1,29 @@ +#include "SwerveModule.h" +#include "eigen/Eigen/Dense" + +class SwerveController{ + private: + Eigen::Rotation2Dd left_actual_angle; + Eigen::Rotation2Dd right_actual_angle; + Eigen::Rotation2Dd rear_actual_angle; + + SwerveModule leftSwerveModule; + SwerveModule rightSwerveModule; + SwerveModule rearSwerveModule; + + MotorPowers left_motor_powers; + MotorPowers right_motor_powers; + MotorPowers rear_motor_powers; + +public: + SwerveController(Eigen::Vector2d left_module_location, Eigen::Vector2d right_module_location, + Eigen::Vector2d rear_module_location, double kP, double kI, double kD); + + void assignActualAngle(int left_pot, int right_pot, int rear_pot); + + MotorPowers calculateLeftModule(Eigen::Vector2d target_velocity, double rotation_velocity); + + MotorPowers calculateRightModule(Eigen::Vector2d target_velocity, double rotation_velocity); + + MotorPowers calculateRearModule(Eigen::Vector2d target_velocity, double rotation_velocity); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/swerve/SwerveModule.h b/old-code/v5_hal/firmware/include/swerve/SwerveModule.h new file mode 100644 index 00000000..6b0ed784 --- /dev/null +++ b/old-code/v5_hal/firmware/include/swerve/SwerveModule.h @@ -0,0 +1,27 @@ +#pragma once + +#include "eigen/Eigen/Dense" +#include "eigen/Eigen/Geometry" +#include "math.h" +#include "util/Constants.h" + +struct MotorPowers { + int8_t left_motor_power; + int8_t right_motor_power; +}; + +class SwerveModule { +private: + Eigen::Vector2d m_module_location; + double m_percent_error; + double m_total_error; + double kP; + double kI; + double kD; + + +public: + SwerveModule (Eigen::Vector2d module_location, double kP, double kI, double kD); + + MotorPowers InverseKinematics(Eigen::Vector2d target_velocity, double target_rotation_velocity, Eigen::Rotation2Dd module_actual_angle); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/util/Constants.h b/old-code/v5_hal/firmware/include/util/Constants.h new file mode 100644 index 00000000..2fce7961 --- /dev/null +++ b/old-code/v5_hal/firmware/include/util/Constants.h @@ -0,0 +1,43 @@ +#ifndef _CONSTANTS_H_ +#define _CONSTANTS_H_ + +#define PUBLISH_DELAY_MS 20 +#define BALL_PRESENT_THRESHOLD 2700 // Threshold for Indexing Sensor to detect ball +#define MAX_MOTOR_VOLTAGE 12000 // Max voltage value for a motor +#define DELAY_TIME_MILLIS 5 // Standard delay time used in NodeManager + +// Offset to apply to get the gyro into our correct frame of reference +// Forward is M_PI_2, so we rotate the gyro angle to match +#define GYRO_OFFSET (M_PI_2) +#define MAX_WHEEL_SPEED 1.1526 // Wheel speed for Holonomic Drive in m/s + +// The following was from code that is no longer in current use +#define MAX_ROBOT_SPEED 41.9 // tank drive max robot speed in/s +// Swerve Drive +#define MAX_VELOCITY 50.0f // in/s +#define MAX_ROTATIONAL_VELOCITY 0.17 // rad/s ? +#define ROTATION_ANGLE_THRESHOLD (M_PI / 3) //Keeping this here because it was in the code but never used +#define LEFT_POT_OFFSET 40 +#define RIGHT_POT_OFFSET 1714 +#define REAR_POT_OFFSET 3083 +#define LEFT_MODULE_LOCATION_X -5.25 +#define LEFT_MODULE_LOCATION_Y 5.55 +#define RIGHT_MODULE_LOCATION_X 5.25 +#define RIGHT_MODULE_LOCATION_Y 5.55 +#define REAR_MODULE_LOCATION_X 0.0 +#define REAR_MODULE_LOCATION_Y -5.21 + +#define POSE_PURSUIT_LINEAR_THRESHOLD 5.0 +#define POSE_PURSUIT_THETA_THRESHOLD 0.3 + +#define ODOM_TRACK_WIDTH 0 + +#define ODOM_PERPENDICULAR_X 0.8 +#define ODOM_PERPENDICULAR_Y -5.478 + +#define ODOM_PARALLEL_X -1.75 +#define ODOM_PARALLEL_Y -3.924 + +#define GYRO_ROLLOVER_ANGLE (M_PI * 3) / 2 + +#endif diff --git a/old-code/v5_hal/firmware/include/util/Encoders.h b/old-code/v5_hal/firmware/include/util/Encoders.h new file mode 100644 index 00000000..9a6a1ea9 --- /dev/null +++ b/old-code/v5_hal/firmware/include/util/Encoders.h @@ -0,0 +1,13 @@ +#pragma once + +#include "api.h" + +/** + * Contains a configuration for encoders, using measurements in + * ticks and meters + */ +struct EncoderConfig { + double initial_ticks; + double ticks_per_wheel_revolution; + double wheel_diameter; +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/include/util/Logger.h b/old-code/v5_hal/firmware/include/util/Logger.h new file mode 100644 index 00000000..44cf8a59 --- /dev/null +++ b/old-code/v5_hal/firmware/include/util/Logger.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nodes/NodeManager.h" + +using namespace std; + +class Logger { +public: + enum LoggingLevel { + INFO, + WARNING, + ERROR + }; + static void logInfo(string message); + static void setConsoleLoggingLevel(LoggingLevel level); + static void giveNodeManager(NodeManager * node_manager); +private: + static LoggingLevel m_console_logging_level; + static NodeManager * m_node_manager; +}; diff --git a/old-code/v5_hal/firmware/include/util/PID.h b/old-code/v5_hal/firmware/include/util/PID.h new file mode 100644 index 00000000..8db408f8 --- /dev/null +++ b/old-code/v5_hal/firmware/include/util/PID.h @@ -0,0 +1,32 @@ +#pragma once + +#include "api.h" +#include "util/Timer.h" +#include "util/Logger.h" + +// +// Created by Jonathan T. Phung on 3/4/2021. +// + +class PID { +private: + float m_kP; + float m_kI; + float m_kD; + float m_feed_forward; + float m_previous_error; + float m_total_error; + Timer m_timer; + +public: + PID(float kP, float kI, float kD, float feed_forward=0.); + + /** + * This function returns the percentage of input to give to a + * mechanism, based off the supplied constants and feedforward + * values + * @param current_error Current error of the mechanism + * @returns percentage of input to give to the mechanism + */ + float calculate(float current_error); +}; diff --git a/old-code/v5_hal/firmware/include/util/Timer.h b/old-code/v5_hal/firmware/include/util/Timer.h new file mode 100644 index 00000000..60b4dcbe --- /dev/null +++ b/old-code/v5_hal/firmware/include/util/Timer.h @@ -0,0 +1,21 @@ +#pragma once + +#include "api.h" +#include +#include +#include "util/Logger.h" + +class Timer { +private: + double m_startTime = 0; + double m_stopTime = 0; + bool m_started = false; + bool m_stopped = false; +public: + static double getTime(); + double Get(); + void Stop(); + void Reset(); + void Start(); + bool isStarted(); +}; \ No newline at end of file diff --git a/old-code/v5_hal/firmware/project.pros b/old-code/v5_hal/firmware/project.pros new file mode 100644 index 00000000..c8a77ba6 --- /dev/null +++ b/old-code/v5_hal/firmware/project.pros @@ -0,0 +1 @@ +{"py/object": "pros.conductor.project.Project", "py/state": {"target": "v5", "templates": {"kernel": {"py/object": "pros.conductor.templates.local_template.LocalTemplate", "location": "/home/nathan/.config/pros/templates/kernel@3.3.1", "system_files": ["include/display/lv_objx/lv_preload.h", "include/display/lv_objx/lv_bar.h", "include/pros/llemu.hpp", "include/display/lv_draw/lv_draw_line.h", "include/display/lv_objx/lv_imgbtn.h", "include/display/lv_core/lv_style.h", "include/display/lv_misc/lv_math.h", "include/display/lv_misc/lv_misc.mk", "include/display/lv_themes/lv_themes.mk", "firmware/v5-common.ld", "include/pros/distance.h", "include/display/lv_core/lv_obj.h", "include/display/lv_misc/lv_circ.h", "include/display/lv_draw/lv_draw_triangle.h", "include/pros/motors.hpp", "include/pros/imu.h", "include/display/lv_draw/lv_draw.h", "include/display/lv_misc/lv_symbol_def.h", "include/display/lv_themes/lv_theme_templ.h", "include/display/lv_misc/lv_gc.h", "include/display/lv_objx/lv_win.h", "include/display/lv_core/lv_refr.h", "include/display/lv_hal/lv_hal_tick.h", "include/display/README.md", "include/pros/misc.h", "include/display/lv_hal/lv_hal_disp.h", "firmware/libc.a", "include/display/lv_misc/lv_color.h", "include/display/lv_themes/lv_theme_night.h", "include/display/lv_misc/lv_fs.h", "include/display/lv_themes/lv_theme_alien.h", "include/display/licence.txt", "include/display/lv_misc/lv_font.h", "include/display/lv_misc/lv_anim.h", "common.mk", "include/display/lvgl.h", "include/display/lv_draw/lv_draw_vbasic.h", "include/display/lv_core/lv_group.h", "include/display/lv_core/lv_core.mk", "include/display/lv_objx/lv_sw.h", "include/display/lv_draw/lv_draw_label.h", "include/pros/imu.hpp", "include/display/lv_objx/lv_img.h", "include/display/lv_misc/lv_txt.h", "include/display/lv_objx/lv_line.h", "include/pros/ext_adi.h", "include/display/lv_draw/lv_draw_arc.h", "include/display/lv_objx/lv_label.h", "include/display/lv_objx/lv_kb.h", "include/display/lv_themes/lv_theme_default.h", "include/display/lv_misc/lv_templ.h", "include/pros/rtos.hpp", "include/pros/apix.h", "include/display/lv_core/lv_indev.h", "include/display/lv_objx/lv_tabview.h", "firmware/libpros.a", "include/display/lv_core/lv_vdb.h", "include/display/lv_objx/lv_lmeter.h", "include/display/lv_themes/lv_theme_nemo.h", "firmware/libm.a", "include/display/lv_themes/lv_theme_zen.h", "include/pros/colors.h", "include/display/lv_objx/lv_ta.h", "include/display/lv_objx/lv_calendar.h", "include/display/lv_hal/lv_hal.h", "include/display/lv_objx/lv_canvas.h", "include/display/lv_fonts/lv_fonts.mk", "include/display/lv_draw/lv_draw_img.h", "include/display/lv_misc/lv_ufs.h", "include/pros/misc.hpp", "include/display/lv_themes/lv_theme.h", "include/display/lv_objx/lv_cb.h", "firmware/v5-hot.ld", "include/display/lv_objx/lv_slider.h", "include/pros/optical.h", "include/display/lv_objx/lv_tileview.h", "include/display/lv_core/lv_lang.h", "include/pros/distance.hpp", "include/pros/optical.hpp", "include/display/lv_objx/lv_spinbox.h", "include/display/lv_draw/lv_draw.mk", "include/pros/rotation.hpp", "include/display/lv_misc/lv_log.h", "include/api.h", "include/pros/llemu.h", "include/display/lv_objx/lv_list.h", "include/display/lv_misc/lv_ll.h", "include/display/lv_objx/lv_roller.h", "include/display/lv_hal/lv_hal.mk", "include/pros/vision.h", "include/pros/adi.h", "include/display/lv_objx/lv_page.h", "include/display/lv_objx/lv_cont.h", "include/display/lv_conf.h", "include/display/lv_conf_checker.h", "include/display/lv_hal/lv_hal_indev.h", "include/pros/rotation.h", "include/pros/motors.h", "include/display/lv_draw/lv_draw_rect.h", "include/pros/adi.hpp", "include/display/lv_objx/lv_gauge.h", "include/display/lv_misc/lv_task.h", "firmware/v5.ld", "include/pros/vision.hpp", "include/display/lv_objx/lv_chart.h", "include/display/lv_objx/lv_mbox.h", "include/pros/rtos.h", "include/display/lv_fonts/lv_font_builtin.h", "include/pros/serial.hpp", "include/display/lv_objx/lv_led.h", "include/display/lv_objx/lv_btn.h", "include/display/lv_themes/lv_theme_mono.h", "include/display/lv_objx/lv_objx.mk", "include/display/lv_objx/lv_ddlist.h", "include/pros/api_legacy.h", "include/display/lv_draw/lv_draw_rbasic.h", "include/display/lv_objx/lv_btnm.h", "include/display/lv_themes/lv_theme_material.h", "include/display/lv_objx/lv_table.h", "include/display/lv_misc/lv_area.h", "include/display/lv_objx/lv_arc.h", "include/display/lv_objx/lv_objx_templ.h", "include/display/lv_misc/lv_mem.h", "include/pros/serial.h", "include/display/lv_version.h"], "user_files": ["src/main.cpp", "include/main.h", "include/main.hh", "Makefile", ".gitignore", "include/main.hpp", "src/main.c", "src/main.cc"], "name": "kernel", "version": "3.3.1", "supported_kernels": null, "target": "v5", "metadata": {"cold_addr": "58720256", "cold_output": "bin/cold.package.bin", "hot_addr": "125829120", "hot_output": "bin/hot.package.bin", "output": "bin/monolith.bin", "origin": "pros-mainline"}}, "okapilib": {"py/object": "pros.conductor.templates.local_template.LocalTemplate", "location": "/home/nathan/.config/pros/templates/okapilib@4.0.5", "system_files": ["include/okapi/api/units/QAngularSpeed.hpp", "include/okapi/pathfinder/include/pathfinder/fit.h", "include/okapi/impl/control/async/asyncPosControllerBuilder.hpp", "include/okapi/impl/device/controllerUtil.hpp", "include/okapi/api/control/util/pidTuner.hpp", "include/okapi/impl/util/timer.hpp", "include/okapi/api/chassis/controller/chassisControllerPid.hpp", "include/okapi/api/filter/velMath.hpp", "include/okapi/api/control/async/asyncVelocityController.hpp", "include/okapi/impl/device/rotarysensor/potentiometer.hpp", "include/okapi/api/odometry/point.hpp", "include/okapi/impl/device/motor/adiMotor.hpp", "include/okapi/api/control/iterative/iterativePositionController.hpp", "include/okapi/api/chassis/controller/chassisController.hpp", "include/okapi/impl/device/rotarysensor/adiGyro.hpp", "include/okapi/pathfinder/include/pathfinder/structs.h", "include/okapi/impl/control/util/controllerRunnerFactory.hpp", "include/okapi/api/filter/composableFilter.hpp", "include/okapi/api/control/util/controllerRunner.hpp", "include/okapi/api/units/QAngularJerk.hpp", "include/okapi/api/units/RQuantity.hpp", "include/okapi/api/odometry/odomMath.hpp", "include/okapi/api/util/abstractTimer.hpp", "include/okapi/impl/device/rotarysensor/adiEncoder.hpp", "include/okapi/api/chassis/controller/chassisControllerIntegrated.hpp", "include/okapi/impl/device/button/controllerButton.hpp", "include/okapi/api/control/util/pathfinderUtil.hpp", "include/okapi/api/units/QLength.hpp", "include/okapi/api/util/logging.hpp", "include/okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp", "firmware/okapilib.a", "include/okapi/api/device/rotarysensor/rotarySensor.hpp", "include/okapi/api/filter/medianFilter.hpp", "include/okapi/pathfinder/include/pathfinder/modifiers/tank.h", "include/okapi/api/control/async/asyncPosPidController.hpp", "include/okapi/api/control/async/asyncPositionController.hpp", "include/okapi/pathfinder/include/pathfinder/lib.h", "include/okapi/api/device/rotarysensor/continuousRotarySensor.hpp", "include/okapi/pathfinder/include/pathfinder/followers/encoder.h", "include/okapi/api/coreProsAPI.hpp", "include/okapi/api/filter/filter.hpp", "include/okapi/api/control/async/asyncWrapper.hpp", "include/okapi/api/control/async/asyncLinearMotionProfileController.hpp", "include/okapi/api/units/QMass.hpp", "include/okapi/api/chassis/controller/chassisScales.hpp", "include/okapi/api/filter/averageFilter.hpp", "include/okapi/impl/device/button/adiButton.hpp", "include/okapi/api/control/async/asyncVelPidController.hpp", "include/okapi/api/control/async/asyncMotionProfileController.hpp", "include/okapi/api/control/controllerInput.hpp", "include/okapi/api/control/iterative/iterativeMotorVelocityController.hpp", "include/okapi/api/units/QVolume.hpp", "include/okapi/pathfinder/include/pathfinder/spline.h", "include/okapi/api/device/button/abstractButton.hpp", "include/okapi/impl/device/adiUltrasonic.hpp", "include/okapi/api/chassis/model/hDriveModel.hpp", "include/okapi/api/control/util/flywheelSimulator.hpp", "include/okapi/api/chassis/model/xDriveModel.hpp", "include/okapi/api/odometry/threeEncoderOdometry.hpp", "include/okapi/pathfinder/include/pathfinder/trajectory.h", "include/okapi/impl/control/iterative/iterativeControllerFactory.hpp", "include/okapi/pathfinder/include/pathfinder/io.h", "include/okapi/api/control/offsettableControllerInput.hpp", "include/okapi/api/control/iterative/iterativeController.hpp", "include/okapi/api/units/QAngularAcceleration.hpp", "include/okapi/api/units/QJerk.hpp", "include/okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp", "include/okapi/impl/device/rotarysensor/integratedEncoder.hpp", "include/okapi/api/util/mathUtil.hpp", "include/okapi/api.hpp", "include/okapi/api/units/QAcceleration.hpp", "include/okapi/pathfinder/include/pathfinder/mathutil.h", "include/okapi/impl/control/async/asyncVelControllerBuilder.hpp", "include/okapi/api/chassis/controller/odomChassisController.hpp", "include/okapi/impl/util/timeUtilFactory.hpp", "include/okapi/impl/device/controller.hpp", "include/okapi/pathfinder/include/pathfinder.h", "include/okapi/api/chassis/model/threeEncoderXDriveModel.hpp", "include/okapi/api/units/QTorque.hpp", "include/okapi/api/odometry/stateMode.hpp", "include/okapi/api/units/QFrequency.hpp", "include/okapi/pathfinder/include/pathfinder/modifiers/swerve.h", "include/okapi/api/control/iterative/iterativeVelPidController.hpp", "include/okapi/api/filter/ekfFilter.hpp", "include/okapi/api/odometry/twoEncoderOdometry.hpp", "include/okapi/api/control/closedLoopController.hpp", "include/okapi/impl/device/motor/motorGroup.hpp", "include/okapi/api/chassis/model/skidSteerModel.hpp", "include/okapi/api/control/async/asyncVelIntegratedController.hpp", "include/okapi/api/util/timeUtil.hpp", "include/okapi/api/filter/filteredControllerInput.hpp", "include/okapi/api/units/QTime.hpp", "include/okapi/api/units/QPressure.hpp", "include/okapi/api/filter/demaFilter.hpp", "include/okapi/api/odometry/odomState.hpp", "include/okapi/impl/control/util/pidTunerFactory.hpp", "include/okapi/api/device/motor/abstractMotor.hpp", "include/okapi/impl/device/motor/motor.hpp", "include/okapi/api/units/QAngle.hpp", "include/okapi/api/control/controllerOutput.hpp", "include/okapi/impl/device/rotarysensor/IMU.hpp", "include/okapi/api/chassis/controller/defaultOdomChassisController.hpp", "include/okapi/api/chassis/model/chassisModel.hpp", "include/okapi/impl/util/rate.hpp", "include/okapi/api/filter/emaFilter.hpp", "include/okapi/api/control/util/settledUtil.hpp", "include/okapi/impl/chassis/controller/chassisControllerBuilder.hpp", "include/okapi/api/util/abstractRate.hpp", "include/okapi/api/odometry/odometry.hpp", "include/okapi/api/units/QSpeed.hpp", "include/okapi/api/control/iterative/iterativeVelocityController.hpp", "include/okapi/api/chassis/model/readOnlyChassisModel.hpp", "include/okapi/api/units/QArea.hpp", "include/okapi/api/filter/passthroughFilter.hpp", "include/okapi/api/util/supplier.hpp", "include/okapi/impl/util/configurableTimeUtilFactory.hpp", "include/okapi/api/control/async/asyncPosIntegratedController.hpp", "include/okapi/impl/filter/velMathFactory.hpp", "include/okapi/pathfinder/include/pathfinder/followers/distance.h", "include/okapi/api/control/async/asyncController.hpp", "include/okapi/api/units/QForce.hpp", "include/okapi/api/control/iterative/iterativePosPidController.hpp", "include/okapi/api/device/button/buttonBase.hpp"], "user_files": [], "name": "okapilib", "version": "4.0.5", "supported_kernels": "^3.3.0", "target": "v5", "metadata": {"origin": "pros-mainline"}}}, "upload_options": {}, "project_name": "ros-pros-project"}} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/auton/Auton.cpp b/old-code/v5_hal/firmware/src/auton/Auton.cpp new file mode 100644 index 00000000..5b61c9eb --- /dev/null +++ b/old-code/v5_hal/firmware/src/auton/Auton.cpp @@ -0,0 +1,263 @@ +#include "auton/Auton.h" + +using namespace std; + +/* + * Create a node with given actions and timeout. These actions will all be run in parallel to each other. + * Nullptrs will not be added as actions, they will be ignored. + */ +AutonNode::AutonNode(double timeout, AutonAction* action1, AutonAction* action2, AutonAction* action3) : + m_children(), m_actions(), m_timeout(timeout) { + m_startCondition = nullptr; + if(action1 != nullptr) { + m_actions.push_back(action1); + } + if(action2 != nullptr) { + m_actions.push_back(action2); + } + if(action3 != nullptr) { + m_actions.push_back(action3); + } +} + +/* + * Add a node to this node which will be run sequentially after this node completes all of its actions + */ +void AutonNode::AddNext(AutonNode* childNode) { + m_children.push_back(childNode); +} + +/* + * Add an action to this node which will be run in parallel to other actions in this node + */ +void AutonNode::AddAction(AutonAction* leaf) { + if(leaf != nullptr) { + m_actions.push_back(leaf); + } +} + +/* + * Add a condition to this node. + * This condition is passed in as a std::function that will be called to check the condition. + * + * Typically, the best way to do this is to create a lambda that contains the code to see if the node should be run. + * + * Example: + * addCondition([]{return shouldNodeRun()}); + * + * This condition will be checked by the previous node while it is not complete. + * While it is true this action will run its actions. + */ +void AutonNode::AddCondition(function startCondition) { + m_startConditonGiven = true; + m_startCondition = startCondition; +} + +/* + * Returns true if all actions are complete and all child nodes are complete or if timeout has been exceeded + */ +bool AutonNode::Complete() { + if(m_actions.empty()) { + for(auto child : m_children) { + if(!child->Complete()) { + return false; + } + } + return true; + } else { + return false; + } +} + +/* + * Prepares node to be run + */ +void AutonNode::Reset() { + for(auto child : m_children) { + child->Reset(); + } + m_actions.clear(); + m_children.clear(); + m_actionsInitialized = false; +} + +/* + * Set the timeout for this node to a given duration in seconds + */ +void AutonNode::SetTimeout(double timeout) { + m_timeout = timeout; +} + +/** + * Runs all actions in node and checks if child node conditions are true. If they are and this node is not done, that + * child node is run. + * @param lastNodeDone If previous node is complete. + */ +void AutonNode::Act(bool lastNodeDone) { + bool shouldAct = (m_startConditonGiven && m_startCondition && !lastNodeDone) + || (!m_startConditonGiven && lastNodeDone); + if(!m_actionsInitialized && shouldAct) { + + m_timer.Reset(); + m_timer.Start(); + + for(auto action : m_actions) { + action->ActionInit(); + } + m_actionsInitialized = true; + } + if(!m_actions.empty() && (m_timer.Get() > m_timeout)) { + for(auto action : m_actions) { + action->ActionEnd(); + } + for (auto i = m_actions.begin(); i != m_actions.end(); i++){ + delete *i; + } + m_actions.clear(); + } + if(!m_actions.empty()) { + if(shouldAct) { + for(unsigned int i = 0; i < m_actions.size(); i++) { + AutonAction::actionStatus status = m_actions[i]->Action(); + switch(status) { + case AutonAction::END: + m_actions[i]->ActionEnd(); + //TODO: There's a memory leak here, need to fix + m_actions.erase(m_actions.begin() + i); + i--; + break; + case AutonAction::CONTINUE: + break; + } + } + for(auto child : m_children) { + child->Act(false); + } + } else if(m_startConditonGiven && !m_startCondition) { + return; + } + } else { + for(auto child : m_children) { + child->Act(true); + } + } +} + +AutonNode::~AutonNode() { + for (auto i = m_actions.begin(); i != m_actions.end(); i++){ + delete *i; + } + m_actions.clear(); + for (auto i = m_children.begin(); i != m_children.end(); i++){ + delete *i; + } + m_children.clear(); +} + +/* + * Initialize an autonomous routine with given name, first node, and whether this autonomous should be the default + * selected autonomous on Smart Dashboard + */ +Auton::Auton(string name, bool defaultAuton) { + m_name = name; + m_defaultAuton = defaultAuton; +} + +/* + * Run autonomous routine. Needs to be called each iteration. + */ +void Auton::AutonPeriodic() { + for(auto node : m_firstNode) { + node->Act(true); + } +} + +/* + * Initialize autonomous routine by resetting and adding all nodes. + */ +void Auton::AutonInit() { + Reset(); + AddNodes(); +} + +/* + * If autonomous routine is complete + */ +bool Auton::Complete() { + for(auto node : m_firstNode) { + if(!node->Complete()) { + return false; + } + } + return true; +} + +/* + * Reset all nodes in autonomous routine + */ +void Auton::Reset() { + for(auto node : m_firstNode) { + if(node != nullptr) { + node->Reset(); + } + } +} + +/* + * Add another node to be run on start of autonomous routine + * Nullptrs will not be added as actions, they will be ignored + */ +void Auton::AddFirstNode(AutonNode* firstNode) { + if(firstNode != nullptr) { + m_firstNode.push_back(firstNode); + } +} + +/* + * Returns human readable name of routine + */ +string Auton::GetName() { + return m_name; +} + +/* + * Automatically deletes all nodes and their actions on deletion of the autonomous routine + */ +Auton::~Auton() { + for (auto i = m_firstNode.begin(); i != m_firstNode.end(); i++){ + delete *i; + } + m_firstNode.clear(); +} + +/* + * Takes a duration in seconds to wait for. + */ +WaitAction::WaitAction(double duration) { + m_duration = duration; +} + +void WaitAction::ActionInit() { + m_timer.Reset(); + m_timer.Start(); +} + +AutonAction::actionStatus WaitAction::Action() { + if(m_timer.Get() > m_duration) { + return AutonAction::END; + } else { + return AutonAction::CONTINUE; + } +} + +PrintAction::PrintAction(string toPrint) { + m_toPrint = toPrint; +} + +void PrintAction::ActionInit() { + cout << m_toPrint << endl; +} + +AutonAction::actionStatus PrintAction::Action() { + return END; +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/auton/AutonSequence.cpp b/old-code/v5_hal/firmware/src/auton/AutonSequence.cpp new file mode 100644 index 00000000..ee3487e8 --- /dev/null +++ b/old-code/v5_hal/firmware/src/auton/AutonSequence.cpp @@ -0,0 +1,25 @@ +#include "auton/AutonSequence.h" + +AutonSequence::AutonSequence(AutonNode* initialNode) { + m_auton_sequence = { initialNode, initialNode }; +} + +void AutonSequence::AddNext(AutonNode* source, AutonNode* node) { + source->AddNext(node); +} + +void AutonSequence::AddAction(AutonAction* action) { + m_auton_sequence.tailNode->AddAction(action); +} + +void AutonSequence::SetTailNode(AutonNode* tail) { + m_auton_sequence.tailNode = tail; +} + +AutonSequence::AutonSequenceList AutonSequence::GetSequence() { + return m_auton_sequence; +} + +AutonSequence::~AutonSequence() { + +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/auton/auton_actions/DriveStraightAction.cpp b/old-code/v5_hal/firmware/src/auton/auton_actions/DriveStraightAction.cpp new file mode 100644 index 00000000..e65d4fd4 --- /dev/null +++ b/old-code/v5_hal/firmware/src/auton/auton_actions/DriveStraightAction.cpp @@ -0,0 +1,56 @@ +#include "auton/auton_actions/DriveStraightAction.h" +#include + +DriveStraightAction::DriveStraightAction(IDriveNode* drive_node, double distance, double max_velocity, + double max_accel) : + m_drive_node(drive_node), m_distance(distance), + m_max_velocity(max_velocity), m_max_accel(max_accel), m_lastSpeed(0), m_feedForward(4.91) { + +} + +void DriveStraightAction::ActionInit() { + m_timer.Start(); + m_drive_node->resetEncoders(); +} + +AutonAction::actionStatus DriveStraightAction::Action() { + double dt = m_timer.Get() - m_lastTime; + double speed = m_max_velocity; + + double accel = (m_max_velocity - m_lastSpeed) / dt; + + if (accel < -m_max_accel) { + speed = m_lastSpeed - m_max_accel * dt; + } else if (accel > m_max_accel) { + speed = m_lastSpeed + m_max_accel * dt; + } + + // Subtract the found offset of 3 inches to shorten the path + double remainingDistance = max(fabs(m_distance) - fabs(((m_drive_node->getIntegratedEncoderVals().left_front_encoder_val / 900.0) * (M_PI * 4.0625))) - 3, 0.); + + double maxAllowedSpeed = sqrt(2 * m_max_accel * remainingDistance); + if (fabs(speed) > maxAllowedSpeed) { + speed = std::copysign(maxAllowedSpeed, speed); + } + + speed = max(speed, m_feedForward); + + m_lastSpeed = speed; + m_lastTime = m_timer.Get(); + + if (remainingDistance < 0.5) { + return END; + } else { + if (m_distance > 0) { + m_drive_node->setDriveVelocity(speed, 0); + } else { + m_drive_node->setDriveVelocity(-speed, 0); + } + + return CONTINUE; + } +} + +void DriveStraightAction::ActionEnd() { + m_drive_node->setDriveVelocity(0, 0); +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/auton/auton_actions/DriveToPoseAction.cpp b/old-code/v5_hal/firmware/src/auton/auton_actions/DriveToPoseAction.cpp new file mode 100644 index 00000000..c35a62b3 --- /dev/null +++ b/old-code/v5_hal/firmware/src/auton/auton_actions/DriveToPoseAction.cpp @@ -0,0 +1,33 @@ +#include "auton/auton_actions/DriveToPoseAction.h" + +DriveToPoseAction::DriveToPoseAction(IDriveNode* drive_node, OdometryNode* odom_node, Pose end_pose) : + m_drive_node(drive_node), + m_odom_node(odom_node), + m_end_pose(end_pose), + m_holonomic_pose_pursuit(end_pose) { + +} + +void DriveToPoseAction::ActionInit() { + m_holonomic_pose_pursuit.startPursuit(); +} + +AutonAction::actionStatus DriveToPoseAction::Action() { + HolonomicPosePursuit::TargetVelocity target_velocity = m_holonomic_pose_pursuit.getTargetVelocity(m_odom_node->getCurrentPose()); + + m_drive_node->setDriveVelocity(target_velocity.linear_velocity.x(), target_velocity.linear_velocity.y(), target_velocity.rotational_velocity); + + if (m_timer.Get() == 0 && target_velocity.is_within_end_tolerance) { + m_timer.Start(); + } else if (m_timer.Get() > 0 && !target_velocity.is_within_end_tolerance) { + m_timer.Reset(); + } else if (m_timer.Get() > 0.5) { + return END; + } + + return CONTINUE; +} + +void DriveToPoseAction::ActionEnd() { + m_drive_node->setDriveVelocity(0, 0, 0); +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/auton/auton_actions/FollowPathAction.cpp b/old-code/v5_hal/firmware/src/auton/auton_actions/FollowPathAction.cpp new file mode 100644 index 00000000..619a7348 --- /dev/null +++ b/old-code/v5_hal/firmware/src/auton/auton_actions/FollowPathAction.cpp @@ -0,0 +1,38 @@ +#include "auton/auton_actions/FollowPathAction.h" + +FollowPathAction::FollowPathAction(IDriveNode* drive_node, OdometryNode* odom_node, Path path, bool reset_pose) : + m_drive_node(drive_node), + m_odom_node(odom_node), + m_holonomic_pursuit(path), + m_path(path), + m_reset_pose(reset_pose) { + +} + +void FollowPathAction::ActionInit() { + if (m_reset_pose) { + m_odom_node->setCurrentPose(m_path.getPathPoints().at(0).getPose()); + } + + m_holonomic_pursuit.startPursuit(); +} + +AutonAction::actionStatus FollowPathAction::Action() { + HolonomicPursuit::TargetVelocity target_velocity = m_holonomic_pursuit.getTargetVelocity(m_odom_node->getCurrentPose()); + + m_drive_node->setDriveVelocity(target_velocity.linear_velocity.x(), target_velocity.linear_velocity.y(), target_velocity.rotational_velocity); + + if (m_timer.Get() == 0 && target_velocity.end_of_path) { + m_timer.Start(); + } else if (m_timer.Get() > 0 && !target_velocity.end_of_path) { + m_timer.Reset(); + } else if (m_timer.Get() > 0.5) { + return END; + } + + return CONTINUE; +} + +void FollowPathAction::ActionEnd() { + m_drive_node->setDriveVelocity(0, 0, 0); +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/auton/auton_actions/ProfiledTurnAction.cpp b/old-code/v5_hal/firmware/src/auton/auton_actions/ProfiledTurnAction.cpp new file mode 100644 index 00000000..f14982e0 --- /dev/null +++ b/old-code/v5_hal/firmware/src/auton/auton_actions/ProfiledTurnAction.cpp @@ -0,0 +1,59 @@ +#include "auton/auton_actions/ProfiledTurnAction.h" + +ProfiledTurnAction::ProfiledTurnAction(IDriveNode* drive_node, InertialSensorNode* imu, Eigen::Rotation2Dd angle, double max_velocity, + double max_accel) : + m_drive_node(drive_node), m_imu(imu), m_angle(angle), + m_max_velocity(max_velocity), m_max_accel(max_accel), m_lastSpeed(0), m_feedForward(3.) { + +} + +void ProfiledTurnAction::ActionInit() { + m_timer.Start(); + m_drive_node->resetEncoders(); +} + +ProfiledTurnAction::actionStatus ProfiledTurnAction::Action() { + double dt = m_timer.Get() - m_lastTime; + double speed = m_max_velocity; + + double accel = (m_max_velocity - m_lastSpeed) / dt; + + if (accel < -m_max_accel) { + speed = m_lastSpeed - m_max_accel * dt; + } else if (accel > m_max_accel) { + speed = m_lastSpeed + m_max_accel * dt; + } + + Eigen::Rotation2Dd m_actual = m_imu->getYaw(); + + // Subtract the found offset of 3 inches to shorten the path + double remainingAngle = (m_actual.inverse() * m_angle).smallestAngle(); + + Logger::logInfo("Remaining angle: " + std::to_string(remainingAngle)); + + double maxAllowedSpeed = sqrt(2 * m_max_accel * remainingAngle); + if (fabs(speed) > maxAllowedSpeed) { + speed = std::copysign(maxAllowedSpeed, speed); + } + + speed = max(speed, m_feedForward); + + m_lastSpeed = speed; + m_lastTime = m_timer.Get(); + + if (remainingAngle < 0.5) { + return END; + } else { + if (remainingAngle > 0) { + m_drive_node->setDriveVelocity(0, 0, -speed); + } else { + m_drive_node->setDriveVelocity(0, 0, speed); + } + + return CONTINUE; + } +} + +void ProfiledTurnAction::ActionEnd() { + m_drive_node->setDriveVelocity(0, 0, 0); +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/auton/auton_actions/TurnToAngleAction.cpp b/old-code/v5_hal/firmware/src/auton/auton_actions/TurnToAngleAction.cpp new file mode 100644 index 00000000..3be1a355 --- /dev/null +++ b/old-code/v5_hal/firmware/src/auton/auton_actions/TurnToAngleAction.cpp @@ -0,0 +1,46 @@ +#include "auton/auton_actions/TurnToAngleAction.h" + +TurnToAngleAction::TurnToAngleAction(IDriveNode* drive_node, InertialSensorNode* inertial_sensor, + Eigen::Rotation2Dd target_angle) : + m_drive_node(drive_node), + m_inertial_sensor(inertial_sensor), + m_target_angle(target_angle), + m_turning_pid(0.2, 0., 0., 0.1) { +} + +void TurnToAngleAction::ActionInit() { + m_turn_timer.Reset(); +} + +AutonAction::actionStatus TurnToAngleAction::Action() { + Eigen::Rotation2Dd current_angle(m_inertial_sensor->getYaw()); + + // std::string log_str = "Gyro Angle: " + to_string(current_angle.angle()) + "\nTarget Angle: " + to_string(m_target_angle.angle()); + // m_tank_drive->m_handle->logwarn(log_str.c_str()); + + Logger::logInfo("Gyro Angle: " + to_string(current_angle.angle()) + "\nTarget Angle: " + to_string(m_target_angle.angle())); + + double delta_angle = (m_target_angle.inverse() * current_angle).smallestAngle(); + + double turning_power = delta_angle / M_PI * -1; + + float total_turn_input = m_turning_pid.calculate(turning_power); + + m_drive_node->setDriveVoltage(0, (int)(total_turn_input * MAX_MOTOR_VOLTAGE)); + + if (m_inertial_sensor->isAtAngle(m_target_angle) && m_turn_timer.Get() == 0) { + m_turn_timer.Start(); + } else { + m_turn_timer.Stop(); + } + + if (m_turn_timer.Get() < 0.5) { + return CONTINUE; + } else { + return END; + } +} + +void TurnToAngleAction::ActionEnd() { + m_drive_node->setDriveVoltage(0, 0); +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/auton/auton_routines/TestPathAuton.cpp b/old-code/v5_hal/firmware/src/auton/auton_routines/TestPathAuton.cpp new file mode 100644 index 00000000..3bd37326 --- /dev/null +++ b/old-code/v5_hal/firmware/src/auton/auton_routines/TestPathAuton.cpp @@ -0,0 +1,23 @@ +#include "auton/auton_routines/TestPathAuton.h" + +TestPathAuton::TestPathAuton(IDriveNode* drive_node, OdometryNode* odom_node) : + Auton("Test Path Node"), + m_drive_node(drive_node), + m_odom_node(odom_node), + m_path_manager(PathManager::GetInstance()) { + +} + +void TestPathAuton::AddNodes() { + Path path = m_path_manager->GetPath("TestPath"); + Pose start_pose = path.getPathPoints().at(0).getPose(); + + m_odom_node->setCurrentPose(start_pose); + + Logger::logInfo("Set current pose of the robot to x:" + std::to_string(start_pose.position.x()) + + " | y:" + std::to_string(start_pose.position.y()) + " | angle:" + std::to_string(start_pose.angle.angle())); + + m_path_node = new AutonNode(20, new FollowPathAction(m_drive_node, m_odom_node, path, true)); + + Auton::AddFirstNode(m_path_node); +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/auton/auton_routines/TestPoseAuton.cpp b/old-code/v5_hal/firmware/src/auton/auton_routines/TestPoseAuton.cpp new file mode 100644 index 00000000..e6d857ef --- /dev/null +++ b/old-code/v5_hal/firmware/src/auton/auton_routines/TestPoseAuton.cpp @@ -0,0 +1,15 @@ +#include "auton/auton_routines/TestPoseAuton.h" + +TestPoseAuton::TestPoseAuton(IDriveNode* drive_node, OdometryNode* odom_node) : + Auton("Test Pose Node"), + m_drive_node(drive_node), + m_odom_node(odom_node) { + +} + +void TestPoseAuton::AddNodes() { + Pose pose(Vector2d(0., 10.), Rotation2Dd(0.)); + + m_pose_node = new AutonNode(10, new DriveToPoseAction(m_drive_node, m_odom_node, pose)); + Auton::AddFirstNode(m_pose_node); +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/auton/auton_routines/TestTurnAuton.cpp b/old-code/v5_hal/firmware/src/auton/auton_routines/TestTurnAuton.cpp new file mode 100644 index 00000000..7fcdd34c --- /dev/null +++ b/old-code/v5_hal/firmware/src/auton/auton_routines/TestTurnAuton.cpp @@ -0,0 +1,13 @@ +#include "auton/auton_routines/TestTurnAuton.h" + +TestTurnAuton::TestTurnAuton(IDriveNode* drive_node, InertialSensorNode* inertial_sensor_node) : + Auton("Test Turn Node"), m_drive_node(drive_node), m_inertial_sensor_node(inertial_sensor_node) { + +} + +void TestTurnAuton::AddNodes() { + Eigen::Rotation2Dd target_angle(M_PI_2); + + m_turn_node = new AutonNode(10, new TurnToAngleAction(m_drive_node, m_inertial_sensor_node, target_angle)); + Auton::AddFirstNode(m_turn_node); +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/duration.cpp b/old-code/v5_hal/firmware/src/duration.cpp new file mode 100644 index 00000000..e49ada9a --- /dev/null +++ b/old-code/v5_hal/firmware/src/duration.cpp @@ -0,0 +1,83 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote prducts derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "ros_lib/ros/duration.h" + +namespace ros +{ +void normalizeSecNSecSigned(int32_t &sec, int32_t &nsec) +{ + int32_t nsec_part = nsec; + int32_t sec_part = sec; + + while (nsec_part > 1000000000L) + { + nsec_part -= 1000000000L; + ++sec_part; + } + while (nsec_part < 0) + { + nsec_part += 1000000000L; + --sec_part; + } + sec = sec_part; + nsec = nsec_part; +} + +Duration& Duration::operator+=(const Duration &rhs) +{ + sec += rhs.sec; + nsec += rhs.nsec; + normalizeSecNSecSigned(sec, nsec); + return *this; +} + +Duration& Duration::operator-=(const Duration &rhs) +{ + sec += -rhs.sec; + nsec += -rhs.nsec; + normalizeSecNSecSigned(sec, nsec); + return *this; +} + +Duration& Duration::operator*=(double scale) +{ + sec *= scale; + nsec *= scale; + normalizeSecNSecSigned(sec, nsec); + return *this; +} + +} diff --git a/old-code/v5_hal/firmware/src/kinematics/HolonomicDriveKinematics.cpp b/old-code/v5_hal/firmware/src/kinematics/HolonomicDriveKinematics.cpp new file mode 100644 index 00000000..4767a250 --- /dev/null +++ b/old-code/v5_hal/firmware/src/kinematics/HolonomicDriveKinematics.cpp @@ -0,0 +1,100 @@ +#include "kinematics/HolonomicDriveKinematics.h" + +HolonomicDriveKinematics::HolonomicDriveKinematics(EncoderConfig encoder_config, HolonomicWheelLocations wheel_locations, + Pose current_pose) : IDriveKinematics(encoder_config, current_pose), + m_wheel_locations(wheel_locations) { + +} + +void HolonomicDriveKinematics::updateForwardKinematics(IDriveNode::FourMotorDriveEncoderVals encoder_vals) { + float left_front_dist = encoder_vals.left_front_encoder_val * m_ticks_to_distance_m; + float left_rear_dist = encoder_vals.left_rear_encoder_val * m_ticks_to_distance_m; + float right_front_dist = encoder_vals.right_front_encoder_val * m_ticks_to_distance_m; + float right_rear_dist = encoder_vals.right_rear_encoder_val * m_ticks_to_distance_m; + + float delta_time = m_timer.Get(); + + if (m_pose_reset) { + m_left_front_previous_dist = left_front_dist; + m_left_rear_previous_dist = left_rear_dist; + m_right_front_previous_dist = right_front_dist; + m_right_rear_previous_dist = right_rear_dist; + m_pose_reset = false; + } + + // Use a vector to describe the velocity of each wheel + Vector2d left_front_velocity((left_front_dist - m_left_front_previous_dist) / delta_time, 0); + Vector2d left_rear_velocity((left_rear_dist - m_left_front_previous_dist) / delta_time, 0); + Vector2d right_front_velocity((right_front_dist - m_left_front_previous_dist) / delta_time, 0); + Vector2d right_rear_velocity((right_rear_dist - m_left_front_previous_dist) / delta_time, 0); + + // Rotate each of the vectors to their respective orientations + left_front_velocity = Rotation2Dd(-3 * M_PI_4) * left_front_velocity; + left_rear_velocity = Rotation2Dd(-1 * M_PI_4) * left_rear_velocity; + right_front_velocity = Rotation2Dd(3 * M_PI_4) * right_front_velocity; + right_rear_velocity = Rotation2Dd(M_PI_4) * right_rear_velocity; + + // Calculate the robot translation as the average of all component vectors + Vector2d robot_velocity = (left_front_velocity + left_rear_velocity + + right_front_velocity + right_rear_velocity) / 4; + + float theta_velocity = (left_front_velocity.norm() / m_wheel_locations.left_front_location.norm()) + + (left_rear_velocity.norm() / m_wheel_locations.left_rear_location.norm()) + + (right_front_velocity.norm() / m_wheel_locations.right_front_location.norm()) + + (right_rear_velocity.norm() / m_wheel_locations.right_rear_location.norm()); + + + // Send the values to be integrated, to update our current robot position + IDriveKinematics::m_updateCurrentPosition(robot_velocity, theta_velocity, delta_time); + + // Update the previous values of each encoder + m_left_front_previous_dist = left_front_dist; + m_left_rear_previous_dist = left_rear_dist; + m_right_front_previous_dist = right_front_dist; + m_right_rear_previous_dist = right_rear_dist; + + // Restart the timer + m_timer.Start(); +} + +IDriveKinematics::FourMotorPercentages HolonomicDriveKinematics::inverseKinematics( + float x, float y, float theta, float max) { + float front_left = y + x - theta; + float back_left = y - x - theta; + float front_right = y - x + theta; + float back_right = y + x + theta; + + float max_val = std::max({fabs(front_left), fabs(back_left), fabs(front_right), fabs(back_right), max}); + + FourMotorPercentages motor_percentages { + front_left / max_val, + back_left / max_val, + front_right / max_val, + back_right / max_val + }; + + return motor_percentages; +} + +IDriveKinematics::FourMotorPercentages HolonomicDriveKinematics::tankKinematics( + float left_x, float left_y, float right_x, float right_y, float max) { + float front_left = left_x + left_y; + float back_left = -left_x + left_y; + float front_right = -right_x + right_y; + float back_right = right_x + right_y; + + float max_val = std::max({fabs(front_left), fabs(back_left), fabs(front_right), fabs(back_right), max}); + + FourMotorPercentages motor_percentages { + front_left / max_val, + back_left / max_val, + front_right / max_val, + back_right / max_val + }; + + return motor_percentages; +} + +HolonomicDriveKinematics::~HolonomicDriveKinematics() { + +} diff --git a/old-code/v5_hal/firmware/src/kinematics/IDriveKinematics.cpp b/old-code/v5_hal/firmware/src/kinematics/IDriveKinematics.cpp new file mode 100644 index 00000000..f84e23ba --- /dev/null +++ b/old-code/v5_hal/firmware/src/kinematics/IDriveKinematics.cpp @@ -0,0 +1,34 @@ +#include "kinematics/IDriveKinematics.h" + +IDriveKinematics::IDriveKinematics(EncoderConfig encoder_config, Pose current_pose) : + m_ticks_to_distance_m((encoder_config.wheel_diameter * M_PI) / + encoder_config.ticks_per_wheel_revolution) { + setCurrentPose(current_pose); +} + +void IDriveKinematics::m_updateCurrentPosition(Vector2d robot_velocity, float theta_velocity, float delta_time) { + // Multiply position and theta velocity by time to get position + Vector2d delta_position = robot_velocity * delta_time; + Rotation2Dd delta_theta(theta_velocity * delta_time); + + // Rotate the translation vector by the current angle rotation matrix + Vector2d robot_translation = delta_theta * delta_position; + + // Add the current translation onto the robot position vector + m_pose.position += robot_translation; + + // Rotate the stored robot angle by the delta angle + m_pose.angle = m_pose.angle * delta_theta; +} + +Pose IDriveKinematics::getPose() { + return m_pose; +} + +void IDriveKinematics::setCurrentPose(Pose current_pose) { + m_pose = current_pose; +} + +IDriveKinematics::~IDriveKinematics() { + +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/kinematics/TankDriveKinematics.cpp b/old-code/v5_hal/firmware/src/kinematics/TankDriveKinematics.cpp new file mode 100644 index 00000000..739941e7 --- /dev/null +++ b/old-code/v5_hal/firmware/src/kinematics/TankDriveKinematics.cpp @@ -0,0 +1,49 @@ +#include "kinematics/TankDriveKinematics.h" + +TankDriveKinematics::TankDriveKinematics(EncoderConfig encoder_config, TankWheelLocations wheel_locations, + Pose current_pose) : IDriveKinematics(encoder_config, current_pose), + m_wheel_locations(wheel_locations) { + +} + +void TankDriveKinematics::updateForwardKinematics(IDriveNode::FourMotorDriveEncoderVals encoder_vals) { + // TODO same math from TankPathPursuit +} + +IDriveKinematics::FourMotorPercentages TankDriveKinematics::inverseKinematics( + float x, float y, float theta, float max) { + float left = y - theta; + float right = y + theta; + + float max_val = std::max({fabs(left), fabs(right), max}); + + FourMotorPercentages motor_percentages { + left / max_val, + left / max_val, + right / max_val, + right / max_val + }; + + return motor_percentages; +} + +IDriveKinematics::FourMotorPercentages TankDriveKinematics::simpleKinematics( + float left_x, float left_y, float right_x, float right_y, float max) { + float left = left_y; + float right = right_y; + + float max_val = std::max({fabs(left), fabs(right), max}); + + FourMotorPercentages motor_percentages { + left / max_val, + left / max_val, + right / max_val, + right / max_val + }; + + return motor_percentages; +} + +TankDriveKinematics::~TankDriveKinematics() { + +} diff --git a/old-code/v5_hal/firmware/src/main.cpp b/old-code/v5_hal/firmware/src/main.cpp new file mode 100644 index 00000000..90226b25 --- /dev/null +++ b/old-code/v5_hal/firmware/src/main.cpp @@ -0,0 +1,172 @@ +#include "main.h" + +NodeManager* node_manager = new NodeManager(pros::millis); + +// Declare all nodes here +ControllerNode* primary_controller; + +MotorNode* left_front_drive; +MotorNode* left_front_drive_2; +MotorNode* left_rear_drive; +MotorNode* left_rear_drive_2; +MotorNode* right_front_drive; +MotorNode* right_front_drive_2; +MotorNode* right_rear_drive; +MotorNode* right_rear_drive_2; +TankDriveNode* holonomic_drive_node; + +ADIEncoderNode* x_odom_encoder; +ADIEncoderNode* y_odom_encoder; + +InertialSensorNode* inertial_sensor; + +OdometryNode* odom_node; + +AutonManagerNode* auton_manager_node; + +ConnectionCheckerNode* connection_checker_node; + +/** + * Runs initialization code. This occurs as soon as the program is started. + * + * All other competition modes are blocked by initialize; it is recommended + * to keep execution time for this mode under a few seconds. + */ +void initialize() { + Logger::giveNodeManager(node_manager); + + // Define all nodes used by the robot here + primary_controller = new ControllerNode(node_manager, "primary"); + + /* Define the odometry components */ + x_odom_encoder = + new ADIEncoderNode(node_manager, 'A', 'B', "xOdomEncoder", false); + y_odom_encoder = + new ADIEncoderNode(node_manager, 'C', 'D', "yOdomEncoder", false); + + inertial_sensor = + new InertialSensorNode(node_manager, "inertialSensor", 20); // Port 14 + + /* Define the drivetrain components */ + left_front_drive = + new MotorNode(node_manager, 17, "leftFrontDrive", true); // previously 16 + left_front_drive_2 = + new MotorNode(node_manager, 18, "leftFrontTopDrive", true); + left_rear_drive = new MotorNode(node_manager, 15, "leftRearDrive", true); + left_rear_drive_2 = new MotorNode(node_manager, 11, "leftRearTopDrive", true); + + right_front_drive = new MotorNode(node_manager, 13, "rightFrontDrive", false); + right_front_drive_2 = + new MotorNode(node_manager, 14, "rightFrontTopDrive", false); + right_rear_drive = + new MotorNode(node_manager, 9, "rightRearDrive", false); // 2 is ded + right_rear_drive_2 = + new MotorNode(node_manager, 10, "rightRearTopDrive", false); // prev + + odom_node = new OdometryNode( + node_manager, "odometry", x_odom_encoder, y_odom_encoder, inertial_sensor, + OdometryNode::FOLLOWER); + + TankDriveNode::TankEightMotors holonomic_drive_motors = { + left_front_drive, left_front_drive_2, left_rear_drive, + left_rear_drive_2, right_front_drive, right_front_drive_2, + right_rear_drive, right_rear_drive_2}; + + EncoderConfig holonomic_encoder_config = { + 0, // Initial ticks + 360, // Ticks per RPM + 3.75 // Wheel diameter + }; + + TankDriveKinematics::TankWheelLocations holonomic_wheel_locations = { + Vector2d(-5.48, 5.48), // Left front + Vector2d(5.48, 5.48), // Right front + }; + + TankDriveKinematics holonomic_drive_kinematics( + holonomic_encoder_config, holonomic_wheel_locations); + + holonomic_drive_node = new TankDriveNode( + node_manager, "drivetrain", primary_controller, holonomic_drive_motors, + holonomic_drive_kinematics); + + /* Define other components */ + connection_checker_node = new ConnectionCheckerNode(node_manager); + + /* Define autonomous components */ + auton_manager_node = new AutonManagerNode( + node_manager, holonomic_drive_node, odom_node, inertial_sensor); + + // Call the node manager to initialize all of the nodes above + node_manager->initialize(); +} + +/** + * Runs while the robot is in the disabled state of Field Management System or + * the VEX Competition Switch, following either autonomous or opcontrol. When + * the robot is enabled, this task will exit. + */ +void disabled() { + while (pros::competition::is_disabled()) { + node_manager->m_handle->spinOnce(); + } +} + +/** + * Runs after initialize(), and before autonomous when connected to the Field + * Management System or the VEX Competition Switch. This is intended for + * competition-specific initialization routines, such as an autonomous selector + * on the LCD. + * + * This task will exit when the robot is enabled and autonomous or opcontrol + * starts. + */ +void competition_initialize() {} + +/** + * Runs the user autonomous code. This function will be started in its own task + * with the default priority and stack size whenever the robot is enabled via + * the Field Management System or the VEX Competition Switch in the autonomous + * mode. Alternatively, this function may be called in initialize or opcontrol + * for non-competition testing purposes. + * + * If the robot is disabled or communications is lost, the autonomous task + * will be stopped. Re-enabling the robot will restart the task, not re-start it + * from where it left off. + */ +void autonomous() { + // Reset all nodes to default configuration + node_manager->reset(); + + // Reset the chosen autonomous and initialize + auton_manager_node->selected_auton->AutonInit(); + + // Execute autonomous code + while (pros::competition::is_autonomous()) { node_manager->executeAuton(); } +} + +/** + * Runs the operator control code. This function will be started in its own task + * with the default priority and stack size whenever the robot is enabled via + * the Field Management System or the VEX Competition Switch in the operator + * control mode. + * + * If no competition control is connected, this function will run immediately + * following initialize(). + * + * If the robot is disabled or communications is lost, the + * operator control task will be stopped. Re-enabling the robot will restart the + * task, not resume it from where it left off. + * + * NOTE: If custom code is needed outside of the node manager, it should be put + * into a different task with a wait. Each node has an embedded timing control + * loop and adding a wait to this thread will disrupt the performance of all + * nodes. + */ +void opcontrol() { + // Reset all nodes to default configuration + node_manager->reset(); + + // Execute teleop code + while (true) { node_manager->executeTeleop(); } +} diff --git a/old-code/v5_hal/firmware/src/nodes/NodeManager.cpp b/old-code/v5_hal/firmware/src/nodes/NodeManager.cpp new file mode 100644 index 00000000..a18cae2a --- /dev/null +++ b/old-code/v5_hal/firmware/src/nodes/NodeManager.cpp @@ -0,0 +1,60 @@ +#include "nodes/NodeManager.h" + +NodeManager::NodeManager(uint32_t(*get_milliseconds)(void)) { + m_get_millis = get_milliseconds; + m_handle = new ros::NodeHandle(); +} + +ros::NodeHandle* NodeManager::addNode(Node* node, + uint32_t interval_milliseconds) { + NodeManager::NodeStructure node_structure = { node, interval_milliseconds, 0 }; + m_node_structures.push_back(node_structure); + + return m_handle; +} + +void NodeManager::initialize() { + m_handle->initNode(); + + for (auto node_structure : m_node_structures) { + node_structure.node->initialize(); + } +} + +void NodeManager::reset() { + for (auto& node_structure : m_node_structures) { + node_structure.last_executed_millis = 0; + } +} + +void NodeManager::executeTeleop() { + m_handle->spinOnce(); + + for (auto& node_structure : m_node_structures) { + auto current_time = m_get_millis(); + if (current_time - node_structure.last_executed_millis >= + node_structure.trigger_millis) { + node_structure.node->teleopPeriodic(); + node_structure.last_executed_millis = current_time; + } + } + + pros::c::delay(DELAY_TIME_MILLIS); +} + +void NodeManager::executeAuton() { + m_handle->spinOnce(); + + for (auto& node_structure : m_node_structures) { + auto current_time = m_get_millis(); + if (current_time - node_structure.last_executed_millis >= + node_structure.trigger_millis) { + node_structure.node->autonPeriodic(); + node_structure.last_executed_millis = current_time; + } + } + + pros::c::delay(DELAY_TIME_MILLIS); +} + +NodeManager::~NodeManager() { m_node_structures.clear(); } \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/nodes/actuator_nodes/MotorNode.cpp b/old-code/v5_hal/firmware/src/nodes/actuator_nodes/MotorNode.cpp new file mode 100644 index 00000000..3fd835d8 --- /dev/null +++ b/old-code/v5_hal/firmware/src/nodes/actuator_nodes/MotorNode.cpp @@ -0,0 +1,95 @@ +#include "nodes/actuator_nodes/MotorNode.h" + +// By default, this constructor calls the constructor for the Node object in +// NodeManager.h +MotorNode::MotorNode(NodeManager* node_manager, int port_number, + std::string handle_name, bool reverse, + pros::motor_gearset_e_t gearset) : Node(node_manager, 10), + m_motor(port_number, gearset, reverse) { + m_handle_name = handle_name.insert(0, "motor/"); + m_sub_move_motor_voltage_name = m_handle_name + "/moveMotorVoltage"; + m_sub_publish_data_name = m_handle_name + "/publish"; + + m_publisher = new ros::Publisher(m_handle_name.c_str(), &m_motor_msg); + + m_publish_data_sub = new ros::Subscriber + (m_sub_publish_data_name.c_str(), &MotorNode::m_publishData, this); + + m_move_motor_voltage_sub = new ros::Subscriber + (m_sub_move_motor_voltage_name.c_str(), &MotorNode::m_moveMotorVoltage, this); +} + +void MotorNode::m_publishData(const std_msgs::Empty& msg) { + m_populateMessage(); + m_publisher->publish(&m_motor_msg); +} + +void MotorNode::m_moveMotorVoltage(const std_msgs::Int8& msg) { + float voltage = (msg.data / 127.0) * (float) MAX_MOTOR_VOLTAGE; + moveVoltage((int)voltage); +} + +int MotorNode::m_getMaxRPM() { + switch (m_motor.get_gearing()) { + case pros::E_MOTOR_GEARSET_06: + return 600; + case pros::E_MOTOR_GEARSET_18: + return 200; + case pros::E_MOTOR_GEARSET_36: + return 100; + default: + return 200; + } +} + +void MotorNode::initialize() { + // Initialize the handler, and set up data to publish + Node::m_handle->advertise(*m_publisher); + Node::m_handle->subscribe(*m_move_motor_voltage_sub); +} + +void MotorNode::resetEncoder() { + m_motor.tare_position(); +} + +int MotorNode::getPosition() { + return m_motor.get_position(); +} + +void MotorNode::move(int value) { + m_motor.move(value); +} + +void MotorNode::moveVoltage(int voltage) { + m_motor.move_voltage(voltage); +} + +void MotorNode::moveVelocity(float velocity) { + float rpm = (velocity / MAX_VELOCITY) * m_getMaxRPM(); + m_motor.move_velocity(rpm); +} + +void MotorNode::moveAbsolute(double position, int max_velocity) { + m_motor.move_absolute(position, max_velocity); +} + +void MotorNode::teleopPeriodic() { + +} + +void MotorNode::autonPeriodic() { + +} + +void MotorNode::m_populateMessage() { + m_motor_msg.direction = m_motor.get_direction(); + m_motor_msg.position = m_motor.get_position(); + m_motor_msg.velocity = m_motor.get_actual_velocity(); + m_motor_msg.voltage = m_motor.get_voltage(); +} + +MotorNode::~MotorNode() { + delete m_publisher; + delete m_publish_data_sub; + delete m_move_motor_voltage_sub; +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/nodes/auton_nodes/AutonManagerNode.cpp b/old-code/v5_hal/firmware/src/nodes/auton_nodes/AutonManagerNode.cpp new file mode 100644 index 00000000..b3ba103e --- /dev/null +++ b/old-code/v5_hal/firmware/src/nodes/auton_nodes/AutonManagerNode.cpp @@ -0,0 +1,17 @@ +#include "nodes/auton_nodes/AutonManagerNode.h" + +AutonManagerNode::AutonManagerNode( + NodeManager* node_manager, IDriveNode* drive_node, + OdometryNode* odometry_node, InertialSensorNode* inertial_sensor_node) + : Node(node_manager, 50) { + m_test_path_auton = new TestPathAuton(drive_node, odometry_node); + selected_auton = m_test_path_auton; +} + +void AutonManagerNode::initialize() { + PathManager::GetInstance()->LoadPathsFile("/usd/path.json"); +} + +void AutonManagerNode::autonPeriodic() { + if (!selected_auton->Complete()) { selected_auton->AutonPeriodic(); } +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/nodes/odometry_nodes/OdometryNode.cpp b/old-code/v5_hal/firmware/src/nodes/odometry_nodes/OdometryNode.cpp new file mode 100644 index 00000000..8acfdaab --- /dev/null +++ b/old-code/v5_hal/firmware/src/nodes/odometry_nodes/OdometryNode.cpp @@ -0,0 +1,58 @@ +#include "nodes/odometry_nodes/OdometryNode.h" + +OdometryNode::OdometryNode(NodeManager* node_manager, std::string handle_name, + ADIEncoderNode* odom_encoder_1, ADIEncoderNode* odom_encoder_2, InertialSensorNode* inertial_sensor_node, + OdomConfig odom_config) : Node(node_manager, 50), m_handle_name(handle_name), + m_odom_encoder_1(odom_encoder_1), m_odom_encoder_2(odom_encoder_2), m_inertial_sensor_node(inertial_sensor_node), + m_current_angle_offset(0), m_odom_config(odom_config) { + m_odom = m_getOdomClass(odom_config); +} + +OdometryNode::OdometryNode(NodeManager* node_manager, std::string handle_name, + MotorNode* motor_1, MotorNode* motor_2, InertialSensorNode* inertial_sensor_node, + OdomConfig odom_config) : Node(node_manager, 50), m_handle_name(handle_name), + m_motor_1(motor_1), m_motor_2(motor_2), m_inertial_sensor_node(inertial_sensor_node), + m_current_angle_offset(0), m_odom_config(odom_config) { + m_odom = m_getOdomClass(odom_config); +} + +Odometry* OdometryNode::m_getOdomClass(OdomConfig config) { + EncoderConfig adi_encoder_config = {0., 360., 2.8}; + EncoderConfig v5_integrated_encoder_config = {0., 900., 4.0625}; + + switch (config) { + case FOLLOWER: + return new FollowerOdometry(adi_encoder_config, adi_encoder_config); + case TANK: + return new TankOdometry(v5_integrated_encoder_config, v5_integrated_encoder_config); + default: + Node::m_handle->logerror("Error creating odometry instance in OdometryNode.cpp"); + return new FollowerOdometry(adi_encoder_config, adi_encoder_config); + } +} + +void OdometryNode::initialize() { + // Calibrate the gyro, and reset the orientation with the correct gyro angle + m_inertial_sensor_node->reset(); + setCurrentPose(Pose(Vector2d(0, 0), m_inertial_sensor_node->getYaw())); +} + +void OdometryNode::setCurrentPose(Pose pose) { + m_odom->SetCurrentPose(pose); +} + +Pose OdometryNode::getCurrentPose() { + return m_odom->GetPose(); +} + +void OdometryNode::teleopPeriodic() { + m_odom->Update(m_odom_encoder_1->getValue(), m_odom_encoder_2->getValue(), m_inertial_sensor_node->getYaw()); +} + +void OdometryNode::autonPeriodic() { + m_odom->Update(m_odom_encoder_1->getValue(), m_odom_encoder_2->getValue(), m_inertial_sensor_node->getYaw()); +} + +OdometryNode::~OdometryNode() { + delete m_odom; +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/nodes/sensor_nodes/ADIEncoderNode.cpp b/old-code/v5_hal/firmware/src/nodes/sensor_nodes/ADIEncoderNode.cpp new file mode 100644 index 00000000..017353c4 --- /dev/null +++ b/old-code/v5_hal/firmware/src/nodes/sensor_nodes/ADIEncoderNode.cpp @@ -0,0 +1,46 @@ +#include "nodes/sensor_nodes/ADIEncoderNode.h" + +// By default, this constructor calls the constructor for the Node object in +// NodeManager.h +ADIEncoderNode::ADIEncoderNode(NodeManager* node_manager, int port_top, + int port_bottom, std::string handle_name, bool reverse) : Node(node_manager, 100), + m_encoder(port_top, port_bottom, reverse) { + m_handle_name = handle_name.insert(0, "sensor/"); + m_sub_publish_data_name = m_handle_name + "/publish"; + + m_publisher = new ros::Publisher(m_handle_name.c_str(), &m_encoder_msg); + + m_publish_data_sub = new ros::Subscriber + (m_sub_publish_data_name.c_str(), &ADIEncoderNode::m_publishData, this); +} + +void ADIEncoderNode::m_publishData(const std_msgs::Empty& msg) { + m_populateMessage(); + m_publisher->publish(&m_encoder_msg); +} + +void ADIEncoderNode::initialize() { + // Initialize the handler, and set up data to publish + Node::m_handle->advertise(*m_publisher); +} + +int ADIEncoderNode::getValue() { + return m_encoder.get_value(); +} + +void ADIEncoderNode::teleopPeriodic() { + // std::string msg = m_handle_name + " value: " + std::to_string(getValue()); + // m_handle->logwarn(msg.c_str()); +} + +void ADIEncoderNode::autonPeriodic() { + +} + +void ADIEncoderNode::m_populateMessage() { + m_encoder_msg.data = getValue(); +} + +ADIEncoderNode::~ADIEncoderNode() { + delete m_publisher; +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/nodes/sensor_nodes/ControllerNode.cpp b/old-code/v5_hal/firmware/src/nodes/sensor_nodes/ControllerNode.cpp new file mode 100644 index 00000000..5f1c8772 --- /dev/null +++ b/old-code/v5_hal/firmware/src/nodes/sensor_nodes/ControllerNode.cpp @@ -0,0 +1,82 @@ +#include "nodes/sensor_nodes/ControllerNode.h" + +//This constructor also calls the Node constructor from NodeManager.h +//The Node class constructor automatically adds the node so we don't have to? + +//controller_id_e_t is a typedef'ed enum which can be located in the pros/misc.h file +//It can only be E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER +//CONTROLLER_MASTER and CONTROLLER_PARTNER are #define as their E_ counterparts +ControllerNode::ControllerNode(NodeManager* node_manager, std::string handle_name, + pros::controller_id_e_t controller_id) : Node(node_manager, 10), + m_controller(controller_id) { + m_handle_name = handle_name.insert(0, "joystick/"); + m_sub_controller_rumble_name = m_handle_name + "/joystickRumble"; + m_sub_publish_data_name = m_handle_name + "/publish"; + + m_publisher = new ros::Publisher(m_handle_name.c_str(), &m_controller_msg); + + m_publish_data_sub = new ros::Subscriber + (m_sub_publish_data_name.c_str(), &ControllerNode::m_publishData, this); + + m_rumble_controller_sub = new ros::Subscriber + (m_sub_controller_rumble_name.c_str(), &ControllerNode::m_rumbleController, this); +} + +void ControllerNode::m_publishData(const std_msgs::Empty& msg) { + m_populateMessage(); + m_publisher->publish(&m_controller_msg); +} + +void ControllerNode::m_rumbleController(const std_msgs::String& msg) { + std::string str = msg.data; + if (str.length() <= 8) { + m_controller.rumble(str.c_str()); + } else { + m_handle->logwarn("Rumble string exceeds 8 characters, will be discarded"); + } +} + +void ControllerNode::initialize() { + // Initialize the handler, and set up data to publish + Node::m_handle->initNode(); + Node::m_handle->advertise(*m_publisher); + Node::m_handle->subscribe(*m_rumble_controller_sub); +} + +pros::Controller* ControllerNode::getController() { + return &m_controller; +} + +void ControllerNode::teleopPeriodic() { + +} + +void ControllerNode::autonPeriodic() { + +} + +//Populates the V5Controller message object +void ControllerNode::m_populateMessage() { + m_controller_msg.analog_left_x = m_controller.get_analog(pros::E_CONTROLLER_ANALOG_LEFT_X); + m_controller_msg.analog_left_y = m_controller.get_analog(pros::E_CONTROLLER_ANALOG_LEFT_Y); + m_controller_msg.analog_right_x = m_controller.get_analog(pros::E_CONTROLLER_ANALOG_RIGHT_X); + m_controller_msg.analog_right_y = m_controller.get_analog(pros::E_CONTROLLER_ANALOG_RIGHT_Y); + m_controller_msg.btn_right = (bool)m_controller.get_digital(pros::E_CONTROLLER_DIGITAL_RIGHT); + m_controller_msg.btn_down = (bool)m_controller.get_digital(pros::E_CONTROLLER_DIGITAL_DOWN); + m_controller_msg.btn_left = (bool)m_controller.get_digital(pros::E_CONTROLLER_DIGITAL_LEFT); + m_controller_msg.btn_up = (bool)m_controller.get_digital(pros::E_CONTROLLER_DIGITAL_UP); + m_controller_msg.btn_a = (bool)m_controller.get_digital(pros::E_CONTROLLER_DIGITAL_A); + m_controller_msg.btn_b = (bool)m_controller.get_digital(pros::E_CONTROLLER_DIGITAL_B); + m_controller_msg.btn_x = (bool)m_controller.get_digital(pros::E_CONTROLLER_DIGITAL_X); + m_controller_msg.btn_y = (bool)m_controller.get_digital(pros::E_CONTROLLER_DIGITAL_Y); + m_controller_msg.btn_r1 = (bool)m_controller.get_digital(pros::E_CONTROLLER_DIGITAL_R1); + m_controller_msg.btn_r2 = (bool)m_controller.get_digital(pros::E_CONTROLLER_DIGITAL_R2); + m_controller_msg.btn_l1 = (bool)m_controller.get_digital(pros::E_CONTROLLER_DIGITAL_L1); + m_controller_msg.btn_l2 = (bool)m_controller.get_digital(pros::E_CONTROLLER_DIGITAL_L2); + m_controller_msg.is_connected = (bool)m_controller.is_connected(); +} + +ControllerNode::~ControllerNode() { + delete m_publisher; + delete m_rumble_controller_sub; +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/nodes/sensor_nodes/InertialSensorNode.cpp b/old-code/v5_hal/firmware/src/nodes/sensor_nodes/InertialSensorNode.cpp new file mode 100644 index 00000000..21c4ab3f --- /dev/null +++ b/old-code/v5_hal/firmware/src/nodes/sensor_nodes/InertialSensorNode.cpp @@ -0,0 +1,88 @@ +#include "nodes/sensor_nodes/InertialSensorNode.h" + +InertialSensorNode::InertialSensorNode(NodeManager* node_manager, + std::string handle_name, int sensor_port) : Node(node_manager, 20), + m_yaw(0), m_gyro_offset_angle(GYRO_OFFSET) { + m_handle_name = handle_name.insert(0, "sensor/"); + m_config = V5; + + m_inertial_sensor = new pros::Imu(sensor_port); +} + +InertialSensorNode::InertialSensorNode(NodeManager* node_manager, std::string handle_name, + std::string subscribe_handle) : Node(node_manager, 20), m_yaw(0), m_gyro_offset_angle(GYRO_OFFSET), + m_sub_inertial_sensor_name(subscribe_handle) { + m_handle_name = handle_name.insert(0, "sensor/"); + m_config = ROS; + + m_inertial_sensor_sub = new ros::Subscriber + (m_sub_inertial_sensor_name.c_str(), &InertialSensorNode::m_handleSensorMsg, this); +} + +void InertialSensorNode::m_handleSensorMsg(const v5_hal::RollPitchYaw& msg) { + // Convert value to radians + Eigen::Rotation2Dd current_angle(msg.yaw * (M_PI/180)); + // Rotate by the initial angle to get our current yaw + m_yaw = current_angle.inverse() * m_gyro_offset_angle; +} + +Eigen::Rotation2Dd InertialSensorNode::m_getV5Yaw() { + Eigen::Rotation2Dd current_angle(m_inertial_sensor->get_yaw() * -(M_PI/180)); + return current_angle * m_gyro_offset_angle; +} + +void InertialSensorNode::initialize() { + switch (m_config) { + case V5: + m_inertial_sensor->reset(); + break; + case ROS: + Node::m_handle->subscribe(*m_inertial_sensor_sub); + break; + default: + Node::m_handle->logerror("Error initializing inertial sensor"); + } +} + +Eigen::Rotation2Dd InertialSensorNode::getYaw() { + return m_yaw; +} + +bool InertialSensorNode::isAtAngle(Eigen::Rotation2Dd angle) { + return fabs((m_yaw * angle.inverse()).smallestAngle()) < turning_threshold; +} + +void InertialSensorNode::reset() { + m_inertial_sensor->reset(); + pros::delay(5000); + m_yaw = m_getV5Yaw(); +} + +void InertialSensorNode::teleopPeriodic() { + switch (m_config) { + case V5: + if (!(m_inertial_sensor->is_calibrating())) { + // Convert sensor input to radians, and reverse orientation + m_yaw = m_getV5Yaw(); + } + } +} + +void InertialSensorNode::autonPeriodic() { + switch (m_config) { + case V5: + if (!m_inertial_sensor->is_calibrating()) { + // Convert sensor input to radians, and reverse orientation + m_yaw = m_getV5Yaw(); + } + } +} + +InertialSensorNode::~InertialSensorNode () { + switch (m_config) { + case V5: + delete m_inertial_sensor; + case ROS: + delete m_inertial_sensor_sub; + } +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/nodes/subsystems/drivetrain_nodes/HolonomicDriveNode.cpp b/old-code/v5_hal/firmware/src/nodes/subsystems/drivetrain_nodes/HolonomicDriveNode.cpp new file mode 100644 index 00000000..1bb9e4e0 --- /dev/null +++ b/old-code/v5_hal/firmware/src/nodes/subsystems/drivetrain_nodes/HolonomicDriveNode.cpp @@ -0,0 +1,151 @@ +#include "nodes/subsystems/drivetrain_nodes/HolonomicDriveNode.h" + +HolonomicDriveNode::HolonomicDriveNode(NodeManager* node_manager, std::string handle_name, ControllerNode* controller, + InertialSensorNode* inertial_sensor, HolonomicEightMotors motors, HolonomicDriveKinematics kinematics) : + IDriveNode(node_manager), + m_controller(controller->getController()), + m_inertial_sensor(inertial_sensor), + m_motors(motors), + m_kinematics(kinematics) { + m_handle_name = handle_name.insert(0, "robot/"); +} + +void HolonomicDriveNode::m_setLeftFrontVoltage(int voltage) { + m_motors.left_front_motor->moveVoltage(voltage); + m_motors.left_front_motor_2->moveVoltage(voltage); +} + +void HolonomicDriveNode::m_setLeftRearVoltage(int voltage) { + m_motors.left_rear_motor->moveVoltage(voltage); + m_motors.left_rear_motor_2->moveVoltage(voltage); +} + +void HolonomicDriveNode::m_setRightFrontVoltage(int voltage) { + m_motors.right_front_motor->moveVoltage(voltage); + m_motors.right_front_motor_2->moveVoltage(voltage); +} + +void HolonomicDriveNode::m_setRightRearVoltage(int voltage) { + m_motors.right_rear_motor->moveVoltage(voltage); + m_motors.right_rear_motor_2->moveVoltage(voltage); +} + +void HolonomicDriveNode::m_setLeftFrontVelocity(float velocity) { + m_motors.left_front_motor->moveVelocity(velocity); + m_motors.left_front_motor_2->moveVelocity(velocity); +} + +void HolonomicDriveNode::m_setLeftRearVelocity(float velocity) { + m_motors.left_rear_motor->moveVelocity(velocity); + m_motors.left_rear_motor_2->moveVelocity(velocity); +} + +void HolonomicDriveNode::m_setRightFrontVelocity(float velocity) { + m_motors.right_front_motor->moveVelocity(velocity); + m_motors.right_front_motor_2->moveVelocity(velocity); +} + +void HolonomicDriveNode::m_setRightRearVelocity(float velocity) { + m_motors.right_rear_motor->moveVelocity(velocity); + m_motors.right_rear_motor_2->moveVelocity(velocity); +} + +void HolonomicDriveNode::m_fieldOrientedControl() { + controller_target_velocity(0) = (m_controller->get_analog(pros::E_CONTROLLER_ANALOG_LEFT_X) / 127.0) * MAX_VELOCITY; + controller_target_velocity(1) = (m_controller->get_analog(pros::E_CONTROLLER_ANALOG_LEFT_Y) / 127.0) * MAX_VELOCITY; + rotation_velocity = -(m_controller->get_analog(pros::E_CONTROLLER_ANALOG_RIGHT_X) / 127.0) * MAX_VELOCITY; + + field_target_velocity = m_inertial_sensor->getYaw().inverse() * Rotation2Dd(GYRO_OFFSET) * controller_target_velocity; + setDriveVelocity(field_target_velocity.x(), field_target_velocity.y(), rotation_velocity); +} + +void HolonomicDriveNode::m_tankControl() { + int left_x = (m_controller->get_analog(pros::E_CONTROLLER_ANALOG_LEFT_X) / 127.0) * MAX_MOTOR_VOLTAGE; + int left_y = (m_controller->get_analog(pros::E_CONTROLLER_ANALOG_LEFT_Y) / 127.0) * MAX_MOTOR_VOLTAGE; + + int right_x = (m_controller->get_analog(pros::E_CONTROLLER_ANALOG_RIGHT_X) / 127.0) * MAX_MOTOR_VOLTAGE; + int right_y = (m_controller->get_analog(pros::E_CONTROLLER_ANALOG_RIGHT_Y) / 127.0) * MAX_MOTOR_VOLTAGE; + + setDriveVoltage(left_x, left_y, right_x, right_y); +} + +void HolonomicDriveNode::initialize() { + resetEncoders(); +} + +void HolonomicDriveNode::resetEncoders() { + m_motors.left_front_motor->resetEncoder(); + m_motors.left_front_motor_2->resetEncoder(); + m_motors.left_rear_motor->resetEncoder(); + m_motors.left_rear_motor_2->resetEncoder(); + m_motors.right_front_motor->resetEncoder(); + m_motors.right_front_motor_2->resetEncoder(); + m_motors.right_rear_motor->resetEncoder(); + m_motors.right_rear_motor_2->resetEncoder(); +} + +IDriveNode::FourMotorDriveEncoderVals HolonomicDriveNode::getIntegratedEncoderVals() { + return FourMotorDriveEncoderVals { + m_motors.left_front_motor->getPosition(), + m_motors.left_rear_motor->getPosition(), + m_motors.right_front_motor->getPosition(), + m_motors.right_rear_motor->getPosition() + }; +} + +void HolonomicDriveNode::setDriveVoltage(int x_voltage, int theta_voltage) { + setDriveVoltage(x_voltage, 0, theta_voltage); +} + +void HolonomicDriveNode::setDriveVoltage(int x_voltage, int y_voltage, int theta_voltage) { + IDriveKinematics::FourMotorPercentages motor_percentages = + m_kinematics.inverseKinematics(x_voltage, y_voltage, theta_voltage, MAX_MOTOR_VOLTAGE); + + m_setLeftFrontVoltage(motor_percentages.left_front_percent * MAX_MOTOR_VOLTAGE); + m_setLeftRearVoltage(motor_percentages.left_rear_percent * MAX_MOTOR_VOLTAGE); + m_setRightFrontVoltage(motor_percentages.right_front_percent * MAX_MOTOR_VOLTAGE); + m_setRightRearVoltage(motor_percentages.right_rear_percent * MAX_MOTOR_VOLTAGE); +} + +void HolonomicDriveNode::setDriveVoltage(int left_x, int left_y, int right_x, int right_y) { + IDriveKinematics::FourMotorPercentages motor_percentages = + m_kinematics.tankKinematics(0, left_y, 0, right_y, MAX_MOTOR_VOLTAGE); + + m_setLeftFrontVoltage(motor_percentages.left_front_percent * MAX_MOTOR_VOLTAGE); + m_setLeftRearVoltage(motor_percentages.left_rear_percent * MAX_MOTOR_VOLTAGE); + m_setRightFrontVoltage(motor_percentages.right_front_percent * MAX_MOTOR_VOLTAGE); + m_setRightRearVoltage(motor_percentages.right_rear_percent * MAX_MOTOR_VOLTAGE); +} + +void HolonomicDriveNode::setDriveVelocity(float x_velocity, float theta_velocity) { + setDriveVelocity(x_velocity, 0, theta_velocity); +} + +void HolonomicDriveNode::setDriveVelocity(float x_velocity, float y_velocity, float theta_velocity) { + IDriveKinematics::FourMotorPercentages motor_percentages = + m_kinematics.inverseKinematics(x_velocity, y_velocity, theta_velocity, MAX_VELOCITY); + + m_setLeftFrontVelocity(motor_percentages.left_front_percent * MAX_VELOCITY); + m_setLeftRearVelocity(motor_percentages.left_rear_percent * MAX_VELOCITY); + m_setRightFrontVelocity(motor_percentages.right_front_percent * MAX_VELOCITY); + m_setRightRearVelocity(motor_percentages.right_rear_percent * MAX_VELOCITY); +} + +void HolonomicDriveNode::teleopPeriodic() { + m_fieldOrientedControl(); +} + +void HolonomicDriveNode::autonPeriodic() { + +} + +HolonomicDriveNode::~HolonomicDriveNode() { + delete m_motors.left_front_motor; + delete m_motors.left_front_motor_2; + delete m_motors.left_rear_motor; + delete m_motors.left_rear_motor_2; + delete m_motors.right_front_motor; + delete m_motors.right_front_motor_2; + delete m_motors.right_rear_motor; + delete m_motors.right_rear_motor_2; +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/nodes/subsystems/drivetrain_nodes/TankDriveNode.cpp b/old-code/v5_hal/firmware/src/nodes/subsystems/drivetrain_nodes/TankDriveNode.cpp new file mode 100644 index 00000000..b729af7f --- /dev/null +++ b/old-code/v5_hal/firmware/src/nodes/subsystems/drivetrain_nodes/TankDriveNode.cpp @@ -0,0 +1,129 @@ +#include "nodes/subsystems/drivetrain_nodes/TankDriveNode.h" +TankDriveNode::TankDriveNode(NodeManager* node_manager, std::string handle_name, ControllerNode* controller, + TankEightMotors motors, TankDriveKinematics kinematics) : IDriveNode(node_manager), + m_controller(controller->getController()), + m_motors(motors), + m_kinematics(kinematics) { + + m_handle_name = handle_name.insert(0, "robot/"); +} + +void TankDriveNode::m_setLeftPosition(float distance, int max_velocity) { + m_motors.left_1_motor->moveAbsolute(distance, max_velocity); + m_motors.left_2_motor->moveAbsolute(distance, max_velocity); + m_motors.left_3_motor->moveAbsolute(distance, max_velocity); + m_motors.left_4_motor->moveAbsolute(distance, max_velocity); +} + +void TankDriveNode::m_setRightPosition(float distance, int max_velocity) { + m_motors.right_1_motor->moveAbsolute(distance, max_velocity); + m_motors.right_2_motor->moveAbsolute(distance, max_velocity); + m_motors.right_3_motor->moveAbsolute(distance, max_velocity); + m_motors.right_4_motor->moveAbsolute(distance, max_velocity); +} + +void TankDriveNode::setLeftVoltage(int voltage) { + m_motors.left_1_motor->moveVoltage(voltage); + m_motors.left_2_motor->moveVoltage(voltage); + m_motors.left_3_motor->moveVoltage(voltage); + m_motors.left_4_motor->moveVoltage(voltage); +} + +void TankDriveNode::setRightVoltage(int voltage) { + m_motors.right_1_motor->moveVoltage(voltage); + m_motors.right_2_motor->moveVoltage(voltage); + m_motors.right_3_motor->moveVoltage(voltage); + m_motors.right_4_motor->moveVoltage(voltage); +} + +void TankDriveNode::setLeftVelocity(float velocity) { + m_motors.left_1_motor->moveVelocity(velocity); + m_motors.left_2_motor->moveVelocity(velocity); + m_motors.left_3_motor->moveVelocity(velocity); + m_motors.left_4_motor->moveVelocity(velocity); +} + +void TankDriveNode::setRightVelocity(float velocity) { + m_motors.right_1_motor->moveVelocity(velocity); + m_motors.right_2_motor->moveVelocity(velocity); + m_motors.right_3_motor->moveVelocity(velocity); + m_motors.right_4_motor->moveVelocity(velocity); +} + +void TankDriveNode::resetEncoders() { + m_motors.left_1_motor->resetEncoder(); + m_motors.left_2_motor->resetEncoder(); + m_motors.left_3_motor->resetEncoder(); + m_motors.left_4_motor->resetEncoder(); + m_motors.right_1_motor->resetEncoder(); + m_motors.right_2_motor->resetEncoder(); + m_motors.right_3_motor->resetEncoder(); + m_motors.right_4_motor->resetEncoder(); +} + +TankDriveNode::FourMotorDriveEncoderVals TankDriveNode::getIntegratedEncoderVals() { + FourMotorDriveEncoderVals encoder_vals = { + m_motors.left_1_motor->getPosition(), + m_motors.left_2_motor->getPosition(), + m_motors.left_3_motor->getPosition(), + m_motors.left_4_motor->getPosition() + }; + + return encoder_vals; +} + +void TankDriveNode::initialize() { + resetEncoders(); +} + +void TankDriveNode::setDriveVoltage(int y_voltage, int theta_voltage) { + IDriveKinematics::FourMotorPercentages motor_percentages = m_kinematics.inverseKinematics(0, y_voltage, theta_voltage, MAX_MOTOR_VOLTAGE); + + setLeftVoltage(motor_percentages.left_front_percent * MAX_MOTOR_VOLTAGE); + setRightVoltage(motor_percentages.right_front_percent * MAX_MOTOR_VOLTAGE); +} + +void TankDriveNode::setDriveVoltage(int x_voltage, int y_voltage, int theta_voltage) { + setDriveVoltage(y_voltage, theta_voltage); +} + +void TankDriveNode::setDriveVelocity(float y_velocity, float theta_velocity) { + IDriveKinematics::FourMotorPercentages motor_percentages = + m_kinematics.inverseKinematics(0, y_velocity, theta_velocity, MAX_VELOCITY); + + //std::cout << "Left: " << motor_percentages.left_front_percent << " | Right: " << motor_percentages.right_front_percent << std::endl; + + setLeftVelocity(motor_percentages.left_front_percent * MAX_VELOCITY); + setRightVelocity(motor_percentages.right_front_percent * MAX_VELOCITY); +} + +void TankDriveNode::setDriveVelocity(float x_velocity, float y_velocity, float theta_velocity) { //incoming values should be in m/s so we convert to rpm here + setDriveVelocity(y_velocity, theta_velocity); +} + +void TankDriveNode::teleopPeriodic() { + // Split driving + // int left_y = m_controller->get_analog(pros::E_CONTROLLER_ANALOG_LEFT_Y); + // int right_x = m_controller->get_analog(pros::E_CONTROLLER_ANALOG_RIGHT_X); + + // int left = left_y + right_x; + // int right = left_y - right_x; + + // setLeftVoltage(copysign(max(min(fabs(left) / 127.0, 127.0), 0.0) * MAX_MOTOR_VOLTAGE, left)); + // setRightVoltage(copysign(max(min(fabs(right) / 127.0, 127.0), 0.0) * MAX_MOTOR_VOLTAGE, right)); + + // Normal tank drive + int left = m_controller->get_analog(pros::E_CONTROLLER_ANALOG_LEFT_Y); + int right = m_controller->get_analog(pros::E_CONTROLLER_ANALOG_RIGHT_Y); + + setLeftVoltage(copysign(max(min(fabs(left) / 127.0, 127.0), 0.0) * MAX_MOTOR_VOLTAGE, left)); + setRightVoltage(copysign(max(min(fabs(right) / 127.0, 127.0), 0.0) * MAX_MOTOR_VOLTAGE, right)); +} + +void TankDriveNode::autonPeriodic() { + +} + +TankDriveNode::~TankDriveNode() { + +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/nodes/system_nodes/ConnectionCheckerNode.cpp b/old-code/v5_hal/firmware/src/nodes/system_nodes/ConnectionCheckerNode.cpp new file mode 100644 index 00000000..728c510c --- /dev/null +++ b/old-code/v5_hal/firmware/src/nodes/system_nodes/ConnectionCheckerNode.cpp @@ -0,0 +1,44 @@ +#include "nodes/system_nodes/ConnectionCheckerNode.h" + +// By default, this constructor calls the constructor for the Node object in +// NodeManager.h +ConnectionCheckerNode::ConnectionCheckerNode(NodeManager* node_manager) : Node(node_manager, 500) { + obj1 = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_size(obj1, 600, 400); + lv_obj_set_style(obj1, &lv_style_plain_color); + + notConnectedStyle = (lv_style_t *)malloc( sizeof( lv_style_t )); + connectedStyle = (lv_style_t *)malloc( sizeof( lv_style_t )); + lv_style_copy(notConnectedStyle, &lv_style_plain_color); + lv_style_copy(connectedStyle, notConnectedStyle); + + notConnectedStyle->body.main_color = LV_COLOR_RED; + notConnectedStyle->body.grad_color = LV_COLOR_RED; + connectedStyle->body.main_color = LV_COLOR_GREEN; + connectedStyle->body.grad_color = LV_COLOR_GREEN; +} + +void ConnectionCheckerNode::m_checkStatus() { + if(Node::m_handle->connected()) { + lv_obj_set_style(obj1, connectedStyle); + } else { + lv_obj_set_style(obj1, notConnectedStyle); + } + lv_obj_refresh_style(obj1); +} + +void ConnectionCheckerNode::initialize() { + lv_obj_set_style(obj1, notConnectedStyle); +} + +void ConnectionCheckerNode::teleopPeriodic() { + m_checkStatus(); +} + +void ConnectionCheckerNode::autonPeriodic() { + m_checkStatus(); +} + +ConnectionCheckerNode::~ConnectionCheckerNode() { + +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/odometry/FollowerOdometry.cpp b/old-code/v5_hal/firmware/src/odometry/FollowerOdometry.cpp new file mode 100644 index 00000000..ce534902 --- /dev/null +++ b/old-code/v5_hal/firmware/src/odometry/FollowerOdometry.cpp @@ -0,0 +1,83 @@ +#include "odometry/FollowerOdometry.h" + +FollowerOdometry::FollowerOdometry(EncoderConfig xEncoderConfig, EncoderConfig yEncoderConfig, + Pose currentPose): Odometry(xEncoderConfig, yEncoderConfig, currentPose) { + +} + +/** + * This function is used to update the internal calculated position of the robot + * + * To maximize accuracy in robot position estimation, this function should be called as frequently as possible, ideally + * at a rate of 50 Hz or greater. + * + * @param x_encoder_raw_ticks The distance in ticks measured by the X encoder since when the tracker was last run + * @param y_encoder_raw_ticks The distance in ticks measured by the Y encoder since when the tracker was last run + * @param gyro_angle The current yaw of the robot as measured by the gyro + */ +void FollowerOdometry::Update(double x_encoder_raw_ticks, double y_encoder_raw_ticks, Rotation2Dd gyro_angle) { + // Convert the current position in ticks to a position in distance units + double x_encoder_dist = x_encoder_raw_ticks * Odometry::m_encoder_1_ticks_to_dist; + double y_encoder_dist = y_encoder_raw_ticks * Odometry::m_encoder_2_ticks_to_dist; + + Vector2d x_encoder_location(ODOM_PERPENDICULAR_X, ODOM_PERPENDICULAR_Y); + Vector2d y_encoder_location(ODOM_PARALLEL_X, ODOM_PARALLEL_Y); + + // Reset the current position of the robot + if (m_pose_reset) { + Odometry::m_last_encoder_1_dist = x_encoder_dist; + Odometry::m_last_encoder_2_dist = y_encoder_dist; + Odometry::m_gyro_initial_angle = gyro_angle; + Odometry::m_pose_reset = false; + } + + // Calculate the change in position of each encoder since the last check + double x_encoder_delta = x_encoder_dist - Odometry::m_last_encoder_1_dist; + double y_encoder_delta = y_encoder_dist - Odometry::m_last_encoder_2_dist; + Rotation2Dd angle_delta = (gyro_angle * Odometry::m_gyro_initial_angle.inverse()) + * Odometry::m_gyro_offset * Odometry::m_robot_pose.angle.inverse(); // Find change in angle + + // Determine the arc length of the turn from the center of each encoder + double x_arc_length = x_encoder_location.norm() * angle_delta.smallestAngle(); + double y_arc_length = y_encoder_location.norm() * angle_delta.smallestAngle(); + + // Determine the tangential component of each encoder relative to the circle of rotation + // TODO update to a vector projection + double x_position_coef = fabs(sin(atan2(x_encoder_location.y(), x_encoder_location.x()))); + double y_position_coef = fabs(cos(atan2(y_encoder_location.y(), y_encoder_location.x()))); + + // Translate to encoder value + double x_encoder_turning_component = x_arc_length * x_position_coef; + double y_encoder_turning_component = y_arc_length * y_position_coef * -1; + + // Calculate the true encoder delta when factoring in contributions from turning + double x_delta = x_encoder_delta - x_encoder_turning_component; + double y_delta = y_encoder_delta - y_encoder_turning_component; + + // Logger::logInfo("x_arc_length: " + std::to_string(x_arc_length) + + // " | y_arc_length: " + std::to_string(y_arc_length) + + // " | x turning coef: " + std::to_string(x_encoder_turning_component) + + // " | y turning coef: " + std::to_string(y_encoder_turning_component) + + // " | x enc: " + std::to_string(x_encoder_dist) + + // " | y enc: " + std::to_string(y_encoder_dist) + + // " | angle:" + std::to_string(gyro_angle.angle())); + + // Convert the x and y deltas into a translation vector + Vector2d robot_translation(x_delta, y_delta); + + // Update the current angle of the robot position + // Find the difference of the current angle to the initial angle + // Rotate this difference by the M_PI_2 offset to put it back in the correct frame of reference + Odometry::m_robot_pose.angle = gyro_angle * Odometry::m_gyro_initial_angle.inverse() * Odometry::m_gyro_offset; + + // Rotate the translation vector by the current angle rotation matrix + // We need to rotate this back, as our encoders are oriented with 0 being forward + robot_translation = (Odometry::m_robot_pose.angle.inverse() * Rotation2Dd(M_PI_2)).inverse() * robot_translation; + + // Add the current translation onto the robot position vector + Odometry::m_robot_pose.position += robot_translation; + + // Update the previous values of the encoders for the next iteration + Odometry::m_last_encoder_1_dist = x_encoder_dist; + Odometry::m_last_encoder_2_dist = y_encoder_dist; +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/odometry/Odometry.cpp b/old-code/v5_hal/firmware/src/odometry/Odometry.cpp new file mode 100644 index 00000000..27f8179e --- /dev/null +++ b/old-code/v5_hal/firmware/src/odometry/Odometry.cpp @@ -0,0 +1,31 @@ +#include "odometry/Odometry.h" + +Odometry::Odometry(EncoderConfig encoder_1_config, EncoderConfig encoder_2_config, Pose current_pose): + m_encoder_1_ticks_to_dist((encoder_1_config.wheel_diameter * PI) / + encoder_1_config.ticks_per_wheel_revolution), + m_encoder_2_ticks_to_dist((encoder_2_config.wheel_diameter * PI) / + encoder_2_config.ticks_per_wheel_revolution), + m_last_encoder_1_dist(0), + m_last_encoder_2_dist(0) { + SetCurrentPose(current_pose); +} + +void Odometry::ResetEncoderTicks(double encoder_1_ticks, double encoder_2_ticks) { + m_last_encoder_1_dist = encoder_1_ticks * m_encoder_1_ticks_to_dist; + m_last_encoder_2_dist = encoder_2_ticks * m_encoder_2_ticks_to_dist; +} + +Pose Odometry::GetPose(){ + return m_robot_pose; +} + +void Odometry::SetCurrentPose(Pose current_pose) { + m_robot_pose = current_pose; + m_gyro_offset = current_pose.angle; + m_pose_reset = true; +} + +Odometry::~Odometry() { + +} + diff --git a/old-code/v5_hal/firmware/src/odometry/TankOdometry.cpp b/old-code/v5_hal/firmware/src/odometry/TankOdometry.cpp new file mode 100644 index 00000000..91537730 --- /dev/null +++ b/old-code/v5_hal/firmware/src/odometry/TankOdometry.cpp @@ -0,0 +1,78 @@ +#include "odometry/TankOdometry.h" + +TankOdometry::TankOdometry(EncoderConfig leftEncoderConfig, EncoderConfig rightEncoderConfig, + Pose currentPose): Odometry(leftEncoderConfig, rightEncoderConfig, currentPose) { + +} + +/** + * This function is used to update the internal calculated position of the robot. Not as accurate as gyro version + * + * To maximize accuracy in robot position estimation, this function should be called as frequently as possible, ideally + * at a rate of 50 Hz or greater. + * + * @param left_encoder_raw_ticks The distance in ticks measured by the left encoder since when the tracker was last run + * @param right_encoder_raw_ticks The distance in ticks measured by the right encoder since when the tracker was last run + * @param track_width The distance between the two sides/tracks of the drivetrain + */ +void TankOdometry::Update(double left_encoder_raw_ticks, double right_encoder_raw_ticks, double track_width) { + double left_dist = left_encoder_raw_ticks * Odometry::m_encoder_1_ticks_to_dist; + double right_dist = right_encoder_raw_ticks * Odometry::m_encoder_2_ticks_to_dist; + + if (m_pose_reset) { + Odometry::m_last_encoder_1_dist = left_dist; + Odometry::m_last_encoder_2_dist = right_dist; + Odometry::m_pose_reset = false; + } + + double left_delta = left_dist - Odometry::m_last_encoder_1_dist; + double right_delta = right_dist - Odometry:: m_last_encoder_2_dist; + double distance_moved = (left_delta + right_delta) / 2.0; + + double rotation = (right_delta - left_delta) / track_width; + + Vector2d robot_translation(0, distance_moved); + + Odometry::m_robot_pose.angle = Odometry::m_robot_pose.angle * Rotation2Dd(rotation); + robot_translation = Odometry::m_robot_pose.angle * robot_translation; + Odometry::m_robot_pose.position += robot_translation; + + Odometry::m_last_encoder_1_dist = left_dist; + Odometry::m_last_encoder_2_dist = right_dist; +} + +/** + * This function is used to update the internal calculated position of the robot + * + * To maximize accuracy in robot position estimation, this function should be called as frequently as possible, ideally + * at a rate of 50 Hz or greater. + * + * @param left_encoder_raw_ticks The distance in ticks measured by the left encoder since when the tracker was last run + * @param right_encoder_raw_ticks The distance in ticks measured by the right encoder since when the tracker was last run + * @param gyro_angle The current yaw of the robot as measured by the gyro + */ +void TankOdometry::Update(double left_encoder_raw_ticks, double right_encoder_raw_ticks, Rotation2Dd gyro_angle) { + double left_dist = left_encoder_raw_ticks * Odometry::m_encoder_1_ticks_to_dist; + double right_dist = right_encoder_raw_ticks * Odometry::m_encoder_2_ticks_to_dist; + + if (m_pose_reset) { + Odometry::m_last_encoder_1_dist = left_dist; + Odometry::m_last_encoder_2_dist = right_dist; + Odometry::m_gyro_initial_angle = gyro_angle; + Odometry::m_pose_reset = false; + } + + double left_delta = left_dist - Odometry::m_last_encoder_1_dist; + double right_delta = right_dist - Odometry::m_last_encoder_2_dist; + double distance_moved = (left_delta + right_delta) / 2.0; + + Vector2d robot_translation(0, distance_moved); + robot_translation = gyro_angle * robot_translation; + Odometry::m_robot_pose.position += robot_translation; + + Eigen::Rotation2Dd angle_offset(M_PI_2); + Odometry::m_robot_pose.angle = gyro_angle * Odometry::m_gyro_initial_angle.inverse() * angle_offset; + + Odometry::m_last_encoder_1_dist = left_dist; + Odometry::m_last_encoder_2_dist = right_dist; +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/pathing/Path.cpp b/old-code/v5_hal/firmware/src/pathing/Path.cpp new file mode 100644 index 00000000..a93b7bd6 --- /dev/null +++ b/old-code/v5_hal/firmware/src/pathing/Path.cpp @@ -0,0 +1,41 @@ +#include "pathing/Path.h" + +Path::Path() : + m_is_complete(false), + m_last_point(0, Pose(), Vector2d(0., 0.), 0.) { + +} + +Path::Path(vector pathPoints) : + m_pathPoints(pathPoints), + m_is_complete(false), + m_last_point(pathPoints.back()) { +} + +Pose Path::update(float time) { + if (m_pathPoints.size() == 0 || m_pathPoints.size() == 1) { + m_is_complete = true; + return m_last_point.getPose(); + } else { + // Remove any points that have been passed + for (auto it = m_pathPoints.begin(); it != m_pathPoints.end(); it++) { + if(time > (it + 1)->getTime()) { // Point has been passed + m_pathPoints.erase(it); + } else { // Point not yet reached + break; + } + } + + auto path_point = m_pathPoints.begin()->interpolateTo(*(m_pathPoints.begin() + 1), time); + //return path_point.getPose(); + return (m_pathPoints.begin() + 1)->getPose(); // Temporary fix until interpolation works + } +} + +vector Path::getPathPoints() { + return m_pathPoints; +} + +bool Path::isComplete() { + return m_is_complete; +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/pathing/PathManager.cpp b/old-code/v5_hal/firmware/src/pathing/PathManager.cpp new file mode 100644 index 00000000..4000b6bd --- /dev/null +++ b/old-code/v5_hal/firmware/src/pathing/PathManager.cpp @@ -0,0 +1,94 @@ +#include "PathManager.h" + +PathManager* PathManager::m_instance = nullptr; + +PathManager * PathManager::GetInstance() { + if(!m_instance) { + m_instance = new PathManager; + } + + return m_instance; +} + +int PathManager::NumPaths() { + return m_paths.size(); +} + +bool PathManager::LoadPathsText(string text) { + json loadedJson; + + try { + loadedJson = json::parse(text); + } catch (const exception& e) { + Logger::logInfo("Could not parse paths file:" + string(e.what())); + return false; + } + + return LoadPaths(loadedJson); +} + +bool PathManager::LoadPaths(json loadedJson) { + m_paths.clear(); + + try { + for (auto pathJson : loadedJson["paths"]) { + string name = pathJson["name"]; + vector pathPoints; + for (auto point : pathJson["points"]) { + Vector2d linear_velocity(point["vx"], point["vy"]); + float time = point["time"]; + float rotational_velocity = point["omega"]; + Rotation2Dd rotation(toRadians(point["theta"])); + Vector2d position(point["x"], point["y"]); + pathPoints.push_back(PathPoint(time, Pose(position, rotation), linear_velocity, rotational_velocity)); + Logger::logInfo(" Time: " + std::to_string(time) + " Pose: " + std::to_string(position.x()) + " " + std::to_string(position.y()) + " velocity: " + std::to_string(linear_velocity.x()) + " " + std::to_string(linear_velocity.y())); + } + Path newPath(pathPoints); + m_paths[name] = newPath; + } + } catch (const exception& e) { + Logger::logInfo("Error reading json path! " + string(e.what())); + return false; + } + + return true; +} + +bool PathManager::LoadPathsFile(string filePath) { + ifstream pathsFile; + try { + pathsFile.open(filePath); + if(!pathsFile.is_open()) { + Logger::logInfo("Could not open paths file at " + filePath); + return false; + } + } catch (const exception& e) { + Logger::logInfo("Could not open paths file at " + filePath + " : " + string(e.what())); + return false; + } + + json loadedJson; + try { + pathsFile >> loadedJson; + } catch (const exception& e) { + Logger::logInfo("Could not parse paths file:" + string(e.what())); + pathsFile.close(); + return false; + } + + pathsFile.close(); + return LoadPaths(loadedJson); +} + +unordered_map PathManager::GetPaths() { + return m_paths; +} + +Path PathManager::GetPath(string name) { + if (m_paths.find(name) == m_paths.end()) { + Logger::logInfo("Path with key: " + name + " not found!"); + return m_paths[m_paths.begin()->first]; + } else { + return m_paths[name]; + } +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/pathing/PathPoint.cpp b/old-code/v5_hal/firmware/src/pathing/PathPoint.cpp new file mode 100644 index 00000000..8c118ac9 --- /dev/null +++ b/old-code/v5_hal/firmware/src/pathing/PathPoint.cpp @@ -0,0 +1,57 @@ +#include "pathing/PathPoint.h" + +PathPoint::PathPoint(float time, Pose pose, Vector2d linear_velocity, float rotational_velocity) { + m_time = time; + m_pose = pose; + m_linear_velocity = linear_velocity; + m_rotational_velocity = rotational_velocity; +} + +float PathPoint::getTime() { + return m_time; +} + +Pose PathPoint::getPose() { + return m_pose; +} + +Vector2d PathPoint::getLinearVelocity() { + return m_linear_velocity; +} + +float PathPoint::getRotationalVelocity() { + return m_rotational_velocity; +} + +PathPoint PathPoint::interpolateTo(PathPoint other, float time) { + float t = time - getTime(); + float deltaTime = other.getTime() - getTime(); + + Eigen::Vector2d acceleration = deltaTime == 0. ? Eigen::Vector2d(0., 0.) : ((other.getLinearVelocity() - getLinearVelocity()) / deltaTime); + Eigen::Vector2d position = 0.5 * acceleration * (t * t) + getLinearVelocity() * t + getPose().position; + Eigen::Vector2d velocity = acceleration * t + getLinearVelocity(); + + // Logger::logInfo("Time: " + std::to_string(time) + " | position: " + std::to_string(position.x()) + " " + std::to_string(position.y()) + + // " | velocity: " + std::to_string(velocity.x()) + " " + std::to_string(velocity.y())); + + float alpha = deltaTime == 0. ? 0. : (other.getRotationalVelocity() - getRotationalVelocity()) / deltaTime; + Eigen::Rotation2Dd theta = Eigen::Rotation2Dd(0.5 * alpha * (t * t) + getRotationalVelocity() * t) * getPose().angle; + float omega = alpha * t + getRotationalVelocity(); + + return PathPoint(time, Pose(position, theta), velocity, omega); +} + +// Not robust, used for testing +bool PathPoint::equals(PathPoint* other_point) { + if (other_point == nullptr) { + return false; + } else if(this == other_point) { + return true; + } else { + return this->m_time == other_point->m_time && + this->m_pose.position == other_point->m_pose.position && + this->m_pose.angle.angle() == other_point->m_pose.angle.angle() && + this->m_linear_velocity == other_point->m_linear_velocity && + this->m_rotational_velocity == other_point->m_rotational_velocity; + } +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/pathing/Waypoint.cpp b/old-code/v5_hal/firmware/src/pathing/Waypoint.cpp new file mode 100644 index 00000000..696a8ef0 --- /dev/null +++ b/old-code/v5_hal/firmware/src/pathing/Waypoint.cpp @@ -0,0 +1,19 @@ +#include "pathing/Waypoint.h" + +Waypoint::Waypoint(Pose position, Vector2d velocity, float time) { + m_position = position; + m_velocity = velocity; + m_time = time; +} + +Pose Waypoint::getPosition() { + return m_position; +} + +Vector2d Waypoint::getVelocity() { + return m_velocity; +} + +float Waypoint::getTime() { + return m_time; +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/pursuit/adaptive_pursuit/Position2d.cpp b/old-code/v5_hal/firmware/src/pursuit/adaptive_pursuit/Position2d.cpp new file mode 100644 index 00000000..daebceda --- /dev/null +++ b/old-code/v5_hal/firmware/src/pursuit/adaptive_pursuit/Position2d.cpp @@ -0,0 +1,81 @@ +#include "pursuit/adaptive_pursuit/Position2d.h" + +Position2d::Delta::Delta(double x, double y, double t) { + dx = x; + dy = y; + dtheta = t; +} + +Position2d::Position2d() { + m_translation = Trans2d(); + m_rotation = Rotation2d(); +} + +Position2d::Position2d(Trans2d tran, Rotation2d rot) { + m_translation = tran; + m_rotation = rot; +} + +Position2d::Position2d(const Position2d& other) { + m_translation = other.m_translation; + m_rotation = other.m_rotation; +} + +Position2d Position2d::fromTranslation(Trans2d tran) { + return Position2d(tran, Rotation2d()); +} + +Position2d Position2d::fromRotation(Rotation2d rot) { + return Position2d(Trans2d(), rot); +} + +Position2d Position2d::fromVelocity(Delta delta) { + double sinT = sin(delta.dtheta); + double cosT = cos(delta.dtheta); + double s, c; + if(fabs(delta.dtheta) < kE){ + s = 1.0 - 1.0 / 6.0 * delta.dtheta * delta.dtheta; + c = .5 * delta.dtheta; + } else { + s = sinT / delta.dtheta; + c = (1.0 - cosT) / delta.dtheta; + } + return Position2d(Trans2d(delta.dx * s - delta.dy * c, delta.dx * c + delta.dy * s), + Rotation2d(cosT, sinT, false)); +} + +Trans2d Position2d::getTranslation() { + return m_translation; +} + +void Position2d::setTranslation(Trans2d tran) { + m_translation = tran; +} + +Rotation2d Position2d::getRotation() { + return m_rotation; +} + +void Position2d::setRotation(Rotation2d rot) { + m_rotation = rot; +} + +Position2d Position2d::transformBy(Position2d other) { + return Position2d(m_translation.translateBy(other.m_translation.rotateBy(m_rotation)), + m_rotation.rotateBy(other.m_rotation)); +} + +Position2d Position2d::inverse() { + Rotation2d invert = m_rotation.inverse(); + return Position2d(m_translation.inverse().rotateBy(invert), invert); +} + +Position2d Position2d::interpolate(Position2d other, double x) { + if (x <= 0){ + return *this; + } else if (x >= 1){ + return other; + } + return Position2d(m_translation.interpolate(other.m_translation, x), + m_rotation.interpolate(other.m_rotation, x)); +} diff --git a/old-code/v5_hal/firmware/src/pursuit/adaptive_pursuit/Rotation2d.cpp b/old-code/v5_hal/firmware/src/pursuit/adaptive_pursuit/Rotation2d.cpp new file mode 100644 index 00000000..b4854588 --- /dev/null +++ b/old-code/v5_hal/firmware/src/pursuit/adaptive_pursuit/Rotation2d.cpp @@ -0,0 +1,77 @@ +#include "pursuit/adaptive_pursuit/Rotation2d.h" + +Rotation2d::Rotation2d() { + m_cos = 1; + m_sin = 0; +} + +Rotation2d::Rotation2d(double x, double y, bool doNormalize) { + m_cos = x; + m_sin = y; + if(doNormalize){ + normalize(); + } +} + +Rotation2d::Rotation2d(const Rotation2d& other) { + m_cos = other.m_cos; + m_sin = other.m_sin; +} + +Rotation2d Rotation2d::fromRadians(double radians) { + return Rotation2d(cos(radians), sin(radians), false); +} + +Rotation2d Rotation2d::fromDegrees(double degrees) { + return fromRadians(toRadians(degrees)); +} + +void Rotation2d::normalize() { + double mag = hypot(m_cos, m_sin); + if (mag > kE){ + m_sin /= mag; + m_cos /= mag; + } else { + m_sin = 0; + m_cos = 1; + } +} + +double Rotation2d::getCos() { + return m_cos; +} + +double Rotation2d::getSin() { + return m_sin; +} + +double Rotation2d::getRadians() { + return atan2(m_sin, m_cos); +} + +double Rotation2d::getDegrees() { + return toDegrees(getRadians()); +} + +Rotation2d Rotation2d::rotateBy(Rotation2d other) { + return Rotation2d(m_cos * other.getCos() - m_sin * other.getSin(), + m_cos * other.getSin() + m_sin * other.getCos(), true); +} + +Rotation2d Rotation2d::inverse() { + return Rotation2d(m_cos, -m_sin, false); +} + +Rotation2d Rotation2d::opposite() { + return Rotation2d(-m_cos, -m_sin, false); +} + +Rotation2d Rotation2d::interpolate(Rotation2d other, double x) { + if (x <= 0){ + return *this; + } else if (x >= 1){ + return other; + } + double diff = inverse().rotateBy(other).getRadians(); + return rotateBy(fromRadians(diff * x)); +} diff --git a/old-code/v5_hal/firmware/src/pursuit/adaptive_pursuit/Trans2d.cpp b/old-code/v5_hal/firmware/src/pursuit/adaptive_pursuit/Trans2d.cpp new file mode 100644 index 00000000..e8e15f33 --- /dev/null +++ b/old-code/v5_hal/firmware/src/pursuit/adaptive_pursuit/Trans2d.cpp @@ -0,0 +1,73 @@ +#include "pursuit/adaptive_pursuit/Trans2d.h" + +Trans2d::Trans2d() { + m_x = 0; + m_y = 0; +} + +Trans2d::Trans2d(double x, double y) { + m_x = x; + m_y = y; +} + +double Trans2d::norm() { + return hypot(m_x, m_y); +} + +double Trans2d::getX() { + return m_x; +} + +double Trans2d::getY() { + return m_y; +} + +void Trans2d::setX(double x) { + m_x = x; +} + +void Trans2d::setY(double y) { + m_y = y; +} + +Trans2d Trans2d::translateBy(Trans2d other) { + return Trans2d(m_x + other.getX(), m_y + other.getY()); +} + +Trans2d Trans2d::rotateBy(Rotation2d rotation) { + return Trans2d(m_x * rotation.getCos() - m_y * rotation.getSin(), + m_x * rotation.getSin() + m_y * rotation.getCos()); +} + +Trans2d Trans2d::inverse() { + return Trans2d(-m_x, -m_y); +} + +Trans2d Trans2d::interpolate(Trans2d other, double x) { + if(x <=0){ + return *this; + } else if (x >= 1){ + return other; + } + return extrapolate(other, x); +} + +Trans2d Trans2d::extrapolate(Trans2d other, double x) { + return Trans2d(x * (other.getX() - m_x) + m_x, x * (other.getY() - m_y) + m_y); +} + +Trans2d Trans2d::flipX() { + return Trans2d(-m_x, m_y); +} + +Trans2d Trans2d::flipY() { + return Trans2d(m_x, -m_y); +} + +double Trans2d::getSin() { + return getY() / norm(); +} + +double Trans2d::getCos() { + return getX() / norm(); +} diff --git a/old-code/v5_hal/firmware/src/pursuit/holonomic_pursuit/HolonomicPosePursuit.cpp b/old-code/v5_hal/firmware/src/pursuit/holonomic_pursuit/HolonomicPosePursuit.cpp new file mode 100644 index 00000000..482ea8a3 --- /dev/null +++ b/old-code/v5_hal/firmware/src/pursuit/holonomic_pursuit/HolonomicPosePursuit.cpp @@ -0,0 +1,41 @@ +#include "pursuit/holonomic_pursuit/HolonomicPosePursuit.h" + +HolonomicPosePursuit::HolonomicPosePursuit(Pose target_pose, Timer timer) : + m_target_pose(target_pose), + m_timer(timer), + m_x_pid(0.1, 0., 0., 0.), + m_y_pid(0.1, 0., 0., 0.), + m_theta_pid(0.1, 0., 0., 0.) { + +} + +void HolonomicPosePursuit::startPursuit() { + m_timer.Start(); +} + +HolonomicPosePursuit::TargetVelocity HolonomicPosePursuit::getTargetVelocity(Pose current_pose) { + float current_time = m_timer.Get(); + + m_previous_time = m_timer.Get(); + + Vector2d linear_error = m_target_pose.position - current_pose.position; + float theta_error = m_target_pose.angle.angle() - current_pose.angle.angle(); + + // Determine the feedback of each movement component to get to our new position + float x_feedback = m_x_pid.calculate(linear_error.x()); + float y_feedback = m_y_pid.calculate(linear_error.y()); + float theta_feedback = m_theta_pid.calculate(theta_error); + + // Return the target velocities, and whether the path is at the end point + TargetVelocity target_velocity = { + Vector2d(x_feedback * MAX_VELOCITY, y_feedback * MAX_VELOCITY), + theta_feedback * MAX_VELOCITY, + linear_error.norm() < POSE_PURSUIT_LINEAR_THRESHOLD && theta_error < POSE_PURSUIT_THETA_THRESHOLD + }; + + return target_velocity; +} + +HolonomicPosePursuit::~HolonomicPosePursuit() { + +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/pursuit/holonomic_pursuit/HolonomicPursuit.cpp b/old-code/v5_hal/firmware/src/pursuit/holonomic_pursuit/HolonomicPursuit.cpp new file mode 100644 index 00000000..4deb57f4 --- /dev/null +++ b/old-code/v5_hal/firmware/src/pursuit/holonomic_pursuit/HolonomicPursuit.cpp @@ -0,0 +1,46 @@ +#include "pursuit/holonomic_pursuit/HolonomicPursuit.h" + +HolonomicPursuit::HolonomicPursuit(Path path, Timer timer) : + m_path(path), + m_timer(timer), + m_x_pid(0.03, 0., 0., 0.), + m_y_pid(0.03, 0., 0., 0.), + m_theta_pid(0.4, 0., 0., 0.) { + +} + +void HolonomicPursuit::startPursuit() { + m_timer.Start(); +} + +HolonomicPursuit::TargetVelocity HolonomicPursuit::getTargetVelocity(Pose current_pose) { + Pose next_pose = m_path.update(m_timer.Get()); + + Logger::logInfo("Current Pose| x: " + std::to_string(current_pose.position.x()) + + " y: " + std::to_string(current_pose.position.y()) + + " angle: " + std::to_string(current_pose.angle.angle()) + + "Next Pose| x: " + std::to_string(next_pose.position.x()) + + " y: " + std::to_string(next_pose.position.y()) + + " angle: " + std::to_string(next_pose.angle.angle())); + + Vector2d linear_error = (current_pose.angle.inverse() * Rotation2Dd(M_PI_2)) * (next_pose.position - current_pose.position); + float theta_error = (next_pose.angle * current_pose.angle.inverse()).smallestAngle(); + + // Determine the feedback of each movement component to get to our new position + float x_feedback = m_x_pid.calculate(linear_error.x()); + float y_feedback = m_y_pid.calculate(linear_error.y()); + float theta_feedback = m_theta_pid.calculate(theta_error); + + // Return the target velocities, and whether the path is at the end point + TargetVelocity target_velocity = { + Vector2d(x_feedback * MAX_VELOCITY, y_feedback * MAX_VELOCITY), + theta_feedback * MAX_VELOCITY, + m_path.isComplete() + }; + + return target_velocity; +} + +HolonomicPursuit::~HolonomicPursuit() { + +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/swerve/SwerveController.cpp b/old-code/v5_hal/firmware/src/swerve/SwerveController.cpp new file mode 100644 index 00000000..b8f9b41e --- /dev/null +++ b/old-code/v5_hal/firmware/src/swerve/SwerveController.cpp @@ -0,0 +1,36 @@ +#include "swerve/SwerveController.h" + + +SwerveController::SwerveController(Eigen::Vector2d left_module_location, Eigen::Vector2d right_module_location, + Eigen::Vector2d rear_module_location, double kP, double kI, double kD) : + leftSwerveModule(left_module_location, kP, kI, kD), + rightSwerveModule(right_module_location, kP, kI, kD), + rearSwerveModule(rear_module_location, kP, kI, kD) { +} + +void SwerveController::assignActualAngle(int left_pot, int right_pot, int rear_pot) { + left_actual_angle = Eigen::Rotation2Dd((((((float)left_pot - LEFT_POT_OFFSET) / 4095.0) * M_PI) * 2.0) * -1); + right_actual_angle = Eigen::Rotation2Dd((((((float)right_pot - RIGHT_POT_OFFSET) / 4095.0) * M_PI) * 2.0) * -1); + rear_actual_angle = Eigen::Rotation2Dd((((((float)rear_pot - REAR_POT_OFFSET) / 4095.0) * M_PI) * 2.0) * -1); +} + +MotorPowers SwerveController::calculateLeftModule(Eigen::Vector2d target_velocity, double rotation_velocity) { + MotorPowers motor_powers = leftSwerveModule.InverseKinematics(target_velocity, rotation_velocity, left_actual_angle); + + //printf("Motor Powers %i %i\n", motor_powers.left_motor_power, motor_powers.right_motor_power); + + return motor_powers; +} + +MotorPowers SwerveController::calculateRightModule(Eigen::Vector2d target_velocity, double rotation_velocity) { + right_motor_powers = rightSwerveModule.InverseKinematics(target_velocity, rotation_velocity, right_actual_angle); + + return right_motor_powers; +} + +MotorPowers SwerveController::calculateRearModule(Eigen::Vector2d target_velocity, double rotation_velocity) { + rear_motor_powers = rearSwerveModule.InverseKinematics(target_velocity, rotation_velocity, rear_actual_angle); + + return rear_motor_powers; +} + diff --git a/old-code/v5_hal/firmware/src/swerve/SwerveModule.cpp b/old-code/v5_hal/firmware/src/swerve/SwerveModule.cpp new file mode 100644 index 00000000..f004a4b4 --- /dev/null +++ b/old-code/v5_hal/firmware/src/swerve/SwerveModule.cpp @@ -0,0 +1,165 @@ +#include "swerve/SwerveModule.h" + +SwerveModule::SwerveModule(Eigen::Vector2d module_location, double kP, double kI, double kD) : + m_module_location(module_location), + m_percent_error(0), + m_total_error(0), + kP(kP), + kI(kI), + kD(kD) { + +} + +MotorPowers SwerveModule::InverseKinematics(Eigen::Vector2d target_velocity, double target_rotation_velocity, Eigen::Rotation2Dd module_actual_angle) { + // ROS_INFO("Target Velocity - x:%.2f y:%.2f", target_velocity(0), target_velocity(1)); + // ROS_INFO("Target Rotation Velocity: %.2f", target_rotation_velocity); + + // std::cout << "Target Velocity: " << target_velocity(0) << " " << target_velocity(1) << "\n" << std::endl; + // std::cout << "Target Rotation Velocity: " << target_rotation_velocity << "\n" << std::endl; + + // If you aren't trying to move, make sure to send no velocity to the motors + if ((target_velocity(0) == 0) && (target_velocity(1) == 0) && (target_rotation_velocity == 0)) { //not sure if this works, might need to be reworked + double scaled_motor_1_mag = 0; + double scaled_motor_2_mag = 0; + + MotorPowers motor_powers; + + motor_powers.left_motor_power = scaled_motor_1_mag; + motor_powers.right_motor_power = scaled_motor_2_mag; + + return motor_powers; + } + + // Create a maximum power vector for translating motor into percent motor output power + Eigen::Vector2d max_motor_vector(MAX_VELOCITY, MAX_ROTATIONAL_VELOCITY); + + // Find the length of the maxium power vector, but divide by sqrt(2) to account for the fact that later + // we will be projecting vectors onto this vector and due to the 45-45-90 nature of this conversion need to + // divide this vector by sqrt(2) + float max_motor_power = max_motor_vector.norm() / sqrt(2); + + // Take the vector from the origin to the module (module_location) and rotate it to + // make it orthogonal to the current (module_location) vector + Eigen::Vector2d rotated_module_location = Eigen::Rotation2Dd(M_PI / 2) * m_module_location; + + // Multiply the orthogonal vector (rotated_module_location) by the target angular velocity + // (target_rotation_velocity) to create your target rotation vector + Eigen::Vector2d target_rotation_vector = target_rotation_velocity * rotated_module_location; + + // Add the target velocity and rotation vectors to get a resultant target vector + Eigen::Vector2d target_vector = target_velocity + target_rotation_vector; + + // std::cout << "Target Velocity Vector (x, y): " << target_velocity(0) << " " << target_velocity(1) << "\n" << std::endl; + // std::cout << "Target Rotation Vector (x, y): " << target_rotation_vector(0) << " " << target_rotation_vector(1) << "\n" << std::endl; + + // ROS_INFO("Target Vector - x:%.2f y:%.2f", target_vector(0), target_vector(1)); + + // std::cout << "Target Vector (x, y): " << target_vector(0) << " " << target_vector(1) << "\n" << std::endl; + + // Get the angle of the target vector by taking tangent inverse of y and x components + // of the vector, and convert to a Rotation2D angle object + Eigen::Rotation2Dd target_vector_angle = Eigen::Rotation2Dd(atan2(target_vector(1), target_vector(0))); + + // ROS_INFO("Current Angle: %.2f", module_actual_angle.angle()); + // ROS_INFO("Target Angle: %.2f", target_vector_angle.angle()); + + // std::cout << "Current Angle: " << module_actual_angle.angle() << "\n" << std::endl; + // std::cout << "Target Angle: " << target_vector_angle.angle() << "\n" << std::endl; + + // Subtract the actual module vector from the target to find the change in angle needed + double module_rotation_delta = (target_vector_angle * module_actual_angle.inverse()).smallestAngle(); + + // PID control for turning + Eigen::Vector2d motor_power_vector; + + if(fabs(module_rotation_delta) > M_PI_2){ + module_rotation_delta = (target_vector_angle * module_actual_angle.inverse() * Eigen::Rotation2Dd(M_PI)).smallestAngle(); + + // Set the power as the magnitude of the vector + motor_power_vector(0) = -target_vector.norm() / MAX_VELOCITY; + + // std::cout << "Forward %: " << motor_power_vector(0) << "\n" << std::endl; + } else{ + // Set the power as the magnitude of the vector + motor_power_vector(0) = target_vector.norm() / MAX_VELOCITY; + + // std::cout << "Forward %: " << motor_power_vector(0) << "\n" << std::endl; + } + + double error; + double derivative; + + // Proportional + error = module_rotation_delta; + + // std::cout << "PID Error: " << module_rotation_delta << "\n" << std::endl; + + // Derivative + derivative = error - m_percent_error; + + // Integral + m_total_error += error; + + // The last value of error + m_percent_error = error; + + // Set the turn as the error * a constant + the derivative * a constant + the integral * a constant + motor_power_vector(1) = error * kP + derivative * kD + m_total_error * kI; + + // std::cout << "PID Output: " << motor_power_vector(1) << "\n" << std::endl; + + + + // ROS_INFO("Motor Power Vector - x:%.2f y:%.2f", motor_power_vector(0), motor_power_vector(1)); + + // std::cout << "Target Vector (x, y): " << motor_power_vector(0) << " " << motor_power_vector(1) << "\n" << std::endl; + + // We are working in the (m/s Forward)-(rpm Speed of Rotation) plane now + // Project the target vector onto each max motor vector to get components + // This finds the projection magnitude onto the max motor vector + double scaled_motor_1_mag = motor_power_vector.dot(Eigen::Vector2d(1, 1)); + double scaled_motor_2_mag = motor_power_vector.dot(Eigen::Vector2d(-1, 1)); + + // ROS_INFO("Max Motor Mag: %.2f", max_motor_power); + + // std::cout << "Max Motor Magnitude: " << max_motor_power << "\n" << std::endl; + + // ROS_INFO("Scaled Motor 1 Mag (START): %.2f", scaled_motor_1_mag); + // ROS_INFO("Scaled Motor 2 Mag (START): %.2f", scaled_motor_2_mag); + + // std::cout << "Scaled Motor 1 Magnitude (0): " << scaled_motor_1_mag << "\n" << std::endl; + // std::cout << "Scaled Motor 2 Magnitude (0): " << scaled_motor_2_mag << "\n" << std::endl; + + float max_scaled_motor_mag = fmax(fabs(scaled_motor_1_mag), fabs(scaled_motor_2_mag)); + + // If the max of the two motor powers is more than we can ouput, scale both down so the max motor's power + // is equal to the max_motor_power + if (max_scaled_motor_mag > 1.0) { + scaled_motor_1_mag /= max_scaled_motor_mag; + scaled_motor_2_mag /= max_scaled_motor_mag; + } + + // ROS_INFO("Scaled Motor 1 Mag (1): %.2f", scaled_motor_1_mag); + // ROS_INFO("Scaled Motor 2 Mag (1): %.2f", scaled_motor_2_mag); + + // std::cout << "Scaled Motor 1 Magnitude (1): " << scaled_motor_1_mag << "\n" << std::endl; + // std::cout << "Scaled Motor 2 Magnitude (1): " << scaled_motor_2_mag << "\n" << std::endl; + + // Scale motors between -127 and 127 + scaled_motor_1_mag = scaled_motor_1_mag * 127.0; + scaled_motor_2_mag = scaled_motor_2_mag * 127.0; + + // ROS_INFO("Scaled Motor 1 Mag (FINAL): %.2f", scaled_motor_1_mag); + // ROS_INFO("Scaled Motor 2 Mag (FINAL): %.2f", scaled_motor_2_mag); + + // std::cout << "Scaled Motor 1 Magnitude (2): " << scaled_motor_1_mag << "\n" << std::endl; + // std::cout << "Scaled Motor 2 Magnitude (2): " << scaled_motor_2_mag << "\n" << std::endl; + + // Set and return the motor powers + MotorPowers motor_powers; + + motor_powers.left_motor_power = (int8_t)scaled_motor_1_mag; + motor_powers.right_motor_power = (int8_t)scaled_motor_2_mag; + + return motor_powers; +} \ No newline at end of file diff --git a/old-code/v5_hal/firmware/src/time.cpp b/old-code/v5_hal/firmware/src/time.cpp new file mode 100644 index 00000000..1f5b5b5a --- /dev/null +++ b/old-code/v5_hal/firmware/src/time.cpp @@ -0,0 +1,79 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote prducts derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ros_lib/ros/time.h" + +namespace ros +{ +void normalizeSecNSec(uint32_t& sec, uint32_t& nsec) +{ + uint32_t nsec_part = nsec % 1000000000UL; + uint32_t sec_part = nsec / 1000000000UL; + sec += sec_part; + nsec = nsec_part; +} + +Time& Time::fromNSec(int32_t t) +{ + sec = t / 1000000000; + nsec = t % 1000000000; + normalizeSecNSec(sec, nsec); + return *this; +} + +Time& Time::operator +=(const Duration &rhs) +{ + sec = sec - 1 + rhs.sec; + nsec = nsec + 1000000000UL + rhs.nsec; + normalizeSecNSec(sec, nsec); + return *this; +} + +Time& Time::operator -=(const Duration &rhs){ + sec = sec - 1 - rhs.sec; + nsec = nsec + 1000000000UL - rhs.nsec; + normalizeSecNSec(sec, nsec); + return *this; +} + +Duration Time::operator-(const Time &rhs) const { + // Note: Considers wrap around as a continuation of time, e.g., + // (0,0) - (0xFFFFFFFF, 0) = (1, 0) + Duration d; + d.sec = sec > rhs.sec ? sec - rhs.sec : -(rhs.sec - sec); + d.nsec = nsec > rhs.nsec ? nsec - rhs.nsec : -(rhs.nsec - nsec); + normalizeSecNSecSigned(d.sec, d.nsec); + return d; +} +} diff --git a/old-code/v5_hal/firmware/src/util/Logger.cpp b/old-code/v5_hal/firmware/src/util/Logger.cpp new file mode 100644 index 00000000..e1eb0539 --- /dev/null +++ b/old-code/v5_hal/firmware/src/util/Logger.cpp @@ -0,0 +1,19 @@ +#include "util/Logger.h" + +Logger::LoggingLevel Logger::m_console_logging_level; +NodeManager* Logger::m_node_manager = nullptr; + +void Logger::giveNodeManager(NodeManager* node_manager) { + m_node_manager = node_manager; +} + +void Logger::logInfo(string message) { + if(m_node_manager != nullptr) { + string msg = message; + m_node_manager->m_handle->logwarn(msg.c_str()); + } +} + +void Logger::setConsoleLoggingLevel(Logger::LoggingLevel level) { + m_console_logging_level = level; +} diff --git a/old-code/v5_hal/firmware/src/util/PID.cpp b/old-code/v5_hal/firmware/src/util/PID.cpp new file mode 100644 index 00000000..b26a52fc --- /dev/null +++ b/old-code/v5_hal/firmware/src/util/PID.cpp @@ -0,0 +1,40 @@ +#include "util/PID.h" + +// +// Created by Jonathan T. Phung on 3/4/2021. +// + +PID::PID(float kP, float kI, float kD, float feed_forward) { + m_kP = kP; + m_kI = kI; + m_kD = kD; + m_feed_forward = feed_forward; + m_previous_error = 0; + m_total_error = 0; +} + +float PID::calculate(float current_error) { + // Calculate change in time + float delta_time = m_timer.Get(); + + // Proportional (current_error) + + // Integral + m_total_error += (current_error * delta_time); + + // Derivative (make sure it doesn't break when dt = 0) + const float delta_error = delta_time == 0 ? + 0 : ((current_error - m_previous_error) / delta_time); + + // Update previous error + m_previous_error = current_error; + + // Compute the total input + float total_input = (m_kP * current_error) + (m_kI * m_total_error) + (m_kD * delta_error); + + // Restart the timer so it can be used next loop + m_timer.Start(); + + // Return the total input plus a feed forward value, with a limit + return std::copysign(std::min(fabs(total_input) + m_feed_forward, 1.0f), total_input); +} diff --git a/old-code/v5_hal/firmware/src/util/Timer.cpp b/old-code/v5_hal/firmware/src/util/Timer.cpp new file mode 100644 index 00000000..9309821b --- /dev/null +++ b/old-code/v5_hal/firmware/src/util/Timer.cpp @@ -0,0 +1,41 @@ +#include +#include "util/Timer.h" + +using namespace std::chrono; + +double Timer::Get() { + if(m_started && !m_stopped) { + return getTime() - m_startTime; + } else if(m_started && m_stopped) { + return m_stopTime - m_startTime; + } + Logger::logInfo("Error: Get called on timer which was not started"); + return 0; +} + +void Timer::Reset() { + m_started = false; + m_startTime = getTime(); +} + +void Timer::Stop() { + if(!m_started) { + Logger::logInfo("Error: Timer stopped without starting"); + } else { + m_stopped = true; + m_stopTime = getTime(); + } +} + +void Timer::Start() { + m_started = true; + m_startTime = getTime(); +} + +double Timer::getTime() { + return pros::millis() / 1000.0; +} + +bool Timer::isStarted() { + return m_started; +} \ No newline at end of file diff --git a/old-code/v5_hal/msg/CompetitionStatus.msg b/old-code/v5_hal/msg/CompetitionStatus.msg new file mode 100644 index 00000000..e5425841 --- /dev/null +++ b/old-code/v5_hal/msg/CompetitionStatus.msg @@ -0,0 +1,4 @@ +uint8 status +bool is_autonomous +bool is_comp_connected +bool is_disabled \ No newline at end of file diff --git a/old-code/v5_hal/msg/RollPitchYaw.msg b/old-code/v5_hal/msg/RollPitchYaw.msg new file mode 100644 index 00000000..84885f7f --- /dev/null +++ b/old-code/v5_hal/msg/RollPitchYaw.msg @@ -0,0 +1,3 @@ +float32 roll +float32 pitch +float32 yaw \ No newline at end of file diff --git a/old-code/v5_hal/msg/V5Battery.msg b/old-code/v5_hal/msg/V5Battery.msg new file mode 100644 index 00000000..0acb2717 --- /dev/null +++ b/old-code/v5_hal/msg/V5Battery.msg @@ -0,0 +1,4 @@ +float64 capacity +float64 current +float64 temperature +float64 voltage \ No newline at end of file diff --git a/old-code/v5_hal/msg/V5Controller.msg b/old-code/v5_hal/msg/V5Controller.msg new file mode 100644 index 00000000..0f92a297 --- /dev/null +++ b/old-code/v5_hal/msg/V5Controller.msg @@ -0,0 +1,17 @@ +int8 analog_left_x +int8 analog_left_y +int8 analog_right_x +int8 analog_right_y +bool btn_right +bool btn_down +bool btn_left +bool btn_up +bool btn_a +bool btn_b +bool btn_x +bool btn_y +bool btn_r1 +bool btn_r2 +bool btn_l1 +bool btn_l2 +bool is_connected \ No newline at end of file diff --git a/old-code/v5_hal/msg/V5InertialSensor.msg b/old-code/v5_hal/msg/V5InertialSensor.msg new file mode 100644 index 00000000..40c76242 --- /dev/null +++ b/old-code/v5_hal/msg/V5InertialSensor.msg @@ -0,0 +1,4 @@ +int32 distance +int32 confidence +int32 object_size +int32 object_velocity \ No newline at end of file diff --git a/old-code/v5_hal/msg/V5Motor.msg b/old-code/v5_hal/msg/V5Motor.msg new file mode 100644 index 00000000..dceea79e --- /dev/null +++ b/old-code/v5_hal/msg/V5Motor.msg @@ -0,0 +1,4 @@ +int8 direction +float32 position +float32 velocity +float32 voltage \ No newline at end of file diff --git a/old-code/v5_hal/package.xml b/old-code/v5_hal/package.xml new file mode 100644 index 00000000..bee2035a --- /dev/null +++ b/old-code/v5_hal/package.xml @@ -0,0 +1,68 @@ + + + v5_hal + 0.0.0 + The V5HAL package + + + + + kempena + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + message_generation + roscpp + rosserial_vex_v5 + roscpp + rosserial_vex_v5 + roscpp + rosserial_vex_v5 + message_runtime + + + + + + + + + diff --git a/old-code/v5_hal/test/pathing/test_PathPoint.cpp b/old-code/v5_hal/test/pathing/test_PathPoint.cpp new file mode 100644 index 00000000..a4c5ac84 --- /dev/null +++ b/old-code/v5_hal/test/pathing/test_PathPoint.cpp @@ -0,0 +1,136 @@ +#include +#include "pathing/PathPoint.h" + +class PathPointTest : public ::testing::Test { + virtual void SetUp() { + + } + + virtual void TearDown() { + + } +}; + +/** + * @brief Given two points with only constant x velocities, when the first PathPoint is interpolated to the second PathPoint at the second's time, then the resulting PathPoint should be equivalent to the second point. + * @param PathPointTest The fixture used for testing PathPoints. + * @param xChangeConstantVel The name of this test. + * @author Jonathan Phung + */ +TEST(PathPointTest, xChangeConstantVel) { + PathPoint* firstPoint = new PathPoint(0, Pose(Eigen::Vector2d(0, 0), Eigen::Rotation2Dd(0)), Eigen::Vector2d(1, 0), 0); + PathPoint* secondPoint = new PathPoint(1, Pose(Eigen::Vector2d(1, 0), Eigen::Rotation2Dd(0)), Eigen::Vector2d(1, 0), 0); + PathPoint result = firstPoint->interpolateTo(*secondPoint, 1); + + EXPECT_EQ(secondPoint->getLinearVelocity().x(), result.getLinearVelocity().x()); + EXPECT_EQ(secondPoint->getLinearVelocity().y(), result.getLinearVelocity().y()); + EXPECT_EQ(secondPoint->getPose().position.x(), result.getPose().position.x()); + EXPECT_EQ(secondPoint->getPose().position.y(), result.getPose().position.y()); + EXPECT_EQ(secondPoint->getPose().angle.angle(), result.getPose().angle.angle()); + EXPECT_EQ(secondPoint->getRotationalVelocity(), result.getRotationalVelocity()); + EXPECT_EQ(secondPoint->getTime(), result.getTime()); + + delete firstPoint; + delete secondPoint; +} + + +/** + * @brief Given two points with only constant y velocities, when the first PathPoint is interpolated to the second PathPoint at the second's time, then the resulting PathPoint should be equivalent to the second point. + * @param PathPointTest The fixture used for testing PathPoints. + * @param yChangeConstantVel The name of this test. + * @author Jonathan Phung + */ +TEST(PathPointTest, yChangeConstantVel) { + PathPoint* firstPoint = new PathPoint(0, Pose(Eigen::Vector2d(0, 0), Eigen::Rotation2Dd(0)), Eigen::Vector2d(0, 1), 0); + PathPoint* secondPoint = new PathPoint(1, Pose(Eigen::Vector2d(0, 1), Eigen::Rotation2Dd(0)), Eigen::Vector2d(0, 1), 0); + PathPoint result = firstPoint->interpolateTo(*secondPoint, 1); + + EXPECT_EQ(secondPoint->getLinearVelocity().x(), result.getLinearVelocity().x()); + EXPECT_EQ(secondPoint->getLinearVelocity().y(), result.getLinearVelocity().y()); + EXPECT_EQ(secondPoint->getPose().position.x(), result.getPose().position.x()); + EXPECT_EQ(secondPoint->getPose().position.y(), result.getPose().position.y()); + EXPECT_EQ(secondPoint->getPose().angle.angle(), result.getPose().angle.angle()); + EXPECT_EQ(secondPoint->getRotationalVelocity(), result.getRotationalVelocity()); + EXPECT_EQ(secondPoint->getTime(), result.getTime()); + + delete firstPoint; + delete secondPoint; +} + + +/** + * @brief Given two points with only constant x and y velocities, when the first PathPoint is interpolated to the second PathPoint at the second's time, then the resulting PathPoint should be equivalent to the second point. + * @param PathPointTest The fixture used for testing PathPoints. + * @param xyChangeConstantVel The name of this test. + * @author Jonathan Phung + */ +TEST(PathPointTest, xyChangeConstantVel) { + PathPoint* firstPoint = new PathPoint(0, Pose(Eigen::Vector2d(0, 0), Eigen::Rotation2Dd(0)), Eigen::Vector2d(1, 1), 0); + PathPoint* secondPoint = new PathPoint(1, Pose(Eigen::Vector2d(1, 1), Eigen::Rotation2Dd(0)), Eigen::Vector2d(1, 1), 0); + PathPoint result = firstPoint->interpolateTo(*secondPoint, 1); + + EXPECT_EQ(secondPoint->getLinearVelocity().x(), result.getLinearVelocity().x()); + EXPECT_EQ(secondPoint->getLinearVelocity().y(), result.getLinearVelocity().y()); + EXPECT_EQ(secondPoint->getPose().position.x(), result.getPose().position.x()); + EXPECT_EQ(secondPoint->getPose().position.y(), result.getPose().position.y()); + EXPECT_EQ(secondPoint->getPose().angle.angle(), result.getPose().angle.angle()); + EXPECT_EQ(secondPoint->getRotationalVelocity(), result.getRotationalVelocity()); + EXPECT_EQ(secondPoint->getTime(), result.getTime()); + + delete firstPoint; + delete secondPoint; +} + +/** + * @brief Given two points with no velocity or acceleration, when the first PathPoint is interpolated to the second PathPoint at the second's time, then the resulting PathPoint should be equivalent to the second point. + * @param PathPointTest The fixture used for testing PathPoints. + * @param noChange The name of this test. + * @author Jonathan Phung + */ +TEST(PathPointTest, noChange) { + PathPoint* firstPoint = new PathPoint(0, Pose(Eigen::Vector2d(0, 0), Eigen::Rotation2Dd(0)), Eigen::Vector2d(0, 0), 0); + PathPoint* secondPoint = new PathPoint(1, Pose(Eigen::Vector2d(0, 0), Eigen::Rotation2Dd(0)), Eigen::Vector2d(0, 0), 0); + PathPoint result = firstPoint->interpolateTo(*secondPoint, 1); + + EXPECT_EQ(secondPoint->getLinearVelocity().x(), result.getLinearVelocity().x()); + EXPECT_EQ(secondPoint->getLinearVelocity().y(), result.getLinearVelocity().y()); + EXPECT_EQ(secondPoint->getPose().position.x(), result.getPose().position.x()); + EXPECT_EQ(secondPoint->getPose().position.y(), result.getPose().position.y()); + EXPECT_EQ(secondPoint->getPose().angle.angle(), result.getPose().angle.angle()); + EXPECT_EQ(secondPoint->getRotationalVelocity(), result.getRotationalVelocity()); + EXPECT_EQ(secondPoint->getTime(), result.getTime()); + + delete firstPoint; + delete secondPoint; +} + +/** + * @brief Given four points, all 90 degrees clockwise apart, the path should correctly interpolate between them + * @param PathPointTest The fixture used for testing PathPoints. + * @param rotateInPlace The name of this test. + * @author Nathan DuPont + */ +TEST(PathPointTest, rotateInPlace) { + PathPoint* pointAt0Degrees = new PathPoint(0, Pose(Eigen::Vector2d(0, 0), Eigen::Rotation2Dd(0)), Eigen::Vector2d(0, 0), 0.1); + PathPoint* pointAt90Degrees = new PathPoint(1, Pose(Eigen::Vector2d(0, 0), Eigen::Rotation2Dd(M_PI_2)), Eigen::Vector2d(0, 0), 0.1); + PathPoint* pointAt180Degrees = new PathPoint(2, Pose(Eigen::Vector2d(0, 0), Eigen::Rotation2Dd(M_PI)), Eigen::Vector2d(0, 0), 0.1); + PathPoint* pointAt270Degrees = new PathPoint(3, Pose(Eigen::Vector2d(0, 0), Eigen::Rotation2Dd(3 * M_PI_2)), Eigen::Vector2d(0, 0), 0.1); + PathPoint* pointAt360Degrees = new PathPoint(3, Pose(Eigen::Vector2d(0, 0), Eigen::Rotation2Dd(M_2_PI)), Eigen::Vector2d(0, 0), 0.1); + + PathPoint testPointAt45Degrees = pointAt0Degrees->interpolateTo(*pointAt90Degrees, 0.5); + + EXPECT_EQ(testPointAt45Degrees.getLinearVelocity().x(), 0.); + EXPECT_EQ(testPointAt45Degrees.getLinearVelocity().y(), 0.); + EXPECT_EQ(testPointAt45Degrees.getPose().position.x(), 0.); + EXPECT_EQ(testPointAt45Degrees.getPose().position.y(), 0.); + EXPECT_NEAR(testPointAt45Degrees.getPose().angle.angle(), M_PI_4, 0.001); + EXPECT_EQ(testPointAt45Degrees.getRotationalVelocity(), 0.1); + EXPECT_EQ(testPointAt45Degrees.getTime(), 0.5); + + delete pointAt0Degrees; + delete pointAt90Degrees; + delete pointAt180Degrees; + delete pointAt270Degrees; + delete pointAt360Degrees; +} \ No newline at end of file diff --git a/old-code/v5_hal/test/swerve/test_SwerveModule.cpp b/old-code/v5_hal/test/swerve/test_SwerveModule.cpp new file mode 100644 index 00000000..8899469a --- /dev/null +++ b/old-code/v5_hal/test/swerve/test_SwerveModule.cpp @@ -0,0 +1,72 @@ +#include +#include "swerve/SwerveModule.h" + +class SimpleForwardModule : public ::testing::Test { +protected: + SwerveModule* swerveModule; + + virtual void SetUp() { + // Swerve Module centered in x direction, and 1 meter forward in y direction + // Threshold for full power rotation of pi/3 (60 deg) + // Max velocity of 100 m/s, max module rotational speed of 100 RPM + swerveModule = new SwerveModule(Eigen::Vector2d(0, 1), 1, 1, 1); + } + + virtual void TearDown() { + delete swerveModule; + } +}; + +TEST_F(SimpleForwardModule, DriveForwardFullSpeed) { + // Drive forwards at full speed, module already facing correct direction + MotorPowers motorMags = swerveModule->InverseKinematics(Eigen::Vector2d(0, 100), 0, Eigen::Rotation2Dd(M_PI/2)); + + EXPECT_EQ(motorMags.left_motor_power, 127); + EXPECT_EQ(motorMags.right_motor_power, -127); +} + +TEST_F(SimpleForwardModule, DriveForwardHalfSpeed) { + // Drive forwards at full speed, module already facing correct direction + MotorPowers motorMags = swerveModule->InverseKinematics(Eigen::Vector2d(0, 50), 0, Eigen::Rotation2Dd(M_PI/2)); + + EXPECT_EQ(motorMags.left_motor_power, 127/2); + EXPECT_EQ(motorMags.right_motor_power, -127/2); +} + +TEST_F(SimpleForwardModule, RotateInPlaceFullPower) { + // Drive forwards at full speed, module already facing correct direction + MotorPowers motorMags = swerveModule->InverseKinematics(Eigen::Vector2d(0, 0), 1, Eigen::Rotation2Dd(0)); + + EXPECT_EQ(motorMags.left_motor_power, 127); + EXPECT_EQ(motorMags.right_motor_power, 127); +} + +TEST_F(SimpleForwardModule, RotateInPlaceHalfPower) { + // Drive forwards at full speed, module already facing correct direction + MotorPowers motorMags = swerveModule->InverseKinematics(Eigen::Vector2d(0, 0), 50, Eigen::Rotation2Dd(M_PI - M_PI/6)); + + EXPECT_NEAR(motorMags.left_motor_power, 127, 1); + EXPECT_EQ(motorMags.right_motor_power, 0); +} + +TEST_F(SimpleForwardModule, OverSpeedNegativeDirection) { + // Drive forwards at full speed, module already facing correct direction + MotorPowers motorMags = swerveModule->InverseKinematics(Eigen::Vector2d(0, -1000), 0, Eigen::Rotation2Dd(-M_PI/2)); + + EXPECT_EQ(motorMags.left_motor_power, 127); + EXPECT_EQ(motorMags.right_motor_power, -127); +} + +TEST_F(SimpleForwardModule, SetModuleToAngleNoForwardSpeed) { + // Drive forwards at full speed, module already facing correct direction + MotorPowers motorMags = swerveModule->InverseKinematics(Eigen::Vector2d(0, 0.00000000001), 0, Eigen::Rotation2Dd(M_PI/3)); + + EXPECT_EQ(motorMags.left_motor_power, 63); + EXPECT_EQ(motorMags.right_motor_power, 63); +} + + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/paths/programming-skills_06-25_03-00AM.json b/paths/programming-skills_06-25_03-00AM.json new file mode 100644 index 00000000..82653cec --- /dev/null +++ b/paths/programming-skills_06-25_03-00AM.json @@ -0,0 +1,13387 @@ +{ + "sharedWaypoints": [ + { + "name": "Goal1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -55.25, + "y": 16.43, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal2", + "omega": 0, + "angle": 180, + "spline_angle": -180, + "x": -57.68, + "y": 71.76, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal3", + "omega": 0, + "angle": 135, + "spline_angle": 105, + "x": -59.75, + "y": 131.9, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal6", + "omega": 0, + "angle": 90, + "spline_angle": 80.85, + "x": 0.24, + "y": 128.08, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal9", + "omega": 0, + "angle": 45, + "spline_angle": 26.49, + "x": 58.79, + "y": 129.99, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal8", + "omega": 0, + "angle": 0, + "spline_angle": 163.67, + "x": 57.04, + "y": 71.76, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal7", + "omega": 0, + "angle": -45, + "spline_angle": 113.16, + "x": 62.36, + "y": 14.38, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal5", + "omega": 0, + "angle": 90, + "spline_angle": 89.98, + "x": 0.24, + "y": 60.94, + "shared": true, + "speed": 41.9 + }, + { + "name": "Deploy4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": 0, + "y": 24.12, + "shared": true, + "speed": 41.9 + }, + { + "name": "Deploy1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -52.32, + "y": 18.69, + "shared": true, + "speed": 41.9 + }, + { + "name": "DeployWall1", + "omega": 0, + "angle": 90, + "spline_angle": 88.38, + "x": -36.52, + "y": 9.85, + "shared": true, + "speed": 41.9 + }, + { + "name": "DeployWall2", + "omega": 0, + "angle": -90, + "spline_angle": 90, + "x": -12.17, + "y": 14.16, + "shared": true, + "speed": 41.9 + } + ], + "robot": { + "robotName": "", + "robotWidth": "", + "robotLength": "", + "savedIsTank": false + }, + "paths": [ + { + "name": "StartToGoal1", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "startWaypoint", + "omega": 0, + "angle": 150, + "spline_angle": 150, + "x": -16.15, + "y": 16.07, + "shared": false, + "speed": 0 + }, + { + "name": "endWaypoint", + "omega": 0, + "angle": 180, + "spline_angle": 180, + "x": -27.92, + "y": 23.55, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -135, + "spline_angle": 21.77, + "x": -48.13, + "y": 21, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -55.25, + "y": 16.43, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -16.15, + "y": 16.07, + "speed": 0, + "time": 0, + "theta": 150, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -17.78, + "y": 17.22, + "speed": 19.97, + "time": 0.1, + "theta": 151.16, + "omega": 23.14, + "vx": -16.34, + "vy": 11.48, + "splineNum": 0 + }, + { + "x": -19.28, + "y": 18.57, + "speed": 28.34, + "time": 0.17, + "theta": 153.39, + "omega": 39.66, + "vx": -21.04, + "vy": 18.98, + "splineNum": 0 + }, + { + "x": -20.74, + "y": 19.99, + "speed": 34.79, + "time": 0.23, + "theta": 156.11, + "omega": 53.21, + "vx": -24.92, + "vy": 24.28, + "splineNum": 0 + }, + { + "x": -22.24, + "y": 21.34, + "speed": 35.25, + "time": 0.29, + "theta": 159.54, + "omega": 169.32, + "vx": -26.25, + "vy": 23.53, + "splineNum": 0 + }, + { + "x": -23.88, + "y": 22.47, + "speed": 29.05, + "time": 0.36, + "theta": 164.65, + "omega": 153.42, + "vx": -23.88, + "vy": 16.55, + "splineNum": 0 + }, + { + "x": -25.75, + "y": 23.26, + "speed": 23.95, + "time": 0.44, + "theta": 172.42, + "omega": 133.88, + "vx": -22.08, + "vy": 9.29, + "splineNum": 0 + }, + { + "x": -27.92, + "y": 23.55, + "speed": 31.82, + "time": 0.51, + "theta": 180, + "omega": 117.9, + "vx": -31.54, + "vy": 4.24, + "splineNum": 0 + }, + { + "x": -27.92, + "y": 23.55, + "speed": 31.82, + "time": 0.51, + "theta": 180, + "omega": 117.9, + "vx": 31.82, + "vy": 0, + "splineNum": 0 + }, + { + "x": -30.85, + "y": 23.55, + "speed": 39.99, + "time": 0.58, + "theta": 181.24, + "omega": 33.76, + "vx": -39.99, + "vy": -0.06, + "splineNum": 1 + }, + { + "x": -33.78, + "y": 23.5, + "speed": 46.74, + "time": 0.64, + "theta": 184.26, + "omega": 62.6, + "vx": -46.74, + "vy": -0.73, + "splineNum": 1 + }, + { + "x": -36.7, + "y": 23.37, + "speed": 50, + "time": 0.7, + "theta": 188.7, + "omega": 89.48, + "vx": -49.95, + "vy": -2.29, + "splineNum": 1 + }, + { + "x": -39.6, + "y": 23.1, + "speed": 50, + "time": 0.76, + "theta": 194.69, + "omega": 290.83, + "vx": -49.79, + "vy": -4.63, + "splineNum": 1 + }, + { + "x": -42.47, + "y": 22.64, + "speed": 50, + "time": 0.82, + "theta": 202.24, + "omega": 264.02, + "vx": -49.39, + "vy": -7.77, + "splineNum": 1 + }, + { + "x": -45.32, + "y": 21.96, + "speed": 48.48, + "time": 0.88, + "theta": 211.72, + "omega": 236.21, + "vx": -47.14, + "vy": -11.31, + "splineNum": 1 + }, + { + "x": -48.13, + "y": 21, + "speed": 41.9, + "time": 0.95, + "theta": 225, + "omega": 203.56, + "vx": -39.65, + "vy": -13.54, + "splineNum": 1 + }, + { + "x": -48.13, + "y": 21, + "speed": 41.9, + "time": 0.95, + "theta": 225, + "omega": 203.56, + "vx": -32, + "vy": -16, + "splineNum": 1 + }, + { + "x": -49.26, + "y": 20.52, + "speed": 44.73, + "time": 0.98, + "theta": -135, + "omega": 0, + "vx": -41.13, + "vy": -17.57, + "splineNum": 2 + }, + { + "x": -50.35, + "y": 19.99, + "speed": 47.37, + "time": 1, + "theta": -135, + "omega": 0, + "vx": -42.58, + "vy": -20.76, + "splineNum": 2 + }, + { + "x": -51.41, + "y": 19.4, + "speed": 49.86, + "time": 1.03, + "theta": -135, + "omega": 0, + "vx": -43.58, + "vy": -24.23, + "splineNum": 2 + }, + { + "x": -52.43, + "y": 18.75, + "speed": 49.87, + "time": 1.05, + "theta": -135, + "omega": 0, + "vx": -42.13, + "vy": -26.68, + "splineNum": 2 + }, + { + "x": -53.41, + "y": 18.04, + "speed": 47.38, + "time": 1.08, + "theta": -135, + "omega": 0, + "vx": -38.43, + "vy": -27.71, + "splineNum": 2 + }, + { + "x": -54.35, + "y": 17.27, + "speed": 44.74, + "time": 1.11, + "theta": -135, + "omega": 0, + "vx": -34.57, + "vy": -28.39, + "splineNum": 2 + }, + { + "x": -55.25, + "y": 16.43, + "speed": 41.9, + "time": 1.13, + "theta": -135, + "omega": 0, + "vx": -30.59, + "vy": -28.64, + "splineNum": 2 + } + ] + }, + { + "name": "Goal1ToGoal2", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal1", + "omega": 183.36749403282326, + "angle": -135, + "spline_angle": -135, + "x": -55.25, + "y": 16.43, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 183.36749403282326, + "angle": -66.51, + "spline_angle": 8.94, + "x": -53.34, + "y": 16.14, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 183.36749403282326, + "angle": -122.24, + "spline_angle": 78.63, + "x": -47.4, + "y": 20.39, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 183.36749403282326, + "angle": 165, + "spline_angle": 118.84, + "x": -51.31, + "y": 33.41, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 183.36749403282326, + "angle": 180, + "spline_angle": 85, + "x": -58.27, + "y": 40.6, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 183.36749403282326, + "angle": 90, + "spline_angle": 53.01, + "x": -44.51, + "y": 48.25, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 183.36749403282326, + "angle": 127.94, + "spline_angle": 116.52, + "x": -42.64, + "y": 65.4, + "shared": false, + "speed": 50 + }, + { + "name": "Goal2", + "omega": 183.36749403282326, + "angle": 180, + "spline_angle": -180, + "x": -59.97, + "y": 69.82, + "shared": true, + "speed": 50 + } + ], + "points": [ + { + "x": -55.25, + "y": 16.43, + "speed": 9, + "time": 0, + "theta": -135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -54.94, + "y": 16.65, + "speed": 2.14, + "time": 0.18, + "theta": -129.67, + "omega": 59.61, + "vx": 1.75, + "vy": 1.23, + "splineNum": 0 + }, + { + "x": -54.65, + "y": 16.69, + "speed": 1.92, + "time": 0.33, + "theta": -116.99, + "omega": 317.7, + "vx": 1.9, + "vy": 0.27, + "splineNum": 0 + }, + { + "x": -54.39, + "y": 16.61, + "speed": 3.75, + "time": 0.4, + "theta": -107.9, + "omega": 292.87, + "vx": 3.57, + "vy": -1.14, + "splineNum": 0 + }, + { + "x": -54.13, + "y": 16.45, + "speed": 8.59, + "time": 0.44, + "theta": -103.03, + "omega": 281.29, + "vx": 7.36, + "vy": -4.41, + "splineNum": 0 + }, + { + "x": -53.88, + "y": 16.29, + "speed": 6.39, + "time": 0.49, + "theta": -95.72, + "omega": 265.47, + "vx": 5.35, + "vy": -3.49, + "splineNum": 0 + }, + { + "x": -53.62, + "y": 16.16, + "speed": 2.39, + "time": 0.61, + "theta": -73.86, + "omega": 225.41, + "vx": 2.17, + "vy": -1.02, + "splineNum": 0 + }, + { + "x": -53.34, + "y": 16.14, + "speed": 7.81, + "time": 0.64, + "theta": -66.51, + "omega": 213.62, + "vx": 7.79, + "vy": -0.66, + "splineNum": 0 + }, + { + "x": -53.34, + "y": 16.14, + "speed": 7.81, + "time": 0.64, + "theta": -66.51, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": -52.2, + "y": 16.34, + "speed": 17.11, + "time": 0.71, + "theta": -66.89, + "omega": -11.09, + "vx": 16.86, + "vy": 2.91, + "splineNum": 1 + }, + { + "x": -51.1, + "y": 16.6, + "speed": 22.77, + "time": 0.76, + "theta": -67.64, + "omega": -19.2, + "vx": 22.16, + "vy": 5.23, + "splineNum": 1 + }, + { + "x": -50.08, + "y": 16.96, + "speed": 18.67, + "time": 0.82, + "theta": -69.03, + "omega": -28.72, + "vx": 17.57, + "vy": 6.29, + "splineNum": 1 + }, + { + "x": -49.17, + "y": 17.48, + "speed": 13.7, + "time": 0.89, + "theta": -71.71, + "omega": -41.26, + "vx": 11.92, + "vy": 6.75, + "splineNum": 1 + }, + { + "x": -48.39, + "y": 18.19, + "speed": 12.41, + "time": 0.98, + "theta": -75.79, + "omega": -55.14, + "vx": 9.11, + "vy": 8.42, + "splineNum": 1 + }, + { + "x": -47.79, + "y": 19.15, + "speed": 14.47, + "time": 1.06, + "theta": -80.59, + "omega": -202.3, + "vx": 7.69, + "vy": 12.25, + "splineNum": 1 + }, + { + "x": -47.4, + "y": 20.39, + "speed": 3.18, + "time": 1.47, + "theta": -122.24, + "omega": -135.1, + "vx": 0.96, + "vy": 3.03, + "splineNum": 1 + }, + { + "x": -47.4, + "y": 20.39, + "speed": 3.18, + "time": 1.47, + "theta": -122.24, + "omega": -135.1, + "vx": 0, + "vy": 3.2, + "splineNum": 1 + }, + { + "x": -47.18, + "y": 22.48, + "speed": 20.76, + "time": 1.57, + "theta": -125.41, + "omega": -62.49, + "vx": 2.17, + "vy": 20.65, + "splineNum": 2 + }, + { + "x": -47.34, + "y": 24.46, + "speed": 28.78, + "time": 1.64, + "theta": -131.19, + "omega": -105.03, + "vx": -2.33, + "vy": 28.69, + "splineNum": 2 + }, + { + "x": -47.81, + "y": 26.35, + "speed": 34.89, + "time": 1.69, + "theta": -138, + "omega": -139.38, + "vx": -8.41, + "vy": 33.86, + "splineNum": 2 + }, + { + "x": -48.51, + "y": 28.17, + "speed": 40.08, + "time": 1.74, + "theta": -145.5, + "omega": -429.65, + "vx": -14.48, + "vy": 37.38, + "splineNum": 2 + }, + { + "x": -49.38, + "y": 29.93, + "speed": 35.88, + "time": 1.8, + "theta": -155.72, + "omega": -395.83, + "vx": -15.79, + "vy": 32.21, + "splineNum": 2 + }, + { + "x": -50.34, + "y": 31.67, + "speed": 29.83, + "time": 1.86, + "theta": -170.61, + "omega": -354.8, + "vx": -14.36, + "vy": 26.14, + "splineNum": 2 + }, + { + "x": -51.31, + "y": 33.41, + "speed": 22.18, + "time": 1.95, + "theta": -195, + "omega": -299.49, + "vx": -10.85, + "vy": 19.34, + "splineNum": 2 + }, + { + "x": -51.31, + "y": 33.41, + "speed": 22.18, + "time": 1.95, + "theta": -195, + "omega": -299.49, + "vx": -32, + "vy": 0, + "splineNum": 2 + }, + { + "x": -52.24, + "y": 34.5, + "speed": 14.33, + "time": 2.05, + "theta": 165.18, + "omega": 3.56, + "vx": -9.35, + "vy": 10.87, + "splineNum": 3 + }, + { + "x": -53.5, + "y": 35.27, + "speed": 22.37, + "time": 2.12, + "theta": 165.49, + "omega": 5.91, + "vx": -19.01, + "vy": 11.79, + "splineNum": 3 + }, + { + "x": -54.89, + "y": 35.91, + "speed": 26.91, + "time": 2.17, + "theta": 165.89, + "omega": 7.95, + "vx": -24.44, + "vy": 11.26, + "splineNum": 3 + }, + { + "x": -56.24, + "y": 36.59, + "speed": 20.53, + "time": 2.25, + "theta": 166.57, + "omega": 10.58, + "vx": -18.34, + "vy": 9.22, + "splineNum": 3 + }, + { + "x": -57.38, + "y": 37.49, + "speed": 11.53, + "time": 2.37, + "theta": 168.17, + "omega": 15.04, + "vx": -9.06, + "vy": 7.13, + "splineNum": 3 + }, + { + "x": -58.11, + "y": 38.76, + "speed": 11.49, + "time": 2.5, + "theta": 170.39, + "omega": 45.81, + "vx": -5.74, + "vy": 9.96, + "splineNum": 3 + }, + { + "x": -58.27, + "y": 40.6, + "speed": 5.02, + "time": 2.87, + "theta": 180, + "omega": 32.71, + "vx": -0.43, + "vy": 5, + "splineNum": 3 + }, + { + "x": -58.27, + "y": 40.6, + "speed": 5.02, + "time": 2.87, + "theta": 180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 4 + }, + { + "x": -57.43, + "y": 43.72, + "speed": 16.48, + "time": 3.07, + "theta": 175.15, + "omega": -49.51, + "vx": 4.27, + "vy": 15.92, + "splineNum": 4 + }, + { + "x": -55.79, + "y": 45.4, + "speed": 14.35, + "time": 3.23, + "theta": 163.69, + "omega": -90.76, + "vx": 10.05, + "vy": 10.24, + "splineNum": 4 + }, + { + "x": -53.6, + "y": 46.08, + "speed": 25.79, + "time": 3.32, + "theta": 154.61, + "omega": -313.12, + "vx": 24.6, + "vy": 7.74, + "splineNum": 4 + }, + { + "x": -51.12, + "y": 46.25, + "speed": 34.09, + "time": 3.39, + "theta": 145.68, + "omega": -294.71, + "vx": 34.02, + "vy": 2.3, + "splineNum": 4 + }, + { + "x": -48.61, + "y": 46.36, + "speed": 27.03, + "time": 3.48, + "theta": 132.34, + "omega": -271.22, + "vx": 27.01, + "vy": 1.16, + "splineNum": 4 + }, + { + "x": -46.32, + "y": 46.87, + "speed": 16.18, + "time": 3.63, + "theta": 107.19, + "omega": -234.62, + "vx": 15.79, + "vy": 3.53, + "splineNum": 4 + }, + { + "x": -44.51, + "y": 48.25, + "speed": 26.76, + "time": 3.71, + "theta": 90, + "omega": -213.18, + "vx": 21.28, + "vy": 16.23, + "splineNum": 4 + }, + { + "x": -44.51, + "y": 48.25, + "speed": 26.76, + "time": 3.71, + "theta": 90, + "omega": -213.18, + "vx": 16, + "vy": 16, + "splineNum": 4 + }, + { + "x": -42.98, + "y": 50.56, + "speed": 35.65, + "time": 3.79, + "theta": 90.29, + "omega": 7.39, + "vx": 19.69, + "vy": 29.72, + "splineNum": 5 + }, + { + "x": -41.84, + "y": 52.92, + "speed": 42.35, + "time": 3.85, + "theta": 90.92, + "omega": 13.25, + "vx": 18.37, + "vy": 38.16, + "splineNum": 5 + }, + { + "x": -41.12, + "y": 55.32, + "speed": 43.43, + "time": 3.91, + "theta": 91.85, + "omega": 18.74, + "vx": 12.51, + "vy": 41.59, + "splineNum": 5 + }, + { + "x": -40.83, + "y": 57.76, + "speed": 40.28, + "time": 3.97, + "theta": 93.17, + "omega": 24.55, + "vx": 4.83, + "vy": 39.99, + "splineNum": 5 + }, + { + "x": -40.97, + "y": 60.26, + "speed": 33.5, + "time": 4.05, + "theta": 95.27, + "omega": 31.64, + "vx": -1.94, + "vy": 33.45, + "splineNum": 5 + }, + { + "x": -41.57, + "y": 62.8, + "speed": 24.49, + "time": 4.15, + "theta": 99.19, + "omega": 41.78, + "vx": -5.62, + "vy": 23.84, + "splineNum": 5 + }, + { + "x": -42.64, + "y": 65.4, + "speed": 6.18, + "time": 4.61, + "theta": 127.94, + "omega": 84.9, + "vx": -2.35, + "vy": 5.72, + "splineNum": 5 + }, + { + "x": -42.64, + "y": 65.4, + "speed": 6.18, + "time": 4.61, + "theta": 127.94, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 6 + }, + { + "x": -44.56, + "y": 68.21, + "speed": 26.82, + "time": 4.73, + "theta": 130.54, + "omega": 41.01, + "vx": -15.11, + "vy": 22.16, + "splineNum": 6 + }, + { + "x": -46.78, + "y": 69.84, + "speed": 23.04, + "time": 4.85, + "theta": 137.76, + "omega": 79.62, + "vx": -18.57, + "vy": 13.64, + "splineNum": 6 + }, + { + "x": -49.23, + "y": 70.57, + "speed": 30.69, + "time": 4.94, + "theta": 145.51, + "omega": 260.22, + "vx": -29.45, + "vy": 8.65, + "splineNum": 6 + }, + { + "x": -51.85, + "y": 70.65, + "speed": 38.28, + "time": 5.01, + "theta": 153.54, + "omega": 238.14, + "vx": -38.26, + "vy": 1.23, + "splineNum": 6 + }, + { + "x": -54.56, + "y": 70.37, + "speed": 44.83, + "time": 5.07, + "theta": 161.95, + "omega": 218.53, + "vx": -44.6, + "vy": -4.59, + "splineNum": 6 + }, + { + "x": -57.29, + "y": 70, + "speed": 50, + "time": 5.12, + "theta": 170.6, + "omega": 200.74, + "vx": -49.55, + "vy": -6.67, + "splineNum": 6 + }, + { + "x": -59.97, + "y": 69.82, + "speed": 50, + "time": 5.18, + "theta": 180, + "omega": 183.37, + "vx": -49.88, + "vy": -3.41, + "splineNum": 6 + } + ] + }, + { + "name": "Goal2ToGoal3", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "wp", + "omega": 16.774945496374254, + "angle": 180, + "spline_angle": 0, + "x": -54.19, + "y": 70.33, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 16.774945496374254, + "angle": -178.65, + "spline_angle": 170.5, + "x": -46.72, + "y": 69.48, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 16.774945496374254, + "angle": -179.15, + "spline_angle": 110.58, + "x": -38.39, + "y": 55.55, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 16.774945496374254, + "angle": 90.04, + "spline_angle": 64.31, + "x": -22.59, + "y": 55.72, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 16.774945496374254, + "angle": 165, + "spline_angle": -36.35, + "x": -33.98, + "y": 82.22, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 16.774945496374254, + "angle": 152.91, + "spline_angle": 129.8, + "x": -62.35, + "y": 91.4, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 16.774945496374254, + "angle": 151.29, + "spline_angle": 85.69, + "x": -63.71, + "y": 104.65, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 16.774945496374254, + "angle": 133.32, + "spline_angle": 122.12, + "x": -57.08, + "y": 122.82, + "shared": false, + "speed": 50 + }, + { + "name": "Goal3", + "omega": 16.774945496374254, + "angle": 135, + "spline_angle": 139.62, + "x": -60.65, + "y": 127.92, + "shared": true, + "speed": 50 + } + ], + "points": [ + { + "x": -54.19, + "y": 70.33, + "speed": 41.74, + "time": 0, + "theta": 180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -53.11, + "y": 70.3, + "speed": 39.07, + "time": 0.03, + "theta": 180.01, + "omega": 0.9, + "vx": 39.06, + "vy": -0.92, + "splineNum": 0 + }, + { + "x": -52.04, + "y": 70.23, + "speed": 36.22, + "time": 0.06, + "theta": 180.05, + "omega": 1.87, + "vx": 36.14, + "vy": -2.38, + "splineNum": 0 + }, + { + "x": -50.97, + "y": 70.13, + "speed": 33.12, + "time": 0.09, + "theta": 180.13, + "omega": 2.92, + "vx": 32.95, + "vy": -3.33, + "splineNum": 0 + }, + { + "x": -49.91, + "y": 69.99, + "speed": 29.7, + "time": 0.13, + "theta": 180.26, + "omega": 4.1, + "vx": 29.45, + "vy": -3.8, + "splineNum": 0 + }, + { + "x": -48.84, + "y": 69.83, + "speed": 25.83, + "time": 0.17, + "theta": 180.46, + "omega": 13.3, + "vx": 25.54, + "vy": -3.82, + "splineNum": 0 + }, + { + "x": -47.78, + "y": 69.66, + "speed": 21.26, + "time": 0.22, + "theta": 180.77, + "omega": 11.65, + "vx": 20.98, + "vy": -3.4, + "splineNum": 0 + }, + { + "x": -46.72, + "y": 69.48, + "speed": 15.39, + "time": 0.29, + "theta": 181.35, + "omega": 9.38, + "vx": 15.18, + "vy": -2.54, + "splineNum": 0 + }, + { + "x": -46.72, + "y": 69.48, + "speed": 15.39, + "time": 0.29, + "theta": -178.65, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": -43.77, + "y": 68.54, + "speed": 23.72, + "time": 0.42, + "theta": -178.67, + "omega": -0.28, + "vx": 22.61, + "vy": -7.16, + "splineNum": 1 + }, + { + "x": -41.8, + "y": 67.02, + "speed": 20.21, + "time": 0.54, + "theta": -178.72, + "omega": -0.55, + "vx": 15.94, + "vy": -12.42, + "splineNum": 1 + }, + { + "x": -40.59, + "y": 65.04, + "speed": 28.29, + "time": 0.62, + "theta": -178.77, + "omega": -0.73, + "vx": 14.79, + "vy": -24.11, + "splineNum": 1 + }, + { + "x": -39.89, + "y": 62.76, + "speed": 35.74, + "time": 0.69, + "theta": -178.83, + "omega": -2.07, + "vx": 10.57, + "vy": -34.14, + "splineNum": 1 + }, + { + "x": -39.45, + "y": 60.32, + "speed": 36.74, + "time": 0.76, + "theta": -178.89, + "omega": -1.93, + "vx": 6.53, + "vy": -36.15, + "splineNum": 1 + }, + { + "x": -39.03, + "y": 57.87, + "speed": 29.2, + "time": 0.84, + "theta": -178.98, + "omega": -1.74, + "vx": 4.91, + "vy": -28.78, + "splineNum": 1 + }, + { + "x": -38.39, + "y": 55.55, + "speed": 19.27, + "time": 0.97, + "theta": -179.15, + "omega": -1.47, + "vx": 5.11, + "vy": -18.58, + "splineNum": 1 + }, + { + "x": -38.39, + "y": 55.55, + "speed": 19.27, + "time": 0.97, + "theta": -179.15, + "omega": -1.47, + "vx": -19.27, + "vy": 0, + "splineNum": 1 + }, + { + "x": -36.92, + "y": 52.06, + "speed": 33.61, + "time": 1.08, + "theta": -180.22, + "omega": -19.02, + "vx": 13.07, + "vy": -30.96, + "splineNum": 2 + }, + { + "x": -35.45, + "y": 49.42, + "speed": 31.55, + "time": 1.18, + "theta": -182.81, + "omega": -35.13, + "vx": 15.33, + "vy": -27.57, + "splineNum": 2 + }, + { + "x": -33.99, + "y": 47.59, + "speed": 22.97, + "time": 1.28, + "theta": -187.26, + "omega": -52.3, + "vx": 14.31, + "vy": -17.97, + "splineNum": 2 + }, + { + "x": -32.55, + "y": 46.52, + "speed": 12.91, + "time": 1.42, + "theta": -196.21, + "omega": -75.85, + "vx": 10.37, + "vy": -7.7, + "splineNum": 2 + }, + { + "x": -31.11, + "y": 46.14, + "speed": 10.04, + "time": 1.57, + "theta": -209.3, + "omega": -249.15, + "vx": 9.72, + "vy": -2.52, + "splineNum": 2 + }, + { + "x": -29.67, + "y": 46.42, + "speed": 13.15, + "time": 1.68, + "theta": -221.53, + "omega": -230.44, + "vx": 12.92, + "vy": 2.48, + "splineNum": 2 + }, + { + "x": -28.25, + "y": 47.29, + "speed": 22.53, + "time": 1.75, + "theta": -230.87, + "omega": -217.92, + "vx": 19.22, + "vy": 11.76, + "splineNum": 2 + }, + { + "x": -26.82, + "y": 48.71, + "speed": 30.15, + "time": 1.82, + "theta": -240.04, + "omega": -206.69, + "vx": 21.34, + "vy": 21.3, + "splineNum": 2 + }, + { + "x": -25.41, + "y": 50.62, + "speed": 37.22, + "time": 1.88, + "theta": -249.55, + "omega": -195.91, + "vx": 22.15, + "vy": 29.91, + "splineNum": 2 + }, + { + "x": -24, + "y": 52.98, + "speed": 43.98, + "time": 1.94, + "theta": -259.49, + "omega": -185.39, + "vx": 22.61, + "vy": 37.72, + "splineNum": 2 + }, + { + "x": -22.59, + "y": 55.72, + "speed": 50, + "time": 2.01, + "theta": -269.96, + "omega": -174.99, + "vx": 22.82, + "vy": 44.49, + "splineNum": 2 + }, + { + "x": -21.22, + "y": 59.16, + "speed": 50, + "time": 2.08, + "theta": 90.94, + "omega": 24.28, + "vx": 18.46, + "vy": 46.47, + "splineNum": 3 + }, + { + "x": -20.54, + "y": 62.31, + "speed": 47.82, + "time": 2.15, + "theta": 93.32, + "omega": 46.36, + "vx": 10.17, + "vy": 46.73, + "splineNum": 3 + }, + { + "x": -20.47, + "y": 65.2, + "speed": 41.35, + "time": 2.22, + "theta": 97.35, + "omega": 69.23, + "vx": 1.01, + "vy": 41.34, + "splineNum": 3 + }, + { + "x": -20.94, + "y": 67.84, + "speed": 40.85, + "time": 2.28, + "theta": 102.62, + "omega": 90.82, + "vx": -7.24, + "vy": 40.21, + "splineNum": 3 + }, + { + "x": -21.9, + "y": 70.29, + "speed": 46.37, + "time": 2.34, + "theta": 108.29, + "omega": 109.36, + "vx": -16.92, + "vy": 43.17, + "splineNum": 3 + }, + { + "x": -23.27, + "y": 72.55, + "speed": 50, + "time": 2.39, + "theta": 114.54, + "omega": 316.6, + "vx": -25.89, + "vy": 42.77, + "splineNum": 3 + }, + { + "x": -24.99, + "y": 74.67, + "speed": 50, + "time": 2.45, + "theta": 121.93, + "omega": 298.73, + "vx": -31.51, + "vy": 38.82, + "splineNum": 3 + }, + { + "x": -26.99, + "y": 76.66, + "speed": 50, + "time": 2.5, + "theta": 130.62, + "omega": 280.23, + "vx": -35.36, + "vy": 35.35, + "splineNum": 3 + }, + { + "x": -29.19, + "y": 78.57, + "speed": 50, + "time": 2.56, + "theta": 140.69, + "omega": 261.11, + "vx": -37.87, + "vy": 32.65, + "splineNum": 3 + }, + { + "x": -31.55, + "y": 80.41, + "speed": 50, + "time": 2.62, + "theta": 152.17, + "omega": 241.52, + "vx": -39.37, + "vy": 30.82, + "splineNum": 3 + }, + { + "x": -33.98, + "y": 82.22, + "speed": 50, + "time": 2.68, + "theta": 165, + "omega": 221.66, + "vx": -40.12, + "vy": 29.84, + "splineNum": 3 + }, + { + "x": -37.31, + "y": 84.03, + "speed": 48.79, + "time": 2.76, + "theta": 164.84, + "omega": -4.2, + "vx": -42.89, + "vy": 23.25, + "splineNum": 4 + }, + { + "x": -40.91, + "y": 85, + "speed": 50, + "time": 2.83, + "theta": 164.37, + "omega": -8.23, + "vx": -48.26, + "vy": 13.09, + "splineNum": 4 + }, + { + "x": -44.68, + "y": 85.47, + "speed": 50, + "time": 2.91, + "theta": 163.59, + "omega": -12.33, + "vx": -49.62, + "vy": 6.17, + "splineNum": 4 + }, + { + "x": -48.51, + "y": 85.75, + "speed": 50, + "time": 2.99, + "theta": 162.49, + "omega": -16.47, + "vx": -49.87, + "vy": 3.65, + "splineNum": 4 + }, + { + "x": -52.29, + "y": 86.16, + "speed": 50, + "time": 3.06, + "theta": 161.08, + "omega": -51.69, + "vx": -49.71, + "vy": 5.41, + "splineNum": 4 + }, + { + "x": -55.93, + "y": 87.03, + "speed": 49.96, + "time": 3.14, + "theta": 159.39, + "omega": -47.65, + "vx": -48.61, + "vy": 11.56, + "splineNum": 4 + }, + { + "x": -59.32, + "y": 88.67, + "speed": 41.76, + "time": 3.23, + "theta": 156.95, + "omega": -42.78, + "vx": -37.59, + "vy": 18.18, + "splineNum": 4 + }, + { + "x": -62.35, + "y": 91.4, + "speed": 33.17, + "time": 3.35, + "theta": 152.91, + "omega": -36.14, + "vx": -24.65, + "vy": 22.2, + "splineNum": 4 + }, + { + "x": -63.52, + "y": 93.19, + "speed": 25.92, + "time": 3.43, + "theta": 152.84, + "omega": -1.62, + "vx": -14.18, + "vy": 21.7, + "splineNum": 5 + }, + { + "x": -64.18, + "y": 95.04, + "speed": 27.93, + "time": 3.5, + "theta": 152.68, + "omega": -3, + "vx": -9.35, + "vy": 26.32, + "splineNum": 5 + }, + { + "x": -64.43, + "y": 96.92, + "speed": 34.07, + "time": 3.56, + "theta": 152.48, + "omega": -11.86, + "vx": -4.53, + "vy": 33.77, + "splineNum": 5 + }, + { + "x": -64.4, + "y": 98.84, + "speed": 39.3, + "time": 3.61, + "theta": 152.26, + "omega": -10.9, + "vx": 0.71, + "vy": 39.29, + "splineNum": 5 + }, + { + "x": -64.19, + "y": 100.78, + "speed": 43.97, + "time": 3.65, + "theta": 152.02, + "omega": -10.03, + "vx": 4.7, + "vy": 43.72, + "splineNum": 5 + }, + { + "x": -63.92, + "y": 102.72, + "speed": 40.12, + "time": 3.7, + "theta": 151.7, + "omega": -9.07, + "vx": 5.46, + "vy": 39.74, + "splineNum": 5 + }, + { + "x": -63.71, + "y": 104.65, + "speed": 34.93, + "time": 3.76, + "theta": 151.29, + "omega": -7.98, + "vx": 3.79, + "vy": 34.73, + "splineNum": 5 + }, + { + "x": -63.71, + "y": 104.65, + "speed": 34.93, + "time": 3.76, + "theta": 151.29, + "omega": -7.98, + "vx": -34.93, + "vy": 0, + "splineNum": 5 + }, + { + "x": -62.89, + "y": 107.29, + "speed": 25.83, + "time": 3.86, + "theta": 150.91, + "omega": -7.09, + "vx": 7.65, + "vy": 24.67, + "splineNum": 6 + }, + { + "x": -61.2, + "y": 109.62, + "speed": 35.24, + "time": 3.95, + "theta": 150.11, + "omega": -12.49, + "vx": 20.75, + "vy": 28.48, + "splineNum": 6 + }, + { + "x": -59.13, + "y": 111.8, + "speed": 39.49, + "time": 4.02, + "theta": 148.97, + "omega": -17.53, + "vx": 27.14, + "vy": 28.69, + "splineNum": 6 + }, + { + "x": -57.18, + "y": 114.03, + "speed": 31.1, + "time": 4.12, + "theta": 147, + "omega": -23.83, + "vx": 20.43, + "vy": 23.45, + "splineNum": 6 + }, + { + "x": -55.86, + "y": 116.49, + "speed": 20.23, + "time": 4.26, + "theta": 143.08, + "omega": -64.58, + "vx": 9.58, + "vy": 17.81, + "splineNum": 6 + }, + { + "x": -55.66, + "y": 119.36, + "speed": 21.8, + "time": 4.39, + "theta": 138.16, + "omega": -55.85, + "vx": 1.53, + "vy": 21.75, + "splineNum": 6 + }, + { + "x": -57.08, + "y": 122.82, + "speed": 34.97, + "time": 4.49, + "theta": 133.32, + "omega": -48.77, + "vx": -13.27, + "vy": 32.36, + "splineNum": 6 + }, + { + "x": -57.08, + "y": 122.82, + "speed": 34.97, + "time": 4.49, + "theta": 133.32, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 7 + }, + { + "x": -57.54, + "y": 123.58, + "speed": 37.43, + "time": 4.52, + "theta": 133.34, + "omega": 1.99, + "vx": -19.31, + "vy": 32.07, + "splineNum": 7 + }, + { + "x": -57.99, + "y": 124.36, + "speed": 36.79, + "time": 4.54, + "theta": 133.42, + "omega": 4.03, + "vx": -18.35, + "vy": 31.89, + "splineNum": 7 + }, + { + "x": -58.43, + "y": 125.13, + "speed": 34.28, + "time": 4.57, + "theta": 133.55, + "omega": 6.21, + "vx": -17.26, + "vy": 29.62, + "splineNum": 7 + }, + { + "x": -58.91, + "y": 125.88, + "speed": 31.57, + "time": 4.6, + "theta": 133.76, + "omega": 24.98, + "vx": -16.75, + "vy": 26.77, + "splineNum": 7 + }, + { + "x": -59.42, + "y": 126.61, + "speed": 28.62, + "time": 4.63, + "theta": 134.07, + "omega": 22.38, + "vx": -16.55, + "vy": 23.35, + "splineNum": 7 + }, + { + "x": -60, + "y": 127.29, + "speed": 25.31, + "time": 4.66, + "theta": 134.51, + "omega": 19.42, + "vx": -16.29, + "vy": 19.37, + "splineNum": 7 + }, + { + "x": -60.65, + "y": 127.92, + "speed": 28.67, + "time": 4.69, + "theta": 135, + "omega": 16.77, + "vx": -20.69, + "vy": 19.85, + "splineNum": 7 + } + ] + }, + { + "name": "Goal3ToGoal6", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal3", + "omega": 0, + "angle": 135, + "spline_angle": -42.4, + "x": -59.75, + "y": 131.9, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 135, + "spline_angle": -22.69, + "x": -51.79, + "y": 127.29, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -40.88, + "spline_angle": 164.18, + "x": -42.72, + "y": 124.27, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 3.12, + "spline_angle": 164.18, + "x": -7.24, + "y": 94.83, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 86.77, + "spline_angle": 94.14, + "x": 6.28, + "y": 105.01, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 80.85, + "x": 3.9, + "y": 114.72, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal6", + "omega": 0, + "angle": 90, + "spline_angle": 80.85, + "x": 0.24, + "y": 128.08, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -59.75, + "y": 131.9, + "speed": 41.9, + "time": 0, + "theta": 135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -58.73, + "y": 131.04, + "speed": 40.16, + "time": 0.03, + "theta": 135, + "omega": 0, + "vx": 30.73, + "vy": -25.85, + "splineNum": 0 + }, + { + "x": -57.66, + "y": 130.27, + "speed": 36.72, + "time": 0.07, + "theta": 135, + "omega": 0, + "vx": 29.8, + "vy": -21.46, + "splineNum": 0 + }, + { + "x": -56.54, + "y": 129.57, + "speed": 32.95, + "time": 0.11, + "theta": 135, + "omega": 0, + "vx": 27.94, + "vy": -17.45, + "splineNum": 0 + }, + { + "x": -55.39, + "y": 128.94, + "speed": 28.68, + "time": 0.15, + "theta": 135, + "omega": 0, + "vx": 25.13, + "vy": -13.83, + "splineNum": 0 + }, + { + "x": -54.21, + "y": 128.36, + "speed": 23.65, + "time": 0.21, + "theta": 135, + "omega": 0, + "vx": 21.2, + "vy": -10.48, + "splineNum": 0 + }, + { + "x": -53.01, + "y": 127.81, + "speed": 17.18, + "time": 0.29, + "theta": 135, + "omega": 0, + "vx": 15.64, + "vy": -7.1, + "splineNum": 0 + }, + { + "x": -51.79, + "y": 127.29, + "speed": 5.51, + "time": 0.53, + "theta": 135, + "omega": 0, + "vx": 5.07, + "vy": -2.16, + "splineNum": 0 + }, + { + "x": -51.79, + "y": 127.29, + "speed": 5.51, + "time": 0.53, + "theta": 135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": -50.52, + "y": 126.78, + "speed": 17.43, + "time": 0.61, + "theta": 128.77, + "omega": -158.72, + "vx": 16.18, + "vy": -6.5, + "splineNum": 1 + }, + { + "x": -49.24, + "y": 126.3, + "speed": 24.03, + "time": 0.66, + "theta": 116.47, + "omega": -273.76, + "vx": 22.52, + "vy": -8.37, + "splineNum": 1 + }, + { + "x": -47.95, + "y": 125.86, + "speed": 29.16, + "time": 0.71, + "theta": 101.43, + "omega": -368.49, + "vx": 27.56, + "vy": -9.54, + "splineNum": 1 + }, + { + "x": -46.65, + "y": 125.44, + "speed": 32.79, + "time": 0.75, + "theta": 84.33, + "omega": -1234.27, + "vx": 31.19, + "vy": -10.13, + "splineNum": 1 + }, + { + "x": -45.34, + "y": 125.03, + "speed": 28.32, + "time": 0.8, + "theta": 60.14, + "omega": -1136.71, + "vx": 27.06, + "vy": -8.34, + "splineNum": 1 + }, + { + "x": -44.03, + "y": 124.65, + "speed": 22.99, + "time": 0.86, + "theta": 23.87, + "omega": -1016.51, + "vx": 22.05, + "vy": -6.51, + "splineNum": 1 + }, + { + "x": -42.72, + "y": 124.27, + "speed": 15.98, + "time": 0.94, + "theta": -40.88, + "omega": -843.5, + "vx": 15.36, + "vy": -4.4, + "splineNum": 1 + }, + { + "x": -42.72, + "y": 124.27, + "speed": 15.98, + "time": 0.94, + "theta": -40.88, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 2 + }, + { + "x": -39.21, + "y": 122.95, + "speed": 31.71, + "time": 1.06, + "theta": -40.41, + "omega": 8.02, + "vx": 29.68, + "vy": -11.17, + "splineNum": 2 + }, + { + "x": -36.09, + "y": 121.16, + "speed": 41.54, + "time": 1.15, + "theta": -39.46, + "omega": 13.89, + "vx": 36.02, + "vy": -20.7, + "splineNum": 2 + }, + { + "x": -33.29, + "y": 118.98, + "speed": 49.35, + "time": 1.22, + "theta": -38.28, + "omega": 18.76, + "vx": 38.95, + "vy": -30.3, + "splineNum": 2 + }, + { + "x": -30.74, + "y": 116.5, + "speed": 50, + "time": 1.29, + "theta": -36.78, + "omega": 23.58, + "vx": 35.86, + "vy": -34.84, + "splineNum": 2 + }, + { + "x": -28.36, + "y": 113.8, + "speed": 50, + "time": 1.36, + "theta": -34.91, + "omega": 28.44, + "vx": 33.06, + "vy": -37.51, + "splineNum": 2 + }, + { + "x": -26.1, + "y": 110.98, + "speed": 50, + "time": 1.44, + "theta": -32.67, + "omega": 33.35, + "vx": 31.31, + "vy": -38.98, + "splineNum": 2 + }, + { + "x": -23.86, + "y": 108.12, + "speed": 50, + "time": 1.51, + "theta": -30.07, + "omega": 38.27, + "vx": 30.72, + "vy": -39.45, + "splineNum": 2 + }, + { + "x": -21.6, + "y": 105.3, + "speed": 50, + "time": 1.58, + "theta": -27.12, + "omega": 111.26, + "vx": 31.31, + "vy": -38.98, + "splineNum": 2 + }, + { + "x": -19.22, + "y": 102.6, + "speed": 50, + "time": 1.65, + "theta": -23.85, + "omega": 106.4, + "vx": 33.06, + "vy": -37.51, + "splineNum": 2 + }, + { + "x": -16.67, + "y": 100.12, + "speed": 50, + "time": 1.73, + "theta": -20.26, + "omega": 101.58, + "vx": 35.86, + "vy": -34.84, + "splineNum": 2 + }, + { + "x": -13.87, + "y": 97.94, + "speed": 43.92, + "time": 1.81, + "theta": -15.77, + "omega": 96.1, + "vx": 34.66, + "vy": -26.97, + "splineNum": 2 + }, + { + "x": -10.75, + "y": 96.15, + "speed": 34.77, + "time": 1.91, + "theta": -9.37, + "omega": 89.09, + "vx": 30.15, + "vy": -17.32, + "splineNum": 2 + }, + { + "x": -7.24, + "y": 94.83, + "speed": 21.42, + "time": 2.08, + "theta": 3.12, + "omega": 77.22, + "vx": 20.05, + "vy": -7.54, + "splineNum": 2 + }, + { + "x": -7.24, + "y": 94.83, + "speed": 21.42, + "time": 2.08, + "theta": 3.12, + "omega": 77.22, + "vx": 8, + "vy": -16, + "splineNum": 2 + }, + { + "x": -3.63, + "y": 94.05, + "speed": 34.62, + "time": 2.19, + "theta": 4.73, + "omega": 30.17, + "vx": 33.84, + "vy": -7.32, + "splineNum": 3 + }, + { + "x": -0.5, + "y": 93.92, + "speed": 31.04, + "time": 2.29, + "theta": 9.2, + "omega": 58.6, + "vx": 31.02, + "vy": -1.27, + "splineNum": 3 + }, + { + "x": 2.09, + "y": 94.5, + "speed": 20.81, + "time": 2.42, + "theta": 18.97, + "omega": 94.61, + "vx": 20.31, + "vy": 4.56, + "splineNum": 3 + }, + { + "x": 4.1, + "y": 95.85, + "speed": 18.48, + "time": 2.55, + "theta": 33.79, + "omega": 303.12, + "vx": 15.37, + "vy": 10.26, + "splineNum": 3 + }, + { + "x": 5.5, + "y": 98.01, + "speed": 25.68, + "time": 2.65, + "theta": 48.41, + "omega": 274.79, + "vx": 13.94, + "vy": 21.57, + "splineNum": 3 + }, + { + "x": 6.24, + "y": 101.05, + "speed": 35.84, + "time": 2.74, + "theta": 63.43, + "omega": 250.16, + "vx": 8.49, + "vy": 34.82, + "splineNum": 3 + }, + { + "x": 6.28, + "y": 105.01, + "speed": 34.14, + "time": 2.85, + "theta": 86.77, + "omega": 217.37, + "vx": 0.36, + "vy": 34.14, + "splineNum": 3 + }, + { + "x": 6.28, + "y": 105.01, + "speed": 34.14, + "time": 2.85, + "theta": 86.77, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 4 + }, + { + "x": 6.04, + "y": 106.42, + "speed": 29.66, + "time": 2.9, + "theta": 86.78, + "omega": 0.48, + "vx": -4.95, + "vy": 29.24, + "splineNum": 4 + }, + { + "x": 5.6, + "y": 107.78, + "speed": 34.14, + "time": 2.94, + "theta": 86.81, + "omega": 0.9, + "vx": -10.5, + "vy": 32.49, + "splineNum": 4 + }, + { + "x": 5.06, + "y": 109.12, + "speed": 34.18, + "time": 2.99, + "theta": 86.86, + "omega": 1.32, + "vx": -12.82, + "vy": 31.69, + "splineNum": 4 + }, + { + "x": 4.52, + "y": 110.46, + "speed": 29.66, + "time": 3.04, + "theta": 86.93, + "omega": 1.81, + "vx": -11.12, + "vy": 27.49, + "splineNum": 4 + }, + { + "x": 4.08, + "y": 111.82, + "speed": 24.36, + "time": 3.09, + "theta": 87.06, + "omega": 2.4, + "vx": -7.5, + "vy": 23.17, + "splineNum": 4 + }, + { + "x": 3.84, + "y": 113.23, + "speed": 17.52, + "time": 3.18, + "theta": 87.29, + "omega": 3.21, + "vx": -2.93, + "vy": 17.27, + "splineNum": 4 + }, + { + "x": 3.9, + "y": 114.72, + "speed": 3.08, + "time": 3.66, + "theta": 90, + "omega": 8.03, + "vx": 0.13, + "vy": 3.08, + "splineNum": 4 + }, + { + "x": 3.9, + "y": 114.72, + "speed": 3.08, + "time": 3.66, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 5 + }, + { + "x": 3.91, + "y": 116.77, + "speed": 20.5, + "time": 3.76, + "theta": 90, + "omega": 0, + "vx": 0.09, + "vy": 20.5, + "splineNum": 5 + }, + { + "x": 3.39, + "y": 118.68, + "speed": 28.57, + "time": 3.83, + "theta": 90, + "omega": 0, + "vx": -7.55, + "vy": 27.55, + "splineNum": 5 + }, + { + "x": 2.54, + "y": 120.5, + "speed": 34.89, + "time": 3.89, + "theta": 90, + "omega": 0, + "vx": -14.64, + "vy": 31.67, + "splineNum": 5 + }, + { + "x": 1.6, + "y": 122.3, + "speed": 36, + "time": 3.94, + "theta": 90, + "omega": 0, + "vx": -16.84, + "vy": 31.82, + "splineNum": 5 + }, + { + "x": 0.75, + "y": 124.12, + "speed": 29.91, + "time": 4.01, + "theta": 90, + "omega": 0, + "vx": -12.55, + "vy": 27.15, + "splineNum": 5 + }, + { + "x": 0.23, + "y": 126.03, + "speed": 22.33, + "time": 4.1, + "theta": 90, + "omega": 0, + "vx": -5.9, + "vy": 21.54, + "splineNum": 5 + }, + { + "x": 0.24, + "y": 128.08, + "speed": 30.16, + "time": 4.17, + "theta": 90, + "omega": 0, + "vx": 0.13, + "vy": 30.16, + "splineNum": 5 + } + ] + }, + { + "name": "Goal6ToGoal9", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal6", + "omega": 28.8318509409838, + "angle": 90, + "spline_angle": 80.85, + "x": 0.24, + "y": 128.08, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 28.8318509409838, + "angle": 90, + "spline_angle": 80.85, + "x": 0.24, + "y": 118.38, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 28.8318509409838, + "angle": 45, + "spline_angle": 26.49, + "x": 16.15, + "y": 107.72, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 28.8318509409838, + "angle": 28.61, + "spline_angle": 26.49, + "x": 29.99, + "y": 116.15, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 28.8318509409838, + "angle": 40.41, + "spline_angle": 23.09, + "x": 46.54, + "y": 121.08, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal9", + "omega": 28.8318509409838, + "angle": 45, + "spline_angle": 26.49, + "x": 58.79, + "y": 129.99, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": 0.24, + "y": 128.08, + "speed": 41.9, + "time": 0, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 0.1, + "y": 126.69, + "speed": 41.21, + "time": 0.03, + "theta": 90, + "omega": 0, + "vx": -4.04, + "vy": -41.02, + "splineNum": 0 + }, + { + "x": 0.1, + "y": 125.31, + "speed": 37.7, + "time": 0.07, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": -37.7, + "splineNum": 0 + }, + { + "x": 0.19, + "y": 123.92, + "speed": 33.82, + "time": 0.11, + "theta": 90, + "omega": 0, + "vx": 2, + "vy": -33.76, + "splineNum": 0 + }, + { + "x": 0.29, + "y": 122.54, + "speed": 29.43, + "time": 0.16, + "theta": 90, + "omega": 0, + "vx": 2.31, + "vy": -29.33, + "splineNum": 0 + }, + { + "x": 0.38, + "y": 121.15, + "speed": 24.25, + "time": 0.22, + "theta": 90, + "omega": 0, + "vx": 1.43, + "vy": -24.21, + "splineNum": 0 + }, + { + "x": 0.38, + "y": 119.77, + "speed": 17.64, + "time": 0.29, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": -17.64, + "splineNum": 0 + }, + { + "x": 0.24, + "y": 118.38, + "speed": 5.71, + "time": 0.54, + "theta": 90, + "omega": 0, + "vx": -0.56, + "vy": -5.68, + "splineNum": 0 + }, + { + "x": 0.24, + "y": 118.38, + "speed": 5.71, + "time": 0.54, + "theta": 90, + "omega": 0, + "vx": -4, + "vy": 0, + "splineNum": 0 + }, + { + "x": -0.2, + "y": 114.6, + "speed": 28.17, + "time": 0.67, + "theta": 89.18, + "omega": -12.21, + "vx": -3.24, + "vy": -27.99, + "splineNum": 1 + }, + { + "x": -0.2, + "y": 111.47, + "speed": 35.44, + "time": 0.76, + "theta": 87.75, + "omega": -20.19, + "vx": 0, + "vy": -35.44, + "splineNum": 1 + }, + { + "x": 0.22, + "y": 108.97, + "speed": 27.35, + "time": 0.85, + "theta": 85.48, + "omega": -28.58, + "vx": 4.5, + "vy": -26.98, + "splineNum": 1 + }, + { + "x": 1.03, + "y": 107.06, + "speed": 18.23, + "time": 0.97, + "theta": 81.64, + "omega": -38.88, + "vx": 7.15, + "vy": -16.77, + "splineNum": 1 + }, + { + "x": 2.23, + "y": 105.71, + "speed": 14.81, + "time": 1.09, + "theta": 76.24, + "omega": -130.52, + "vx": 9.8, + "vy": -11.1, + "splineNum": 1 + }, + { + "x": 3.77, + "y": 104.89, + "speed": 17.24, + "time": 1.19, + "theta": 70.72, + "omega": -121.34, + "vx": 15.25, + "vy": -8.05, + "splineNum": 1 + }, + { + "x": 5.66, + "y": 104.57, + "speed": 26.07, + "time": 1.27, + "theta": 66.15, + "omega": -114.72, + "vx": 25.71, + "vy": -4.31, + "splineNum": 1 + }, + { + "x": 7.86, + "y": 104.73, + "speed": 33.47, + "time": 1.33, + "theta": 61.62, + "omega": -108.76, + "vx": 33.39, + "vy": 2.36, + "splineNum": 1 + }, + { + "x": 10.35, + "y": 105.32, + "speed": 40.42, + "time": 1.39, + "theta": 56.89, + "omega": -103.02, + "vx": 39.31, + "vy": 9.4, + "splineNum": 1 + }, + { + "x": 13.12, + "y": 106.33, + "speed": 47.15, + "time": 1.46, + "theta": 51.88, + "omega": -97.37, + "vx": 44.31, + "vy": 16.11, + "splineNum": 1 + }, + { + "x": 16.15, + "y": 107.72, + "speed": 41.9, + "time": 1.54, + "theta": 45, + "omega": -90.19, + "vx": 38.08, + "vy": 17.47, + "splineNum": 1 + }, + { + "x": 18.19, + "y": 108.82, + "speed": 47.11, + "time": 1.59, + "theta": 44.65, + "omega": -14.04, + "vx": 41.45, + "vy": 22.38, + "splineNum": 2 + }, + { + "x": 20.17, + "y": 110.03, + "speed": 50, + "time": 1.63, + "theta": 43.7, + "omega": -27.25, + "vx": 42.7, + "vy": 26.01, + "splineNum": 2 + }, + { + "x": 22.11, + "y": 111.29, + "speed": 50, + "time": 1.68, + "theta": 42.13, + "omega": -40.46, + "vx": 41.87, + "vy": 27.33, + "splineNum": 2 + }, + { + "x": 24.03, + "y": 112.58, + "speed": 50, + "time": 1.72, + "theta": 39.95, + "omega": -139.73, + "vx": 41.58, + "vy": 27.76, + "splineNum": 2 + }, + { + "x": 25.97, + "y": 113.84, + "speed": 50, + "time": 1.77, + "theta": 37.16, + "omega": -126.51, + "vx": 41.87, + "vy": 27.33, + "splineNum": 2 + }, + { + "x": 27.95, + "y": 115.05, + "speed": 47.11, + "time": 1.82, + "theta": 33.52, + "omega": -112.49, + "vx": 40.23, + "vy": 24.51, + "splineNum": 2 + }, + { + "x": 29.99, + "y": 116.15, + "speed": 41.9, + "time": 1.88, + "theta": 28.61, + "omega": -96.71, + "vx": 36.87, + "vy": 19.91, + "splineNum": 2 + }, + { + "x": 29.99, + "y": 116.15, + "speed": 41.9, + "time": 1.88, + "theta": 28.61, + "omega": -96.71, + "vx": 32, + "vy": 0, + "splineNum": 2 + }, + { + "x": 32.27, + "y": 117.12, + "speed": 47.46, + "time": 1.93, + "theta": 28.86, + "omega": 9.48, + "vx": 43.65, + "vy": 18.63, + "splineNum": 3 + }, + { + "x": 34.63, + "y": 117.87, + "speed": 50, + "time": 1.98, + "theta": 29.55, + "omega": 18.42, + "vx": 47.66, + "vy": 15.1, + "splineNum": 3 + }, + { + "x": 37.02, + "y": 118.47, + "speed": 50, + "time": 2.03, + "theta": 30.68, + "omega": 27.36, + "vx": 48.5, + "vy": 12.14, + "splineNum": 3 + }, + { + "x": 39.44, + "y": 119.01, + "speed": 50, + "time": 2.08, + "theta": 32.25, + "omega": 94.44, + "vx": 48.81, + "vy": 10.86, + "splineNum": 3 + }, + { + "x": 41.84, + "y": 119.56, + "speed": 50, + "time": 2.13, + "theta": 34.27, + "omega": 85.49, + "vx": 48.71, + "vy": 11.3, + "splineNum": 3 + }, + { + "x": 44.22, + "y": 120.23, + "speed": 47.43, + "time": 2.18, + "theta": 36.87, + "omega": 76.07, + "vx": 45.69, + "vy": 12.75, + "splineNum": 3 + }, + { + "x": 46.54, + "y": 121.08, + "speed": 41.9, + "time": 2.24, + "theta": 40.41, + "omega": 65.38, + "vx": 39.33, + "vy": 14.44, + "splineNum": 3 + }, + { + "x": 46.54, + "y": 121.08, + "speed": 41.9, + "time": 2.24, + "theta": 40.41, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 4 + }, + { + "x": 48.48, + "y": 122.09, + "speed": 46.83, + "time": 2.28, + "theta": 40.51, + "omega": 4.23, + "vx": 41.5, + "vy": 21.7, + "splineNum": 4 + }, + { + "x": 50.25, + "y": 123.34, + "speed": 50, + "time": 2.33, + "theta": 40.78, + "omega": 8.15, + "vx": 40.95, + "vy": 28.69, + "splineNum": 4 + }, + { + "x": 51.92, + "y": 124.72, + "speed": 50, + "time": 2.37, + "theta": 41.22, + "omega": 12.08, + "vx": 38.47, + "vy": 31.94, + "splineNum": 4 + }, + { + "x": 53.55, + "y": 126.16, + "speed": 50, + "time": 2.41, + "theta": 41.83, + "omega": 41.65, + "vx": 37.39, + "vy": 33.19, + "splineNum": 4 + }, + { + "x": 55.19, + "y": 127.58, + "speed": 50, + "time": 2.46, + "theta": 42.61, + "omega": 37.72, + "vx": 37.9, + "vy": 32.61, + "splineNum": 4 + }, + { + "x": 56.92, + "y": 128.88, + "speed": 46.8, + "time": 2.5, + "theta": 43.63, + "omega": 33.53, + "vx": 37.36, + "vy": 28.19, + "splineNum": 4 + }, + { + "x": 58.79, + "y": 129.99, + "speed": 41.9, + "time": 2.55, + "theta": 45, + "omega": 28.83, + "vx": 36.07, + "vy": 21.32, + "splineNum": 4 + } + ] + }, + { + "name": "Goal9ToGoal8", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal9", + "omega": -16.328937081995182, + "angle": 45, + "spline_angle": 26.49, + "x": 58.79, + "y": 129.99, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": -16.328937081995182, + "angle": 45, + "spline_angle": 109.96, + "x": 54.02, + "y": 119.97, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": -16.328937081995182, + "angle": -25.23, + "spline_angle": -90.09, + "x": 58.95, + "y": 110.42, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": -16.328937081995182, + "angle": -0.01, + "spline_angle": -90.09, + "x": 59.27, + "y": 94.83, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": -16.328937081995182, + "angle": -85.03, + "spline_angle": -90.09, + "x": 44.47, + "y": 83.06, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": -16.328937081995182, + "angle": 3.54, + "spline_angle": 163.67, + "x": 49.72, + "y": 70.8, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal8", + "omega": -16.328937081995182, + "angle": 0, + "spline_angle": 163.67, + "x": 57.04, + "y": 71.76, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": 58.79, + "y": 129.99, + "speed": 38.83, + "time": 0, + "theta": 45, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 57.11, + "y": 129.04, + "speed": 33.48, + "time": 0.06, + "theta": 45, + "omega": 0, + "vx": -29.12, + "vy": -16.53, + "splineNum": 0 + }, + { + "x": 55.69, + "y": 127.95, + "speed": 27.65, + "time": 0.12, + "theta": 45, + "omega": 0, + "vx": -21.98, + "vy": -16.78, + "splineNum": 0 + }, + { + "x": 54.58, + "y": 126.73, + "speed": 20.82, + "time": 0.2, + "theta": 45, + "omega": 0, + "vx": -13.97, + "vy": -15.44, + "splineNum": 0 + }, + { + "x": 53.82, + "y": 125.33, + "speed": 18.03, + "time": 0.29, + "theta": 45, + "omega": 0, + "vx": -8.66, + "vy": -15.82, + "splineNum": 0 + }, + { + "x": 53.44, + "y": 123.76, + "speed": 19.44, + "time": 0.37, + "theta": 45, + "omega": 0, + "vx": -4.49, + "vy": -18.91, + "splineNum": 0 + }, + { + "x": 53.5, + "y": 121.97, + "speed": 25.75, + "time": 0.44, + "theta": 45, + "omega": 0, + "vx": 0.78, + "vy": -25.74, + "splineNum": 0 + }, + { + "x": 54.02, + "y": 119.97, + "speed": 32.82, + "time": 0.51, + "theta": 45, + "omega": 0, + "vx": 8.28, + "vy": -31.76, + "splineNum": 0 + }, + { + "x": 54.02, + "y": 119.97, + "speed": 32.82, + "time": 0.51, + "theta": 45, + "omega": 0, + "vx": -32.82, + "vy": 0, + "splineNum": 0 + }, + { + "x": 54.68, + "y": 118.58, + "speed": 32.57, + "time": 0.55, + "theta": 44.77, + "omega": -9.93, + "vx": 14.03, + "vy": -29.39, + "splineNum": 1 + }, + { + "x": 55.54, + "y": 117.3, + "speed": 37.01, + "time": 0.59, + "theta": 44.17, + "omega": -18.73, + "vx": 20.51, + "vy": -30.81, + "splineNum": 1 + }, + { + "x": 56.48, + "y": 116.06, + "speed": 35.58, + "time": 0.64, + "theta": 43.15, + "omega": -27.95, + "vx": 21.51, + "vy": -28.34, + "splineNum": 1 + }, + { + "x": 57.4, + "y": 114.8, + "speed": 30.9, + "time": 0.69, + "theta": 41.47, + "omega": -38.55, + "vx": 18.3, + "vy": -24.9, + "splineNum": 1 + }, + { + "x": 58.19, + "y": 113.48, + "speed": 25.44, + "time": 0.75, + "theta": 38.76, + "omega": -51.29, + "vx": 13.07, + "vy": -21.82, + "splineNum": 1 + }, + { + "x": 58.74, + "y": 112.04, + "speed": 18.39, + "time": 0.83, + "theta": 33.7, + "omega": -68.99, + "vx": 6.58, + "vy": -17.17, + "splineNum": 1 + }, + { + "x": 58.95, + "y": 110.42, + "speed": 3.34, + "time": 1.32, + "theta": -25.23, + "omega": -172.01, + "vx": 0.42, + "vy": -3.32, + "splineNum": 1 + }, + { + "x": 58.95, + "y": 110.42, + "speed": 3.34, + "time": 1.32, + "theta": -25.23, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 2 + }, + { + "x": 58.97, + "y": 108.19, + "speed": 21.37, + "time": 1.43, + "theta": -24.89, + "omega": 6.51, + "vx": 0.15, + "vy": -21.37, + "splineNum": 2 + }, + { + "x": 59.01, + "y": 105.97, + "speed": 30.04, + "time": 1.5, + "theta": -24.24, + "omega": 11.15, + "vx": 0.62, + "vy": -30.03, + "splineNum": 2 + }, + { + "x": 59.08, + "y": 103.74, + "speed": 36.71, + "time": 1.56, + "theta": -23.44, + "omega": 14.94, + "vx": 1.05, + "vy": -36.7, + "splineNum": 2 + }, + { + "x": 59.14, + "y": 101.51, + "speed": 36.94, + "time": 1.62, + "theta": -22.43, + "omega": 18.71, + "vx": 1.16, + "vy": -36.92, + "splineNum": 2 + }, + { + "x": 59.21, + "y": 99.28, + "speed": 30.31, + "time": 1.7, + "theta": -20.89, + "omega": 23.3, + "vx": 0.87, + "vy": -30.3, + "splineNum": 2 + }, + { + "x": 59.25, + "y": 97.06, + "speed": 21.75, + "time": 1.8, + "theta": -18.17, + "omega": 82.58, + "vx": 0.45, + "vy": -21.75, + "splineNum": 2 + }, + { + "x": 59.27, + "y": 94.83, + "speed": 5.26, + "time": 2.22, + "theta": -0.01, + "omega": 56.14, + "vx": 0.04, + "vy": -5.26, + "splineNum": 2 + }, + { + "x": 59.27, + "y": 94.83, + "speed": 5.26, + "time": 2.22, + "theta": -0.01, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 3 + }, + { + "x": 58.45, + "y": 91.53, + "speed": 14.26, + "time": 2.46, + "theta": -4.64, + "omega": -38.77, + "vx": -3.45, + "vy": -13.83, + "splineNum": 3 + }, + { + "x": 56.33, + "y": 89.84, + "speed": 19.88, + "time": 2.6, + "theta": -11.4, + "omega": -60.82, + "vx": -15.56, + "vy": -12.38, + "splineNum": 3 + }, + { + "x": 53.44, + "y": 89.14, + "speed": 31.47, + "time": 2.69, + "theta": -17.88, + "omega": -76.17, + "vx": -30.56, + "vy": -7.49, + "splineNum": 3 + }, + { + "x": 50.3, + "y": 88.75, + "speed": 31.47, + "time": 2.79, + "theta": -26.37, + "omega": -239.77, + "vx": -31.24, + "vy": -3.81, + "splineNum": 3 + }, + { + "x": 47.41, + "y": 88.05, + "speed": 19.88, + "time": 2.94, + "theta": -42.03, + "omega": -215.49, + "vx": -19.31, + "vy": -4.73, + "splineNum": 3 + }, + { + "x": 45.29, + "y": 86.36, + "speed": 14.26, + "time": 3.13, + "theta": -67.07, + "omega": -184.73, + "vx": -11.16, + "vy": -8.87, + "splineNum": 3 + }, + { + "x": 44.47, + "y": 83.06, + "speed": 29.74, + "time": 3.24, + "theta": -85.03, + "omega": -166.14, + "vx": -7.2, + "vy": -28.85, + "splineNum": 3 + }, + { + "x": 44.47, + "y": 83.06, + "speed": 29.74, + "time": 3.24, + "theta": -85.03, + "omega": -166.14, + "vx": -29.74, + "vy": 0, + "splineNum": 3 + }, + { + "x": 44.41, + "y": 80.96, + "speed": 36.12, + "time": 3.3, + "theta": -84.42, + "omega": 21.05, + "vx": -1.09, + "vy": -36.1, + "splineNum": 4 + }, + { + "x": 44.33, + "y": 78.86, + "speed": 34.99, + "time": 3.36, + "theta": -82.5, + "omega": 42.81, + "vx": -1.2, + "vy": -34.97, + "splineNum": 4 + }, + { + "x": 44.42, + "y": 76.82, + "speed": 28.58, + "time": 3.43, + "theta": -78.53, + "omega": 68.6, + "vx": 1.22, + "vy": -28.55, + "splineNum": 4 + }, + { + "x": 44.84, + "y": 74.93, + "speed": 20.71, + "time": 3.53, + "theta": -70.51, + "omega": 102.5, + "vx": 4.42, + "vy": -20.23, + "splineNum": 4 + }, + { + "x": 45.75, + "y": 73.24, + "speed": 17.4, + "time": 3.64, + "theta": -57.05, + "omega": 364.06, + "vx": 8.27, + "vy": -15.31, + "splineNum": 4 + }, + { + "x": 47.32, + "y": 71.84, + "speed": 22.41, + "time": 3.73, + "theta": -42.1, + "omega": 330.08, + "vx": 16.74, + "vy": -14.9, + "splineNum": 4 + }, + { + "x": 49.72, + "y": 70.8, + "speed": 12.32, + "time": 3.94, + "theta": 3.54, + "omega": 253.17, + "vx": 11.3, + "vy": -4.91, + "splineNum": 4 + }, + { + "x": 49.72, + "y": 70.8, + "speed": 12.32, + "time": 3.94, + "theta": 3.54, + "omega": 253.17, + "vx": 12.32, + "vy": 0, + "splineNum": 4 + }, + { + "x": 50.8, + "y": 70.65, + "speed": 12.25, + "time": 4.03, + "theta": 3.39, + "omega": -3.36, + "vx": 12.14, + "vy": -1.63, + "splineNum": 5 + }, + { + "x": 51.85, + "y": 70.79, + "speed": 19, + "time": 4.09, + "theta": 3.15, + "omega": -5.45, + "vx": 18.84, + "vy": 2.47, + "splineNum": 5 + }, + { + "x": 52.87, + "y": 71.1, + "speed": 23.97, + "time": 4.13, + "theta": 2.87, + "omega": -7.13, + "vx": 22.96, + "vy": 6.88, + "splineNum": 5 + }, + { + "x": 53.89, + "y": 71.46, + "speed": 23.97, + "time": 4.18, + "theta": 2.51, + "omega": -23.83, + "vx": 22.57, + "vy": 8.07, + "splineNum": 5 + }, + { + "x": 54.91, + "y": 71.77, + "speed": 19, + "time": 4.23, + "theta": 1.95, + "omega": -21.72, + "vx": 18.2, + "vy": 5.45, + "splineNum": 5 + }, + { + "x": 55.96, + "y": 71.91, + "speed": 12.25, + "time": 4.32, + "theta": 0.87, + "omega": -18.47, + "vx": 12.14, + "vy": 1.59, + "splineNum": 5 + }, + { + "x": 57.04, + "y": 71.76, + "speed": 19.2, + "time": 4.38, + "theta": 0, + "omega": -16.33, + "vx": 19.02, + "vy": -2.55, + "splineNum": 5 + } + ] + }, + { + "name": "Goal8ToGoal7", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal8", + "omega": 0, + "angle": 0, + "spline_angle": -179.99, + "x": 57.04, + "y": 71.76, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 0, + "spline_angle": -1.79, + "x": 46.54, + "y": 71.76, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": -1.79, + "x": 41.69, + "y": 71.7, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -180, + "spline_angle": -131.88, + "x": 31.63, + "y": 69, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -90.02, + "spline_angle": 135.12, + "x": 32.35, + "y": 56.07, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -36.59, + "spline_angle": 113.16, + "x": 58.79, + "y": 46.62, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 0, + "spline_angle": -96.16, + "x": 59.9, + "y": 27.84, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -45, + "spline_angle": 113.16, + "x": 56.78, + "y": 20.67, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal7", + "omega": 0, + "angle": -45, + "spline_angle": 113.16, + "x": 62.36, + "y": 14.38, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": 57.04, + "y": 71.76, + "speed": 41.9, + "time": 0, + "theta": 0, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 55.54, + "y": 71.75, + "speed": 45.34, + "time": 0.03, + "theta": 0, + "omega": 0, + "vx": -45.34, + "vy": -0.18, + "splineNum": 0 + }, + { + "x": 54.04, + "y": 71.74, + "speed": 48.53, + "time": 0.06, + "theta": 0, + "omega": 0, + "vx": -48.53, + "vy": -0.44, + "splineNum": 0 + }, + { + "x": 52.54, + "y": 71.73, + "speed": 50, + "time": 0.09, + "theta": 0, + "omega": 0, + "vx": -50, + "vy": -0.51, + "splineNum": 0 + }, + { + "x": 51.04, + "y": 71.71, + "speed": 50, + "time": 0.12, + "theta": 0, + "omega": 0, + "vx": -50, + "vy": -0.38, + "splineNum": 0 + }, + { + "x": 49.54, + "y": 71.71, + "speed": 48.54, + "time": 0.15, + "theta": 0, + "omega": 0, + "vx": -48.54, + "vy": -0.06, + "splineNum": 0 + }, + { + "x": 48.04, + "y": 71.73, + "speed": 45.34, + "time": 0.19, + "theta": 0, + "omega": 0, + "vx": -45.34, + "vy": 0.41, + "splineNum": 0 + }, + { + "x": 46.54, + "y": 71.76, + "speed": 41.9, + "time": 0.22, + "theta": 0, + "omega": 0, + "vx": -41.89, + "vy": 0.96, + "splineNum": 0 + }, + { + "x": 46.54, + "y": 71.76, + "speed": 41.9, + "time": 0.22, + "theta": 0, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": 45.85, + "y": 71.77, + "speed": 43.52, + "time": 0.24, + "theta": 1.93, + "omega": 241.85, + "vx": -43.52, + "vy": 0.62, + "splineNum": 1 + }, + { + "x": 45.15, + "y": 71.76, + "speed": 45.09, + "time": 0.26, + "theta": 7.44, + "omega": 475.22, + "vx": -45.08, + "vy": -0.56, + "splineNum": 1 + }, + { + "x": 44.46, + "y": 71.74, + "speed": 46.6, + "time": 0.27, + "theta": 16.18, + "omega": 701.06, + "vx": -46.58, + "vy": -1.32, + "splineNum": 1 + }, + { + "x": 43.77, + "y": 71.72, + "speed": 46.6, + "time": 0.28, + "theta": 28.29, + "omega": 2379.68, + "vx": -46.57, + "vy": -1.57, + "splineNum": 1 + }, + { + "x": 43.08, + "y": 71.7, + "speed": 45.09, + "time": 0.3, + "theta": 44.33, + "omega": 2146.27, + "vx": -45.07, + "vy": -1.28, + "splineNum": 1 + }, + { + "x": 42.38, + "y": 71.69, + "speed": 43.52, + "time": 0.32, + "theta": 64.73, + "omega": 1904.51, + "vx": -43.52, + "vy": -0.54, + "splineNum": 1 + }, + { + "x": 41.69, + "y": 71.7, + "speed": 41.9, + "time": 0.33, + "theta": 90, + "omega": 1653.29, + "vx": -41.9, + "vy": 0.6, + "splineNum": 1 + }, + { + "x": 41.69, + "y": 71.7, + "speed": 41.9, + "time": 0.33, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 2 + }, + { + "x": 40.14, + "y": 71.75, + "speed": 41.5, + "time": 0.37, + "theta": 90.27, + "omega": 14.19, + "vx": -41.48, + "vy": 1.28, + "splineNum": 2 + }, + { + "x": 38.59, + "y": 71.75, + "speed": 37.6, + "time": 0.41, + "theta": 91.17, + "omega": 29.73, + "vx": -37.6, + "vy": 0.15, + "splineNum": 2 + }, + { + "x": 37.08, + "y": 71.66, + "speed": 33.32, + "time": 0.46, + "theta": 92.91, + "omega": 46.98, + "vx": -33.25, + "vy": -2.14, + "splineNum": 2 + }, + { + "x": 35.61, + "y": 71.39, + "speed": 28.49, + "time": 0.51, + "theta": 95.9, + "omega": 66.85, + "vx": -28.04, + "vy": -5.01, + "splineNum": 2 + }, + { + "x": 34.2, + "y": 70.9, + "speed": 23.48, + "time": 0.57, + "theta": 100.91, + "omega": 90.92, + "vx": -22.18, + "vy": -7.7, + "splineNum": 2 + }, + { + "x": 32.87, + "y": 70.13, + "speed": 18.86, + "time": 0.65, + "theta": 109.61, + "omega": 121.9, + "vx": -16.29, + "vy": -9.51, + "splineNum": 2 + }, + { + "x": 31.63, + "y": 69, + "speed": 4.56, + "time": 1.02, + "theta": 180, + "omega": 261.14, + "vx": -3.37, + "vy": -3.07, + "splineNum": 2 + }, + { + "x": 31.63, + "y": 69, + "speed": 4.56, + "time": 1.02, + "theta": 180, + "omega": 261.14, + "vx": 4.56, + "vy": 0, + "splineNum": 2 + }, + { + "x": 30.17, + "y": 67.07, + "speed": 22.48, + "time": 1.13, + "theta": -178.22, + "omega": 33.09, + "vx": -13.55, + "vy": -17.94, + "splineNum": 3 + }, + { + "x": 29.27, + "y": 65.16, + "speed": 24.12, + "time": 1.22, + "theta": -174.16, + "omega": 59.89, + "vx": -10.31, + "vy": -21.8, + "splineNum": 3 + }, + { + "x": 28.91, + "y": 63.29, + "speed": 20.74, + "time": 1.31, + "theta": -167.35, + "omega": 88.14, + "vx": -3.95, + "vy": -20.36, + "splineNum": 3 + }, + { + "x": 29.06, + "y": 61.45, + "speed": 22.08, + "time": 1.39, + "theta": -158.88, + "omega": 113.87, + "vx": 1.79, + "vy": -22, + "splineNum": 3 + }, + { + "x": 29.7, + "y": 59.63, + "speed": 28.23, + "time": 1.46, + "theta": -150.4, + "omega": 335.27, + "vx": 9.37, + "vy": -26.63, + "splineNum": 3 + }, + { + "x": 30.8, + "y": 57.84, + "speed": 23.82, + "time": 1.55, + "theta": -137.28, + "omega": 308.13, + "vx": 12.51, + "vy": -20.27, + "splineNum": 3 + }, + { + "x": 32.35, + "y": 56.07, + "speed": 9.87, + "time": 1.79, + "theta": -90.02, + "omega": 235.05, + "vx": 6.5, + "vy": -7.42, + "splineNum": 3 + }, + { + "x": 32.35, + "y": 56.07, + "speed": 9.87, + "time": 1.79, + "theta": -90.02, + "omega": 235.05, + "vx": 9.87, + "vy": 0, + "splineNum": 3 + }, + { + "x": 35.37, + "y": 54.09, + "speed": 28.63, + "time": 1.91, + "theta": -89.01, + "omega": 16, + "vx": 23.93, + "vy": -15.72, + "splineNum": 4 + }, + { + "x": 38.81, + "y": 53.29, + "speed": 39.07, + "time": 2, + "theta": -87.05, + "omega": 27.46, + "vx": 38.07, + "vy": -8.77, + "splineNum": 4 + }, + { + "x": 42.51, + "y": 53.21, + "speed": 47.6, + "time": 2.08, + "theta": -84.53, + "omega": 37.32, + "vx": 47.59, + "vy": -1.08, + "splineNum": 4 + }, + { + "x": 46.29, + "y": 53.35, + "speed": 48.38, + "time": 2.16, + "theta": -81.23, + "omega": 47.23, + "vx": 48.35, + "vy": 1.85, + "splineNum": 4 + }, + { + "x": 49.98, + "y": 53.25, + "speed": 40.04, + "time": 2.25, + "theta": -76.33, + "omega": 173.89, + "vx": 40.02, + "vy": -1.15, + "splineNum": 4 + }, + { + "x": 53.41, + "y": 52.41, + "speed": 29.95, + "time": 2.37, + "theta": -68.51, + "omega": 158.96, + "vx": 29.1, + "vy": -7.11, + "splineNum": 4 + }, + { + "x": 56.4, + "y": 50.36, + "speed": 30.3, + "time": 2.49, + "theta": -58.76, + "omega": 143.77, + "vx": 25.01, + "vy": -17.11, + "splineNum": 4 + }, + { + "x": 58.79, + "y": 46.62, + "speed": 20.57, + "time": 2.71, + "theta": -36.59, + "omega": 116.4, + "vx": 11.07, + "vy": -17.33, + "splineNum": 4 + }, + { + "x": 59.71, + "y": 43.98, + "speed": 31.34, + "time": 2.79, + "theta": -35.75, + "omega": 18.9, + "vx": 10.35, + "vy": -29.58, + "splineNum": 5 + }, + { + "x": 60.28, + "y": 41.32, + "speed": 39.06, + "time": 2.86, + "theta": -33.92, + "omega": 33.65, + "vx": 8.09, + "vy": -38.21, + "splineNum": 5 + }, + { + "x": 60.54, + "y": 38.65, + "speed": 45.43, + "time": 2.92, + "theta": -31.55, + "omega": 46.21, + "vx": 4.5, + "vy": -45.2, + "splineNum": 5 + }, + { + "x": 60.57, + "y": 35.96, + "speed": 44.44, + "time": 2.98, + "theta": -28.37, + "omega": 59.04, + "vx": 0.54, + "vy": -44.44, + "splineNum": 5 + }, + { + "x": 60.44, + "y": 33.26, + "speed": 37.87, + "time": 3.06, + "theta": -23.61, + "omega": 174.93, + "vx": -1.93, + "vy": -37.82, + "splineNum": 5 + }, + { + "x": 60.19, + "y": 30.55, + "speed": 29.84, + "time": 3.15, + "theta": -15.98, + "omega": 155.62, + "vx": -2.7, + "vy": -29.72, + "splineNum": 5 + }, + { + "x": 59.9, + "y": 27.84, + "speed": 18.59, + "time": 3.29, + "theta": 0, + "omega": 124.55, + "vx": -1.98, + "vy": -18.49, + "splineNum": 5 + }, + { + "x": 59.9, + "y": 27.84, + "speed": 18.59, + "time": 3.29, + "theta": 0, + "omega": 124.55, + "vx": 16, + "vy": -8, + "splineNum": 5 + }, + { + "x": 59.56, + "y": 26.77, + "speed": 11.01, + "time": 3.4, + "theta": -0.34, + "omega": -6.61, + "vx": -3.37, + "vy": -10.48, + "splineNum": 6 + }, + { + "x": 58.89, + "y": 25.84, + "speed": 18.7, + "time": 3.46, + "theta": -0.86, + "omega": -10.57, + "vx": -10.88, + "vy": -15.21, + "splineNum": 6 + }, + { + "x": 58.08, + "y": 24.98, + "speed": 23.55, + "time": 3.51, + "theta": -1.48, + "omega": -13.84, + "vx": -16.14, + "vy": -17.15, + "splineNum": 6 + }, + { + "x": 57.29, + "y": 24.1, + "speed": 17.86, + "time": 3.57, + "theta": -2.53, + "omega": -18.12, + "vx": -11.97, + "vy": -13.25, + "splineNum": 6 + }, + { + "x": 56.69, + "y": 23.14, + "speed": 9.65, + "time": 3.69, + "theta": -5.09, + "omega": -25.7, + "vx": -5.08, + "vy": -8.2, + "splineNum": 6 + }, + { + "x": 56.47, + "y": 22.02, + "speed": 8.96, + "time": 3.82, + "theta": -8.9, + "omega": -33.97, + "vx": -1.78, + "vy": -8.79, + "splineNum": 6 + }, + { + "x": 56.78, + "y": 20.67, + "speed": 2.12, + "time": 4.47, + "theta": -45, + "omega": -76.39, + "vx": 0.48, + "vy": -2.07, + "splineNum": 6 + }, + { + "x": 56.78, + "y": 20.67, + "speed": 2.12, + "time": 4.47, + "theta": -45, + "omega": -76.39, + "vx": 0, + "vy": -2, + "splineNum": 6 + }, + { + "x": 57.39, + "y": 19.61, + "speed": 15.8, + "time": 4.55, + "theta": -45, + "omega": 0, + "vx": 7.91, + "vy": -13.68, + "splineNum": 7 + }, + { + "x": 58.19, + "y": 18.71, + "speed": 22.13, + "time": 4.6, + "theta": -45, + "omega": 0, + "vx": 14.69, + "vy": -16.56, + "splineNum": 7 + }, + { + "x": 59.1, + "y": 17.91, + "speed": 27.05, + "time": 4.65, + "theta": -45, + "omega": 0, + "vx": 20.28, + "vy": -17.91, + "splineNum": 7 + }, + { + "x": 60.04, + "y": 17.14, + "speed": 28.48, + "time": 4.69, + "theta": -45, + "omega": 0, + "vx": 22.08, + "vy": -17.98, + "splineNum": 7 + }, + { + "x": 60.95, + "y": 16.34, + "speed": 23.85, + "time": 4.74, + "theta": -45, + "omega": 0, + "vx": 17.88, + "vy": -15.79, + "splineNum": 7 + }, + { + "x": 61.75, + "y": 15.44, + "speed": 18.13, + "time": 4.81, + "theta": -45, + "omega": 0, + "vx": 12.03, + "vy": -13.56, + "splineNum": 7 + }, + { + "x": 62.36, + "y": 14.38, + "speed": 12.65, + "time": 4.9, + "theta": -45, + "omega": 0, + "vx": 6.34, + "vy": -10.95, + "splineNum": 7 + } + ] + }, + { + "name": "Goal7ToGoal4", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal7", + "omega": 0, + "angle": -45, + "spline_angle": 127.88, + "x": 62.36, + "y": 14.38, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -45, + "spline_angle": 97.15, + "x": 57.2, + "y": 18.46, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": 177.35, + "x": 48.45, + "y": 23.71, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": 177.35, + "x": 36.99, + "y": 23.71, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -90, + "spline_angle": -11.62, + "x": 14.4, + "y": 27.53, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -90, + "spline_angle": -132.62, + "x": 2.78, + "y": 25.62, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": 62.36, + "y": 14.38, + "speed": 17.4, + "time": 0, + "theta": -45, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 61.66, + "y": 15.01, + "speed": 10.69, + "time": 0.09, + "theta": -45, + "omega": 0, + "vx": -7.98, + "vy": 7.12, + "splineNum": 0 + }, + { + "x": 60.8, + "y": 15.43, + "speed": 17.5, + "time": 0.14, + "theta": -45, + "omega": 0, + "vx": -15.68, + "vy": 7.79, + "splineNum": 0 + }, + { + "x": 59.87, + "y": 15.77, + "speed": 21.51, + "time": 0.19, + "theta": -45, + "omega": 0, + "vx": -20.21, + "vy": 7.36, + "splineNum": 0 + }, + { + "x": 58.96, + "y": 16.13, + "speed": 16.32, + "time": 0.25, + "theta": -45, + "omega": 0, + "vx": -15.17, + "vy": 6, + "splineNum": 0 + }, + { + "x": 58.15, + "y": 16.63, + "speed": 8.77, + "time": 0.36, + "theta": -45, + "omega": 0, + "vx": -7.48, + "vy": 4.58, + "splineNum": 0 + }, + { + "x": 57.53, + "y": 17.37, + "speed": 7.99, + "time": 0.48, + "theta": -45, + "omega": 0, + "vx": -5.11, + "vy": 6.14, + "splineNum": 0 + }, + { + "x": 57.2, + "y": 18.46, + "speed": 3.19, + "time": 0.84, + "theta": -45, + "omega": 0, + "vx": -0.93, + "vy": 3.05, + "splineNum": 0 + }, + { + "x": 57.2, + "y": 18.46, + "speed": 3.19, + "time": 0.84, + "theta": -45, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": 56.7, + "y": 20.46, + "speed": 18.09, + "time": 0.95, + "theta": -50.82, + "omega": -102.08, + "vx": -4.37, + "vy": 17.55, + "splineNum": 1 + }, + { + "x": 55.84, + "y": 21.86, + "speed": 13.22, + "time": 1.07, + "theta": -70.4, + "omega": -213.17, + "vx": -6.94, + "vy": 11.26, + "splineNum": 1 + }, + { + "x": 54.68, + "y": 22.77, + "speed": 14.73, + "time": 1.17, + "theta": -96.11, + "omega": -680.54, + "vx": -11.6, + "vy": 9.07, + "splineNum": 1 + }, + { + "x": 53.3, + "y": 23.29, + "speed": 22.65, + "time": 1.24, + "theta": -117.79, + "omega": -622.05, + "vx": -21.18, + "vy": 8.02, + "splineNum": 1 + }, + { + "x": 51.75, + "y": 23.55, + "speed": 28.75, + "time": 1.29, + "theta": -138.79, + "omega": -573.29, + "vx": -28.36, + "vy": 4.72, + "splineNum": 1 + }, + { + "x": 50.11, + "y": 23.65, + "speed": 33.98, + "time": 1.34, + "theta": -159.62, + "omega": -530.07, + "vx": -33.92, + "vy": 2.12, + "splineNum": 1 + }, + { + "x": 48.45, + "y": 23.71, + "speed": 38.57, + "time": 1.38, + "theta": -180, + "omega": -491.46, + "vx": -38.55, + "vy": 1.39, + "splineNum": 1 + }, + { + "x": 48.45, + "y": 23.71, + "speed": 38.57, + "time": 1.38, + "theta": 180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 2 + }, + { + "x": 46.81, + "y": 23.76, + "speed": 42.61, + "time": 1.42, + "theta": 180, + "omega": 0, + "vx": -42.59, + "vy": 1.21, + "splineNum": 2 + }, + { + "x": 45.18, + "y": 23.76, + "speed": 46.29, + "time": 1.46, + "theta": 180, + "omega": 0, + "vx": -46.29, + "vy": 0, + "splineNum": 2 + }, + { + "x": 43.54, + "y": 23.73, + "speed": 49.7, + "time": 1.49, + "theta": 180, + "omega": 0, + "vx": -49.7, + "vy": -0.84, + "splineNum": 2 + }, + { + "x": 41.9, + "y": 23.69, + "speed": 50, + "time": 1.52, + "theta": 180, + "omega": 0, + "vx": -49.99, + "vy": -1.13, + "splineNum": 2 + }, + { + "x": 40.26, + "y": 23.66, + "speed": 49.1, + "time": 1.56, + "theta": 180, + "omega": 0, + "vx": -49.09, + "vy": -0.83, + "splineNum": 2 + }, + { + "x": 38.63, + "y": 23.66, + "speed": 45.64, + "time": 1.59, + "theta": 180, + "omega": 0, + "vx": -45.64, + "vy": 0, + "splineNum": 2 + }, + { + "x": 36.99, + "y": 23.71, + "speed": 41.9, + "time": 1.63, + "theta": 180, + "omega": 0, + "vx": -41.88, + "vy": 1.19, + "splineNum": 2 + }, + { + "x": 36.99, + "y": 23.71, + "speed": 41.9, + "time": 1.63, + "theta": 180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 3 + }, + { + "x": 33.71, + "y": 23.95, + "speed": 49.12, + "time": 1.7, + "theta": 181.7, + "omega": 50.68, + "vx": -48.99, + "vy": 3.63, + "splineNum": 3 + }, + { + "x": 30.46, + "y": 24.35, + "speed": 50, + "time": 1.77, + "theta": 186.64, + "omega": 100.29, + "vx": -49.62, + "vy": 6.12, + "splineNum": 3 + }, + { + "x": 27.23, + "y": 24.88, + "speed": 50, + "time": 1.83, + "theta": 194.83, + "omega": 149.86, + "vx": -49.35, + "vy": 8.01, + "splineNum": 3 + }, + { + "x": 24.01, + "y": 25.49, + "speed": 50, + "time": 1.9, + "theta": 206.26, + "omega": 538.94, + "vx": -49.11, + "vy": 9.38, + "splineNum": 3 + }, + { + "x": 20.81, + "y": 26.16, + "speed": 50, + "time": 1.96, + "theta": 220.95, + "omega": 489.34, + "vx": -48.94, + "vy": 10.22, + "splineNum": 3 + }, + { + "x": 17.6, + "y": 26.85, + "speed": 45.6, + "time": 2.03, + "theta": 240.8, + "omega": 434.93, + "vx": -44.57, + "vy": 9.61, + "splineNum": 3 + }, + { + "x": 14.4, + "y": 27.53, + "speed": 37.73, + "time": 2.12, + "theta": 270, + "omega": 369.19, + "vx": -36.92, + "vy": 7.81, + "splineNum": 3 + }, + { + "x": 14.4, + "y": 27.53, + "speed": 37.73, + "time": 2.12, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 4 + }, + { + "x": 12.64, + "y": 27.88, + "speed": 41.83, + "time": 2.16, + "theta": -90, + "omega": 0, + "vx": -41.02, + "vy": 8.22, + "splineNum": 4 + }, + { + "x": 10.89, + "y": 28.16, + "speed": 37.35, + "time": 2.21, + "theta": -90, + "omega": 0, + "vx": -36.88, + "vy": 5.9, + "splineNum": 4 + }, + { + "x": 9.16, + "y": 28.29, + "speed": 32.39, + "time": 2.26, + "theta": -90, + "omega": 0, + "vx": -32.31, + "vy": 2.35, + "splineNum": 4 + }, + { + "x": 7.47, + "y": 28.18, + "speed": 26.67, + "time": 2.33, + "theta": -90, + "omega": 0, + "vx": -26.61, + "vy": -1.74, + "splineNum": 4 + }, + { + "x": 5.84, + "y": 27.75, + "speed": 22.77, + "time": 2.4, + "theta": -90, + "omega": 0, + "vx": -22.03, + "vy": -5.76, + "splineNum": 4 + }, + { + "x": 4.27, + "y": 26.93, + "speed": 24.03, + "time": 2.48, + "theta": -90, + "omega": 0, + "vx": -21.27, + "vy": -11.19, + "splineNum": 4 + }, + { + "x": 2.78, + "y": 25.62, + "speed": 20.88, + "time": 2.57, + "theta": -90, + "omega": 0, + "vx": -15.71, + "vy": -13.75, + "splineNum": 4 + }, + { + "x": 2.78, + "y": 25.62, + "speed": 20.88, + "time": 2.57, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 5 + }, + { + "x": 1.52, + "y": 23.95, + "speed": 29.24, + "time": 2.64, + "theta": -90, + "omega": 0, + "vx": -17.61, + "vy": -23.34, + "splineNum": 5 + }, + { + "x": 0.66, + "y": 22.18, + "speed": 33.83, + "time": 2.7, + "theta": -90, + "omega": 0, + "vx": -14.77, + "vy": -30.44, + "splineNum": 5 + }, + { + "x": 0.13, + "y": 20.34, + "speed": 39.09, + "time": 2.75, + "theta": -90, + "omega": 0, + "vx": -10.79, + "vy": -37.57, + "splineNum": 5 + }, + { + "x": -0.15, + "y": 18.44, + "speed": 43.72, + "time": 2.79, + "theta": -90, + "omega": 0, + "vx": -6.32, + "vy": -43.26, + "splineNum": 5 + }, + { + "x": -0.25, + "y": 16.5, + "speed": 47.96, + "time": 2.83, + "theta": -90, + "omega": 0, + "vx": -2.55, + "vy": -47.89, + "splineNum": 5 + }, + { + "x": -0.25, + "y": 14.54, + "speed": 46.36, + "time": 2.88, + "theta": -90, + "omega": 0, + "vx": -0.14, + "vy": -46.36, + "splineNum": 5 + }, + { + "x": -0.24, + "y": 12.57, + "speed": 41.9, + "time": 2.92, + "theta": -90, + "omega": 0, + "vx": 0.31, + "vy": -41.9, + "splineNum": 5 + } + ] + }, + { + "name": "Goal4ToGoal5", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -90, + "spline_angle": 96.27, + "x": -0.56, + "y": 23.55, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 89.98, + "x": -0.56, + "y": 32.78, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal5", + "omega": 0, + "angle": 90, + "spline_angle": 89.98, + "x": 0.24, + "y": 60.94, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -0.24, + "y": 12.57, + "speed": 41.9, + "time": 0, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -0.24, + "y": 14.14, + "speed": 45.49, + "time": 0.03, + "theta": -90, + "omega": 0, + "vx": 0.11, + "vy": 45.49, + "splineNum": 0 + }, + { + "x": -0.23, + "y": 15.71, + "speed": 48.82, + "time": 0.07, + "theta": -90, + "omega": 0, + "vx": 0.11, + "vy": 48.82, + "splineNum": 0 + }, + { + "x": -0.24, + "y": 17.28, + "speed": 50, + "time": 0.1, + "theta": -90, + "omega": 0, + "vx": -0.2, + "vy": 50, + "splineNum": 0 + }, + { + "x": -0.27, + "y": 18.85, + "speed": 50, + "time": 0.13, + "theta": -90, + "omega": 0, + "vx": -0.83, + "vy": 49.99, + "splineNum": 0 + }, + { + "x": -0.32, + "y": 20.42, + "speed": 48.83, + "time": 0.16, + "theta": -90, + "omega": 0, + "vx": -1.73, + "vy": 48.8, + "splineNum": 0 + }, + { + "x": -0.42, + "y": 21.98, + "speed": 45.5, + "time": 0.2, + "theta": -90, + "omega": 0, + "vx": -2.75, + "vy": 45.41, + "splineNum": 0 + }, + { + "x": -0.56, + "y": 23.55, + "speed": 41.9, + "time": 0.23, + "theta": -90, + "omega": 0, + "vx": -3.84, + "vy": 41.72, + "splineNum": 0 + }, + { + "x": -0.56, + "y": 23.55, + "speed": 41.9, + "time": 0.23, + "theta": -90, + "omega": 0, + "vx": -1.33, + "vy": 42.67, + "splineNum": 0 + }, + { + "x": -0.67, + "y": 24.87, + "speed": 40.17, + "time": 0.27, + "theta": -89.29, + "omega": 42.83, + "vx": -3.23, + "vy": 40.04, + "splineNum": 1 + }, + { + "x": -0.71, + "y": 26.19, + "speed": 36.74, + "time": 0.3, + "theta": -86.92, + "omega": 89.52, + "vx": -1.16, + "vy": 36.72, + "splineNum": 1 + }, + { + "x": -0.7, + "y": 27.51, + "speed": 32.95, + "time": 0.34, + "theta": -82.3, + "omega": 141.56, + "vx": 0.14, + "vy": 32.95, + "splineNum": 1 + }, + { + "x": -0.67, + "y": 28.82, + "speed": 28.67, + "time": 0.39, + "theta": -74.41, + "omega": 201.38, + "vx": 0.77, + "vy": 28.66, + "splineNum": 1 + }, + { + "x": -0.62, + "y": 30.14, + "speed": 23.63, + "time": 0.44, + "theta": -61.13, + "omega": 274, + "vx": 0.85, + "vy": 23.61, + "splineNum": 1 + }, + { + "x": -0.58, + "y": 31.46, + "speed": 17.16, + "time": 0.52, + "theta": -36.22, + "omega": 994.4, + "vx": 0.54, + "vy": 17.15, + "splineNum": 1 + }, + { + "x": -0.56, + "y": 32.78, + "speed": 5.53, + "time": 0.76, + "theta": 90, + "omega": 684.2, + "vx": 0.08, + "vy": 5.53, + "splineNum": 1 + }, + { + "x": -0.56, + "y": 32.78, + "speed": 5.53, + "time": 0.76, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 2 + }, + { + "x": -0.52, + "y": 36.3, + "speed": 27.11, + "time": 0.89, + "theta": 90, + "omega": 0, + "vx": 0.27, + "vy": 27.11, + "splineNum": 2 + }, + { + "x": -0.43, + "y": 39.82, + "speed": 37.94, + "time": 0.98, + "theta": 90, + "omega": 0, + "vx": 0.98, + "vy": 37.92, + "splineNum": 2 + }, + { + "x": -0.31, + "y": 43.34, + "speed": 46.3, + "time": 1.06, + "theta": 90, + "omega": 0, + "vx": 1.68, + "vy": 46.27, + "splineNum": 2 + }, + { + "x": -0.16, + "y": 46.86, + "speed": 50, + "time": 1.13, + "theta": 90, + "omega": 0, + "vx": 2.08, + "vy": 49.96, + "splineNum": 2 + }, + { + "x": -0.01, + "y": 50.38, + "speed": 50, + "time": 1.2, + "theta": 90, + "omega": 0, + "vx": 2.08, + "vy": 49.96, + "splineNum": 2 + }, + { + "x": 0.11, + "y": 53.9, + "speed": 50, + "time": 1.27, + "theta": 90, + "omega": 0, + "vx": 1.81, + "vy": 49.97, + "splineNum": 2 + }, + { + "x": 0.2, + "y": 57.42, + "speed": 49.6, + "time": 1.34, + "theta": 90, + "omega": 0, + "vx": 1.28, + "vy": 49.58, + "splineNum": 2 + }, + { + "x": 0.24, + "y": 60.94, + "speed": 41.9, + "time": 1.42, + "theta": 90, + "omega": 0, + "vx": 0.42, + "vy": 41.9, + "splineNum": 2 + } + ] + }, + { + "name": "Goal4ToDeploy4", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + }, + { + "name": "Deploy4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": 0, + "y": 24.12, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -0.24, + "y": 12.57, + "speed": 41.9, + "time": 0, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -0.23, + "y": 14.22, + "speed": 45.67, + "time": 0.04, + "theta": -90, + "omega": 0, + "vx": 0.38, + "vy": 45.67, + "splineNum": 0 + }, + { + "x": -0.19, + "y": 15.87, + "speed": 49.15, + "time": 0.07, + "theta": -90, + "omega": 0, + "vx": 1.02, + "vy": 49.14, + "splineNum": 0 + }, + { + "x": -0.15, + "y": 17.52, + "speed": 50, + "time": 0.1, + "theta": -90, + "omega": 0, + "vx": 1.41, + "vy": 49.98, + "splineNum": 0 + }, + { + "x": -0.09, + "y": 19.17, + "speed": 50, + "time": 0.14, + "theta": -90, + "omega": 0, + "vx": 1.54, + "vy": 49.98, + "splineNum": 0 + }, + { + "x": -0.05, + "y": 20.82, + "speed": 49.15, + "time": 0.17, + "theta": -90, + "omega": 0, + "vx": 1.39, + "vy": 49.13, + "splineNum": 0 + }, + { + "x": -0.01, + "y": 22.47, + "speed": 45.67, + "time": 0.21, + "theta": -90, + "omega": 0, + "vx": 0.95, + "vy": 45.66, + "splineNum": 0 + }, + { + "x": 0, + "y": 24.12, + "speed": 41.9, + "time": 0.24, + "theta": -90, + "omega": 0, + "vx": 0.35, + "vy": 41.9, + "splineNum": 0 + }, + { + "x": 0, + "y": 24.12, + "speed": 41.9, + "time": 0.24, + "theta": -90, + "omega": 0, + "vx": 0.33, + "vy": 42.67, + "splineNum": 0 + } + ] + }, + { + "name": "Deploy4ToGoal4", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Deploy4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": 0, + "y": 24.12, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": 0, + "y": 24.12, + "speed": 41.9, + "time": 0, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -0.01, + "y": 22.47, + "speed": 45.67, + "time": 0.04, + "theta": -90, + "omega": 0, + "vx": -0.38, + "vy": -45.67, + "splineNum": 0 + }, + { + "x": -0.05, + "y": 20.82, + "speed": 49.15, + "time": 0.07, + "theta": -90, + "omega": 0, + "vx": -1.02, + "vy": -49.14, + "splineNum": 0 + }, + { + "x": -0.09, + "y": 19.17, + "speed": 50, + "time": 0.1, + "theta": -90, + "omega": 0, + "vx": -1.41, + "vy": -49.98, + "splineNum": 0 + }, + { + "x": -0.15, + "y": 17.52, + "speed": 50, + "time": 0.14, + "theta": -90, + "omega": 0, + "vx": -1.54, + "vy": -49.98, + "splineNum": 0 + }, + { + "x": -0.19, + "y": 15.87, + "speed": 49.15, + "time": 0.17, + "theta": -90, + "omega": 0, + "vx": -1.39, + "vy": -49.13, + "splineNum": 0 + }, + { + "x": -0.23, + "y": 14.22, + "speed": 45.67, + "time": 0.21, + "theta": -90, + "omega": 0, + "vx": -0.95, + "vy": -45.66, + "splineNum": 0 + }, + { + "x": -0.24, + "y": 12.57, + "speed": 41.9, + "time": 0.24, + "theta": -90, + "omega": 0, + "vx": -0.35, + "vy": -41.9, + "splineNum": 0 + }, + { + "x": -0.24, + "y": 12.57, + "speed": 41.9, + "time": 0.24, + "theta": -90, + "omega": 0, + "vx": -0.5, + "vy": -32, + "splineNum": 0 + } + ] + }, + { + "name": "Goal1ToDeploy1", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -55.25, + "y": 16.43, + "shared": true, + "speed": 41.9 + }, + { + "name": "Deploy1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -52.32, + "y": 18.69, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -55.25, + "y": 16.43, + "speed": 22.62, + "time": 0, + "theta": -135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -54.86, + "y": 16.79, + "speed": 20.14, + "time": 0.03, + "theta": -135, + "omega": 0, + "vx": 14.93, + "vy": 13.52, + "splineNum": 0 + }, + { + "x": -54.44, + "y": 17.11, + "speed": 22.62, + "time": 0.05, + "theta": -135, + "omega": 0, + "vx": 17.91, + "vy": 13.81, + "splineNum": 0 + }, + { + "x": -54, + "y": 17.41, + "speed": 24.85, + "time": 0.07, + "theta": -135, + "omega": 0, + "vx": 20.37, + "vy": 14.23, + "splineNum": 0 + }, + { + "x": -53.57, + "y": 17.71, + "speed": 24.85, + "time": 0.09, + "theta": -135, + "omega": 0, + "vx": 20.59, + "vy": 13.9, + "splineNum": 0 + }, + { + "x": -53.13, + "y": 18.01, + "speed": 22.62, + "time": 0.12, + "theta": -135, + "omega": 0, + "vx": 18.54, + "vy": 12.95, + "splineNum": 0 + }, + { + "x": -52.71, + "y": 18.33, + "speed": 20.14, + "time": 0.14, + "theta": -135, + "omega": 0, + "vx": 15.95, + "vy": 12.3, + "splineNum": 0 + }, + { + "x": -52.32, + "y": 18.69, + "speed": 22.62, + "time": 0.17, + "theta": -135, + "omega": 0, + "vx": 16.77, + "vy": 15.19, + "splineNum": 0 + } + ] + }, + { + "name": "Deploy1ToGoal1", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Deploy1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -52.32, + "y": 18.69, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -55.25, + "y": 16.43, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -52.32, + "y": 18.69, + "speed": 22.62, + "time": 0, + "theta": -135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -52.71, + "y": 18.33, + "speed": 20.14, + "time": 0.03, + "theta": -135, + "omega": 0, + "vx": -14.93, + "vy": -13.52, + "splineNum": 0 + }, + { + "x": -53.13, + "y": 18.01, + "speed": 22.62, + "time": 0.05, + "theta": -135, + "omega": 0, + "vx": -17.91, + "vy": -13.81, + "splineNum": 0 + }, + { + "x": -53.57, + "y": 17.71, + "speed": 24.85, + "time": 0.07, + "theta": -135, + "omega": 0, + "vx": -20.37, + "vy": -14.23, + "splineNum": 0 + }, + { + "x": -54, + "y": 17.41, + "speed": 24.85, + "time": 0.09, + "theta": -135, + "omega": 0, + "vx": -20.59, + "vy": -13.9, + "splineNum": 0 + }, + { + "x": -54.44, + "y": 17.11, + "speed": 22.62, + "time": 0.12, + "theta": -135, + "omega": 0, + "vx": -18.54, + "vy": -12.95, + "splineNum": 0 + }, + { + "x": -54.86, + "y": 16.79, + "speed": 20.14, + "time": 0.14, + "theta": -135, + "omega": 0, + "vx": -15.95, + "vy": -12.3, + "splineNum": 0 + }, + { + "x": -55.25, + "y": 16.43, + "speed": 22.62, + "time": 0.17, + "theta": -135, + "omega": 0, + "vx": -16.77, + "vy": -15.19, + "splineNum": 0 + } + ] + }, + { + "name": "DeployWall1ToGoal1", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "DeployWall1", + "omega": 0, + "angle": 90, + "spline_angle": 88.38, + "x": -36.52, + "y": 9.85, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 101.35, + "spline_angle": 97.52, + "x": -36.86, + "y": 19.54, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -47.74, + "y": 23.61, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -55.25, + "y": 16.43, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -36.52, + "y": 9.85, + "speed": 41.9, + "time": 0, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -36.49, + "y": 11.24, + "speed": 41.08, + "time": 0.03, + "theta": 90.04, + "omega": 2.27, + "vx": 0.96, + "vy": 41.07, + "splineNum": 0 + }, + { + "x": -36.47, + "y": 12.62, + "speed": 37.55, + "time": 0.07, + "theta": 90.17, + "omega": 4.75, + "vx": 0.4, + "vy": 37.55, + "splineNum": 0 + }, + { + "x": -36.48, + "y": 14.01, + "speed": 33.66, + "time": 0.11, + "theta": 90.42, + "omega": 7.52, + "vx": -0.21, + "vy": 33.66, + "splineNum": 0 + }, + { + "x": -36.52, + "y": 15.39, + "speed": 29.26, + "time": 0.16, + "theta": 90.85, + "omega": 10.71, + "vx": -0.79, + "vy": 29.25, + "splineNum": 0 + }, + { + "x": -36.59, + "y": 16.78, + "speed": 24.06, + "time": 0.22, + "theta": 91.58, + "omega": 14.58, + "vx": -1.25, + "vy": 24.03, + "splineNum": 0 + }, + { + "x": -36.7, + "y": 18.16, + "speed": 17.37, + "time": 0.3, + "theta": 92.96, + "omega": 58.2, + "vx": -1.4, + "vy": 17.31, + "splineNum": 0 + }, + { + "x": -36.86, + "y": 19.54, + "speed": 4.89, + "time": 0.58, + "theta": 101.35, + "omega": 39.07, + "vx": -0.55, + "vy": 4.85, + "splineNum": 0 + }, + { + "x": -36.86, + "y": 19.54, + "speed": 4.89, + "time": 0.58, + "theta": 101.35, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": -37.46, + "y": 22.68, + "speed": 25.77, + "time": 0.71, + "theta": 103.75, + "omega": 38.65, + "vx": -4.8, + "vy": 25.32, + "splineNum": 1 + }, + { + "x": -38.33, + "y": 25.07, + "speed": 22.79, + "time": 0.82, + "theta": 110.01, + "omega": 73.41, + "vx": -7.85, + "vy": 21.4, + "splineNum": 1 + }, + { + "x": -39.52, + "y": 26.65, + "speed": 11.2, + "time": 0.99, + "theta": 127.75, + "omega": 128.17, + "vx": -6.72, + "vy": 8.96, + "splineNum": 1 + }, + { + "x": -41.02, + "y": 27.35, + "speed": 9.6, + "time": 1.17, + "theta": 154.63, + "omega": 372.71, + "vx": -8.71, + "vy": 4.05, + "splineNum": 1 + }, + { + "x": -42.88, + "y": 27.12, + "speed": 17.63, + "time": 1.27, + "theta": 175.74, + "omega": 339.64, + "vx": -17.49, + "vy": -2.19, + "splineNum": 1 + }, + { + "x": -45.11, + "y": 25.89, + "speed": 28.64, + "time": 1.36, + "theta": 196.11, + "omega": 311.97, + "vx": -25.09, + "vy": -13.8, + "splineNum": 1 + }, + { + "x": -47.74, + "y": 23.61, + "speed": 31.33, + "time": 1.47, + "theta": 225, + "omega": 277.4, + "vx": -23.64, + "vy": -20.55, + "splineNum": 1 + }, + { + "x": -47.74, + "y": 23.61, + "speed": 31.33, + "time": 1.47, + "theta": 225, + "omega": 277.4, + "vx": -31.33, + "vy": 0, + "splineNum": 1 + }, + { + "x": -48.8, + "y": 22.57, + "speed": 35.75, + "time": 1.51, + "theta": -135, + "omega": 0, + "vx": -25.5, + "vy": -25.06, + "splineNum": 2 + }, + { + "x": -49.87, + "y": 21.54, + "speed": 39.69, + "time": 1.55, + "theta": -135, + "omega": 0, + "vx": -28.69, + "vy": -27.43, + "splineNum": 2 + }, + { + "x": -50.95, + "y": 20.53, + "speed": 43.27, + "time": 1.59, + "theta": -135, + "omega": 0, + "vx": -31.52, + "vy": -29.64, + "splineNum": 2 + }, + { + "x": -52.04, + "y": 19.51, + "speed": 46.57, + "time": 1.62, + "theta": -135, + "omega": 0, + "vx": -34.01, + "vy": -31.81, + "splineNum": 2 + }, + { + "x": -53.12, + "y": 18.5, + "speed": 48.47, + "time": 1.65, + "theta": -135, + "omega": 0, + "vx": -35.31, + "vy": -33.2, + "splineNum": 2 + }, + { + "x": -54.19, + "y": 17.47, + "speed": 45.3, + "time": 1.68, + "theta": -135, + "omega": 0, + "vx": -32.75, + "vy": -31.31, + "splineNum": 2 + }, + { + "x": -55.25, + "y": 16.43, + "speed": 41.9, + "time": 1.72, + "theta": -135, + "omega": 0, + "vx": -29.88, + "vy": -29.37, + "splineNum": 2 + } + ] + }, + { + "name": "Goal4ToGoal1", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -102.53, + "spline_angle": 90, + "x": -1.35, + "y": 24.18, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -78.51, + "spline_angle": 180, + "x": -10.1, + "y": 28.32, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -169.66, + "spline_angle": -178.12, + "x": -23.79, + "y": 25.46, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -159.52, + "spline_angle": -159.52, + "x": -42.72, + "y": 21.16, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -135, + "spline_angle": -153.43, + "x": -52.32, + "y": 17.16, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -55.25, + "y": 16.43, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -0.24, + "y": 12.57, + "speed": 41.9, + "time": 0, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -0.3, + "y": 14.24, + "speed": 45.13, + "time": 0.04, + "theta": -90.05, + "omega": -2.56, + "vx": -1.65, + "vy": 45.1, + "splineNum": 0 + }, + { + "x": -0.46, + "y": 15.9, + "speed": 41.27, + "time": 0.08, + "theta": -90.21, + "omega": -5.35, + "vx": -3.92, + "vy": 41.09, + "splineNum": 0 + }, + { + "x": -0.68, + "y": 17.55, + "speed": 37.01, + "time": 0.12, + "theta": -90.52, + "omega": -8.46, + "vx": -4.81, + "vy": 36.7, + "splineNum": 0 + }, + { + "x": -0.91, + "y": 19.2, + "speed": 32.19, + "time": 0.17, + "theta": -91.05, + "omega": -12.04, + "vx": -4.56, + "vy": 31.87, + "splineNum": 0 + }, + { + "x": -1.13, + "y": 20.85, + "speed": 26.51, + "time": 0.24, + "theta": -91.94, + "omega": -16.39, + "vx": -3.45, + "vy": 26.29, + "splineNum": 0 + }, + { + "x": -1.29, + "y": 22.51, + "speed": 19.23, + "time": 0.32, + "theta": -93.62, + "omega": -60.86, + "vx": -1.83, + "vy": 19.14, + "splineNum": 0 + }, + { + "x": -1.35, + "y": 24.18, + "speed": 6, + "time": 0.6, + "theta": -102.53, + "omega": -41.62, + "vx": -0.22, + "vy": 5.99, + "splineNum": 0 + }, + { + "x": -1.35, + "y": 24.18, + "speed": 6, + "time": 0.6, + "theta": -102.53, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": -1.65, + "y": 26.78, + "speed": 17.31, + "time": 0.75, + "theta": -101.8, + "omega": 9.68, + "vx": -1.96, + "vy": 17.2, + "splineNum": 1 + }, + { + "x": -2.46, + "y": 28.3, + "speed": 8.31, + "time": 0.96, + "theta": -98.43, + "omega": 22.91, + "vx": -3.93, + "vy": 7.32, + "splineNum": 1 + }, + { + "x": -3.67, + "y": 28.98, + "speed": 9.67, + "time": 1.1, + "theta": -94.48, + "omega": 78.76, + "vx": -8.44, + "vy": 4.72, + "splineNum": 1 + }, + { + "x": -5.16, + "y": 29.07, + "speed": 19.79, + "time": 1.18, + "theta": -91.89, + "omega": 73.95, + "vx": -19.75, + "vy": 1.19, + "splineNum": 1 + }, + { + "x": -6.8, + "y": 28.82, + "speed": 26.92, + "time": 1.24, + "theta": -89.48, + "omega": 69.99, + "vx": -26.62, + "vy": -3.99, + "splineNum": 1 + }, + { + "x": -8.49, + "y": 28.49, + "speed": 21.1, + "time": 1.32, + "theta": -85.94, + "omega": 64.78, + "vx": -20.7, + "vy": -4.08, + "splineNum": 1 + }, + { + "x": -10.1, + "y": 28.32, + "speed": 11.04, + "time": 1.47, + "theta": -78.51, + "omega": 55.42, + "vx": -10.98, + "vy": -1.14, + "splineNum": 1 + }, + { + "x": -10.1, + "y": 28.32, + "speed": 11.04, + "time": 1.47, + "theta": -78.51, + "omega": 55.42, + "vx": -11.04, + "vy": 0, + "splineNum": 1 + }, + { + "x": -12.11, + "y": 28.17, + "speed": 22.91, + "time": 1.56, + "theta": -83.11, + "omega": -104.69, + "vx": -22.85, + "vy": -1.71, + "splineNum": 2 + }, + { + "x": -14.07, + "y": 27.78, + "speed": 30.41, + "time": 1.62, + "theta": -92.56, + "omega": -182.89, + "vx": -29.82, + "vy": -5.93, + "splineNum": 2 + }, + { + "x": -16, + "y": 27.24, + "speed": 36.4, + "time": 1.68, + "theta": -104.42, + "omega": -683.24, + "vx": -35.07, + "vy": -9.76, + "splineNum": 2 + }, + { + "x": -17.92, + "y": 26.65, + "speed": 41.55, + "time": 1.73, + "theta": -117.81, + "omega": -625.75, + "vx": -39.7, + "vy": -12.27, + "splineNum": 2 + }, + { + "x": -19.84, + "y": 26.09, + "speed": 46.12, + "time": 1.77, + "theta": -132.22, + "omega": -574.05, + "vx": -44.31, + "vy": -12.8, + "splineNum": 2 + }, + { + "x": -21.79, + "y": 25.67, + "speed": 46.45, + "time": 1.81, + "theta": -148.7, + "omega": -522.85, + "vx": -45.37, + "vy": -9.94, + "splineNum": 2 + }, + { + "x": -23.79, + "y": 25.46, + "speed": 41.9, + "time": 1.86, + "theta": -169.66, + "omega": -465.8, + "vx": -41.68, + "vy": -4.32, + "splineNum": 2 + }, + { + "x": -23.79, + "y": 25.46, + "speed": 41.9, + "time": 1.86, + "theta": -169.66, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 3 + }, + { + "x": -26.59, + "y": 25.27, + "speed": 48.14, + "time": 1.92, + "theta": -169.61, + "omega": 1.55, + "vx": -48.03, + "vy": -3.2, + "splineNum": 3 + }, + { + "x": -29.35, + "y": 24.91, + "speed": 50, + "time": 1.97, + "theta": -169.49, + "omega": 3.02, + "vx": -49.58, + "vy": -6.48, + "splineNum": 3 + }, + { + "x": -32.08, + "y": 24.4, + "speed": 47.61, + "time": 2.03, + "theta": -169.27, + "omega": 4.57, + "vx": -46.78, + "vy": -8.86, + "splineNum": 3 + }, + { + "x": -34.78, + "y": 23.74, + "speed": 41.37, + "time": 2.1, + "theta": -168.9, + "omega": 6.34, + "vx": -40.21, + "vy": -9.74, + "splineNum": 3 + }, + { + "x": -37.44, + "y": 22.97, + "speed": 34, + "time": 2.18, + "theta": -168.29, + "omega": 8.51, + "vx": -32.67, + "vy": -9.42, + "splineNum": 3 + }, + { + "x": -40.09, + "y": 22.11, + "speed": 24.48, + "time": 2.3, + "theta": -167.16, + "omega": 11.52, + "vx": -23.26, + "vy": -7.62, + "splineNum": 3 + }, + { + "x": -42.72, + "y": 21.16, + "speed": 6.35, + "time": 2.74, + "theta": -159.52, + "omega": 23.18, + "vx": -5.97, + "vy": -2.15, + "splineNum": 3 + }, + { + "x": -42.72, + "y": 21.16, + "speed": 6.35, + "time": 2.74, + "theta": -159.52, + "omega": 23.18, + "vx": 0, + "vy": -8, + "splineNum": 3 + }, + { + "x": -44.11, + "y": 20.64, + "speed": 18.38, + "time": 2.82, + "theta": -159.4, + "omega": 3.07, + "vx": -17.2, + "vy": -6.45, + "splineNum": 4 + }, + { + "x": -45.5, + "y": 20.11, + "speed": 25.2, + "time": 2.88, + "theta": -159.15, + "omega": 5.32, + "vx": -23.54, + "vy": -8.98, + "splineNum": 4 + }, + { + "x": -46.88, + "y": 19.57, + "speed": 30.53, + "time": 2.92, + "theta": -158.84, + "omega": 7.17, + "vx": -28.42, + "vy": -11.15, + "splineNum": 4 + }, + { + "x": -48.26, + "y": 19, + "speed": 29.93, + "time": 2.97, + "theta": -158.44, + "omega": 9.05, + "vx": -27.72, + "vy": -11.3, + "splineNum": 4 + }, + { + "x": -49.63, + "y": 18.42, + "speed": 24.47, + "time": 3.03, + "theta": -157.82, + "omega": 11.36, + "vx": -22.5, + "vy": -9.62, + "splineNum": 4 + }, + { + "x": -50.98, + "y": 17.81, + "speed": 17.36, + "time": 3.12, + "theta": -156.71, + "omega": 14.61, + "vx": -15.82, + "vy": -7.16, + "splineNum": 4 + }, + { + "x": -52.32, + "y": 17.16, + "speed": 1.98, + "time": 3.87, + "theta": -135, + "omega": 43.17, + "vx": -1.78, + "vy": -0.86, + "splineNum": 4 + }, + { + "x": -52.32, + "y": 17.16, + "speed": 1.98, + "time": 3.87, + "theta": -135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 5 + }, + { + "x": -52.73, + "y": 17.02, + "speed": 6.59, + "time": 3.94, + "theta": -135, + "omega": 0, + "vx": -6.23, + "vy": -2.16, + "splineNum": 5 + }, + { + "x": -53.16, + "y": 16.96, + "speed": 11.41, + "time": 3.97, + "theta": -135, + "omega": 0, + "vx": -11.3, + "vy": -1.55, + "splineNum": 5 + }, + { + "x": -53.6, + "y": 16.94, + "speed": 14.67, + "time": 4, + "theta": -135, + "omega": 0, + "vx": -14.66, + "vy": -0.61, + "splineNum": 5 + }, + { + "x": -54.04, + "y": 16.92, + "speed": 11.28, + "time": 4.04, + "theta": -135, + "omega": 0, + "vx": -11.27, + "vy": -0.51, + "splineNum": 5 + }, + { + "x": -54.47, + "y": 16.86, + "speed": 6.37, + "time": 4.11, + "theta": -135, + "omega": 0, + "vx": -6.3, + "vy": -0.93, + "splineNum": 5 + }, + { + "x": -54.87, + "y": 16.71, + "speed": 4.75, + "time": 4.2, + "theta": -135, + "omega": 0, + "vx": -4.46, + "vy": -1.64, + "splineNum": 5 + }, + { + "x": -55.25, + "y": 16.43, + "speed": 10.77, + "time": 4.25, + "theta": -135, + "omega": 0, + "vx": -8.66, + "vy": -6.41, + "splineNum": 5 + } + ] + }, + { + "name": "Goal7ToGoal5", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal7", + "omega": 0, + "angle": -45, + "spline_angle": 134.17, + "x": 62.36, + "y": 14.38, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -75, + "spline_angle": 106.69, + "x": 55.04, + "y": 19.88, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -165, + "spline_angle": -173.19, + "x": 46.38, + "y": 26.16, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -180, + "spline_angle": -173.19, + "x": 31.43, + "y": 22.42, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 134.97, + "x": 10.53, + "y": 25.14, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 104.06, + "x": 1.7, + "y": 36.35, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 90.01, + "x": 0.51, + "y": 47.23, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal5", + "omega": 0, + "angle": 90, + "spline_angle": 89.98, + "x": 0.24, + "y": 60.94, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": 62.36, + "y": 14.38, + "speed": 26.44, + "time": 0, + "theta": -45, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 61.33, + "y": 15.19, + "speed": 20.91, + "time": 0.06, + "theta": -45.14, + "omega": -4.62, + "vx": -16.4, + "vy": 12.98, + "splineNum": 0 + }, + { + "x": 60.16, + "y": 15.8, + "speed": 26.51, + "time": 0.11, + "theta": -45.47, + "omega": -8.32, + "vx": -23.51, + "vy": 12.24, + "splineNum": 0 + }, + { + "x": 58.92, + "y": 16.33, + "speed": 28.14, + "time": 0.16, + "theta": -45.95, + "omega": -11.86, + "vx": -25.89, + "vy": 11.01, + "splineNum": 0 + }, + { + "x": 57.7, + "y": 16.89, + "speed": 22.89, + "time": 0.22, + "theta": -46.77, + "omega": -16.18, + "vx": -20.81, + "vy": 9.52, + "splineNum": 0 + }, + { + "x": 56.59, + "y": 17.59, + "speed": 16.17, + "time": 0.3, + "theta": -48.33, + "omega": -22.18, + "vx": -13.67, + "vy": 8.63, + "splineNum": 0 + }, + { + "x": 55.68, + "y": 18.55, + "speed": 13.31, + "time": 0.4, + "theta": -50.9, + "omega": -29.54, + "vx": -9.19, + "vy": 9.63, + "splineNum": 0 + }, + { + "x": 55.04, + "y": 19.88, + "speed": 2.94, + "time": 0.9, + "theta": -75, + "omega": -66.58, + "vx": -1.27, + "vy": 2.66, + "splineNum": 0 + }, + { + "x": 55.04, + "y": 19.88, + "speed": 2.94, + "time": 0.9, + "theta": -75, + "omega": -66.58, + "vx": 0, + "vy": 2.91, + "splineNum": 0 + }, + { + "x": 54.41, + "y": 21.61, + "speed": 19.42, + "time": 1, + "theta": -77.63, + "omega": -55.4, + "vx": -6.66, + "vy": 18.24, + "splineNum": 1 + }, + { + "x": 53.6, + "y": 23.11, + "speed": 26.63, + "time": 1.06, + "theta": -82.34, + "omega": -92.6, + "vx": -12.63, + "vy": 23.45, + "splineNum": 1 + }, + { + "x": 52.61, + "y": 24.34, + "speed": 20.8, + "time": 1.14, + "theta": -91.08, + "omega": -137.05, + "vx": -13.06, + "vy": 16.18, + "splineNum": 1 + }, + { + "x": 51.41, + "y": 25.28, + "speed": 18.75, + "time": 1.22, + "theta": -104.2, + "omega": -463.7, + "vx": -14.73, + "vy": 11.6, + "splineNum": 1 + }, + { + "x": 49.98, + "y": 25.92, + "speed": 20.34, + "time": 1.29, + "theta": -120.11, + "omega": -418.86, + "vx": -18.58, + "vy": 8.27, + "splineNum": 1 + }, + { + "x": 48.31, + "y": 26.22, + "speed": 26.14, + "time": 1.36, + "theta": -136.23, + "omega": -380.97, + "vx": -25.73, + "vy": 4.63, + "splineNum": 1 + }, + { + "x": 46.38, + "y": 26.16, + "speed": 19.86, + "time": 1.46, + "theta": -165, + "omega": -324.19, + "vx": -19.85, + "vy": -0.61, + "splineNum": 1 + }, + { + "x": 46.38, + "y": 26.16, + "speed": 19.86, + "time": 1.46, + "theta": -165, + "omega": -324.19, + "vx": 19.86, + "vy": 0, + "splineNum": 1 + }, + { + "x": 44.2, + "y": 25.79, + "speed": 28.91, + "time": 1.53, + "theta": -165.51, + "omega": -13.44, + "vx": -28.51, + "vy": -4.82, + "splineNum": 2 + }, + { + "x": 42.07, + "y": 25.26, + "speed": 35.73, + "time": 1.59, + "theta": -166.68, + "omega": -24.28, + "vx": -34.66, + "vy": -8.67, + "splineNum": 2 + }, + { + "x": 39.96, + "y": 24.62, + "speed": 41.44, + "time": 1.65, + "theta": -168.22, + "omega": -33.64, + "vx": -39.69, + "vy": -11.92, + "splineNum": 2 + }, + { + "x": 37.85, + "y": 23.96, + "speed": 46.46, + "time": 1.69, + "theta": -170.01, + "omega": -103.32, + "vx": -44.28, + "vy": -14.05, + "splineNum": 2 + }, + { + "x": 35.74, + "y": 23.32, + "speed": 44.14, + "time": 1.74, + "theta": -172.33, + "omega": -94.53, + "vx": -42.27, + "vy": -12.7, + "splineNum": 2 + }, + { + "x": 33.61, + "y": 22.79, + "speed": 38.83, + "time": 1.8, + "theta": -175.49, + "omega": -84.56, + "vx": -37.67, + "vy": -9.42, + "splineNum": 2 + }, + { + "x": 31.43, + "y": 22.42, + "speed": 32.65, + "time": 1.87, + "theta": -180, + "omega": -72.66, + "vx": -32.2, + "vy": -5.45, + "splineNum": 2 + }, + { + "x": 31.43, + "y": 22.42, + "speed": 32.65, + "time": 1.87, + "theta": -180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 3 + }, + { + "x": 28.34, + "y": 21.97, + "speed": 41.13, + "time": 1.95, + "theta": -182.02, + "omega": -53.11, + "vx": -40.7, + "vy": -5.91, + "splineNum": 3 + }, + { + "x": 25.24, + "y": 21.49, + "speed": 48.16, + "time": 2.01, + "theta": -186.96, + "omega": -98.62, + "vx": -47.58, + "vy": -7.45, + "splineNum": 3 + }, + { + "x": 22.16, + "y": 21.15, + "speed": 50, + "time": 2.07, + "theta": -194.41, + "omega": -141.89, + "vx": -49.71, + "vy": -5.36, + "splineNum": 3 + }, + { + "x": 19.12, + "y": 21.16, + "speed": 46.63, + "time": 2.14, + "theta": -205.13, + "omega": -521.84, + "vx": -46.62, + "vy": 0.16, + "splineNum": 3 + }, + { + "x": 16.16, + "y": 21.71, + "speed": 39.64, + "time": 2.21, + "theta": -221.4, + "omega": -468.71, + "vx": -38.99, + "vy": 7.12, + "splineNum": 3 + }, + { + "x": 13.28, + "y": 22.97, + "speed": 39.39, + "time": 2.29, + "theta": -242.77, + "omega": -413.07, + "vx": -36.06, + "vy": 15.85, + "splineNum": 3 + }, + { + "x": 10.53, + "y": 25.14, + "speed": 41.9, + "time": 2.38, + "theta": -270, + "omega": -354.6, + "vx": -32.9, + "vy": 25.94, + "splineNum": 3 + }, + { + "x": 10.53, + "y": 25.14, + "speed": 41.9, + "time": 2.38, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 4 + }, + { + "x": 9.04, + "y": 26.56, + "speed": 46.56, + "time": 2.42, + "theta": 90, + "omega": 0, + "vx": -33.66, + "vy": 32.17, + "splineNum": 4 + }, + { + "x": 7.52, + "y": 27.96, + "speed": 50, + "time": 2.46, + "theta": 90, + "omega": 0, + "vx": -36.82, + "vy": 33.83, + "splineNum": 4 + }, + { + "x": 6.03, + "y": 29.38, + "speed": 50, + "time": 2.5, + "theta": 90, + "omega": 0, + "vx": -36.14, + "vy": 34.55, + "splineNum": 4 + }, + { + "x": 4.64, + "y": 30.88, + "speed": 46.88, + "time": 2.55, + "theta": 90, + "omega": 0, + "vx": -31.88, + "vy": 34.36, + "splineNum": 4 + }, + { + "x": 3.41, + "y": 32.51, + "speed": 42.3, + "time": 2.6, + "theta": 90, + "omega": 0, + "vx": -25.5, + "vy": 33.76, + "splineNum": 4 + }, + { + "x": 2.41, + "y": 34.31, + "speed": 37.1, + "time": 2.65, + "theta": 90, + "omega": 0, + "vx": -18, + "vy": 32.44, + "splineNum": 4 + }, + { + "x": 1.7, + "y": 36.35, + "speed": 41.9, + "time": 2.7, + "theta": 90, + "omega": 0, + "vx": -13.8, + "vy": 39.56, + "splineNum": 4 + }, + { + "x": 1.7, + "y": 36.35, + "speed": 41.9, + "time": 2.7, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 5 + }, + { + "x": 1.35, + "y": 37.88, + "speed": 43.48, + "time": 2.74, + "theta": 90, + "omega": 0, + "vx": -9.6, + "vy": 42.41, + "splineNum": 5 + }, + { + "x": 1.07, + "y": 39.43, + "speed": 39.71, + "time": 2.78, + "theta": 90, + "omega": 0, + "vx": -7.08, + "vy": 39.08, + "splineNum": 5 + }, + { + "x": 0.86, + "y": 40.98, + "speed": 35.56, + "time": 2.82, + "theta": 90, + "omega": 0, + "vx": -4.93, + "vy": 35.21, + "splineNum": 5 + }, + { + "x": 0.7, + "y": 42.53, + "speed": 30.85, + "time": 2.87, + "theta": 90, + "omega": 0, + "vx": -3.14, + "vy": 30.69, + "splineNum": 5 + }, + { + "x": 0.59, + "y": 44.09, + "speed": 25.27, + "time": 2.93, + "theta": 90, + "omega": 0, + "vx": -1.73, + "vy": 25.21, + "splineNum": 5 + }, + { + "x": 0.53, + "y": 45.66, + "speed": 18.03, + "time": 3.02, + "theta": 90, + "omega": 0, + "vx": -0.7, + "vy": 18.02, + "splineNum": 5 + }, + { + "x": 0.51, + "y": 47.23, + "speed": 3.3, + "time": 3.5, + "theta": 90, + "omega": 0, + "vx": -0.04, + "vy": 3.3, + "splineNum": 5 + }, + { + "x": 0.51, + "y": 47.23, + "speed": 3.3, + "time": 3.5, + "theta": 90, + "omega": 0, + "vx": -3.3, + "vy": 0, + "splineNum": 5 + }, + { + "x": 0.49, + "y": 49.19, + "speed": 20.07, + "time": 3.59, + "theta": 90, + "omega": 0, + "vx": -0.16, + "vy": 20.07, + "splineNum": 6 + }, + { + "x": 0.46, + "y": 51.15, + "speed": 28.19, + "time": 3.66, + "theta": 90, + "omega": 0, + "vx": -0.56, + "vy": 28.18, + "splineNum": 6 + }, + { + "x": 0.4, + "y": 53.11, + "speed": 34.44, + "time": 3.72, + "theta": 90, + "omega": 0, + "vx": -0.93, + "vy": 34.43, + "splineNum": 6 + }, + { + "x": 0.35, + "y": 55.06, + "speed": 39.73, + "time": 3.77, + "theta": 90, + "omega": 0, + "vx": -1.17, + "vy": 39.71, + "splineNum": 6 + }, + { + "x": 0.29, + "y": 57.02, + "speed": 44.38, + "time": 3.81, + "theta": 90, + "omega": 0, + "vx": -1.19, + "vy": 44.37, + "splineNum": 6 + }, + { + "x": 0.25, + "y": 58.98, + "speed": 46.34, + "time": 3.86, + "theta": 90, + "omega": 0, + "vx": -0.91, + "vy": 46.33, + "splineNum": 6 + }, + { + "x": 0.24, + "y": 60.94, + "speed": 41.9, + "time": 3.9, + "theta": 90, + "omega": 0, + "vx": -0.31, + "vy": 41.9, + "splineNum": 6 + } + ] + }, + { + "name": "DeployWall2ToGoal4", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "DeployWall2", + "omega": 0, + "angle": -90, + "spline_angle": 90, + "x": -16.89, + "y": 13.66, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -90, + "spline_angle": 179.94, + "x": -8.66, + "y": 23.1, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -16.89, + "y": 13.66, + "speed": 41.24, + "time": 0, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -16.77, + "y": 15.93, + "speed": 35.3, + "time": 0.06, + "theta": -90, + "omega": 0, + "vx": 1.9, + "vy": 35.25, + "splineNum": 0 + }, + { + "x": -16.37, + "y": 17.95, + "speed": 28.87, + "time": 0.14, + "theta": -90, + "omega": 0, + "vx": 5.55, + "vy": 28.33, + "splineNum": 0 + }, + { + "x": -15.65, + "y": 19.7, + "speed": 21.34, + "time": 0.22, + "theta": -90, + "omega": 0, + "vx": 8.1, + "vy": 19.74, + "splineNum": 0 + }, + { + "x": -14.57, + "y": 21.13, + "speed": 18.15, + "time": 0.32, + "theta": -90, + "omega": 0, + "vx": 10.97, + "vy": 14.46, + "splineNum": 0 + }, + { + "x": -13.07, + "y": 22.2, + "speed": 20.25, + "time": 0.41, + "theta": -90, + "omega": 0, + "vx": 16.48, + "vy": 11.77, + "splineNum": 0 + }, + { + "x": -11.12, + "y": 22.87, + "speed": 28.69, + "time": 0.49, + "theta": -90, + "omega": 0, + "vx": 27.14, + "vy": 9.3, + "splineNum": 0 + }, + { + "x": -8.66, + "y": 23.1, + "speed": 36.29, + "time": 0.55, + "theta": -90, + "omega": 0, + "vx": 36.13, + "vy": 3.38, + "splineNum": 0 + }, + { + "x": -8.66, + "y": 23.1, + "speed": 36.29, + "time": 0.55, + "theta": -90, + "omega": 0, + "vx": 36.29, + "vy": 0, + "splineNum": 0 + }, + { + "x": -5.93, + "y": 22.82, + "speed": 28.43, + "time": 0.65, + "theta": -90, + "omega": 0, + "vx": 28.28, + "vy": -2.94, + "splineNum": 1 + }, + { + "x": -3.85, + "y": 22.02, + "speed": 19.64, + "time": 0.76, + "theta": -90, + "omega": 0, + "vx": 18.34, + "vy": -7.05, + "splineNum": 1 + }, + { + "x": -2.33, + "y": 20.76, + "speed": 18.59, + "time": 0.87, + "theta": -90, + "omega": 0, + "vx": 14.35, + "vy": -11.82, + "splineNum": 1 + }, + { + "x": -1.29, + "y": 19.13, + "speed": 24.09, + "time": 0.95, + "theta": -90, + "omega": 0, + "vx": 12.9, + "vy": -20.34, + "splineNum": 1 + }, + { + "x": -0.65, + "y": 17.17, + "speed": 31.49, + "time": 1.02, + "theta": -90, + "omega": 0, + "vx": 9.78, + "vy": -29.93, + "splineNum": 1 + }, + { + "x": -0.33, + "y": 14.97, + "speed": 37.92, + "time": 1.07, + "theta": -90, + "omega": 0, + "vx": 5.48, + "vy": -37.52, + "splineNum": 1 + }, + { + "x": -0.24, + "y": 12.57, + "speed": 35.42, + "time": 1.14, + "theta": -90, + "omega": 0, + "vx": 1.31, + "vy": -35.39, + "splineNum": 1 + }, + { + "x": -0.24, + "y": 12.57, + "speed": 35.42, + "time": 1.14, + "theta": -90, + "omega": 0, + "vx": -8, + "vy": -24, + "splineNum": 1 + } + ] + }, + { + "name": "V2-Goal4ToGoal1", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -102.53, + "spline_angle": 90, + "x": -1.35, + "y": 24.18, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -75, + "spline_angle": -142.88, + "x": -10.1, + "y": 28.32, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": 14.05, + "x": -24.23, + "y": 19.12, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": 160.88, + "x": -43.85, + "y": 21.97, + "shared": false, + "speed": 40 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": -177.9, + "x": -62.97, + "y": 34.21, + "shared": false, + "speed": 5 + }, + { + "name": "wp", + "omega": 0, + "angle": -135, + "spline_angle": 79.17, + "x": -54.08, + "y": 15.6, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -135, + "spline_angle": 59.02, + "x": -60.96, + "y": 6.88, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": -0.24, + "y": 12.57, + "speed": 41.9, + "time": 0, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -0.3, + "y": 14.24, + "speed": 45.14, + "time": 0.04, + "theta": -90.05, + "omega": -2.59, + "vx": -1.65, + "vy": 45.11, + "splineNum": 0 + }, + { + "x": -0.46, + "y": 15.9, + "speed": 41.28, + "time": 0.08, + "theta": -90.21, + "omega": -5.42, + "vx": -3.93, + "vy": 41.1, + "splineNum": 0 + }, + { + "x": -0.68, + "y": 17.55, + "speed": 37.03, + "time": 0.12, + "theta": -90.52, + "omega": -8.57, + "vx": -4.82, + "vy": 36.71, + "splineNum": 0 + }, + { + "x": -0.91, + "y": 19.2, + "speed": 32.21, + "time": 0.17, + "theta": -91.06, + "omega": -12.2, + "vx": -4.56, + "vy": 31.88, + "splineNum": 0 + }, + { + "x": -1.13, + "y": 20.85, + "speed": 26.53, + "time": 0.24, + "theta": -91.97, + "omega": -16.61, + "vx": -3.45, + "vy": 26.31, + "splineNum": 0 + }, + { + "x": -1.29, + "y": 22.51, + "speed": 19.26, + "time": 0.32, + "theta": -93.67, + "omega": -61.14, + "vx": -1.83, + "vy": 19.17, + "splineNum": 0 + }, + { + "x": -1.35, + "y": 24.18, + "speed": 6.08, + "time": 0.6, + "theta": -102.53, + "omega": -41.91, + "vx": -0.22, + "vy": 6.08, + "splineNum": 0 + }, + { + "x": -1.35, + "y": 24.18, + "speed": 6.08, + "time": 0.6, + "theta": -102.53, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": -1.54, + "y": 27.01, + "speed": 24.56, + "time": 0.71, + "theta": -102.03, + "omega": 8.68, + "vx": -1.67, + "vy": 24.51, + "splineNum": 1 + }, + { + "x": -2.11, + "y": 29.04, + "speed": 15.38, + "time": 0.85, + "theta": -100.13, + "omega": 19.01, + "vx": -4.15, + "vy": 14.81, + "splineNum": 1 + }, + { + "x": -3.04, + "y": 30.3, + "speed": 8.27, + "time": 1.04, + "theta": -95.16, + "omega": 95.47, + "vx": -4.9, + "vy": 6.66, + "splineNum": 1 + }, + { + "x": -4.32, + "y": 30.83, + "speed": 9.1, + "time": 1.19, + "theta": -89.22, + "omega": 84.01, + "vx": -8.4, + "vy": 3.49, + "splineNum": 1 + }, + { + "x": -5.93, + "y": 30.66, + "speed": 18.33, + "time": 1.28, + "theta": -84.96, + "omega": 77.35, + "vx": -18.23, + "vy": -1.96, + "splineNum": 1 + }, + { + "x": -7.86, + "y": 29.81, + "speed": 27.53, + "time": 1.36, + "theta": -80.8, + "omega": 71.58, + "vx": -25.21, + "vy": -11.07, + "splineNum": 1 + }, + { + "x": -10.1, + "y": 28.32, + "speed": 28.18, + "time": 1.45, + "theta": -75, + "omega": 64.39, + "vx": -23.44, + "vy": -15.64, + "splineNum": 1 + }, + { + "x": -10.1, + "y": 28.32, + "speed": 28.18, + "time": 1.45, + "theta": -75, + "omega": 64.39, + "vx": -28.18, + "vy": 0, + "splineNum": 1 + }, + { + "x": -11.99, + "y": 26.82, + "speed": 35.75, + "time": 1.52, + "theta": -76.5, + "omega": -44.24, + "vx": -27.99, + "vy": -22.23, + "splineNum": 2 + }, + { + "x": -13.86, + "y": 25.26, + "speed": 41.99, + "time": 1.58, + "theta": -80.14, + "omega": -82, + "vx": -32.24, + "vy": -26.9, + "splineNum": 2 + }, + { + "x": -15.73, + "y": 23.73, + "speed": 46.5, + "time": 1.63, + "theta": -85.3, + "omega": -116.06, + "vx": -35.97, + "vy": -29.47, + "splineNum": 2 + }, + { + "x": -17.66, + "y": 22.28, + "speed": 40.98, + "time": 1.69, + "theta": -93.27, + "omega": -154.57, + "vx": -32.77, + "vy": -24.61, + "splineNum": 2 + }, + { + "x": -19.69, + "y": 20.98, + "speed": 34.61, + "time": 1.76, + "theta": -105.61, + "omega": -540.94, + "vx": -29.17, + "vy": -18.62, + "splineNum": 2 + }, + { + "x": -21.87, + "y": 19.91, + "speed": 26.7, + "time": 1.85, + "theta": -126.49, + "omega": -481.55, + "vx": -23.94, + "vy": -11.83, + "splineNum": 2 + }, + { + "x": -24.23, + "y": 19.12, + "speed": 14.66, + "time": 2.02, + "theta": -180, + "omega": -370.5, + "vx": -13.91, + "vy": -4.62, + "splineNum": 2 + }, + { + "x": -24.23, + "y": 19.12, + "speed": 14.66, + "time": 2.02, + "theta": -180, + "omega": -370.5, + "vx": -16, + "vy": 0, + "splineNum": 2 + }, + { + "x": -27.17, + "y": 18.62, + "speed": 28.47, + "time": 2.12, + "theta": 180, + "omega": 0, + "vx": -28.06, + "vy": -4.82, + "splineNum": 3 + }, + { + "x": -30.04, + "y": 18.54, + "speed": 37.22, + "time": 2.2, + "theta": 180, + "omega": 0, + "vx": -37.21, + "vy": -0.97, + "splineNum": 3 + }, + { + "x": -32.86, + "y": 18.82, + "speed": 44.18, + "time": 2.27, + "theta": 180, + "omega": 0, + "vx": -43.97, + "vy": 4.34, + "splineNum": 3 + }, + { + "x": -35.64, + "y": 19.38, + "speed": 46.38, + "time": 2.33, + "theta": 180, + "omega": 0, + "vx": -45.48, + "vy": 9.11, + "splineNum": 3 + }, + { + "x": -38.39, + "y": 20.14, + "speed": 39.75, + "time": 2.4, + "theta": 180, + "omega": 0, + "vx": -38.31, + "vy": 10.59, + "splineNum": 3 + }, + { + "x": -41.12, + "y": 21.03, + "speed": 31.71, + "time": 2.49, + "theta": 180, + "omega": 0, + "vx": -30.15, + "vy": 9.81, + "splineNum": 3 + }, + { + "x": -43.85, + "y": 21.97, + "speed": 20.71, + "time": 2.63, + "theta": 180, + "omega": 0, + "vx": -19.57, + "vy": 6.77, + "splineNum": 3 + }, + { + "x": -43.85, + "y": 21.97, + "speed": 20.71, + "time": 2.63, + "theta": 180, + "omega": 0, + "vx": -20.71, + "vy": 0, + "splineNum": 3 + }, + { + "x": -46.74, + "y": 23.47, + "speed": 32.87, + "time": 2.73, + "theta": 180, + "omega": 0, + "vx": -29.18, + "vy": 15.12, + "splineNum": 4 + }, + { + "x": -49.25, + "y": 25.57, + "speed": 41.64, + "time": 2.81, + "theta": 180, + "omega": 0, + "vx": -31.9, + "vy": 26.77, + "splineNum": 4 + }, + { + "x": -51.57, + "y": 27.96, + "speed": 49, + "time": 2.87, + "theta": 180, + "omega": 0, + "vx": -34.09, + "vy": 35.19, + "splineNum": 4 + }, + { + "x": -53.9, + "y": 30.34, + "speed": 45.29, + "time": 2.95, + "theta": 180, + "omega": 0, + "vx": -31.74, + "vy": 32.3, + "splineNum": 4 + }, + { + "x": -56.44, + "y": 32.38, + "speed": 37.4, + "time": 3.04, + "theta": 180, + "omega": 0, + "vx": -29.18, + "vy": 23.39, + "splineNum": 4 + }, + { + "x": -59.4, + "y": 33.77, + "speed": 27.28, + "time": 3.15, + "theta": 180, + "omega": 0, + "vx": -24.68, + "vy": 11.64, + "splineNum": 4 + }, + { + "x": -62.97, + "y": 34.21, + "speed": 5, + "time": 3.87, + "theta": 180, + "omega": 0, + "vx": -4.96, + "vy": 0.61, + "splineNum": 4 + }, + { + "x": -62.97, + "y": 34.21, + "speed": 5, + "time": 3.87, + "theta": 180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 5 + }, + { + "x": -59.14, + "y": 34.14, + "speed": 28.14, + "time": 4.01, + "theta": 180.81, + "omega": 11.9, + "vx": 28.14, + "vy": -0.54, + "splineNum": 5 + }, + { + "x": -56.2, + "y": 33.63, + "speed": 29.61, + "time": 4.11, + "theta": 182.45, + "omega": 20.68, + "vx": 29.18, + "vy": -5.01, + "splineNum": 5 + }, + { + "x": -54.07, + "y": 32.75, + "speed": 20.36, + "time": 4.22, + "theta": 185.36, + "omega": 30.59, + "vx": 18.8, + "vy": -7.8, + "splineNum": 5 + }, + { + "x": -52.63, + "y": 31.53, + "speed": 15.2, + "time": 4.35, + "theta": 189.82, + "omega": 41.41, + "vx": 11.59, + "vy": -9.83, + "splineNum": 5 + }, + { + "x": -51.79, + "y": 30.03, + "speed": 16.79, + "time": 4.45, + "theta": 194.53, + "omega": 126.94, + "vx": 8.19, + "vy": -14.65, + "splineNum": 5 + }, + { + "x": -51.45, + "y": 28.29, + "speed": 25.2, + "time": 4.52, + "theta": 198.29, + "omega": 120.79, + "vx": 4.91, + "vy": -24.71, + "splineNum": 5 + }, + { + "x": -51.49, + "y": 26.36, + "speed": 31.94, + "time": 4.58, + "theta": 201.86, + "omega": 115.52, + "vx": -0.79, + "vy": -31.93, + "splineNum": 5 + }, + { + "x": -51.83, + "y": 24.29, + "speed": 37.94, + "time": 4.64, + "theta": 205.41, + "omega": 110.7, + "vx": -6.15, + "vy": -37.44, + "splineNum": 5 + }, + { + "x": -52.36, + "y": 22.13, + "speed": 43.4, + "time": 4.69, + "theta": 208.93, + "omega": 106.22, + "vx": -10.35, + "vy": -42.15, + "splineNum": 5 + }, + { + "x": -52.98, + "y": 19.93, + "speed": 40.72, + "time": 4.74, + "theta": 213.06, + "omega": 101.32, + "vx": -11.03, + "vy": -39.2, + "splineNum": 5 + }, + { + "x": -53.59, + "y": 17.74, + "speed": 34.69, + "time": 4.81, + "theta": 218.23, + "omega": 95.59, + "vx": -9.24, + "vy": -33.43, + "splineNum": 5 + }, + { + "x": -54.08, + "y": 15.6, + "speed": 27.64, + "time": 4.89, + "theta": 225, + "omega": 88.65, + "vx": -6.19, + "vy": -26.94, + "splineNum": 5 + }, + { + "x": -54.61, + "y": 13.99, + "speed": 20.64, + "time": 4.97, + "theta": -135, + "omega": 0, + "vx": -6.44, + "vy": -19.61, + "splineNum": 6 + }, + { + "x": -55.45, + "y": 12.64, + "speed": 27.3, + "time": 5.03, + "theta": -135, + "omega": 0, + "vx": -14.42, + "vy": -23.18, + "splineNum": 6 + }, + { + "x": -56.51, + "y": 11.46, + "speed": 32.61, + "time": 5.08, + "theta": -135, + "omega": 0, + "vx": -21.77, + "vy": -24.28, + "splineNum": 6 + }, + { + "x": -57.69, + "y": 10.37, + "speed": 37.21, + "time": 5.12, + "theta": -135, + "omega": 0, + "vx": -27.34, + "vy": -25.24, + "splineNum": 6 + }, + { + "x": -58.89, + "y": 9.29, + "speed": 38.16, + "time": 5.16, + "theta": -135, + "omega": 0, + "vx": -28.44, + "vy": -25.44, + "splineNum": 6 + }, + { + "x": -60.02, + "y": 8.16, + "speed": 33.72, + "time": 5.21, + "theta": -135, + "omega": 0, + "vx": -23.7, + "vy": -23.99, + "splineNum": 6 + }, + { + "x": -60.96, + "y": 6.88, + "speed": 38.14, + "time": 5.25, + "theta": -135, + "omega": 0, + "vx": -22.7, + "vy": -30.64, + "splineNum": 6 + } + ] + }, + { + "name": "V2-Goal1ToGoal2", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": -135, + "spline_angle": 37.87, + "x": -60.96, + "y": 9.73, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": 0, + "angle": -165, + "spline_angle": 43.29, + "x": -38.9, + "y": 31.34, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 67.84, + "spline_angle": 68.3, + "x": -25.7, + "y": 55.53, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 89.95, + "spline_angle": 84.05, + "x": -23.47, + "y": 83.21, + "shared": false, + "speed": 5 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": -176.28, + "x": -37.31, + "y": 67.58, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": 3.51, + "x": -60.12, + "y": 69.09, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": -60.96, + "y": 9.73, + "speed": 0, + "time": 0, + "theta": -135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -57.97, + "y": 12.2, + "speed": 27.84, + "time": 0.14, + "theta": -136.13, + "omega": -16.21, + "vx": 21.47, + "vy": 17.71, + "splineNum": 0 + }, + { + "x": -55.12, + "y": 14.8, + "speed": 39.34, + "time": 0.24, + "theta": -138.28, + "omega": -27.64, + "vx": 29.07, + "vy": 26.5, + "splineNum": 0 + }, + { + "x": -52.36, + "y": 17.5, + "speed": 48.16, + "time": 0.32, + "theta": -140.87, + "omega": -36.97, + "vx": 34.37, + "vy": 33.74, + "splineNum": 0 + }, + { + "x": -49.67, + "y": 20.27, + "speed": 50, + "time": 0.39, + "theta": -144.07, + "omega": -121.21, + "vx": 34.81, + "vy": 35.89, + "splineNum": 0 + }, + { + "x": -47.02, + "y": 23.08, + "speed": 50, + "time": 0.47, + "theta": -147.97, + "omega": -112.21, + "vx": 34.39, + "vy": 36.3, + "splineNum": 0 + }, + { + "x": -44.36, + "y": 25.88, + "speed": 50, + "time": 0.55, + "theta": -152.57, + "omega": -103.21, + "vx": 34.41, + "vy": 36.28, + "splineNum": 0 + }, + { + "x": -41.66, + "y": 28.65, + "speed": 50, + "time": 0.63, + "theta": -157.85, + "omega": -94.22, + "vx": 34.89, + "vy": 35.82, + "splineNum": 0 + }, + { + "x": -38.9, + "y": 31.34, + "speed": 42.26, + "time": 0.72, + "theta": -165, + "omega": -83.59, + "vx": 30.26, + "vy": 29.5, + "splineNum": 0 + }, + { + "x": -36.45, + "y": 33.93, + "speed": 49.99, + "time": 0.79, + "theta": -167.09, + "omega": -58.59, + "vx": 34.33, + "vy": 36.33, + "splineNum": 1 + }, + { + "x": -34.35, + "y": 36.71, + "speed": 50, + "time": 0.86, + "theta": -173.16, + "omega": -115.86, + "vx": 30.18, + "vy": 39.86, + "splineNum": 1 + }, + { + "x": -32.53, + "y": 39.64, + "speed": 50, + "time": 0.93, + "theta": -183.11, + "omega": -172.58, + "vx": 26.33, + "vy": 42.51, + "splineNum": 1 + }, + { + "x": -30.95, + "y": 42.7, + "speed": 50, + "time": 1, + "theta": -196.96, + "omega": -685.29, + "vx": 23.06, + "vy": 44.36, + "splineNum": 1 + }, + { + "x": -29.53, + "y": 45.85, + "speed": 50, + "time": 1.07, + "theta": -214.76, + "omega": -628.48, + "vx": 20.55, + "vy": 45.58, + "splineNum": 1 + }, + { + "x": -28.22, + "y": 49.06, + "speed": 50, + "time": 1.14, + "theta": -236.56, + "omega": -571.48, + "vx": 18.88, + "vy": 46.3, + "splineNum": 1 + }, + { + "x": -26.96, + "y": 52.29, + "speed": 50, + "time": 1.2, + "theta": -262.38, + "omega": -514.37, + "vx": 18.07, + "vy": 46.62, + "splineNum": 1 + }, + { + "x": -25.7, + "y": 55.53, + "speed": 50, + "time": 1.27, + "theta": -292.16, + "omega": -457.26, + "vx": 18.15, + "vy": 46.59, + "splineNum": 1 + }, + { + "x": -24.62, + "y": 58.93, + "speed": 50, + "time": 1.35, + "theta": 67.91, + "omega": 1.95, + "vx": 15.21, + "vy": 47.63, + "splineNum": 2 + }, + { + "x": -23.98, + "y": 62.36, + "speed": 50, + "time": 1.42, + "theta": 68.11, + "omega": 3.85, + "vx": 9.16, + "vy": 49.15, + "splineNum": 2 + }, + { + "x": -23.67, + "y": 65.81, + "speed": 50, + "time": 1.48, + "theta": 68.44, + "omega": 5.75, + "vx": 4.35, + "vy": 49.81, + "splineNum": 2 + }, + { + "x": -23.6, + "y": 69.29, + "speed": 50, + "time": 1.55, + "theta": 68.91, + "omega": 7.65, + "vx": 1.03, + "vy": 49.99, + "splineNum": 2 + }, + { + "x": -23.65, + "y": 72.78, + "speed": 45.97, + "time": 1.63, + "theta": 69.57, + "omega": 9.72, + "vx": -0.67, + "vy": 45.96, + "splineNum": 2 + }, + { + "x": -23.72, + "y": 76.27, + "speed": 37.62, + "time": 1.72, + "theta": 70.59, + "omega": 12.25, + "vx": -0.72, + "vy": 37.62, + "splineNum": 2 + }, + { + "x": -23.69, + "y": 79.75, + "speed": 26.82, + "time": 1.85, + "theta": 72.41, + "omega": 15.79, + "vx": 0.19, + "vy": 26.82, + "splineNum": 2 + }, + { + "x": -23.47, + "y": 83.21, + "speed": 5, + "time": 2.55, + "theta": 89.95, + "omega": 34.74, + "vx": 0.32, + "vy": 4.99, + "splineNum": 2 + }, + { + "x": -24, + "y": 79.7, + "speed": 27.12, + "time": 2.68, + "theta": 94.05, + "omega": 62.55, + "vx": -4.07, + "vy": -26.81, + "splineNum": 3 + }, + { + "x": -24.89, + "y": 76.5, + "speed": 37.4, + "time": 2.77, + "theta": 101.47, + "omega": 104.91, + "vx": -10.01, + "vy": -36.04, + "splineNum": 3 + }, + { + "x": -26.21, + "y": 73.69, + "speed": 41.87, + "time": 2.84, + "theta": 110.58, + "omega": 140.37, + "vx": -17.77, + "vy": -37.91, + "splineNum": 3 + }, + { + "x": -28.04, + "y": 71.32, + "speed": 35.1, + "time": 2.93, + "theta": 124.27, + "omega": 405.49, + "vx": -21.44, + "vy": -27.79, + "splineNum": 3 + }, + { + "x": -30.44, + "y": 69.47, + "speed": 36.36, + "time": 3.01, + "theta": 141.06, + "omega": 365.59, + "vx": -28.83, + "vy": -22.16, + "splineNum": 3 + }, + { + "x": -33.51, + "y": 68.2, + "speed": 44.56, + "time": 3.08, + "theta": 158.84, + "omega": 330.03, + "vx": -41.17, + "vy": -17.04, + "splineNum": 3 + }, + { + "x": -37.31, + "y": 67.58, + "speed": 50, + "time": 3.16, + "theta": 180, + "omega": 293.26, + "vx": -49.35, + "vy": -8.05, + "splineNum": 3 + }, + { + "x": -37.31, + "y": 67.58, + "speed": 50, + "time": 3.16, + "theta": 180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 4 + }, + { + "x": -40.59, + "y": 67.53, + "speed": 50, + "time": 3.23, + "theta": 180, + "omega": 0, + "vx": -49.99, + "vy": -0.74, + "splineNum": 4 + }, + { + "x": -43.84, + "y": 67.74, + "speed": 50, + "time": 3.29, + "theta": 180, + "omega": 0, + "vx": -49.89, + "vy": 3.25, + "splineNum": 4 + }, + { + "x": -47.09, + "y": 68.11, + "speed": 50, + "time": 3.36, + "theta": 180, + "omega": 0, + "vx": -49.68, + "vy": 5.65, + "splineNum": 4 + }, + { + "x": -50.34, + "y": 68.54, + "speed": 50, + "time": 3.42, + "theta": 180, + "omega": 0, + "vx": -49.58, + "vy": 6.46, + "splineNum": 4 + }, + { + "x": -53.59, + "y": 68.91, + "speed": 50, + "time": 3.49, + "theta": 180, + "omega": 0, + "vx": -49.67, + "vy": 5.7, + "splineNum": 4 + }, + { + "x": -56.84, + "y": 69.13, + "speed": 50, + "time": 3.55, + "theta": 180, + "omega": 0, + "vx": -49.89, + "vy": 3.36, + "splineNum": 4 + }, + { + "x": -60.12, + "y": 69.09, + "speed": 50, + "time": 3.62, + "theta": 180, + "omega": 0, + "vx": -50, + "vy": -0.58, + "splineNum": 4 + } + ] + }, + { + "name": "V2-Goal2ToGoal3", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": 180, + "spline_angle": 0, + "x": -57.77, + "y": 71.44, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": 0, + "angle": -137.41, + "spline_angle": 0, + "x": -45.36, + "y": 71.27, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -179.04, + "spline_angle": 99.9, + "x": -36.64, + "y": 86.53, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 90.07, + "x": -38.65, + "y": 106.65, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 90.02, + "x": -37.98, + "y": 124.76, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": -157.65, + "x": -52.91, + "y": 104.3, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": 4.39, + "x": -69.93, + "y": 102.94, + "shared": false, + "speed": 10 + }, + { + "name": "wp", + "omega": 0, + "angle": 135, + "spline_angle": 114.75, + "x": -55.29, + "y": 119.33, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 135, + "spline_angle": 139.34, + "x": -65.99, + "y": 131.13, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": -57.77, + "y": 71.44, + "speed": 0, + "time": 0, + "theta": 180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -56, + "y": 71.43, + "speed": 18.83, + "time": 0.09, + "theta": 182.56, + "omega": 54.28, + "vx": 18.83, + "vy": -0.1, + "splineNum": 0 + }, + { + "x": -54.22, + "y": 71.41, + "speed": 26.63, + "time": 0.16, + "theta": 187.45, + "omega": 92.66, + "vx": 26.63, + "vy": -0.36, + "splineNum": 0 + }, + { + "x": -52.45, + "y": 71.37, + "speed": 32.62, + "time": 0.22, + "theta": 193.34, + "omega": 319.2, + "vx": 32.61, + "vy": -0.61, + "splineNum": 0 + }, + { + "x": -50.68, + "y": 71.34, + "speed": 37.66, + "time": 0.26, + "theta": 199.81, + "omega": 292.06, + "vx": 37.65, + "vy": -0.77, + "splineNum": 0 + }, + { + "x": -48.91, + "y": 71.3, + "speed": 42.11, + "time": 0.3, + "theta": 206.69, + "omega": 267.78, + "vx": 42.1, + "vy": -0.79, + "splineNum": 0 + }, + { + "x": -47.13, + "y": 71.28, + "speed": 46.13, + "time": 0.34, + "theta": 213.86, + "omega": 245.62, + "vx": 46.12, + "vy": -0.63, + "splineNum": 0 + }, + { + "x": -45.36, + "y": 71.27, + "speed": 42.55, + "time": 0.38, + "theta": 222.59, + "omega": 221.6, + "vx": 42.55, + "vy": -0.23, + "splineNum": 0 + }, + { + "x": -45.36, + "y": 71.27, + "speed": 42.55, + "time": 0.38, + "theta": -137.41, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": -41.54, + "y": 71.62, + "speed": 32.31, + "time": 0.5, + "theta": -138.47, + "omega": -17.8, + "vx": 32.17, + "vy": 2.93, + "splineNum": 1 + }, + { + "x": -38.83, + "y": 72.6, + "speed": 21.62, + "time": 0.64, + "theta": -142.17, + "omega": -37.79, + "vx": 20.32, + "vy": 7.37, + "splineNum": 1 + }, + { + "x": -37.07, + "y": 74.12, + "speed": 17.32, + "time": 0.77, + "theta": -148.61, + "omega": -165.51, + "vx": 13.12, + "vy": 11.31, + "splineNum": 1 + }, + { + "x": -36.08, + "y": 76.09, + "speed": 22.39, + "time": 0.87, + "theta": -155.03, + "omega": -150.77, + "vx": 10.03, + "vy": 20.02, + "splineNum": 1 + }, + { + "x": -35.71, + "y": 78.41, + "speed": 31.16, + "time": 0.94, + "theta": -160.93, + "omega": -139.47, + "vx": 4.92, + "vy": 30.77, + "splineNum": 1 + }, + { + "x": -35.79, + "y": 80.98, + "speed": 38.55, + "time": 1.01, + "theta": -166.88, + "omega": -129.45, + "vx": -1.19, + "vy": 38.53, + "splineNum": 1 + }, + { + "x": -36.15, + "y": 83.72, + "speed": 45.15, + "time": 1.07, + "theta": -172.92, + "omega": -120.28, + "vx": -5.96, + "vy": 44.76, + "splineNum": 1 + }, + { + "x": -36.64, + "y": 86.53, + "speed": 50, + "time": 1.13, + "theta": -179.04, + "omega": -111.73, + "vx": -8.51, + "vy": 49.27, + "splineNum": 1 + }, + { + "x": -37.12, + "y": 89.39, + "speed": 50, + "time": 1.19, + "theta": -180.9, + "omega": -64.25, + "vx": -8.23, + "vy": 49.32, + "splineNum": 2 + }, + { + "x": -37.55, + "y": 92.25, + "speed": 50, + "time": 1.25, + "theta": -186.47, + "omega": -128.43, + "vx": -7.41, + "vy": 49.45, + "splineNum": 2 + }, + { + "x": -37.92, + "y": 95.11, + "speed": 50, + "time": 1.3, + "theta": -195.75, + "omega": -192.57, + "vx": -6.42, + "vy": 49.59, + "splineNum": 2 + }, + { + "x": -38.22, + "y": 97.98, + "speed": 50, + "time": 1.36, + "theta": -208.73, + "omega": -641.92, + "vx": -5.28, + "vy": 49.72, + "splineNum": 2 + }, + { + "x": -38.45, + "y": 100.86, + "speed": 50, + "time": 1.42, + "theta": -225.41, + "omega": -577.8, + "vx": -3.98, + "vy": 49.84, + "splineNum": 2 + }, + { + "x": -38.6, + "y": 103.75, + "speed": 50, + "time": 1.48, + "theta": -245.82, + "omega": -513.62, + "vx": -2.52, + "vy": 49.94, + "splineNum": 2 + }, + { + "x": -38.65, + "y": 106.65, + "speed": 50, + "time": 1.53, + "theta": -270, + "omega": -449.3, + "vx": -0.91, + "vy": 49.99, + "splineNum": 2 + }, + { + "x": -38.65, + "y": 106.65, + "speed": 50, + "time": 1.53, + "theta": -270, + "omega": -449.3, + "vx": -50, + "vy": 0, + "splineNum": 2 + }, + { + "x": -38.62, + "y": 109.24, + "speed": 50, + "time": 1.59, + "theta": 90, + "omega": 0, + "vx": 0.67, + "vy": 50, + "splineNum": 3 + }, + { + "x": -38.52, + "y": 111.83, + "speed": 50, + "time": 1.64, + "theta": 90, + "omega": 0, + "vx": 1.84, + "vy": 49.97, + "splineNum": 3 + }, + { + "x": -38.39, + "y": 114.41, + "speed": 45.86, + "time": 1.69, + "theta": 90, + "omega": 0, + "vx": 2.33, + "vy": 45.8, + "splineNum": 3 + }, + { + "x": -38.25, + "y": 117, + "speed": 39.81, + "time": 1.76, + "theta": 90, + "omega": 0, + "vx": 2.21, + "vy": 39.75, + "splineNum": 3 + }, + { + "x": -38.11, + "y": 119.58, + "speed": 32.67, + "time": 1.84, + "theta": 90, + "omega": 0, + "vx": 1.66, + "vy": 32.63, + "splineNum": 3 + }, + { + "x": -38.02, + "y": 122.17, + "speed": 23.44, + "time": 1.95, + "theta": 90, + "omega": 0, + "vx": 0.87, + "vy": 23.42, + "splineNum": 3 + }, + { + "x": -37.98, + "y": 124.76, + "speed": 5.62, + "time": 2.41, + "theta": 90, + "omega": 0, + "vx": 0.08, + "vy": 5.62, + "splineNum": 3 + }, + { + "x": -37.98, + "y": 124.76, + "speed": 5.62, + "time": 2.41, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 5.33, + "splineNum": 3 + }, + { + "x": -38.24, + "y": 121.03, + "speed": 27.9, + "time": 2.54, + "theta": 94.09, + "omega": 61.12, + "vx": -1.98, + "vy": -27.83, + "splineNum": 4 + }, + { + "x": -39.02, + "y": 117.68, + "speed": 38.3, + "time": 2.63, + "theta": 101.42, + "omega": 102.14, + "vx": -8.66, + "vy": -37.31, + "splineNum": 4 + }, + { + "x": -40.29, + "y": 114.69, + "speed": 46.01, + "time": 2.7, + "theta": 109.79, + "omega": 134.41, + "vx": -17.88, + "vy": -42.4, + "splineNum": 4 + }, + { + "x": -42.01, + "y": 112.02, + "speed": 50, + "time": 2.77, + "theta": 119.23, + "omega": 409.98, + "vx": -27.14, + "vy": -41.99, + "splineNum": 4 + }, + { + "x": -44.16, + "y": 109.67, + "speed": 50, + "time": 2.83, + "theta": 130.56, + "omega": 380.89, + "vx": -33.76, + "vy": -36.88, + "splineNum": 4 + }, + { + "x": -46.71, + "y": 107.62, + "speed": 50, + "time": 2.9, + "theta": 144.16, + "omega": 350.96, + "vx": -38.93, + "vy": -31.37, + "splineNum": 4 + }, + { + "x": -49.64, + "y": 105.83, + "speed": 50, + "time": 2.97, + "theta": 160.48, + "omega": 319.67, + "vx": -42.69, + "vy": -26.03, + "splineNum": 4 + }, + { + "x": -52.91, + "y": 104.3, + "speed": 50, + "time": 3.04, + "theta": 180, + "omega": 286.68, + "vx": -45.28, + "vy": -21.2, + "splineNum": 4 + }, + { + "x": -55.3, + "y": 103.53, + "speed": 50, + "time": 3.09, + "theta": 180, + "omega": 0, + "vx": -47.59, + "vy": -15.32, + "splineNum": 5 + }, + { + "x": -57.71, + "y": 103.11, + "speed": 50, + "time": 3.14, + "theta": 180, + "omega": 0, + "vx": -49.26, + "vy": -8.56, + "splineNum": 5 + }, + { + "x": -60.14, + "y": 102.95, + "speed": 45.36, + "time": 3.19, + "theta": 180, + "omega": 0, + "vx": -45.26, + "vy": -3.07, + "splineNum": 5 + }, + { + "x": -62.59, + "y": 102.94, + "speed": 39.61, + "time": 3.25, + "theta": 180, + "omega": 0, + "vx": -39.61, + "vy": -0.08, + "splineNum": 5 + }, + { + "x": -65.04, + "y": 103, + "speed": 32.84, + "time": 3.33, + "theta": 180, + "omega": 0, + "vx": -32.83, + "vy": 0.8, + "splineNum": 5 + }, + { + "x": -67.49, + "y": 103.03, + "speed": 24.25, + "time": 3.43, + "theta": 180, + "omega": 0, + "vx": -24.25, + "vy": 0.3, + "splineNum": 5 + }, + { + "x": -69.93, + "y": 102.94, + "speed": 10, + "time": 3.67, + "theta": 180, + "omega": 0, + "vx": -9.99, + "vy": -0.38, + "splineNum": 5 + }, + { + "x": -69.93, + "y": 102.94, + "speed": 10, + "time": 3.67, + "theta": 180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 6 + }, + { + "x": -66.08, + "y": 103.18, + "speed": 29.53, + "time": 3.8, + "theta": 179.17, + "omega": -12.77, + "vx": 29.47, + "vy": 1.86, + "splineNum": 6 + }, + { + "x": -62.29, + "y": 103.48, + "speed": 40.4, + "time": 3.9, + "theta": 177.53, + "omega": -21.97, + "vx": 40.28, + "vy": 3.17, + "splineNum": 6 + }, + { + "x": -58.82, + "y": 104.06, + "speed": 34.57, + "time": 4, + "theta": 174.79, + "omega": -31.91, + "vx": 34.09, + "vy": 5.74, + "splineNum": 6 + }, + { + "x": -55.93, + "y": 105.16, + "speed": 24.01, + "time": 4.13, + "theta": 169.86, + "omega": -44.5, + "vx": 22.44, + "vy": 8.53, + "splineNum": 6 + }, + { + "x": -53.87, + "y": 107.01, + "speed": 17.08, + "time": 4.29, + "theta": 161.38, + "omega": -127.23, + "vx": 12.71, + "vy": 11.41, + "splineNum": 6 + }, + { + "x": -52.91, + "y": 109.83, + "speed": 25.03, + "time": 4.41, + "theta": 153.5, + "omega": -115.59, + "vx": 8.08, + "vy": 23.69, + "splineNum": 6 + }, + { + "x": -53.29, + "y": 113.86, + "speed": 37.9, + "time": 4.52, + "theta": 145.25, + "omega": -105.15, + "vx": -3.63, + "vy": 37.72, + "splineNum": 6 + }, + { + "x": -55.29, + "y": 119.33, + "speed": 50, + "time": 4.63, + "theta": 135, + "omega": -93.78, + "vx": -17.15, + "vy": 46.97, + "splineNum": 6 + }, + { + "x": -56.4, + "y": 121.39, + "speed": 50, + "time": 4.68, + "theta": 135, + "omega": 0, + "vx": -23.75, + "vy": 44, + "splineNum": 7 + }, + { + "x": -57.72, + "y": 123.27, + "speed": 50, + "time": 4.73, + "theta": 135, + "omega": 0, + "vx": -28.71, + "vy": 40.94, + "splineNum": 7 + }, + { + "x": -59.2, + "y": 125, + "speed": 50, + "time": 4.77, + "theta": 135, + "omega": 0, + "vx": -32.53, + "vy": 37.97, + "splineNum": 7 + }, + { + "x": -60.81, + "y": 126.61, + "speed": 50, + "time": 4.82, + "theta": 135, + "omega": 0, + "vx": -35.26, + "vy": 35.45, + "splineNum": 7 + }, + { + "x": -62.5, + "y": 128.15, + "speed": 50, + "time": 4.86, + "theta": 135, + "omega": 0, + "vx": -37.02, + "vy": 33.6, + "splineNum": 7 + }, + { + "x": -64.24, + "y": 129.64, + "speed": 50, + "time": 4.91, + "theta": 135, + "omega": 0, + "vx": -37.94, + "vy": 32.57, + "splineNum": 7 + }, + { + "x": -65.99, + "y": 131.13, + "speed": 50, + "time": 4.95, + "theta": 135, + "omega": 0, + "vx": -38.1, + "vy": 32.38, + "splineNum": 7 + } + ] + }, + { + "name": "V2-Goal3ToGoal6", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": 135, + "spline_angle": -43.83, + "x": -60.12, + "y": 132.31, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": 0, + "angle": 104.92, + "spline_angle": -35.51, + "x": -40.65, + "y": 109.95, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -38.66, + "spline_angle": -35.51, + "x": -25.06, + "y": 99.13, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 0, + "spline_angle": -176.95, + "x": 1.67, + "y": 93.56, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 94.76, + "x": 10.74, + "y": 104.38, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 94.76, + "x": -4.22, + "y": 120.61, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 94.76, + "x": -4.53, + "y": 135.56, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": -60.12, + "y": 132.31, + "speed": 0, + "time": 0, + "theta": 135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -57.57, + "y": 129.62, + "speed": 27.24, + "time": 0.14, + "theta": 133.81, + "omega": -17.54, + "vx": 18.74, + "vy": -19.76, + "splineNum": 0 + }, + { + "x": -55.22, + "y": 126.75, + "speed": 38.52, + "time": 0.23, + "theta": 131.52, + "omega": -29.93, + "vx": 24.37, + "vy": -29.82, + "splineNum": 0 + }, + { + "x": -52.99, + "y": 123.77, + "speed": 47.19, + "time": 0.31, + "theta": 128.76, + "omega": -40.07, + "vx": 28.27, + "vy": -37.78, + "splineNum": 0 + }, + { + "x": -50.8, + "y": 120.77, + "speed": 50, + "time": 0.39, + "theta": 125.43, + "omega": -126.38, + "vx": 29.47, + "vy": -40.39, + "splineNum": 0 + }, + { + "x": -48.56, + "y": 117.81, + "speed": 50, + "time": 0.46, + "theta": 121.38, + "omega": -116.81, + "vx": 30.21, + "vy": -39.84, + "splineNum": 0 + }, + { + "x": -46.18, + "y": 114.97, + "speed": 50, + "time": 0.53, + "theta": 116.64, + "omega": -107.26, + "vx": 32.14, + "vy": -38.3, + "splineNum": 0 + }, + { + "x": -43.57, + "y": 112.32, + "speed": 50, + "time": 0.61, + "theta": 111.18, + "omega": -97.7, + "vx": 35.11, + "vy": -35.6, + "splineNum": 0 + }, + { + "x": -40.65, + "y": 109.95, + "speed": 50, + "time": 0.68, + "theta": 104.92, + "omega": -88.01, + "vx": 38.79, + "vy": -31.55, + "splineNum": 0 + }, + { + "x": -38.44, + "y": 108.39, + "speed": 50, + "time": 0.74, + "theta": 101.99, + "omega": -108.09, + "vx": 40.85, + "vy": -28.84, + "splineNum": 1 + }, + { + "x": -36.21, + "y": 106.84, + "speed": 50, + "time": 0.79, + "theta": 93.2, + "omega": -216.17, + "vx": 41.08, + "vy": -28.51, + "splineNum": 1 + }, + { + "x": -33.97, + "y": 105.31, + "speed": 50, + "time": 0.85, + "theta": 78.55, + "omega": -324.25, + "vx": 41.21, + "vy": -28.31, + "splineNum": 1 + }, + { + "x": -31.74, + "y": 103.77, + "speed": 50, + "time": 0.9, + "theta": 58.04, + "omega": -1080.85, + "vx": 41.26, + "vy": -28.25, + "splineNum": 1 + }, + { + "x": -29.5, + "y": 102.24, + "speed": 50, + "time": 0.95, + "theta": 31.66, + "omega": -972.76, + "vx": 41.21, + "vy": -28.31, + "splineNum": 1 + }, + { + "x": -27.27, + "y": 100.69, + "speed": 50, + "time": 1.01, + "theta": -0.57, + "omega": -864.68, + "vx": 41.08, + "vy": -28.51, + "splineNum": 1 + }, + { + "x": -25.06, + "y": 99.13, + "speed": 50, + "time": 1.06, + "theta": -38.66, + "omega": -756.59, + "vx": 40.85, + "vy": -28.84, + "splineNum": 1 + }, + { + "x": -25.06, + "y": 99.13, + "speed": 50, + "time": 1.06, + "theta": -38.66, + "omega": -756.59, + "vx": 32, + "vy": 0, + "splineNum": 1 + }, + { + "x": -21.97, + "y": 97.21, + "speed": 50, + "time": 1.14, + "theta": -38.04, + "omega": 17.01, + "vx": 42.47, + "vy": -26.39, + "splineNum": 2 + }, + { + "x": -18.79, + "y": 95.75, + "speed": 50, + "time": 1.21, + "theta": -36.28, + "omega": 33.4, + "vx": 45.45, + "vy": -20.84, + "splineNum": 2 + }, + { + "x": -15.52, + "y": 94.7, + "speed": 50, + "time": 1.27, + "theta": -33.43, + "omega": 49.46, + "vx": 47.58, + "vy": -15.37, + "splineNum": 2 + }, + { + "x": -12.19, + "y": 93.99, + "speed": 50, + "time": 1.34, + "theta": -29.51, + "omega": 65.44, + "vx": 48.92, + "vy": -10.35, + "splineNum": 2 + }, + { + "x": -8.78, + "y": 93.58, + "speed": 50, + "time": 1.41, + "theta": -24.48, + "omega": 187.57, + "vx": 49.64, + "vy": -6.01, + "splineNum": 2 + }, + { + "x": -5.33, + "y": 93.41, + "speed": 50, + "time": 1.48, + "theta": -18.29, + "omega": 171.4, + "vx": 49.94, + "vy": -2.5, + "splineNum": 2 + }, + { + "x": -1.85, + "y": 93.42, + "speed": 48.76, + "time": 1.55, + "theta": -10.7, + "omega": 154.65, + "vx": 48.76, + "vy": 0.16, + "splineNum": 2 + }, + { + "x": 1.67, + "y": 93.56, + "speed": 40.91, + "time": 1.64, + "theta": 0, + "omega": 134.52, + "vx": 40.87, + "vy": 1.64, + "splineNum": 2 + }, + { + "x": 4.37, + "y": 93.93, + "speed": 33.59, + "time": 1.72, + "theta": 1.75, + "omega": 43.07, + "vx": 33.28, + "vy": 4.54, + "splineNum": 3 + }, + { + "x": 6.58, + "y": 94.71, + "speed": 25.69, + "time": 1.81, + "theta": 7.88, + "omega": 91.45, + "vx": 24.22, + "vy": 8.59, + "splineNum": 3 + }, + { + "x": 8.3, + "y": 95.89, + "speed": 21.16, + "time": 1.91, + "theta": 19.53, + "omega": 144.02, + "vx": 17.46, + "vy": 11.95, + "splineNum": 3 + }, + { + "x": 9.57, + "y": 97.47, + "speed": 22.17, + "time": 2, + "theta": 34.84, + "omega": 425.96, + "vx": 13.9, + "vy": 17.27, + "splineNum": 3 + }, + { + "x": 10.39, + "y": 99.41, + "speed": 28.81, + "time": 2.07, + "theta": 50.36, + "omega": 387.05, + "vx": 11.15, + "vy": 26.56, + "splineNum": 3 + }, + { + "x": 10.77, + "y": 101.72, + "speed": 36.03, + "time": 2.14, + "theta": 66.5, + "omega": 352.55, + "vx": 5.93, + "vy": 35.54, + "splineNum": 3 + }, + { + "x": 10.74, + "y": 104.38, + "speed": 32.53, + "time": 2.22, + "theta": 90, + "omega": 309.15, + "vx": -0.39, + "vy": 32.53, + "splineNum": 3 + }, + { + "x": 10.74, + "y": 104.38, + "speed": 32.53, + "time": 2.22, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 4 + }, + { + "x": 9.71, + "y": 107.72, + "speed": 22.6, + "time": 2.37, + "theta": 90, + "omega": 0, + "vx": -6.67, + "vy": 21.59, + "splineNum": 4 + }, + { + "x": 7.57, + "y": 110.04, + "speed": 33.78, + "time": 2.47, + "theta": 90, + "omega": 0, + "vx": -22.9, + "vy": 24.84, + "splineNum": 4 + }, + { + "x": 4.77, + "y": 111.74, + "speed": 42.39, + "time": 2.55, + "theta": 90, + "omega": 0, + "vx": -36.2, + "vy": 22.07, + "splineNum": 4 + }, + { + "x": 1.75, + "y": 113.25, + "speed": 42.39, + "time": 2.62, + "theta": 90, + "omega": 0, + "vx": -37.95, + "vy": 18.89, + "splineNum": 4 + }, + { + "x": -1.05, + "y": 114.95, + "speed": 33.78, + "time": 2.72, + "theta": 90, + "omega": 0, + "vx": -28.85, + "vy": 17.59, + "splineNum": 4 + }, + { + "x": -3.19, + "y": 117.27, + "speed": 22.6, + "time": 2.86, + "theta": 90, + "omega": 0, + "vx": -15.32, + "vy": 16.62, + "splineNum": 4 + }, + { + "x": -4.22, + "y": 120.61, + "speed": 34.78, + "time": 2.96, + "theta": 90, + "omega": 0, + "vx": -10.27, + "vy": 33.22, + "splineNum": 4 + }, + { + "x": -4.22, + "y": 120.61, + "speed": 34.78, + "time": 2.96, + "theta": 90, + "omega": 0, + "vx": -12, + "vy": 32, + "splineNum": 4 + }, + { + "x": -4.35, + "y": 122.74, + "speed": 40.46, + "time": 3.01, + "theta": 90, + "omega": 0, + "vx": -2.38, + "vy": 40.39, + "splineNum": 5 + }, + { + "x": -4.39, + "y": 124.88, + "speed": 45.43, + "time": 3.06, + "theta": 90, + "omega": 0, + "vx": -0.94, + "vy": 45.42, + "splineNum": 5 + }, + { + "x": -4.39, + "y": 127.02, + "speed": 49.91, + "time": 3.1, + "theta": 90, + "omega": 0, + "vx": 0.11, + "vy": 49.91, + "splineNum": 5 + }, + { + "x": -4.36, + "y": 129.15, + "speed": 50, + "time": 3.15, + "theta": 90, + "omega": 0, + "vx": 0.49, + "vy": 50, + "splineNum": 5 + }, + { + "x": -4.36, + "y": 131.29, + "speed": 50, + "time": 3.19, + "theta": 90, + "omega": 0, + "vx": 0.11, + "vy": 50, + "splineNum": 5 + }, + { + "x": -4.4, + "y": 133.43, + "speed": 50, + "time": 3.23, + "theta": 90, + "omega": 0, + "vx": -1.04, + "vy": 49.99, + "splineNum": 5 + }, + { + "x": -4.53, + "y": 135.56, + "speed": 50, + "time": 3.28, + "theta": 90, + "omega": 0, + "vx": -2.94, + "vy": 49.91, + "splineNum": 5 + } + ] + }, + { + "name": "V2-Goal6ToGoal9", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": 90, + "spline_angle": -92.82, + "x": -5.65, + "y": 129.99, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": 0, + "angle": 120, + "spline_angle": 127.72, + "x": -3.74, + "y": 118.22, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 53.81, + "spline_angle": 43.48, + "x": 8.83, + "y": 122.2, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -11.86, + "spline_angle": 0, + "x": 17.74, + "y": 126.02, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -20.18, + "spline_angle": 150.51, + "x": 38.9, + "y": 122.51, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -0.02, + "spline_angle": 162.58, + "x": 61.5, + "y": 112.97, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 45, + "spline_angle": 72.3, + "x": 51.15, + "y": 129.83, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 45, + "spline_angle": -122.24, + "x": 58.31, + "y": 139.7, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": -5.65, + "y": 129.99, + "speed": 0, + "time": 0, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -5.75, + "y": 128.25, + "speed": 18.68, + "time": 0.09, + "theta": 90.83, + "omega": 17.87, + "vx": -1.1, + "vy": -18.65, + "splineNum": 0 + }, + { + "x": -5.84, + "y": 126.51, + "speed": 26.41, + "time": 0.16, + "theta": 92.43, + "omega": 30.49, + "vx": -1.37, + "vy": -26.38, + "splineNum": 0 + }, + { + "x": -5.85, + "y": 124.78, + "speed": 32.3, + "time": 0.21, + "theta": 94.34, + "omega": 40.73, + "vx": -0.2, + "vy": -32.3, + "splineNum": 0 + }, + { + "x": -5.72, + "y": 123.08, + "speed": 34.52, + "time": 0.26, + "theta": 96.59, + "omega": 50.2, + "vx": 2.77, + "vy": -34.41, + "splineNum": 0 + }, + { + "x": -5.36, + "y": 121.41, + "speed": 29.16, + "time": 0.32, + "theta": 99.85, + "omega": 152.89, + "vx": 6.03, + "vy": -28.53, + "splineNum": 0 + }, + { + "x": -4.73, + "y": 119.79, + "speed": 22.4, + "time": 0.4, + "theta": 105.2, + "omega": 138.01, + "vx": 8.18, + "vy": -20.85, + "splineNum": 0 + }, + { + "x": -3.74, + "y": 118.22, + "speed": 11.47, + "time": 0.56, + "theta": 120, + "omega": 107.14, + "vx": 6.12, + "vy": -9.7, + "splineNum": 0 + }, + { + "x": -3.74, + "y": 118.22, + "speed": 11.47, + "time": 0.56, + "theta": 120, + "omega": 107.14, + "vx": 12, + "vy": 0, + "splineNum": 0 + }, + { + "x": -1.1, + "y": 115.36, + "speed": 24.94, + "time": 0.72, + "theta": 118.02, + "omega": -25.33, + "vx": 16.89, + "vy": -18.35, + "splineNum": 1 + }, + { + "x": 1.02, + "y": 114.11, + "speed": 11.4, + "time": 0.93, + "theta": 108.78, + "omega": -60.35, + "vx": 9.84, + "vy": -5.77, + "splineNum": 1 + }, + { + "x": 2.73, + "y": 114.16, + "speed": 8.85, + "time": 1.13, + "theta": 94.03, + "omega": -201.36, + "vx": 8.84, + "vy": 0.24, + "splineNum": 1 + }, + { + "x": 4.14, + "y": 115.16, + "speed": 18.07, + "time": 1.22, + "theta": 84.48, + "omega": -185.79, + "vx": 14.7, + "vy": 10.5, + "splineNum": 1 + }, + { + "x": 5.35, + "y": 116.8, + "speed": 27.09, + "time": 1.3, + "theta": 75.95, + "omega": -173.59, + "vx": 16.1, + "vy": 21.78, + "splineNum": 1 + }, + { + "x": 6.47, + "y": 118.74, + "speed": 34.37, + "time": 1.36, + "theta": 67.83, + "omega": -163.03, + "vx": 17.14, + "vy": 29.79, + "splineNum": 1 + }, + { + "x": 7.59, + "y": 120.65, + "speed": 40.3, + "time": 1.42, + "theta": 60.43, + "omega": -154.11, + "vx": 20.45, + "vy": 34.73, + "splineNum": 1 + }, + { + "x": 8.83, + "y": 122.2, + "speed": 42.81, + "time": 1.46, + "theta": 53.81, + "omega": -146.58, + "vx": 26.71, + "vy": 33.45, + "splineNum": 1 + }, + { + "x": 9.93, + "y": 123.16, + "speed": 44.83, + "time": 1.5, + "theta": 52.78, + "omega": -63.43, + "vx": 33.75, + "vy": 29.5, + "splineNum": 2 + }, + { + "x": 11.07, + "y": 123.99, + "speed": 41.54, + "time": 1.53, + "theta": 49.47, + "omega": -130.22, + "vx": 33.58, + "vy": 24.44, + "splineNum": 2 + }, + { + "x": 12.28, + "y": 124.7, + "speed": 38.03, + "time": 1.57, + "theta": 43.37, + "omega": -201.91, + "vx": 32.82, + "vy": 19.2, + "splineNum": 2 + }, + { + "x": 13.54, + "y": 125.26, + "speed": 35.54, + "time": 1.61, + "theta": 34.02, + "omega": -734.94, + "vx": 32.46, + "vy": 14.48, + "splineNum": 2 + }, + { + "x": 14.87, + "y": 125.68, + "speed": 34.76, + "time": 1.65, + "theta": 21.32, + "omega": -656.72, + "vx": 33.19, + "vy": 10.35, + "splineNum": 2 + }, + { + "x": 16.27, + "y": 125.93, + "speed": 35.72, + "time": 1.69, + "theta": 5.61, + "omega": -579.04, + "vx": 35.14, + "vy": 6.42, + "splineNum": 2 + }, + { + "x": 17.74, + "y": 126.02, + "speed": 39.63, + "time": 1.72, + "theta": -11.86, + "omega": -506.48, + "vx": 39.56, + "vy": 2.35, + "splineNum": 2 + }, + { + "x": 17.74, + "y": 126.02, + "speed": 39.63, + "time": 1.72, + "theta": -11.86, + "omega": -506.48, + "vx": 39.63, + "vy": 0, + "splineNum": 2 + }, + { + "x": 20.85, + "y": 126.02, + "speed": 46.81, + "time": 1.79, + "theta": -11.93, + "omega": -2.01, + "vx": 46.81, + "vy": 0.03, + "splineNum": 3 + }, + { + "x": 23.95, + "y": 125.98, + "speed": 50, + "time": 1.85, + "theta": -12.11, + "omega": -3.89, + "vx": 50, + "vy": -0.69, + "splineNum": 3 + }, + { + "x": 27.02, + "y": 125.82, + "speed": 50, + "time": 1.91, + "theta": -12.41, + "omega": -5.76, + "vx": 49.93, + "vy": -2.61, + "splineNum": 3 + }, + { + "x": 30.07, + "y": 125.46, + "speed": 44.66, + "time": 1.98, + "theta": -12.87, + "omega": -7.84, + "vx": 44.36, + "vy": -5.15, + "splineNum": 3 + }, + { + "x": 33.08, + "y": 124.84, + "speed": 37.16, + "time": 2.06, + "theta": -13.62, + "omega": -10.34, + "vx": 36.39, + "vy": -7.51, + "splineNum": 3 + }, + { + "x": 36.02, + "y": 123.88, + "speed": 27.59, + "time": 2.18, + "theta": -14.98, + "omega": -31.17, + "vx": 26.23, + "vy": -8.55, + "splineNum": 3 + }, + { + "x": 38.9, + "y": 122.51, + "speed": 11.1, + "time": 2.46, + "theta": -20.18, + "omega": -22.46, + "vx": 10.02, + "vy": -4.78, + "splineNum": 3 + }, + { + "x": 38.9, + "y": 122.51, + "speed": 11.1, + "time": 2.46, + "theta": -20.18, + "omega": -22.46, + "vx": 11.1, + "vy": 0, + "splineNum": 3 + }, + { + "x": 42, + "y": 120.83, + "speed": 28.76, + "time": 2.59, + "theta": -19.69, + "omega": 7.95, + "vx": 25.3, + "vy": -13.69, + "splineNum": 4 + }, + { + "x": 45.14, + "y": 119.28, + "speed": 39.11, + "time": 2.68, + "theta": -18.72, + "omega": 13.77, + "vx": 35.05, + "vy": -17.35, + "splineNum": 4 + }, + { + "x": 48.34, + "y": 117.83, + "speed": 47.23, + "time": 2.75, + "theta": -17.52, + "omega": 18.59, + "vx": 43.01, + "vy": -19.51, + "splineNum": 4 + }, + { + "x": 51.57, + "y": 116.48, + "speed": 48.42, + "time": 2.82, + "theta": -16, + "omega": 23.29, + "vx": 44.7, + "vy": -18.61, + "splineNum": 4 + }, + { + "x": 54.85, + "y": 115.23, + "speed": 40.53, + "time": 2.91, + "theta": -13.74, + "omega": 73.41, + "vx": 37.85, + "vy": -14.49, + "splineNum": 4 + }, + { + "x": 58.16, + "y": 114.06, + "speed": 30.67, + "time": 3.02, + "theta": -10.01, + "omega": 65.98, + "vx": 28.92, + "vy": -10.2, + "splineNum": 4 + }, + { + "x": 61.5, + "y": 112.97, + "speed": 15.4, + "time": 3.25, + "theta": -0.02, + "omega": 51.16, + "vx": 14.64, + "vy": -4.77, + "splineNum": 4 + }, + { + "x": 61.5, + "y": 112.97, + "speed": 15.4, + "time": 3.25, + "theta": -0.02, + "omega": 51.16, + "vx": 15.4, + "vy": 0, + "splineNum": 4 + }, + { + "x": 58.14, + "y": 114.22, + "speed": 30.9, + "time": 3.37, + "theta": 1.38, + "omega": 24.17, + "vx": -28.95, + "vy": 10.79, + "splineNum": 5 + }, + { + "x": 55.26, + "y": 115.77, + "speed": 40.1, + "time": 3.45, + "theta": 4.04, + "omega": 41.14, + "vx": -35.3, + "vy": 19.03, + "splineNum": 5 + }, + { + "x": 52.96, + "y": 117.67, + "speed": 33.7, + "time": 3.54, + "theta": 8.51, + "omega": 59.6, + "vx": -26, + "vy": 21.44, + "splineNum": 5 + }, + { + "x": 51.31, + "y": 119.98, + "speed": 28.47, + "time": 3.64, + "theta": 15.47, + "omega": 193.53, + "vx": -16.58, + "vy": 23.15, + "splineNum": 5 + }, + { + "x": 50.4, + "y": 122.74, + "speed": 31.69, + "time": 3.73, + "theta": 23.71, + "omega": 174.44, + "vx": -9.91, + "vy": 30.1, + "splineNum": 5 + }, + { + "x": 50.32, + "y": 126, + "speed": 40.72, + "time": 3.81, + "theta": 32.36, + "omega": 157.73, + "vx": -1.01, + "vy": 40.7, + "splineNum": 5 + }, + { + "x": 51.15, + "y": 129.83, + "speed": 39.18, + "time": 3.91, + "theta": 45, + "omega": 136.92, + "vx": 8.32, + "vy": 38.29, + "splineNum": 5 + }, + { + "x": 51.15, + "y": 129.83, + "speed": 39.18, + "time": 3.91, + "theta": 45, + "omega": 136.92, + "vx": -39.18, + "vy": 0, + "splineNum": 5 + }, + { + "x": 51.84, + "y": 131.48, + "speed": 34.32, + "time": 3.96, + "theta": 45, + "omega": 0, + "vx": 13.28, + "vy": 31.64, + "splineNum": 6 + }, + { + "x": 52.76, + "y": 132.97, + "speed": 39.08, + "time": 4.01, + "theta": 45, + "omega": 0, + "vx": 20.49, + "vy": 33.27, + "splineNum": 6 + }, + { + "x": 53.83, + "y": 134.34, + "speed": 43.31, + "time": 4.05, + "theta": 45, + "omega": 0, + "vx": 26.63, + "vy": 34.15, + "splineNum": 6 + }, + { + "x": 54.99, + "y": 135.65, + "speed": 47.18, + "time": 4.08, + "theta": 45, + "omega": 0, + "vx": 31.25, + "vy": 35.34, + "splineNum": 6 + }, + { + "x": 56.17, + "y": 136.95, + "speed": 50, + "time": 4.12, + "theta": 45, + "omega": 0, + "vx": 33.62, + "vy": 37.01, + "splineNum": 6 + }, + { + "x": 57.3, + "y": 138.28, + "speed": 50, + "time": 4.15, + "theta": 45, + "omega": 0, + "vx": 32.33, + "vy": 38.14, + "splineNum": 6 + }, + { + "x": 58.31, + "y": 139.7, + "speed": 50, + "time": 4.19, + "theta": 45, + "omega": 0, + "vx": 29.06, + "vy": 40.69, + "splineNum": 6 + } + ] + }, + { + "name": "V2-Goal9ToGoal8", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": 45, + "spline_angle": -131.76, + "x": 60.7, + "y": 133.97, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": 0, + "angle": 17.97, + "spline_angle": 50.22, + "x": 39.38, + "y": 110.74, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -105, + "spline_angle": 68.26, + "x": 29.67, + "y": 89.26, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -90, + "spline_angle": 84.25, + "x": 26.65, + "y": 70.01, + "shared": false, + "speed": 5 + }, + { + "name": "wp", + "omega": 0, + "angle": 0, + "spline_angle": 177.2, + "x": 40.49, + "y": 78.28, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 0, + "spline_angle": 177.2, + "x": 67.7, + "y": 78.12, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": 60.7, + "y": 133.97, + "speed": 0, + "time": 0, + "theta": 45, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 58.05, + "y": 131.05, + "speed": 28.08, + "time": 0.14, + "theta": 43.96, + "omega": -14.85, + "vx": -18.88, + "vy": -20.78, + "splineNum": 0 + }, + { + "x": 55.36, + "y": 128.17, + "speed": 39.71, + "time": 0.24, + "theta": 41.96, + "omega": -25.35, + "vx": -27.08, + "vy": -29.04, + "splineNum": 0 + }, + { + "x": 52.65, + "y": 125.31, + "speed": 48.63, + "time": 0.32, + "theta": 39.56, + "omega": -33.92, + "vx": -33.42, + "vy": -35.32, + "splineNum": 0 + }, + { + "x": 49.94, + "y": 122.45, + "speed": 50, + "time": 0.4, + "theta": 36.56, + "omega": -108.98, + "vx": -34.42, + "vy": -36.27, + "splineNum": 0 + }, + { + "x": 47.24, + "y": 119.58, + "speed": 50, + "time": 0.48, + "theta": 32.9, + "omega": -100.64, + "vx": -34.26, + "vy": -36.42, + "splineNum": 0 + }, + { + "x": 44.57, + "y": 116.68, + "speed": 50, + "time": 0.56, + "theta": 28.58, + "omega": -92.3, + "vx": -33.89, + "vy": -36.76, + "splineNum": 0 + }, + { + "x": 41.94, + "y": 113.74, + "speed": 50, + "time": 0.64, + "theta": 23.61, + "omega": -83.96, + "vx": -33.3, + "vy": -37.3, + "splineNum": 0 + }, + { + "x": 39.38, + "y": 110.74, + "speed": 50, + "time": 0.71, + "theta": 17.97, + "omega": -75.62, + "vx": -32.48, + "vy": -38.01, + "splineNum": 0 + }, + { + "x": 37.35, + "y": 107.96, + "speed": 50, + "time": 0.78, + "theta": 15.38, + "omega": -75.31, + "vx": -29.47, + "vy": -40.39, + "splineNum": 1 + }, + { + "x": 35.68, + "y": 105.02, + "speed": 50, + "time": 0.85, + "theta": 7.78, + "omega": -149.35, + "vx": -24.68, + "vy": -43.49, + "splineNum": 1 + }, + { + "x": 34.29, + "y": 101.96, + "speed": 50, + "time": 0.92, + "theta": -4.76, + "omega": -223.08, + "vx": -20.75, + "vy": -45.49, + "splineNum": 1 + }, + { + "x": 33.07, + "y": 98.81, + "speed": 50, + "time": 0.99, + "theta": -22.3, + "omega": -740.81, + "vx": -17.99, + "vy": -46.65, + "splineNum": 1 + }, + { + "x": 31.96, + "y": 95.62, + "speed": 50, + "time": 1.05, + "theta": -44.88, + "omega": -666.79, + "vx": -16.5, + "vy": -47.2, + "splineNum": 1 + }, + { + "x": 30.85, + "y": 92.42, + "speed": 50, + "time": 1.12, + "theta": -72.47, + "omega": -592.76, + "vx": -16.34, + "vy": -47.25, + "splineNum": 1 + }, + { + "x": 29.67, + "y": 89.26, + "speed": 50, + "time": 1.19, + "theta": -105, + "omega": -518.87, + "vx": -17.5, + "vy": -46.84, + "splineNum": 1 + }, + { + "x": 29.67, + "y": 89.26, + "speed": 50, + "time": 1.19, + "theta": -105, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 2 + }, + { + "x": 28.76, + "y": 86.59, + "speed": 50, + "time": 1.25, + "theta": -104.95, + "omega": 1.71, + "vx": -16.1, + "vy": -47.34, + "splineNum": 2 + }, + { + "x": 28.11, + "y": 83.87, + "speed": 50, + "time": 1.3, + "theta": -104.81, + "omega": 3.41, + "vx": -11.7, + "vy": -48.61, + "splineNum": 2 + }, + { + "x": 27.65, + "y": 81.12, + "speed": 47.51, + "time": 1.36, + "theta": -104.56, + "omega": 5.18, + "vx": -7.77, + "vy": -46.87, + "splineNum": 2 + }, + { + "x": 27.34, + "y": 78.36, + "speed": 41.23, + "time": 1.43, + "theta": -104.14, + "omega": 7.23, + "vx": -4.67, + "vy": -40.96, + "splineNum": 2 + }, + { + "x": 27.1, + "y": 75.57, + "speed": 33.79, + "time": 1.51, + "theta": -103.44, + "omega": 9.73, + "vx": -2.82, + "vy": -33.67, + "splineNum": 2 + }, + { + "x": 26.89, + "y": 72.79, + "speed": 24.15, + "time": 1.63, + "theta": -102.11, + "omega": 13.24, + "vx": -1.81, + "vy": -24.08, + "splineNum": 2 + }, + { + "x": 26.65, + "y": 70.01, + "speed": 5, + "time": 2.18, + "theta": -90, + "omega": 30.16, + "vx": -0.44, + "vy": -4.98, + "splineNum": 2 + }, + { + "x": 26.65, + "y": 70.01, + "speed": 5, + "time": 2.18, + "theta": -90, + "omega": 30.16, + "vx": -4, + "vy": 0, + "splineNum": 2 + }, + { + "x": 27.36, + "y": 73.31, + "speed": 26.45, + "time": 2.31, + "theta": -86.2, + "omega": 59.65, + "vx": 5.59, + "vy": 25.86, + "splineNum": 3 + }, + { + "x": 28.66, + "y": 75.63, + "speed": 20.87, + "time": 2.44, + "theta": -74.82, + "omega": 119.17, + "vx": 10.2, + "vy": 18.21, + "splineNum": 3 + }, + { + "x": 30.45, + "y": 77.13, + "speed": 21.57, + "time": 2.55, + "theta": -59.18, + "omega": 410.5, + "vx": 16.5, + "vy": 13.89, + "splineNum": 3 + }, + { + "x": 32.62, + "y": 77.98, + "speed": 30.53, + "time": 2.62, + "theta": -44.83, + "omega": 374.73, + "vx": 28.43, + "vy": 11.14, + "splineNum": 3 + }, + { + "x": 35.08, + "y": 78.35, + "speed": 37.82, + "time": 2.69, + "theta": -30.28, + "omega": 343.93, + "vx": 37.41, + "vy": 5.56, + "splineNum": 3 + }, + { + "x": 37.74, + "y": 78.39, + "speed": 44.29, + "time": 2.75, + "theta": -15.26, + "omega": 315.88, + "vx": 44.29, + "vy": 0.75, + "splineNum": 3 + }, + { + "x": 40.49, + "y": 78.28, + "speed": 50, + "time": 2.8, + "theta": 0, + "omega": 290.14, + "vx": 49.96, + "vy": -2.03, + "splineNum": 3 + }, + { + "x": 40.49, + "y": 78.28, + "speed": 50, + "time": 2.8, + "theta": 0, + "omega": 290.14, + "vx": 50, + "vy": 0, + "splineNum": 3 + }, + { + "x": 44.38, + "y": 78.15, + "speed": 50, + "time": 2.88, + "theta": 0, + "omega": 0, + "vx": 49.97, + "vy": -1.61, + "splineNum": 4 + }, + { + "x": 48.26, + "y": 78.13, + "speed": 50, + "time": 2.96, + "theta": 0, + "omega": 0, + "vx": 50, + "vy": -0.29, + "splineNum": 4 + }, + { + "x": 52.15, + "y": 78.17, + "speed": 50, + "time": 3.04, + "theta": 0, + "omega": 0, + "vx": 50, + "vy": 0.5, + "splineNum": 4 + }, + { + "x": 56.04, + "y": 78.23, + "speed": 50, + "time": 3.12, + "theta": 0, + "omega": 0, + "vx": 49.99, + "vy": 0.76, + "splineNum": 4 + }, + { + "x": 59.93, + "y": 78.27, + "speed": 50, + "time": 3.19, + "theta": 0, + "omega": 0, + "vx": 50, + "vy": 0.5, + "splineNum": 4 + }, + { + "x": 63.81, + "y": 78.25, + "speed": 50, + "time": 3.27, + "theta": 0, + "omega": 0, + "vx": 50, + "vy": -0.29, + "splineNum": 4 + }, + { + "x": 67.7, + "y": 78.12, + "speed": 50, + "time": 3.35, + "theta": 0, + "omega": 0, + "vx": 49.97, + "vy": -1.61, + "splineNum": 4 + } + ] + }, + { + "name": "V2-Goal8ToGoal7", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": -1.3922608532172043, + "angle": 0, + "spline_angle": 0, + "x": 52.75, + "y": 72.24, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": -1.3922608532172043, + "angle": 45, + "spline_angle": 50.1, + "x": 38.74, + "y": 68.26, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": -1.3922608532172043, + "angle": 0, + "spline_angle": 81.18, + "x": 37.15, + "y": 54.89, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": -1.3922608532172043, + "angle": -90, + "spline_angle": -90.82, + "x": 36.2, + "y": 36.28, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": -1.3922608532172043, + "angle": -90, + "spline_angle": -90.82, + "x": 35.72, + "y": 18.14, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": -1.3922608532172043, + "angle": 0, + "spline_angle": 34.79, + "x": 46.54, + "y": 32.78, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": -1.3922608532172043, + "angle": 0, + "spline_angle": -179.97, + "x": 67.86, + "y": 36.28, + "shared": false, + "speed": 10 + }, + { + "name": "wp", + "omega": -1.3922608532172043, + "angle": -44.51, + "spline_angle": 95.97, + "x": 51.63, + "y": 26.25, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": -1.3922608532172043, + "angle": -45, + "spline_angle": -30.95, + "x": 62.13, + "y": 11.14, + "shared": false, + "speed": 10 + } + ], + "points": [ + { + "x": 52.75, + "y": 72.24, + "speed": 0, + "time": 0, + "theta": 0, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 50.58, + "y": 72.26, + "speed": 20.82, + "time": 0.1, + "theta": 1.9, + "omega": 36.5, + "vx": -20.82, + "vy": 0.15, + "splineNum": 0 + }, + { + "x": 48.42, + "y": 72.24, + "speed": 29.41, + "time": 0.18, + "theta": 5.52, + "omega": 62.22, + "vx": -29.41, + "vy": -0.23, + "splineNum": 0 + }, + { + "x": 46.3, + "y": 72.09, + "speed": 35.92, + "time": 0.24, + "theta": 9.82, + "omega": 82.97, + "vx": -35.84, + "vy": -2.48, + "splineNum": 0 + }, + { + "x": 44.25, + "y": 71.72, + "speed": 37.33, + "time": 0.29, + "theta": 15.01, + "omega": 252.65, + "vx": -36.72, + "vy": -6.68, + "splineNum": 0 + }, + { + "x": 42.28, + "y": 71.02, + "speed": 31.24, + "time": 0.36, + "theta": 22.64, + "omega": 229.26, + "vx": -29.44, + "vy": -10.47, + "splineNum": 0 + }, + { + "x": 40.44, + "y": 69.9, + "speed": 30.56, + "time": 0.43, + "theta": 32.41, + "omega": 204.5, + "vx": -26.12, + "vy": -15.86, + "splineNum": 0 + }, + { + "x": 38.74, + "y": 68.26, + "speed": 30.78, + "time": 0.51, + "theta": 45, + "omega": 177.63, + "vx": -22.14, + "vy": -21.38, + "splineNum": 0 + }, + { + "x": 38.74, + "y": 68.26, + "speed": 30.78, + "time": 0.51, + "theta": 45, + "omega": 177.63, + "vx": -32, + "vy": 0, + "splineNum": 0 + }, + { + "x": 37.61, + "y": 66.46, + "speed": 22.84, + "time": 0.6, + "theta": 42.5, + "omega": -53.62, + "vx": -12.16, + "vy": -19.33, + "splineNum": 1 + }, + { + "x": 37.04, + "y": 64.59, + "speed": 27.41, + "time": 0.67, + "theta": 37.22, + "omega": -94.6, + "vx": -7.91, + "vy": -26.24, + "splineNum": 1 + }, + { + "x": 36.89, + "y": 62.67, + "speed": 33.71, + "time": 0.73, + "theta": 30.88, + "omega": -327.56, + "vx": -2.7, + "vy": -33.6, + "splineNum": 1 + }, + { + "x": 36.98, + "y": 60.72, + "speed": 39.07, + "time": 0.78, + "theta": 23.8, + "omega": -298.85, + "vx": 1.9, + "vy": -39.02, + "splineNum": 1 + }, + { + "x": 37.17, + "y": 58.76, + "speed": 43.81, + "time": 0.82, + "theta": 16.21, + "omega": -273.02, + "vx": 4.06, + "vy": -43.62, + "splineNum": 1 + }, + { + "x": 37.27, + "y": 56.81, + "speed": 48.06, + "time": 0.86, + "theta": 8.34, + "omega": -249.66, + "vx": 2.69, + "vy": -47.99, + "splineNum": 1 + }, + { + "x": 37.15, + "y": 54.89, + "speed": 50, + "time": 0.9, + "theta": 0, + "omega": -227.5, + "vx": -3.23, + "vy": -49.9, + "splineNum": 1 + }, + { + "x": 37.15, + "y": 54.89, + "speed": 50, + "time": 0.9, + "theta": 0, + "omega": -227.5, + "vx": -64, + "vy": 0, + "splineNum": 1 + }, + { + "x": 36.8, + "y": 52.24, + "speed": 50, + "time": 0.96, + "theta": -1.56, + "omega": -58.45, + "vx": -6.54, + "vy": -49.57, + "splineNum": 2 + }, + { + "x": 36.56, + "y": 49.59, + "speed": 50, + "time": 1.01, + "theta": -6.23, + "omega": -116.76, + "vx": -4.54, + "vy": -49.79, + "splineNum": 2 + }, + { + "x": 36.4, + "y": 46.93, + "speed": 50, + "time": 1.06, + "theta": -14, + "omega": -175.03, + "vx": -2.94, + "vy": -49.91, + "splineNum": 2 + }, + { + "x": 36.31, + "y": 44.27, + "speed": 50, + "time": 1.12, + "theta": -24.87, + "omega": -654.35, + "vx": -1.73, + "vy": -49.97, + "splineNum": 2 + }, + { + "x": 36.26, + "y": 41.61, + "speed": 48.37, + "time": 1.17, + "theta": -39.37, + "omega": -594.09, + "vx": -0.91, + "vy": -48.36, + "splineNum": 2 + }, + { + "x": 36.23, + "y": 38.94, + "speed": 42.51, + "time": 1.23, + "theta": -59.92, + "omega": -525.51, + "vx": -0.47, + "vy": -42.5, + "splineNum": 2 + }, + { + "x": 36.2, + "y": 36.28, + "speed": 35.69, + "time": 1.31, + "theta": -90, + "omega": -443.82, + "vx": -0.41, + "vy": -35.69, + "splineNum": 2 + }, + { + "x": 36.2, + "y": 36.28, + "speed": 35.69, + "time": 1.31, + "theta": -90, + "omega": -443.82, + "vx": -35.69, + "vy": 0, + "splineNum": 2 + }, + { + "x": 36.15, + "y": 33.69, + "speed": 42.34, + "time": 1.37, + "theta": -90, + "omega": 0, + "vx": -0.81, + "vy": -42.33, + "splineNum": 3 + }, + { + "x": 36.08, + "y": 31.1, + "speed": 48.07, + "time": 1.42, + "theta": -90, + "omega": 0, + "vx": -1.27, + "vy": -48.06, + "splineNum": 3 + }, + { + "x": 36, + "y": 28.51, + "speed": 45.76, + "time": 1.48, + "theta": -90, + "omega": 0, + "vx": -1.41, + "vy": -45.74, + "splineNum": 3 + }, + { + "x": 35.92, + "y": 25.91, + "speed": 39.7, + "time": 1.54, + "theta": -90, + "omega": 0, + "vx": -1.29, + "vy": -39.68, + "splineNum": 3 + }, + { + "x": 35.84, + "y": 23.32, + "speed": 32.52, + "time": 1.62, + "theta": -90, + "omega": 0, + "vx": -1.01, + "vy": -32.5, + "splineNum": 3 + }, + { + "x": 35.77, + "y": 20.73, + "speed": 23.21, + "time": 1.74, + "theta": -90, + "omega": 0, + "vx": -0.61, + "vy": -23.21, + "splineNum": 3 + }, + { + "x": 35.72, + "y": 18.14, + "speed": 4.52, + "time": 2.31, + "theta": -90, + "omega": 0, + "vx": -0.09, + "vy": -4.52, + "splineNum": 3 + }, + { + "x": 35.72, + "y": 18.14, + "speed": 4.52, + "time": 2.31, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": -4, + "splineNum": 3 + }, + { + "x": 36.08, + "y": 21.11, + "speed": 24.87, + "time": 2.43, + "theta": -84.39, + "omega": 93.32, + "vx": 2.97, + "vy": 24.7, + "splineNum": 4 + }, + { + "x": 36.99, + "y": 23.67, + "speed": 34.09, + "time": 2.51, + "theta": -74.49, + "omega": 155.16, + "vx": 11.47, + "vy": 32.1, + "splineNum": 4 + }, + { + "x": 38.37, + "y": 25.89, + "speed": 41.04, + "time": 2.57, + "theta": -63.05, + "omega": 542.97, + "vx": 21.63, + "vy": 34.87, + "splineNum": 4 + }, + { + "x": 40.11, + "y": 27.83, + "speed": 46.97, + "time": 2.63, + "theta": -50.48, + "omega": 499.82, + "vx": 31.28, + "vy": 35.04, + "splineNum": 4 + }, + { + "x": 42.11, + "y": 29.58, + "speed": 50, + "time": 2.68, + "theta": -36.19, + "omega": 458.49, + "vx": 37.67, + "vy": 32.87, + "splineNum": 4 + }, + { + "x": 44.29, + "y": 31.21, + "speed": 50, + "time": 2.74, + "theta": -19.34, + "omega": 416.33, + "vx": 40.07, + "vy": 29.91, + "splineNum": 4 + }, + { + "x": 46.54, + "y": 32.78, + "speed": 50, + "time": 2.79, + "theta": 0, + "omega": 373.73, + "vx": 41.01, + "vy": 28.61, + "splineNum": 4 + }, + { + "x": 46.54, + "y": 32.78, + "speed": 50, + "time": 2.79, + "theta": 0, + "omega": 373.73, + "vx": -50, + "vy": 0, + "splineNum": 4 + }, + { + "x": 49.4, + "y": 34.41, + "speed": 50, + "time": 2.86, + "theta": 0, + "omega": 0, + "vx": 43.46, + "vy": 24.72, + "splineNum": 5 + }, + { + "x": 52.36, + "y": 35.46, + "speed": 50, + "time": 2.92, + "theta": 0, + "omega": 0, + "vx": 47.08, + "vy": 16.84, + "splineNum": 5 + }, + { + "x": 55.38, + "y": 36.07, + "speed": 50, + "time": 2.98, + "theta": 0, + "omega": 0, + "vx": 49.04, + "vy": 9.77, + "splineNum": 5 + }, + { + "x": 58.47, + "y": 36.33, + "speed": 44.48, + "time": 3.05, + "theta": 0, + "omega": 0, + "vx": 44.32, + "vy": 3.83, + "splineNum": 5 + }, + { + "x": 61.59, + "y": 36.38, + "speed": 36.8, + "time": 3.14, + "theta": 0, + "omega": 0, + "vx": 36.8, + "vy": 0.55, + "splineNum": 5 + }, + { + "x": 64.73, + "y": 36.32, + "speed": 26.96, + "time": 3.25, + "theta": 0, + "omega": 0, + "vx": 26.96, + "vy": -0.49, + "splineNum": 5 + }, + { + "x": 67.86, + "y": 36.28, + "speed": 10, + "time": 3.57, + "theta": 0, + "omega": 0, + "vx": 10, + "vy": -0.14, + "splineNum": 5 + }, + { + "x": 67.86, + "y": 36.28, + "speed": 10, + "time": 3.57, + "theta": 0, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 6 + }, + { + "x": 64.53, + "y": 36.49, + "speed": 27.71, + "time": 3.69, + "theta": -0.84, + "omega": -13.9, + "vx": -27.65, + "vy": 1.72, + "splineNum": 6 + }, + { + "x": 61.11, + "y": 36.84, + "speed": 38.15, + "time": 3.78, + "theta": -2.56, + "omega": -24.3, + "vx": -37.95, + "vy": 3.88, + "splineNum": 6 + }, + { + "x": 57.85, + "y": 36.92, + "speed": 30.4, + "time": 3.88, + "theta": -5.82, + "omega": -36.65, + "vx": -30.39, + "vy": 0.73, + "splineNum": 6 + }, + { + "x": 55.03, + "y": 36.31, + "speed": 18.59, + "time": 4.04, + "theta": -12.93, + "omega": -148.09, + "vx": -18.18, + "vy": -3.89, + "splineNum": 6 + }, + { + "x": 52.87, + "y": 34.61, + "speed": 17.42, + "time": 4.2, + "theta": -22.96, + "omega": -129.91, + "vx": -13.66, + "vy": -10.82, + "splineNum": 6 + }, + { + "x": 51.66, + "y": 31.39, + "speed": 31.48, + "time": 4.31, + "theta": -31.6, + "omega": -117.31, + "vx": -11.14, + "vy": -29.44, + "splineNum": 6 + }, + { + "x": 51.63, + "y": 26.25, + "speed": 37.18, + "time": 4.44, + "theta": -44.51, + "omega": -101.35, + "vx": -0.2, + "vy": -37.18, + "splineNum": 6 + }, + { + "x": 51.63, + "y": 26.25, + "speed": 37.18, + "time": 4.44, + "theta": -44.51, + "omega": -101.35, + "vx": -37.18, + "vy": 0, + "splineNum": 6 + }, + { + "x": 52.14, + "y": 23.4, + "speed": 44.28, + "time": 4.51, + "theta": -44.51, + "omega": -0.13, + "vx": 7.78, + "vy": -43.59, + "splineNum": 7 + }, + { + "x": 53.02, + "y": 20.81, + "speed": 50, + "time": 4.56, + "theta": -44.52, + "omega": -0.24, + "vx": 16.14, + "vy": -47.32, + "splineNum": 7 + }, + { + "x": 54.25, + "y": 18.47, + "speed": 47.66, + "time": 4.62, + "theta": -44.54, + "omega": -0.35, + "vx": 22.14, + "vy": -42.2, + "splineNum": 7 + }, + { + "x": 55.8, + "y": 16.35, + "speed": 41.78, + "time": 4.68, + "theta": -44.57, + "omega": -0.47, + "vx": 24.67, + "vy": -33.71, + "splineNum": 7 + }, + { + "x": 57.65, + "y": 14.43, + "speed": 34.82, + "time": 4.76, + "theta": -44.61, + "omega": -0.62, + "vx": 24.17, + "vy": -25.07, + "splineNum": 7 + }, + { + "x": 59.77, + "y": 12.7, + "speed": 25.81, + "time": 4.87, + "theta": -44.69, + "omega": -1.95, + "vx": 19.98, + "vy": -16.33, + "splineNum": 7 + }, + { + "x": 62.13, + "y": 11.14, + "speed": 10, + "time": 5.15, + "theta": -45, + "omega": -1.39, + "vx": 8.34, + "vy": -5.52, + "splineNum": 7 + }, + { + "x": 62.13, + "y": 11.14, + "speed": 10, + "time": 5.15, + "theta": -45, + "omega": -1.39, + "vx": 8, + "vy": -2, + "splineNum": 7 + } + ] + }, + { + "name": "V2-Goal7ToGoal5", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": -38.85, + "spline_angle": 126.08, + "x": 58.95, + "y": 11.46, + "shared": false, + "speed": 0 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": -3.7, + "x": 23.63, + "y": 21.32, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 162.65, + "spline_angle": 162.65, + "x": 0.08, + "y": 23.23, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 94.29, + "x": -6.44, + "y": 32.3, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 94.27, + "x": -3.9, + "y": 65.08, + "shared": false, + "speed": 20 + } + ], + "points": [ + { + "x": 58.95, + "y": 11.46, + "speed": 0, + "time": 0, + "theta": -38.85, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 56.57, + "y": 14.28, + "speed": 27.19, + "time": 0.14, + "theta": -35.62, + "omega": 47.51, + "vx": -17.54, + "vy": 20.77, + "splineNum": 0 + }, + { + "x": 54.01, + "y": 16.51, + "speed": 37.63, + "time": 0.23, + "theta": -29.93, + "omega": 78.94, + "vx": -28.38, + "vy": 24.71, + "splineNum": 0 + }, + { + "x": 51.31, + "y": 18.2, + "speed": 45.32, + "time": 0.3, + "theta": -23.52, + "omega": 103.52, + "vx": -38.39, + "vy": 24.07, + "splineNum": 0 + }, + { + "x": 48.49, + "y": 19.43, + "speed": 50, + "time": 0.36, + "theta": -16.46, + "omega": 125.09, + "vx": -45.83, + "vy": 20, + "splineNum": 0 + }, + { + "x": 45.55, + "y": 20.28, + "speed": 50, + "time": 0.42, + "theta": -8.16, + "omega": 146.45, + "vx": -48.04, + "vy": 13.85, + "splineNum": 0 + }, + { + "x": 42.52, + "y": 20.81, + "speed": 50, + "time": 0.48, + "theta": 1.49, + "omega": 432.3, + "vx": -49.25, + "vy": 8.63, + "splineNum": 0 + }, + { + "x": 39.43, + "y": 21.09, + "speed": 50, + "time": 0.54, + "theta": 12.6, + "omega": 410.59, + "vx": -49.79, + "vy": 4.57, + "splineNum": 0 + }, + { + "x": 36.29, + "y": 21.2, + "speed": 50, + "time": 0.61, + "theta": 25.21, + "omega": 388.61, + "vx": -49.97, + "vy": 1.75, + "splineNum": 0 + }, + { + "x": 33.12, + "y": 21.21, + "speed": 50, + "time": 0.67, + "theta": 39.33, + "omega": 366.45, + "vx": -50, + "vy": 0.1, + "splineNum": 0 + }, + { + "x": 29.94, + "y": 21.18, + "speed": 50, + "time": 0.73, + "theta": 54.91, + "omega": 344.22, + "vx": -50, + "vy": -0.41, + "splineNum": 0 + }, + { + "x": 26.77, + "y": 21.2, + "speed": 50, + "time": 0.8, + "theta": 71.84, + "omega": 322.06, + "vx": -50, + "vy": 0.2, + "splineNum": 0 + }, + { + "x": 23.63, + "y": 21.32, + "speed": 50, + "time": 0.86, + "theta": 90, + "omega": 300.11, + "vx": -49.96, + "vy": 1.96, + "splineNum": 0 + }, + { + "x": 20.25, + "y": 21.46, + "speed": 50, + "time": 0.93, + "theta": 90.97, + "omega": 28.67, + "vx": -49.96, + "vy": 2.06, + "splineNum": 1 + }, + { + "x": 16.87, + "y": 21.5, + "speed": 50, + "time": 0.99, + "theta": 93.88, + "omega": 57.38, + "vx": -50, + "vy": 0.6, + "splineNum": 1 + }, + { + "x": 13.49, + "y": 21.53, + "speed": 50, + "time": 1.06, + "theta": 98.74, + "omega": 86.1, + "vx": -50, + "vy": 0.4, + "splineNum": 1 + }, + { + "x": 10.11, + "y": 21.63, + "speed": 50, + "time": 1.13, + "theta": 105.53, + "omega": 114.79, + "vx": -49.98, + "vy": 1.49, + "splineNum": 1 + }, + { + "x": 6.74, + "y": 21.89, + "speed": 44.01, + "time": 1.21, + "theta": 115.58, + "omega": 349.28, + "vx": -43.88, + "vy": 3.39, + "splineNum": 1 + }, + { + "x": 3.4, + "y": 22.39, + "speed": 35.5, + "time": 1.3, + "theta": 131.55, + "omega": 308.84, + "vx": -35.1, + "vy": 5.3, + "splineNum": 1 + }, + { + "x": 0.08, + "y": 23.23, + "speed": 23.99, + "time": 1.44, + "theta": 162.65, + "omega": 248.31, + "vx": -23.26, + "vy": 5.87, + "splineNum": 1 + }, + { + "x": 0.08, + "y": 23.23, + "speed": 23.99, + "time": 1.44, + "theta": 162.65, + "omega": 248.31, + "vx": -16, + "vy": 0, + "splineNum": 1 + }, + { + "x": -1.66, + "y": 23.94, + "speed": 28.6, + "time": 1.51, + "theta": 161.2, + "omega": -44.18, + "vx": -26.48, + "vy": 10.8, + "splineNum": 2 + }, + { + "x": -3.1, + "y": 24.87, + "speed": 24.52, + "time": 1.58, + "theta": 156.47, + "omega": -91.03, + "vx": -20.56, + "vy": 13.36, + "splineNum": 2 + }, + { + "x": -4.25, + "y": 26.01, + "speed": 23.95, + "time": 1.65, + "theta": 148.79, + "omega": -136.37, + "vx": -17.02, + "vy": 16.85, + "splineNum": 2 + }, + { + "x": -5.14, + "y": 27.34, + "speed": 26.58, + "time": 1.71, + "theta": 139.39, + "omega": -447.76, + "vx": -14.76, + "vy": 22.1, + "splineNum": 2 + }, + { + "x": -5.78, + "y": 28.84, + "speed": 32.14, + "time": 1.76, + "theta": 129.54, + "omega": -413.65, + "vx": -12.7, + "vy": 29.53, + "splineNum": 2 + }, + { + "x": -6.21, + "y": 30.5, + "speed": 27.8, + "time": 1.82, + "theta": 115.28, + "omega": -372.33, + "vx": -6.93, + "vy": 26.92, + "splineNum": 2 + }, + { + "x": -6.44, + "y": 32.3, + "speed": 20.25, + "time": 1.91, + "theta": 90, + "omega": -312.22, + "vx": -2.57, + "vy": 20.08, + "splineNum": 2 + }, + { + "x": -6.44, + "y": 32.3, + "speed": 20.25, + "time": 1.91, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 3 + }, + { + "x": -6.54, + "y": 35.97, + "speed": 33.83, + "time": 2.02, + "theta": 90, + "omega": 0, + "vx": -0.96, + "vy": 33.82, + "splineNum": 3 + }, + { + "x": -6.36, + "y": 39.62, + "speed": 43.31, + "time": 2.1, + "theta": 90, + "omega": 0, + "vx": 2.2, + "vy": 43.25, + "splineNum": 3 + }, + { + "x": -5.97, + "y": 43.26, + "speed": 50, + "time": 2.18, + "theta": 90, + "omega": 0, + "vx": 5.37, + "vy": 49.71, + "splineNum": 3 + }, + { + "x": -5.45, + "y": 46.88, + "speed": 50, + "time": 2.25, + "theta": 90, + "omega": 0, + "vx": 7.05, + "vy": 49.5, + "splineNum": 3 + }, + { + "x": -4.89, + "y": 50.5, + "speed": 50, + "time": 2.32, + "theta": 90, + "omega": 0, + "vx": 7.61, + "vy": 49.42, + "splineNum": 3 + }, + { + "x": -4.38, + "y": 54.12, + "speed": 50, + "time": 2.39, + "theta": 90, + "omega": 0, + "vx": 7.06, + "vy": 49.5, + "splineNum": 3 + }, + { + "x": -3.98, + "y": 57.76, + "speed": 43.19, + "time": 2.48, + "theta": 90, + "omega": 0, + "vx": 4.64, + "vy": 42.94, + "splineNum": 3 + }, + { + "x": -3.8, + "y": 61.41, + "speed": 33.69, + "time": 2.59, + "theta": 90, + "omega": 0, + "vx": 1.72, + "vy": 33.64, + "splineNum": 3 + }, + { + "x": -3.9, + "y": 65.08, + "speed": 20, + "time": 2.77, + "theta": 90, + "omega": 0, + "vx": -0.56, + "vy": 19.99, + "splineNum": 3 + } + ] + }, + { + "name": "V2-BackUp", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": 90, + "spline_angle": 93.98, + "x": 0.56, + "y": 65.71, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": 0, + "angle": 90, + "spline_angle": 93.27, + "x": 0.72, + "y": 42.16, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": 0.56, + "y": 65.71, + "speed": 0, + "time": 0, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 0.72, + "y": 62.35, + "speed": 25.95, + "time": 0.13, + "theta": 90, + "omega": 0, + "vx": 1.21, + "vy": -25.92, + "splineNum": 0 + }, + { + "x": 0.75, + "y": 58.98, + "speed": 36.69, + "time": 0.22, + "theta": 90, + "omega": 0, + "vx": 0.38, + "vy": -36.69, + "splineNum": 0 + }, + { + "x": 0.71, + "y": 55.62, + "speed": 44.94, + "time": 0.3, + "theta": 90, + "omega": 0, + "vx": -0.55, + "vy": -44.93, + "splineNum": 0 + }, + { + "x": 0.64, + "y": 52.25, + "speed": 50, + "time": 0.36, + "theta": 90, + "omega": 0, + "vx": -1.04, + "vy": -49.99, + "splineNum": 0 + }, + { + "x": 0.59, + "y": 48.89, + "speed": 50, + "time": 0.43, + "theta": 90, + "omega": 0, + "vx": -0.79, + "vy": -49.99, + "splineNum": 0 + }, + { + "x": 0.6, + "y": 45.52, + "speed": 50, + "time": 0.5, + "theta": 90, + "omega": 0, + "vx": 0.16, + "vy": -50, + "splineNum": 0 + }, + { + "x": 0.72, + "y": 42.16, + "speed": 50, + "time": 0.57, + "theta": 90, + "omega": 0, + "vx": 1.8, + "vy": -49.97, + "splineNum": 0 + } + ] + }, + { + "name": "V2-Forward", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": 90, + "spline_angle": 85.97, + "x": 0.88, + "y": 55.69, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": 0, + "angle": 90, + "spline_angle": -91.3, + "x": 1.03, + "y": 70.64, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": 0.88, + "y": 55.69, + "speed": 0, + "time": 0, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 0.99, + "y": 57.82, + "speed": 20.68, + "time": 0.1, + "theta": 90, + "omega": 0, + "vx": 1.09, + "vy": 20.65, + "splineNum": 0 + }, + { + "x": 1.04, + "y": 59.96, + "speed": 29.24, + "time": 0.18, + "theta": 90, + "omega": 0, + "vx": 0.69, + "vy": 29.23, + "splineNum": 0 + }, + { + "x": 1.05, + "y": 62.1, + "speed": 35.8, + "time": 0.24, + "theta": 90, + "omega": 0, + "vx": 0.12, + "vy": 35.8, + "splineNum": 0 + }, + { + "x": 1.03, + "y": 64.23, + "speed": 41.34, + "time": 0.29, + "theta": 90, + "omega": 0, + "vx": -0.32, + "vy": 41.34, + "splineNum": 0 + }, + { + "x": 1.01, + "y": 66.37, + "speed": 46.22, + "time": 0.33, + "theta": 90, + "omega": 0, + "vx": -0.47, + "vy": 46.22, + "splineNum": 0 + }, + { + "x": 1, + "y": 68.5, + "speed": 50, + "time": 0.38, + "theta": 90, + "omega": 0, + "vx": -0.18, + "vy": 50, + "splineNum": 0 + }, + { + "x": 1.03, + "y": 70.64, + "speed": 50, + "time": 0.42, + "theta": 90, + "omega": 0, + "vx": 0.6, + "vy": 50, + "splineNum": 0 + } + ] + } + ] +} \ No newline at end of file diff --git a/paths/programming-skills_06-26_03-00AM.json b/paths/programming-skills_06-26_03-00AM.json new file mode 100644 index 00000000..86f130eb --- /dev/null +++ b/paths/programming-skills_06-26_03-00AM.json @@ -0,0 +1,13409 @@ +{ + "sharedWaypoints": [ + { + "name": "Goal1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -55.25, + "y": 16.43, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal2", + "omega": 0, + "angle": 180, + "spline_angle": -180, + "x": -57.68, + "y": 71.76, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal3", + "omega": 0, + "angle": 135, + "spline_angle": 105, + "x": -59.75, + "y": 131.9, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal6", + "omega": 0, + "angle": 90, + "spline_angle": 80.85, + "x": 0.24, + "y": 128.08, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal9", + "omega": 0, + "angle": 45, + "spline_angle": 26.49, + "x": 58.79, + "y": 129.99, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal8", + "omega": 0, + "angle": 0, + "spline_angle": 163.67, + "x": 57.04, + "y": 71.76, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal7", + "omega": 0, + "angle": -45, + "spline_angle": 113.16, + "x": 62.36, + "y": 14.38, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal5", + "omega": 0, + "angle": 90, + "spline_angle": 89.98, + "x": 0.24, + "y": 60.94, + "shared": true, + "speed": 41.9 + }, + { + "name": "Deploy4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": 0, + "y": 24.12, + "shared": true, + "speed": 41.9 + }, + { + "name": "Deploy1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -52.32, + "y": 18.69, + "shared": true, + "speed": 41.9 + }, + { + "name": "DeployWall1", + "omega": 0, + "angle": 90, + "spline_angle": 88.38, + "x": -36.52, + "y": 9.85, + "shared": true, + "speed": 41.9 + }, + { + "name": "DeployWall2", + "omega": 0, + "angle": -90, + "spline_angle": 90, + "x": -12.17, + "y": 14.16, + "shared": true, + "speed": 41.9 + } + ], + "robot": { + "robotName": "", + "robotWidth": "", + "robotLength": "", + "savedIsTank": false + }, + "paths": [ + { + "name": "StartToGoal1", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "startWaypoint", + "omega": 0, + "angle": 150, + "spline_angle": 150, + "x": -16.15, + "y": 16.07, + "shared": false, + "speed": 0 + }, + { + "name": "endWaypoint", + "omega": 0, + "angle": 180, + "spline_angle": 180, + "x": -27.92, + "y": 23.55, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -135, + "spline_angle": 21.77, + "x": -48.13, + "y": 21, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -55.25, + "y": 16.43, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -16.15, + "y": 16.07, + "speed": 0, + "time": 0, + "theta": 150, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -17.78, + "y": 17.22, + "speed": 19.97, + "time": 0.1, + "theta": 151.16, + "omega": 23.14, + "vx": -16.34, + "vy": 11.48, + "splineNum": 0 + }, + { + "x": -19.28, + "y": 18.57, + "speed": 28.34, + "time": 0.17, + "theta": 153.39, + "omega": 39.66, + "vx": -21.04, + "vy": 18.98, + "splineNum": 0 + }, + { + "x": -20.74, + "y": 19.99, + "speed": 34.79, + "time": 0.23, + "theta": 156.11, + "omega": 53.21, + "vx": -24.92, + "vy": 24.28, + "splineNum": 0 + }, + { + "x": -22.24, + "y": 21.34, + "speed": 35.25, + "time": 0.29, + "theta": 159.54, + "omega": 169.32, + "vx": -26.25, + "vy": 23.53, + "splineNum": 0 + }, + { + "x": -23.88, + "y": 22.47, + "speed": 29.05, + "time": 0.36, + "theta": 164.65, + "omega": 153.42, + "vx": -23.88, + "vy": 16.55, + "splineNum": 0 + }, + { + "x": -25.75, + "y": 23.26, + "speed": 23.95, + "time": 0.44, + "theta": 172.42, + "omega": 133.88, + "vx": -22.08, + "vy": 9.29, + "splineNum": 0 + }, + { + "x": -27.92, + "y": 23.55, + "speed": 31.82, + "time": 0.51, + "theta": 180, + "omega": 117.9, + "vx": -31.54, + "vy": 4.24, + "splineNum": 0 + }, + { + "x": -27.92, + "y": 23.55, + "speed": 31.82, + "time": 0.51, + "theta": 180, + "omega": 117.9, + "vx": 31.82, + "vy": 0, + "splineNum": 0 + }, + { + "x": -30.85, + "y": 23.55, + "speed": 39.99, + "time": 0.58, + "theta": 181.24, + "omega": 33.76, + "vx": -39.99, + "vy": -0.06, + "splineNum": 1 + }, + { + "x": -33.78, + "y": 23.5, + "speed": 46.74, + "time": 0.64, + "theta": 184.26, + "omega": 62.6, + "vx": -46.74, + "vy": -0.73, + "splineNum": 1 + }, + { + "x": -36.7, + "y": 23.37, + "speed": 50, + "time": 0.7, + "theta": 188.7, + "omega": 89.48, + "vx": -49.95, + "vy": -2.29, + "splineNum": 1 + }, + { + "x": -39.6, + "y": 23.1, + "speed": 50, + "time": 0.76, + "theta": 194.69, + "omega": 290.83, + "vx": -49.79, + "vy": -4.63, + "splineNum": 1 + }, + { + "x": -42.47, + "y": 22.64, + "speed": 50, + "time": 0.82, + "theta": 202.24, + "omega": 264.02, + "vx": -49.39, + "vy": -7.77, + "splineNum": 1 + }, + { + "x": -45.32, + "y": 21.96, + "speed": 48.48, + "time": 0.88, + "theta": 211.72, + "omega": 236.21, + "vx": -47.14, + "vy": -11.31, + "splineNum": 1 + }, + { + "x": -48.13, + "y": 21, + "speed": 41.9, + "time": 0.95, + "theta": 225, + "omega": 203.56, + "vx": -39.65, + "vy": -13.54, + "splineNum": 1 + }, + { + "x": -48.13, + "y": 21, + "speed": 41.9, + "time": 0.95, + "theta": 225, + "omega": 203.56, + "vx": -32, + "vy": -16, + "splineNum": 1 + }, + { + "x": -49.26, + "y": 20.52, + "speed": 44.73, + "time": 0.98, + "theta": -135, + "omega": 0, + "vx": -41.13, + "vy": -17.57, + "splineNum": 2 + }, + { + "x": -50.35, + "y": 19.99, + "speed": 47.37, + "time": 1, + "theta": -135, + "omega": 0, + "vx": -42.58, + "vy": -20.76, + "splineNum": 2 + }, + { + "x": -51.41, + "y": 19.4, + "speed": 49.86, + "time": 1.03, + "theta": -135, + "omega": 0, + "vx": -43.58, + "vy": -24.23, + "splineNum": 2 + }, + { + "x": -52.43, + "y": 18.75, + "speed": 49.87, + "time": 1.05, + "theta": -135, + "omega": 0, + "vx": -42.13, + "vy": -26.68, + "splineNum": 2 + }, + { + "x": -53.41, + "y": 18.04, + "speed": 47.38, + "time": 1.08, + "theta": -135, + "omega": 0, + "vx": -38.43, + "vy": -27.71, + "splineNum": 2 + }, + { + "x": -54.35, + "y": 17.27, + "speed": 44.74, + "time": 1.11, + "theta": -135, + "omega": 0, + "vx": -34.57, + "vy": -28.39, + "splineNum": 2 + }, + { + "x": -55.25, + "y": 16.43, + "speed": 41.9, + "time": 1.13, + "theta": -135, + "omega": 0, + "vx": -30.59, + "vy": -28.64, + "splineNum": 2 + } + ] + }, + { + "name": "Goal1ToGoal2", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal1", + "omega": 183.36749403282326, + "angle": -135, + "spline_angle": -135, + "x": -55.25, + "y": 16.43, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 183.36749403282326, + "angle": -66.51, + "spline_angle": 8.94, + "x": -53.34, + "y": 16.14, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 183.36749403282326, + "angle": -122.24, + "spline_angle": 78.63, + "x": -47.4, + "y": 20.39, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 183.36749403282326, + "angle": 165, + "spline_angle": 118.84, + "x": -51.31, + "y": 33.41, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 183.36749403282326, + "angle": 180, + "spline_angle": 85, + "x": -58.27, + "y": 40.6, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 183.36749403282326, + "angle": 90, + "spline_angle": 53.01, + "x": -44.51, + "y": 48.25, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 183.36749403282326, + "angle": 127.94, + "spline_angle": 116.52, + "x": -42.64, + "y": 65.4, + "shared": false, + "speed": 50 + }, + { + "name": "Goal2", + "omega": 183.36749403282326, + "angle": 180, + "spline_angle": -180, + "x": -59.97, + "y": 69.82, + "shared": true, + "speed": 50 + } + ], + "points": [ + { + "x": -55.25, + "y": 16.43, + "speed": 9, + "time": 0, + "theta": -135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -54.94, + "y": 16.65, + "speed": 2.14, + "time": 0.18, + "theta": -129.67, + "omega": 59.61, + "vx": 1.75, + "vy": 1.23, + "splineNum": 0 + }, + { + "x": -54.65, + "y": 16.69, + "speed": 1.92, + "time": 0.33, + "theta": -116.99, + "omega": 317.7, + "vx": 1.9, + "vy": 0.27, + "splineNum": 0 + }, + { + "x": -54.39, + "y": 16.61, + "speed": 3.75, + "time": 0.4, + "theta": -107.9, + "omega": 292.87, + "vx": 3.57, + "vy": -1.14, + "splineNum": 0 + }, + { + "x": -54.13, + "y": 16.45, + "speed": 8.59, + "time": 0.44, + "theta": -103.03, + "omega": 281.29, + "vx": 7.36, + "vy": -4.41, + "splineNum": 0 + }, + { + "x": -53.88, + "y": 16.29, + "speed": 6.39, + "time": 0.49, + "theta": -95.72, + "omega": 265.47, + "vx": 5.35, + "vy": -3.49, + "splineNum": 0 + }, + { + "x": -53.62, + "y": 16.16, + "speed": 2.39, + "time": 0.61, + "theta": -73.86, + "omega": 225.41, + "vx": 2.17, + "vy": -1.02, + "splineNum": 0 + }, + { + "x": -53.34, + "y": 16.14, + "speed": 7.81, + "time": 0.64, + "theta": -66.51, + "omega": 213.62, + "vx": 7.79, + "vy": -0.66, + "splineNum": 0 + }, + { + "x": -53.34, + "y": 16.14, + "speed": 7.81, + "time": 0.64, + "theta": -66.51, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": -52.2, + "y": 16.34, + "speed": 17.11, + "time": 0.71, + "theta": -66.89, + "omega": -11.09, + "vx": 16.86, + "vy": 2.91, + "splineNum": 1 + }, + { + "x": -51.1, + "y": 16.6, + "speed": 22.77, + "time": 0.76, + "theta": -67.64, + "omega": -19.2, + "vx": 22.16, + "vy": 5.23, + "splineNum": 1 + }, + { + "x": -50.08, + "y": 16.96, + "speed": 18.67, + "time": 0.82, + "theta": -69.03, + "omega": -28.72, + "vx": 17.57, + "vy": 6.29, + "splineNum": 1 + }, + { + "x": -49.17, + "y": 17.48, + "speed": 13.7, + "time": 0.89, + "theta": -71.71, + "omega": -41.26, + "vx": 11.92, + "vy": 6.75, + "splineNum": 1 + }, + { + "x": -48.39, + "y": 18.19, + "speed": 12.41, + "time": 0.98, + "theta": -75.79, + "omega": -55.14, + "vx": 9.11, + "vy": 8.42, + "splineNum": 1 + }, + { + "x": -47.79, + "y": 19.15, + "speed": 14.47, + "time": 1.06, + "theta": -80.59, + "omega": -202.3, + "vx": 7.69, + "vy": 12.25, + "splineNum": 1 + }, + { + "x": -47.4, + "y": 20.39, + "speed": 3.18, + "time": 1.47, + "theta": -122.24, + "omega": -135.1, + "vx": 0.96, + "vy": 3.03, + "splineNum": 1 + }, + { + "x": -47.4, + "y": 20.39, + "speed": 3.18, + "time": 1.47, + "theta": -122.24, + "omega": -135.1, + "vx": 0, + "vy": 3.2, + "splineNum": 1 + }, + { + "x": -47.18, + "y": 22.48, + "speed": 20.76, + "time": 1.57, + "theta": -125.41, + "omega": -62.49, + "vx": 2.17, + "vy": 20.65, + "splineNum": 2 + }, + { + "x": -47.34, + "y": 24.46, + "speed": 28.78, + "time": 1.64, + "theta": -131.19, + "omega": -105.03, + "vx": -2.33, + "vy": 28.69, + "splineNum": 2 + }, + { + "x": -47.81, + "y": 26.35, + "speed": 34.89, + "time": 1.69, + "theta": -138, + "omega": -139.38, + "vx": -8.41, + "vy": 33.86, + "splineNum": 2 + }, + { + "x": -48.51, + "y": 28.17, + "speed": 40.08, + "time": 1.74, + "theta": -145.5, + "omega": -429.65, + "vx": -14.48, + "vy": 37.38, + "splineNum": 2 + }, + { + "x": -49.38, + "y": 29.93, + "speed": 35.88, + "time": 1.8, + "theta": -155.72, + "omega": -395.83, + "vx": -15.79, + "vy": 32.21, + "splineNum": 2 + }, + { + "x": -50.34, + "y": 31.67, + "speed": 29.83, + "time": 1.86, + "theta": -170.61, + "omega": -354.8, + "vx": -14.36, + "vy": 26.14, + "splineNum": 2 + }, + { + "x": -51.31, + "y": 33.41, + "speed": 22.18, + "time": 1.95, + "theta": -195, + "omega": -299.49, + "vx": -10.85, + "vy": 19.34, + "splineNum": 2 + }, + { + "x": -51.31, + "y": 33.41, + "speed": 22.18, + "time": 1.95, + "theta": -195, + "omega": -299.49, + "vx": -32, + "vy": 0, + "splineNum": 2 + }, + { + "x": -52.24, + "y": 34.5, + "speed": 14.33, + "time": 2.05, + "theta": 165.18, + "omega": 3.56, + "vx": -9.35, + "vy": 10.87, + "splineNum": 3 + }, + { + "x": -53.5, + "y": 35.27, + "speed": 22.37, + "time": 2.12, + "theta": 165.49, + "omega": 5.91, + "vx": -19.01, + "vy": 11.79, + "splineNum": 3 + }, + { + "x": -54.89, + "y": 35.91, + "speed": 26.91, + "time": 2.17, + "theta": 165.89, + "omega": 7.95, + "vx": -24.44, + "vy": 11.26, + "splineNum": 3 + }, + { + "x": -56.24, + "y": 36.59, + "speed": 20.53, + "time": 2.25, + "theta": 166.57, + "omega": 10.58, + "vx": -18.34, + "vy": 9.22, + "splineNum": 3 + }, + { + "x": -57.38, + "y": 37.49, + "speed": 11.53, + "time": 2.37, + "theta": 168.17, + "omega": 15.04, + "vx": -9.06, + "vy": 7.13, + "splineNum": 3 + }, + { + "x": -58.11, + "y": 38.76, + "speed": 11.49, + "time": 2.5, + "theta": 170.39, + "omega": 45.81, + "vx": -5.74, + "vy": 9.96, + "splineNum": 3 + }, + { + "x": -58.27, + "y": 40.6, + "speed": 5.02, + "time": 2.87, + "theta": 180, + "omega": 32.71, + "vx": -0.43, + "vy": 5, + "splineNum": 3 + }, + { + "x": -58.27, + "y": 40.6, + "speed": 5.02, + "time": 2.87, + "theta": 180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 4 + }, + { + "x": -57.43, + "y": 43.72, + "speed": 16.48, + "time": 3.07, + "theta": 175.15, + "omega": -49.51, + "vx": 4.27, + "vy": 15.92, + "splineNum": 4 + }, + { + "x": -55.79, + "y": 45.4, + "speed": 14.35, + "time": 3.23, + "theta": 163.69, + "omega": -90.76, + "vx": 10.05, + "vy": 10.24, + "splineNum": 4 + }, + { + "x": -53.6, + "y": 46.08, + "speed": 25.79, + "time": 3.32, + "theta": 154.61, + "omega": -313.12, + "vx": 24.6, + "vy": 7.74, + "splineNum": 4 + }, + { + "x": -51.12, + "y": 46.25, + "speed": 34.09, + "time": 3.39, + "theta": 145.68, + "omega": -294.71, + "vx": 34.02, + "vy": 2.3, + "splineNum": 4 + }, + { + "x": -48.61, + "y": 46.36, + "speed": 27.03, + "time": 3.48, + "theta": 132.34, + "omega": -271.22, + "vx": 27.01, + "vy": 1.16, + "splineNum": 4 + }, + { + "x": -46.32, + "y": 46.87, + "speed": 16.18, + "time": 3.63, + "theta": 107.19, + "omega": -234.62, + "vx": 15.79, + "vy": 3.53, + "splineNum": 4 + }, + { + "x": -44.51, + "y": 48.25, + "speed": 26.76, + "time": 3.71, + "theta": 90, + "omega": -213.18, + "vx": 21.28, + "vy": 16.23, + "splineNum": 4 + }, + { + "x": -44.51, + "y": 48.25, + "speed": 26.76, + "time": 3.71, + "theta": 90, + "omega": -213.18, + "vx": 16, + "vy": 16, + "splineNum": 4 + }, + { + "x": -42.98, + "y": 50.56, + "speed": 35.65, + "time": 3.79, + "theta": 90.29, + "omega": 7.39, + "vx": 19.69, + "vy": 29.72, + "splineNum": 5 + }, + { + "x": -41.84, + "y": 52.92, + "speed": 42.35, + "time": 3.85, + "theta": 90.92, + "omega": 13.25, + "vx": 18.37, + "vy": 38.16, + "splineNum": 5 + }, + { + "x": -41.12, + "y": 55.32, + "speed": 43.43, + "time": 3.91, + "theta": 91.85, + "omega": 18.74, + "vx": 12.51, + "vy": 41.59, + "splineNum": 5 + }, + { + "x": -40.83, + "y": 57.76, + "speed": 40.28, + "time": 3.97, + "theta": 93.17, + "omega": 24.55, + "vx": 4.83, + "vy": 39.99, + "splineNum": 5 + }, + { + "x": -40.97, + "y": 60.26, + "speed": 33.5, + "time": 4.05, + "theta": 95.27, + "omega": 31.64, + "vx": -1.94, + "vy": 33.45, + "splineNum": 5 + }, + { + "x": -41.57, + "y": 62.8, + "speed": 24.49, + "time": 4.15, + "theta": 99.19, + "omega": 41.78, + "vx": -5.62, + "vy": 23.84, + "splineNum": 5 + }, + { + "x": -42.64, + "y": 65.4, + "speed": 6.18, + "time": 4.61, + "theta": 127.94, + "omega": 84.9, + "vx": -2.35, + "vy": 5.72, + "splineNum": 5 + }, + { + "x": -42.64, + "y": 65.4, + "speed": 6.18, + "time": 4.61, + "theta": 127.94, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 6 + }, + { + "x": -44.56, + "y": 68.21, + "speed": 26.82, + "time": 4.73, + "theta": 130.54, + "omega": 41.01, + "vx": -15.11, + "vy": 22.16, + "splineNum": 6 + }, + { + "x": -46.78, + "y": 69.84, + "speed": 23.04, + "time": 4.85, + "theta": 137.76, + "omega": 79.62, + "vx": -18.57, + "vy": 13.64, + "splineNum": 6 + }, + { + "x": -49.23, + "y": 70.57, + "speed": 30.69, + "time": 4.94, + "theta": 145.51, + "omega": 260.22, + "vx": -29.45, + "vy": 8.65, + "splineNum": 6 + }, + { + "x": -51.85, + "y": 70.65, + "speed": 38.28, + "time": 5.01, + "theta": 153.54, + "omega": 238.14, + "vx": -38.26, + "vy": 1.23, + "splineNum": 6 + }, + { + "x": -54.56, + "y": 70.37, + "speed": 44.83, + "time": 5.07, + "theta": 161.95, + "omega": 218.53, + "vx": -44.6, + "vy": -4.59, + "splineNum": 6 + }, + { + "x": -57.29, + "y": 70, + "speed": 50, + "time": 5.12, + "theta": 170.6, + "omega": 200.74, + "vx": -49.55, + "vy": -6.67, + "splineNum": 6 + }, + { + "x": -59.97, + "y": 69.82, + "speed": 50, + "time": 5.18, + "theta": 180, + "omega": 183.37, + "vx": -49.88, + "vy": -3.41, + "splineNum": 6 + } + ] + }, + { + "name": "Goal2ToGoal3", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "wp", + "omega": 16.774945496374254, + "angle": 180, + "spline_angle": 0, + "x": -54.19, + "y": 70.33, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 16.774945496374254, + "angle": -178.65, + "spline_angle": 170.5, + "x": -46.72, + "y": 69.48, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 16.774945496374254, + "angle": -179.15, + "spline_angle": 110.58, + "x": -38.39, + "y": 55.55, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 16.774945496374254, + "angle": 90.04, + "spline_angle": 64.31, + "x": -22.59, + "y": 55.72, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 16.774945496374254, + "angle": 165, + "spline_angle": -36.35, + "x": -33.98, + "y": 82.22, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 16.774945496374254, + "angle": 152.91, + "spline_angle": 129.8, + "x": -62.35, + "y": 91.4, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 16.774945496374254, + "angle": 151.29, + "spline_angle": 85.69, + "x": -63.71, + "y": 104.65, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 16.774945496374254, + "angle": 133.32, + "spline_angle": 122.12, + "x": -57.08, + "y": 122.82, + "shared": false, + "speed": 50 + }, + { + "name": "Goal3", + "omega": 16.774945496374254, + "angle": 135, + "spline_angle": 139.62, + "x": -60.65, + "y": 127.92, + "shared": true, + "speed": 50 + } + ], + "points": [ + { + "x": -54.19, + "y": 70.33, + "speed": 41.74, + "time": 0, + "theta": 180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -53.11, + "y": 70.3, + "speed": 39.07, + "time": 0.03, + "theta": 180.01, + "omega": 0.9, + "vx": 39.06, + "vy": -0.92, + "splineNum": 0 + }, + { + "x": -52.04, + "y": 70.23, + "speed": 36.22, + "time": 0.06, + "theta": 180.05, + "omega": 1.87, + "vx": 36.14, + "vy": -2.38, + "splineNum": 0 + }, + { + "x": -50.97, + "y": 70.13, + "speed": 33.12, + "time": 0.09, + "theta": 180.13, + "omega": 2.92, + "vx": 32.95, + "vy": -3.33, + "splineNum": 0 + }, + { + "x": -49.91, + "y": 69.99, + "speed": 29.7, + "time": 0.13, + "theta": 180.26, + "omega": 4.1, + "vx": 29.45, + "vy": -3.8, + "splineNum": 0 + }, + { + "x": -48.84, + "y": 69.83, + "speed": 25.83, + "time": 0.17, + "theta": 180.46, + "omega": 13.3, + "vx": 25.54, + "vy": -3.82, + "splineNum": 0 + }, + { + "x": -47.78, + "y": 69.66, + "speed": 21.26, + "time": 0.22, + "theta": 180.77, + "omega": 11.65, + "vx": 20.98, + "vy": -3.4, + "splineNum": 0 + }, + { + "x": -46.72, + "y": 69.48, + "speed": 15.39, + "time": 0.29, + "theta": 181.35, + "omega": 9.38, + "vx": 15.18, + "vy": -2.54, + "splineNum": 0 + }, + { + "x": -46.72, + "y": 69.48, + "speed": 15.39, + "time": 0.29, + "theta": -178.65, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": -43.77, + "y": 68.54, + "speed": 23.72, + "time": 0.42, + "theta": -178.67, + "omega": -0.28, + "vx": 22.61, + "vy": -7.16, + "splineNum": 1 + }, + { + "x": -41.8, + "y": 67.02, + "speed": 20.21, + "time": 0.54, + "theta": -178.72, + "omega": -0.55, + "vx": 15.94, + "vy": -12.42, + "splineNum": 1 + }, + { + "x": -40.59, + "y": 65.04, + "speed": 28.29, + "time": 0.62, + "theta": -178.77, + "omega": -0.73, + "vx": 14.79, + "vy": -24.11, + "splineNum": 1 + }, + { + "x": -39.89, + "y": 62.76, + "speed": 35.74, + "time": 0.69, + "theta": -178.83, + "omega": -2.07, + "vx": 10.57, + "vy": -34.14, + "splineNum": 1 + }, + { + "x": -39.45, + "y": 60.32, + "speed": 36.74, + "time": 0.76, + "theta": -178.89, + "omega": -1.93, + "vx": 6.53, + "vy": -36.15, + "splineNum": 1 + }, + { + "x": -39.03, + "y": 57.87, + "speed": 29.2, + "time": 0.84, + "theta": -178.98, + "omega": -1.74, + "vx": 4.91, + "vy": -28.78, + "splineNum": 1 + }, + { + "x": -38.39, + "y": 55.55, + "speed": 19.27, + "time": 0.97, + "theta": -179.15, + "omega": -1.47, + "vx": 5.11, + "vy": -18.58, + "splineNum": 1 + }, + { + "x": -38.39, + "y": 55.55, + "speed": 19.27, + "time": 0.97, + "theta": -179.15, + "omega": -1.47, + "vx": -19.27, + "vy": 0, + "splineNum": 1 + }, + { + "x": -36.92, + "y": 52.06, + "speed": 33.61, + "time": 1.08, + "theta": -180.22, + "omega": -19.02, + "vx": 13.07, + "vy": -30.96, + "splineNum": 2 + }, + { + "x": -35.45, + "y": 49.42, + "speed": 31.55, + "time": 1.18, + "theta": -182.81, + "omega": -35.13, + "vx": 15.33, + "vy": -27.57, + "splineNum": 2 + }, + { + "x": -33.99, + "y": 47.59, + "speed": 22.97, + "time": 1.28, + "theta": -187.26, + "omega": -52.3, + "vx": 14.31, + "vy": -17.97, + "splineNum": 2 + }, + { + "x": -32.55, + "y": 46.52, + "speed": 12.91, + "time": 1.42, + "theta": -196.21, + "omega": -75.85, + "vx": 10.37, + "vy": -7.7, + "splineNum": 2 + }, + { + "x": -31.11, + "y": 46.14, + "speed": 10.04, + "time": 1.57, + "theta": -209.3, + "omega": -249.15, + "vx": 9.72, + "vy": -2.52, + "splineNum": 2 + }, + { + "x": -29.67, + "y": 46.42, + "speed": 13.15, + "time": 1.68, + "theta": -221.53, + "omega": -230.44, + "vx": 12.92, + "vy": 2.48, + "splineNum": 2 + }, + { + "x": -28.25, + "y": 47.29, + "speed": 22.53, + "time": 1.75, + "theta": -230.87, + "omega": -217.92, + "vx": 19.22, + "vy": 11.76, + "splineNum": 2 + }, + { + "x": -26.82, + "y": 48.71, + "speed": 30.15, + "time": 1.82, + "theta": -240.04, + "omega": -206.69, + "vx": 21.34, + "vy": 21.3, + "splineNum": 2 + }, + { + "x": -25.41, + "y": 50.62, + "speed": 37.22, + "time": 1.88, + "theta": -249.55, + "omega": -195.91, + "vx": 22.15, + "vy": 29.91, + "splineNum": 2 + }, + { + "x": -24, + "y": 52.98, + "speed": 43.98, + "time": 1.94, + "theta": -259.49, + "omega": -185.39, + "vx": 22.61, + "vy": 37.72, + "splineNum": 2 + }, + { + "x": -22.59, + "y": 55.72, + "speed": 50, + "time": 2.01, + "theta": -269.96, + "omega": -174.99, + "vx": 22.82, + "vy": 44.49, + "splineNum": 2 + }, + { + "x": -21.22, + "y": 59.16, + "speed": 50, + "time": 2.08, + "theta": 90.94, + "omega": 24.28, + "vx": 18.46, + "vy": 46.47, + "splineNum": 3 + }, + { + "x": -20.54, + "y": 62.31, + "speed": 47.82, + "time": 2.15, + "theta": 93.32, + "omega": 46.36, + "vx": 10.17, + "vy": 46.73, + "splineNum": 3 + }, + { + "x": -20.47, + "y": 65.2, + "speed": 41.35, + "time": 2.22, + "theta": 97.35, + "omega": 69.23, + "vx": 1.01, + "vy": 41.34, + "splineNum": 3 + }, + { + "x": -20.94, + "y": 67.84, + "speed": 40.85, + "time": 2.28, + "theta": 102.62, + "omega": 90.82, + "vx": -7.24, + "vy": 40.21, + "splineNum": 3 + }, + { + "x": -21.9, + "y": 70.29, + "speed": 46.37, + "time": 2.34, + "theta": 108.29, + "omega": 109.36, + "vx": -16.92, + "vy": 43.17, + "splineNum": 3 + }, + { + "x": -23.27, + "y": 72.55, + "speed": 50, + "time": 2.39, + "theta": 114.54, + "omega": 316.6, + "vx": -25.89, + "vy": 42.77, + "splineNum": 3 + }, + { + "x": -24.99, + "y": 74.67, + "speed": 50, + "time": 2.45, + "theta": 121.93, + "omega": 298.73, + "vx": -31.51, + "vy": 38.82, + "splineNum": 3 + }, + { + "x": -26.99, + "y": 76.66, + "speed": 50, + "time": 2.5, + "theta": 130.62, + "omega": 280.23, + "vx": -35.36, + "vy": 35.35, + "splineNum": 3 + }, + { + "x": -29.19, + "y": 78.57, + "speed": 50, + "time": 2.56, + "theta": 140.69, + "omega": 261.11, + "vx": -37.87, + "vy": 32.65, + "splineNum": 3 + }, + { + "x": -31.55, + "y": 80.41, + "speed": 50, + "time": 2.62, + "theta": 152.17, + "omega": 241.52, + "vx": -39.37, + "vy": 30.82, + "splineNum": 3 + }, + { + "x": -33.98, + "y": 82.22, + "speed": 50, + "time": 2.68, + "theta": 165, + "omega": 221.66, + "vx": -40.12, + "vy": 29.84, + "splineNum": 3 + }, + { + "x": -37.31, + "y": 84.03, + "speed": 48.79, + "time": 2.76, + "theta": 164.84, + "omega": -4.2, + "vx": -42.89, + "vy": 23.25, + "splineNum": 4 + }, + { + "x": -40.91, + "y": 85, + "speed": 50, + "time": 2.83, + "theta": 164.37, + "omega": -8.23, + "vx": -48.26, + "vy": 13.09, + "splineNum": 4 + }, + { + "x": -44.68, + "y": 85.47, + "speed": 50, + "time": 2.91, + "theta": 163.59, + "omega": -12.33, + "vx": -49.62, + "vy": 6.17, + "splineNum": 4 + }, + { + "x": -48.51, + "y": 85.75, + "speed": 50, + "time": 2.99, + "theta": 162.49, + "omega": -16.47, + "vx": -49.87, + "vy": 3.65, + "splineNum": 4 + }, + { + "x": -52.29, + "y": 86.16, + "speed": 50, + "time": 3.06, + "theta": 161.08, + "omega": -51.69, + "vx": -49.71, + "vy": 5.41, + "splineNum": 4 + }, + { + "x": -55.93, + "y": 87.03, + "speed": 49.96, + "time": 3.14, + "theta": 159.39, + "omega": -47.65, + "vx": -48.61, + "vy": 11.56, + "splineNum": 4 + }, + { + "x": -59.32, + "y": 88.67, + "speed": 41.76, + "time": 3.23, + "theta": 156.95, + "omega": -42.78, + "vx": -37.59, + "vy": 18.18, + "splineNum": 4 + }, + { + "x": -62.35, + "y": 91.4, + "speed": 33.17, + "time": 3.35, + "theta": 152.91, + "omega": -36.14, + "vx": -24.65, + "vy": 22.2, + "splineNum": 4 + }, + { + "x": -63.52, + "y": 93.19, + "speed": 25.92, + "time": 3.43, + "theta": 152.84, + "omega": -1.62, + "vx": -14.18, + "vy": 21.7, + "splineNum": 5 + }, + { + "x": -64.18, + "y": 95.04, + "speed": 27.93, + "time": 3.5, + "theta": 152.68, + "omega": -3, + "vx": -9.35, + "vy": 26.32, + "splineNum": 5 + }, + { + "x": -64.43, + "y": 96.92, + "speed": 34.07, + "time": 3.56, + "theta": 152.48, + "omega": -11.86, + "vx": -4.53, + "vy": 33.77, + "splineNum": 5 + }, + { + "x": -64.4, + "y": 98.84, + "speed": 39.3, + "time": 3.61, + "theta": 152.26, + "omega": -10.9, + "vx": 0.71, + "vy": 39.29, + "splineNum": 5 + }, + { + "x": -64.19, + "y": 100.78, + "speed": 43.97, + "time": 3.65, + "theta": 152.02, + "omega": -10.03, + "vx": 4.7, + "vy": 43.72, + "splineNum": 5 + }, + { + "x": -63.92, + "y": 102.72, + "speed": 40.12, + "time": 3.7, + "theta": 151.7, + "omega": -9.07, + "vx": 5.46, + "vy": 39.74, + "splineNum": 5 + }, + { + "x": -63.71, + "y": 104.65, + "speed": 34.93, + "time": 3.76, + "theta": 151.29, + "omega": -7.98, + "vx": 3.79, + "vy": 34.73, + "splineNum": 5 + }, + { + "x": -63.71, + "y": 104.65, + "speed": 34.93, + "time": 3.76, + "theta": 151.29, + "omega": -7.98, + "vx": -34.93, + "vy": 0, + "splineNum": 5 + }, + { + "x": -62.89, + "y": 107.29, + "speed": 25.83, + "time": 3.86, + "theta": 150.91, + "omega": -7.09, + "vx": 7.65, + "vy": 24.67, + "splineNum": 6 + }, + { + "x": -61.2, + "y": 109.62, + "speed": 35.24, + "time": 3.95, + "theta": 150.11, + "omega": -12.49, + "vx": 20.75, + "vy": 28.48, + "splineNum": 6 + }, + { + "x": -59.13, + "y": 111.8, + "speed": 39.49, + "time": 4.02, + "theta": 148.97, + "omega": -17.53, + "vx": 27.14, + "vy": 28.69, + "splineNum": 6 + }, + { + "x": -57.18, + "y": 114.03, + "speed": 31.1, + "time": 4.12, + "theta": 147, + "omega": -23.83, + "vx": 20.43, + "vy": 23.45, + "splineNum": 6 + }, + { + "x": -55.86, + "y": 116.49, + "speed": 20.23, + "time": 4.26, + "theta": 143.08, + "omega": -64.58, + "vx": 9.58, + "vy": 17.81, + "splineNum": 6 + }, + { + "x": -55.66, + "y": 119.36, + "speed": 21.8, + "time": 4.39, + "theta": 138.16, + "omega": -55.85, + "vx": 1.53, + "vy": 21.75, + "splineNum": 6 + }, + { + "x": -57.08, + "y": 122.82, + "speed": 34.97, + "time": 4.49, + "theta": 133.32, + "omega": -48.77, + "vx": -13.27, + "vy": 32.36, + "splineNum": 6 + }, + { + "x": -57.08, + "y": 122.82, + "speed": 34.97, + "time": 4.49, + "theta": 133.32, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 7 + }, + { + "x": -57.54, + "y": 123.58, + "speed": 37.43, + "time": 4.52, + "theta": 133.34, + "omega": 1.99, + "vx": -19.31, + "vy": 32.07, + "splineNum": 7 + }, + { + "x": -57.99, + "y": 124.36, + "speed": 36.79, + "time": 4.54, + "theta": 133.42, + "omega": 4.03, + "vx": -18.35, + "vy": 31.89, + "splineNum": 7 + }, + { + "x": -58.43, + "y": 125.13, + "speed": 34.28, + "time": 4.57, + "theta": 133.55, + "omega": 6.21, + "vx": -17.26, + "vy": 29.62, + "splineNum": 7 + }, + { + "x": -58.91, + "y": 125.88, + "speed": 31.57, + "time": 4.6, + "theta": 133.76, + "omega": 24.98, + "vx": -16.75, + "vy": 26.77, + "splineNum": 7 + }, + { + "x": -59.42, + "y": 126.61, + "speed": 28.62, + "time": 4.63, + "theta": 134.07, + "omega": 22.38, + "vx": -16.55, + "vy": 23.35, + "splineNum": 7 + }, + { + "x": -60, + "y": 127.29, + "speed": 25.31, + "time": 4.66, + "theta": 134.51, + "omega": 19.42, + "vx": -16.29, + "vy": 19.37, + "splineNum": 7 + }, + { + "x": -60.65, + "y": 127.92, + "speed": 28.67, + "time": 4.69, + "theta": 135, + "omega": 16.77, + "vx": -20.69, + "vy": 19.85, + "splineNum": 7 + } + ] + }, + { + "name": "Goal3ToGoal6", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal3", + "omega": 0, + "angle": 135, + "spline_angle": -42.4, + "x": -59.75, + "y": 131.9, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 135, + "spline_angle": -22.69, + "x": -51.79, + "y": 127.29, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -40.88, + "spline_angle": 164.18, + "x": -42.72, + "y": 124.27, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 3.12, + "spline_angle": 164.18, + "x": -7.24, + "y": 94.83, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 86.77, + "spline_angle": 94.14, + "x": 6.28, + "y": 105.01, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 80.85, + "x": 3.9, + "y": 114.72, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal6", + "omega": 0, + "angle": 90, + "spline_angle": 80.85, + "x": 0.24, + "y": 128.08, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -59.75, + "y": 131.9, + "speed": 41.9, + "time": 0, + "theta": 135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -58.73, + "y": 131.04, + "speed": 40.16, + "time": 0.03, + "theta": 135, + "omega": 0, + "vx": 30.73, + "vy": -25.85, + "splineNum": 0 + }, + { + "x": -57.66, + "y": 130.27, + "speed": 36.72, + "time": 0.07, + "theta": 135, + "omega": 0, + "vx": 29.8, + "vy": -21.46, + "splineNum": 0 + }, + { + "x": -56.54, + "y": 129.57, + "speed": 32.95, + "time": 0.11, + "theta": 135, + "omega": 0, + "vx": 27.94, + "vy": -17.45, + "splineNum": 0 + }, + { + "x": -55.39, + "y": 128.94, + "speed": 28.68, + "time": 0.15, + "theta": 135, + "omega": 0, + "vx": 25.13, + "vy": -13.83, + "splineNum": 0 + }, + { + "x": -54.21, + "y": 128.36, + "speed": 23.65, + "time": 0.21, + "theta": 135, + "omega": 0, + "vx": 21.2, + "vy": -10.48, + "splineNum": 0 + }, + { + "x": -53.01, + "y": 127.81, + "speed": 17.18, + "time": 0.29, + "theta": 135, + "omega": 0, + "vx": 15.64, + "vy": -7.1, + "splineNum": 0 + }, + { + "x": -51.79, + "y": 127.29, + "speed": 5.51, + "time": 0.53, + "theta": 135, + "omega": 0, + "vx": 5.07, + "vy": -2.16, + "splineNum": 0 + }, + { + "x": -51.79, + "y": 127.29, + "speed": 5.51, + "time": 0.53, + "theta": 135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": -50.52, + "y": 126.78, + "speed": 17.43, + "time": 0.61, + "theta": 128.77, + "omega": -158.72, + "vx": 16.18, + "vy": -6.5, + "splineNum": 1 + }, + { + "x": -49.24, + "y": 126.3, + "speed": 24.03, + "time": 0.66, + "theta": 116.47, + "omega": -273.76, + "vx": 22.52, + "vy": -8.37, + "splineNum": 1 + }, + { + "x": -47.95, + "y": 125.86, + "speed": 29.16, + "time": 0.71, + "theta": 101.43, + "omega": -368.49, + "vx": 27.56, + "vy": -9.54, + "splineNum": 1 + }, + { + "x": -46.65, + "y": 125.44, + "speed": 32.79, + "time": 0.75, + "theta": 84.33, + "omega": -1234.27, + "vx": 31.19, + "vy": -10.13, + "splineNum": 1 + }, + { + "x": -45.34, + "y": 125.03, + "speed": 28.32, + "time": 0.8, + "theta": 60.14, + "omega": -1136.71, + "vx": 27.06, + "vy": -8.34, + "splineNum": 1 + }, + { + "x": -44.03, + "y": 124.65, + "speed": 22.99, + "time": 0.86, + "theta": 23.87, + "omega": -1016.51, + "vx": 22.05, + "vy": -6.51, + "splineNum": 1 + }, + { + "x": -42.72, + "y": 124.27, + "speed": 15.98, + "time": 0.94, + "theta": -40.88, + "omega": -843.5, + "vx": 15.36, + "vy": -4.4, + "splineNum": 1 + }, + { + "x": -42.72, + "y": 124.27, + "speed": 15.98, + "time": 0.94, + "theta": -40.88, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 2 + }, + { + "x": -39.21, + "y": 122.95, + "speed": 31.71, + "time": 1.06, + "theta": -40.41, + "omega": 8.02, + "vx": 29.68, + "vy": -11.17, + "splineNum": 2 + }, + { + "x": -36.09, + "y": 121.16, + "speed": 41.54, + "time": 1.15, + "theta": -39.46, + "omega": 13.89, + "vx": 36.02, + "vy": -20.7, + "splineNum": 2 + }, + { + "x": -33.29, + "y": 118.98, + "speed": 49.35, + "time": 1.22, + "theta": -38.28, + "omega": 18.76, + "vx": 38.95, + "vy": -30.3, + "splineNum": 2 + }, + { + "x": -30.74, + "y": 116.5, + "speed": 50, + "time": 1.29, + "theta": -36.78, + "omega": 23.58, + "vx": 35.86, + "vy": -34.84, + "splineNum": 2 + }, + { + "x": -28.36, + "y": 113.8, + "speed": 50, + "time": 1.36, + "theta": -34.91, + "omega": 28.44, + "vx": 33.06, + "vy": -37.51, + "splineNum": 2 + }, + { + "x": -26.1, + "y": 110.98, + "speed": 50, + "time": 1.44, + "theta": -32.67, + "omega": 33.35, + "vx": 31.31, + "vy": -38.98, + "splineNum": 2 + }, + { + "x": -23.86, + "y": 108.12, + "speed": 50, + "time": 1.51, + "theta": -30.07, + "omega": 38.27, + "vx": 30.72, + "vy": -39.45, + "splineNum": 2 + }, + { + "x": -21.6, + "y": 105.3, + "speed": 50, + "time": 1.58, + "theta": -27.12, + "omega": 111.26, + "vx": 31.31, + "vy": -38.98, + "splineNum": 2 + }, + { + "x": -19.22, + "y": 102.6, + "speed": 50, + "time": 1.65, + "theta": -23.85, + "omega": 106.4, + "vx": 33.06, + "vy": -37.51, + "splineNum": 2 + }, + { + "x": -16.67, + "y": 100.12, + "speed": 50, + "time": 1.73, + "theta": -20.26, + "omega": 101.58, + "vx": 35.86, + "vy": -34.84, + "splineNum": 2 + }, + { + "x": -13.87, + "y": 97.94, + "speed": 43.92, + "time": 1.81, + "theta": -15.77, + "omega": 96.1, + "vx": 34.66, + "vy": -26.97, + "splineNum": 2 + }, + { + "x": -10.75, + "y": 96.15, + "speed": 34.77, + "time": 1.91, + "theta": -9.37, + "omega": 89.09, + "vx": 30.15, + "vy": -17.32, + "splineNum": 2 + }, + { + "x": -7.24, + "y": 94.83, + "speed": 21.42, + "time": 2.08, + "theta": 3.12, + "omega": 77.22, + "vx": 20.05, + "vy": -7.54, + "splineNum": 2 + }, + { + "x": -7.24, + "y": 94.83, + "speed": 21.42, + "time": 2.08, + "theta": 3.12, + "omega": 77.22, + "vx": 8, + "vy": -16, + "splineNum": 2 + }, + { + "x": -3.63, + "y": 94.05, + "speed": 34.62, + "time": 2.19, + "theta": 4.73, + "omega": 30.17, + "vx": 33.84, + "vy": -7.32, + "splineNum": 3 + }, + { + "x": -0.5, + "y": 93.92, + "speed": 31.04, + "time": 2.29, + "theta": 9.2, + "omega": 58.6, + "vx": 31.02, + "vy": -1.27, + "splineNum": 3 + }, + { + "x": 2.09, + "y": 94.5, + "speed": 20.81, + "time": 2.42, + "theta": 18.97, + "omega": 94.61, + "vx": 20.31, + "vy": 4.56, + "splineNum": 3 + }, + { + "x": 4.1, + "y": 95.85, + "speed": 18.48, + "time": 2.55, + "theta": 33.79, + "omega": 303.12, + "vx": 15.37, + "vy": 10.26, + "splineNum": 3 + }, + { + "x": 5.5, + "y": 98.01, + "speed": 25.68, + "time": 2.65, + "theta": 48.41, + "omega": 274.79, + "vx": 13.94, + "vy": 21.57, + "splineNum": 3 + }, + { + "x": 6.24, + "y": 101.05, + "speed": 35.84, + "time": 2.74, + "theta": 63.43, + "omega": 250.16, + "vx": 8.49, + "vy": 34.82, + "splineNum": 3 + }, + { + "x": 6.28, + "y": 105.01, + "speed": 34.14, + "time": 2.85, + "theta": 86.77, + "omega": 217.37, + "vx": 0.36, + "vy": 34.14, + "splineNum": 3 + }, + { + "x": 6.28, + "y": 105.01, + "speed": 34.14, + "time": 2.85, + "theta": 86.77, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 4 + }, + { + "x": 6.04, + "y": 106.42, + "speed": 29.66, + "time": 2.9, + "theta": 86.78, + "omega": 0.48, + "vx": -4.95, + "vy": 29.24, + "splineNum": 4 + }, + { + "x": 5.6, + "y": 107.78, + "speed": 34.14, + "time": 2.94, + "theta": 86.81, + "omega": 0.9, + "vx": -10.5, + "vy": 32.49, + "splineNum": 4 + }, + { + "x": 5.06, + "y": 109.12, + "speed": 34.18, + "time": 2.99, + "theta": 86.86, + "omega": 1.32, + "vx": -12.82, + "vy": 31.69, + "splineNum": 4 + }, + { + "x": 4.52, + "y": 110.46, + "speed": 29.66, + "time": 3.04, + "theta": 86.93, + "omega": 1.81, + "vx": -11.12, + "vy": 27.49, + "splineNum": 4 + }, + { + "x": 4.08, + "y": 111.82, + "speed": 24.36, + "time": 3.09, + "theta": 87.06, + "omega": 2.4, + "vx": -7.5, + "vy": 23.17, + "splineNum": 4 + }, + { + "x": 3.84, + "y": 113.23, + "speed": 17.52, + "time": 3.18, + "theta": 87.29, + "omega": 3.21, + "vx": -2.93, + "vy": 17.27, + "splineNum": 4 + }, + { + "x": 3.9, + "y": 114.72, + "speed": 3.08, + "time": 3.66, + "theta": 90, + "omega": 8.03, + "vx": 0.13, + "vy": 3.08, + "splineNum": 4 + }, + { + "x": 3.9, + "y": 114.72, + "speed": 3.08, + "time": 3.66, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 5 + }, + { + "x": 3.91, + "y": 116.77, + "speed": 20.5, + "time": 3.76, + "theta": 90, + "omega": 0, + "vx": 0.09, + "vy": 20.5, + "splineNum": 5 + }, + { + "x": 3.39, + "y": 118.68, + "speed": 28.57, + "time": 3.83, + "theta": 90, + "omega": 0, + "vx": -7.55, + "vy": 27.55, + "splineNum": 5 + }, + { + "x": 2.54, + "y": 120.5, + "speed": 34.89, + "time": 3.89, + "theta": 90, + "omega": 0, + "vx": -14.64, + "vy": 31.67, + "splineNum": 5 + }, + { + "x": 1.6, + "y": 122.3, + "speed": 36, + "time": 3.94, + "theta": 90, + "omega": 0, + "vx": -16.84, + "vy": 31.82, + "splineNum": 5 + }, + { + "x": 0.75, + "y": 124.12, + "speed": 29.91, + "time": 4.01, + "theta": 90, + "omega": 0, + "vx": -12.55, + "vy": 27.15, + "splineNum": 5 + }, + { + "x": 0.23, + "y": 126.03, + "speed": 22.33, + "time": 4.1, + "theta": 90, + "omega": 0, + "vx": -5.9, + "vy": 21.54, + "splineNum": 5 + }, + { + "x": 0.24, + "y": 128.08, + "speed": 30.16, + "time": 4.17, + "theta": 90, + "omega": 0, + "vx": 0.13, + "vy": 30.16, + "splineNum": 5 + } + ] + }, + { + "name": "Goal6ToGoal9", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal6", + "omega": 28.8318509409838, + "angle": 90, + "spline_angle": 80.85, + "x": 0.24, + "y": 128.08, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 28.8318509409838, + "angle": 90, + "spline_angle": 80.85, + "x": 0.24, + "y": 118.38, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 28.8318509409838, + "angle": 45, + "spline_angle": 26.49, + "x": 16.15, + "y": 107.72, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 28.8318509409838, + "angle": 28.61, + "spline_angle": 26.49, + "x": 29.99, + "y": 116.15, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 28.8318509409838, + "angle": 40.41, + "spline_angle": 23.09, + "x": 46.54, + "y": 121.08, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal9", + "omega": 28.8318509409838, + "angle": 45, + "spline_angle": 26.49, + "x": 58.79, + "y": 129.99, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": 0.24, + "y": 128.08, + "speed": 41.9, + "time": 0, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 0.1, + "y": 126.69, + "speed": 41.21, + "time": 0.03, + "theta": 90, + "omega": 0, + "vx": -4.04, + "vy": -41.02, + "splineNum": 0 + }, + { + "x": 0.1, + "y": 125.31, + "speed": 37.7, + "time": 0.07, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": -37.7, + "splineNum": 0 + }, + { + "x": 0.19, + "y": 123.92, + "speed": 33.82, + "time": 0.11, + "theta": 90, + "omega": 0, + "vx": 2, + "vy": -33.76, + "splineNum": 0 + }, + { + "x": 0.29, + "y": 122.54, + "speed": 29.43, + "time": 0.16, + "theta": 90, + "omega": 0, + "vx": 2.31, + "vy": -29.33, + "splineNum": 0 + }, + { + "x": 0.38, + "y": 121.15, + "speed": 24.25, + "time": 0.22, + "theta": 90, + "omega": 0, + "vx": 1.43, + "vy": -24.21, + "splineNum": 0 + }, + { + "x": 0.38, + "y": 119.77, + "speed": 17.64, + "time": 0.29, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": -17.64, + "splineNum": 0 + }, + { + "x": 0.24, + "y": 118.38, + "speed": 5.71, + "time": 0.54, + "theta": 90, + "omega": 0, + "vx": -0.56, + "vy": -5.68, + "splineNum": 0 + }, + { + "x": 0.24, + "y": 118.38, + "speed": 5.71, + "time": 0.54, + "theta": 90, + "omega": 0, + "vx": -4, + "vy": 0, + "splineNum": 0 + }, + { + "x": -0.2, + "y": 114.6, + "speed": 28.17, + "time": 0.67, + "theta": 89.18, + "omega": -12.21, + "vx": -3.24, + "vy": -27.99, + "splineNum": 1 + }, + { + "x": -0.2, + "y": 111.47, + "speed": 35.44, + "time": 0.76, + "theta": 87.75, + "omega": -20.19, + "vx": 0, + "vy": -35.44, + "splineNum": 1 + }, + { + "x": 0.22, + "y": 108.97, + "speed": 27.35, + "time": 0.85, + "theta": 85.48, + "omega": -28.58, + "vx": 4.5, + "vy": -26.98, + "splineNum": 1 + }, + { + "x": 1.03, + "y": 107.06, + "speed": 18.23, + "time": 0.97, + "theta": 81.64, + "omega": -38.88, + "vx": 7.15, + "vy": -16.77, + "splineNum": 1 + }, + { + "x": 2.23, + "y": 105.71, + "speed": 14.81, + "time": 1.09, + "theta": 76.24, + "omega": -130.52, + "vx": 9.8, + "vy": -11.1, + "splineNum": 1 + }, + { + "x": 3.77, + "y": 104.89, + "speed": 17.24, + "time": 1.19, + "theta": 70.72, + "omega": -121.34, + "vx": 15.25, + "vy": -8.05, + "splineNum": 1 + }, + { + "x": 5.66, + "y": 104.57, + "speed": 26.07, + "time": 1.27, + "theta": 66.15, + "omega": -114.72, + "vx": 25.71, + "vy": -4.31, + "splineNum": 1 + }, + { + "x": 7.86, + "y": 104.73, + "speed": 33.47, + "time": 1.33, + "theta": 61.62, + "omega": -108.76, + "vx": 33.39, + "vy": 2.36, + "splineNum": 1 + }, + { + "x": 10.35, + "y": 105.32, + "speed": 40.42, + "time": 1.39, + "theta": 56.89, + "omega": -103.02, + "vx": 39.31, + "vy": 9.4, + "splineNum": 1 + }, + { + "x": 13.12, + "y": 106.33, + "speed": 47.15, + "time": 1.46, + "theta": 51.88, + "omega": -97.37, + "vx": 44.31, + "vy": 16.11, + "splineNum": 1 + }, + { + "x": 16.15, + "y": 107.72, + "speed": 41.9, + "time": 1.54, + "theta": 45, + "omega": -90.19, + "vx": 38.08, + "vy": 17.47, + "splineNum": 1 + }, + { + "x": 18.19, + "y": 108.82, + "speed": 47.11, + "time": 1.59, + "theta": 44.65, + "omega": -14.04, + "vx": 41.45, + "vy": 22.38, + "splineNum": 2 + }, + { + "x": 20.17, + "y": 110.03, + "speed": 50, + "time": 1.63, + "theta": 43.7, + "omega": -27.25, + "vx": 42.7, + "vy": 26.01, + "splineNum": 2 + }, + { + "x": 22.11, + "y": 111.29, + "speed": 50, + "time": 1.68, + "theta": 42.13, + "omega": -40.46, + "vx": 41.87, + "vy": 27.33, + "splineNum": 2 + }, + { + "x": 24.03, + "y": 112.58, + "speed": 50, + "time": 1.72, + "theta": 39.95, + "omega": -139.73, + "vx": 41.58, + "vy": 27.76, + "splineNum": 2 + }, + { + "x": 25.97, + "y": 113.84, + "speed": 50, + "time": 1.77, + "theta": 37.16, + "omega": -126.51, + "vx": 41.87, + "vy": 27.33, + "splineNum": 2 + }, + { + "x": 27.95, + "y": 115.05, + "speed": 47.11, + "time": 1.82, + "theta": 33.52, + "omega": -112.49, + "vx": 40.23, + "vy": 24.51, + "splineNum": 2 + }, + { + "x": 29.99, + "y": 116.15, + "speed": 41.9, + "time": 1.88, + "theta": 28.61, + "omega": -96.71, + "vx": 36.87, + "vy": 19.91, + "splineNum": 2 + }, + { + "x": 29.99, + "y": 116.15, + "speed": 41.9, + "time": 1.88, + "theta": 28.61, + "omega": -96.71, + "vx": 32, + "vy": 0, + "splineNum": 2 + }, + { + "x": 32.27, + "y": 117.12, + "speed": 47.46, + "time": 1.93, + "theta": 28.86, + "omega": 9.48, + "vx": 43.65, + "vy": 18.63, + "splineNum": 3 + }, + { + "x": 34.63, + "y": 117.87, + "speed": 50, + "time": 1.98, + "theta": 29.55, + "omega": 18.42, + "vx": 47.66, + "vy": 15.1, + "splineNum": 3 + }, + { + "x": 37.02, + "y": 118.47, + "speed": 50, + "time": 2.03, + "theta": 30.68, + "omega": 27.36, + "vx": 48.5, + "vy": 12.14, + "splineNum": 3 + }, + { + "x": 39.44, + "y": 119.01, + "speed": 50, + "time": 2.08, + "theta": 32.25, + "omega": 94.44, + "vx": 48.81, + "vy": 10.86, + "splineNum": 3 + }, + { + "x": 41.84, + "y": 119.56, + "speed": 50, + "time": 2.13, + "theta": 34.27, + "omega": 85.49, + "vx": 48.71, + "vy": 11.3, + "splineNum": 3 + }, + { + "x": 44.22, + "y": 120.23, + "speed": 47.43, + "time": 2.18, + "theta": 36.87, + "omega": 76.07, + "vx": 45.69, + "vy": 12.75, + "splineNum": 3 + }, + { + "x": 46.54, + "y": 121.08, + "speed": 41.9, + "time": 2.24, + "theta": 40.41, + "omega": 65.38, + "vx": 39.33, + "vy": 14.44, + "splineNum": 3 + }, + { + "x": 46.54, + "y": 121.08, + "speed": 41.9, + "time": 2.24, + "theta": 40.41, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 4 + }, + { + "x": 48.48, + "y": 122.09, + "speed": 46.83, + "time": 2.28, + "theta": 40.51, + "omega": 4.23, + "vx": 41.5, + "vy": 21.7, + "splineNum": 4 + }, + { + "x": 50.25, + "y": 123.34, + "speed": 50, + "time": 2.33, + "theta": 40.78, + "omega": 8.15, + "vx": 40.95, + "vy": 28.69, + "splineNum": 4 + }, + { + "x": 51.92, + "y": 124.72, + "speed": 50, + "time": 2.37, + "theta": 41.22, + "omega": 12.08, + "vx": 38.47, + "vy": 31.94, + "splineNum": 4 + }, + { + "x": 53.55, + "y": 126.16, + "speed": 50, + "time": 2.41, + "theta": 41.83, + "omega": 41.65, + "vx": 37.39, + "vy": 33.19, + "splineNum": 4 + }, + { + "x": 55.19, + "y": 127.58, + "speed": 50, + "time": 2.46, + "theta": 42.61, + "omega": 37.72, + "vx": 37.9, + "vy": 32.61, + "splineNum": 4 + }, + { + "x": 56.92, + "y": 128.88, + "speed": 46.8, + "time": 2.5, + "theta": 43.63, + "omega": 33.53, + "vx": 37.36, + "vy": 28.19, + "splineNum": 4 + }, + { + "x": 58.79, + "y": 129.99, + "speed": 41.9, + "time": 2.55, + "theta": 45, + "omega": 28.83, + "vx": 36.07, + "vy": 21.32, + "splineNum": 4 + } + ] + }, + { + "name": "Goal9ToGoal8", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal9", + "omega": -16.328937081995182, + "angle": 45, + "spline_angle": 26.49, + "x": 58.79, + "y": 129.99, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": -16.328937081995182, + "angle": 45, + "spline_angle": 109.96, + "x": 54.02, + "y": 119.97, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": -16.328937081995182, + "angle": -25.23, + "spline_angle": -90.09, + "x": 58.95, + "y": 110.42, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": -16.328937081995182, + "angle": -0.01, + "spline_angle": -90.09, + "x": 59.27, + "y": 94.83, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": -16.328937081995182, + "angle": -85.03, + "spline_angle": -90.09, + "x": 44.47, + "y": 83.06, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": -16.328937081995182, + "angle": 3.54, + "spline_angle": 163.67, + "x": 49.72, + "y": 70.8, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal8", + "omega": -16.328937081995182, + "angle": 0, + "spline_angle": 163.67, + "x": 57.04, + "y": 71.76, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": 58.79, + "y": 129.99, + "speed": 38.83, + "time": 0, + "theta": 45, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 57.11, + "y": 129.04, + "speed": 33.48, + "time": 0.06, + "theta": 45, + "omega": 0, + "vx": -29.12, + "vy": -16.53, + "splineNum": 0 + }, + { + "x": 55.69, + "y": 127.95, + "speed": 27.65, + "time": 0.12, + "theta": 45, + "omega": 0, + "vx": -21.98, + "vy": -16.78, + "splineNum": 0 + }, + { + "x": 54.58, + "y": 126.73, + "speed": 20.82, + "time": 0.2, + "theta": 45, + "omega": 0, + "vx": -13.97, + "vy": -15.44, + "splineNum": 0 + }, + { + "x": 53.82, + "y": 125.33, + "speed": 18.03, + "time": 0.29, + "theta": 45, + "omega": 0, + "vx": -8.66, + "vy": -15.82, + "splineNum": 0 + }, + { + "x": 53.44, + "y": 123.76, + "speed": 19.44, + "time": 0.37, + "theta": 45, + "omega": 0, + "vx": -4.49, + "vy": -18.91, + "splineNum": 0 + }, + { + "x": 53.5, + "y": 121.97, + "speed": 25.75, + "time": 0.44, + "theta": 45, + "omega": 0, + "vx": 0.78, + "vy": -25.74, + "splineNum": 0 + }, + { + "x": 54.02, + "y": 119.97, + "speed": 32.82, + "time": 0.51, + "theta": 45, + "omega": 0, + "vx": 8.28, + "vy": -31.76, + "splineNum": 0 + }, + { + "x": 54.02, + "y": 119.97, + "speed": 32.82, + "time": 0.51, + "theta": 45, + "omega": 0, + "vx": -32.82, + "vy": 0, + "splineNum": 0 + }, + { + "x": 54.68, + "y": 118.58, + "speed": 32.57, + "time": 0.55, + "theta": 44.77, + "omega": -9.93, + "vx": 14.03, + "vy": -29.39, + "splineNum": 1 + }, + { + "x": 55.54, + "y": 117.3, + "speed": 37.01, + "time": 0.59, + "theta": 44.17, + "omega": -18.73, + "vx": 20.51, + "vy": -30.81, + "splineNum": 1 + }, + { + "x": 56.48, + "y": 116.06, + "speed": 35.58, + "time": 0.64, + "theta": 43.15, + "omega": -27.95, + "vx": 21.51, + "vy": -28.34, + "splineNum": 1 + }, + { + "x": 57.4, + "y": 114.8, + "speed": 30.9, + "time": 0.69, + "theta": 41.47, + "omega": -38.55, + "vx": 18.3, + "vy": -24.9, + "splineNum": 1 + }, + { + "x": 58.19, + "y": 113.48, + "speed": 25.44, + "time": 0.75, + "theta": 38.76, + "omega": -51.29, + "vx": 13.07, + "vy": -21.82, + "splineNum": 1 + }, + { + "x": 58.74, + "y": 112.04, + "speed": 18.39, + "time": 0.83, + "theta": 33.7, + "omega": -68.99, + "vx": 6.58, + "vy": -17.17, + "splineNum": 1 + }, + { + "x": 58.95, + "y": 110.42, + "speed": 3.34, + "time": 1.32, + "theta": -25.23, + "omega": -172.01, + "vx": 0.42, + "vy": -3.32, + "splineNum": 1 + }, + { + "x": 58.95, + "y": 110.42, + "speed": 3.34, + "time": 1.32, + "theta": -25.23, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 2 + }, + { + "x": 58.97, + "y": 108.19, + "speed": 21.37, + "time": 1.43, + "theta": -24.89, + "omega": 6.51, + "vx": 0.15, + "vy": -21.37, + "splineNum": 2 + }, + { + "x": 59.01, + "y": 105.97, + "speed": 30.04, + "time": 1.5, + "theta": -24.24, + "omega": 11.15, + "vx": 0.62, + "vy": -30.03, + "splineNum": 2 + }, + { + "x": 59.08, + "y": 103.74, + "speed": 36.71, + "time": 1.56, + "theta": -23.44, + "omega": 14.94, + "vx": 1.05, + "vy": -36.7, + "splineNum": 2 + }, + { + "x": 59.14, + "y": 101.51, + "speed": 36.94, + "time": 1.62, + "theta": -22.43, + "omega": 18.71, + "vx": 1.16, + "vy": -36.92, + "splineNum": 2 + }, + { + "x": 59.21, + "y": 99.28, + "speed": 30.31, + "time": 1.7, + "theta": -20.89, + "omega": 23.3, + "vx": 0.87, + "vy": -30.3, + "splineNum": 2 + }, + { + "x": 59.25, + "y": 97.06, + "speed": 21.75, + "time": 1.8, + "theta": -18.17, + "omega": 82.58, + "vx": 0.45, + "vy": -21.75, + "splineNum": 2 + }, + { + "x": 59.27, + "y": 94.83, + "speed": 5.26, + "time": 2.22, + "theta": -0.01, + "omega": 56.14, + "vx": 0.04, + "vy": -5.26, + "splineNum": 2 + }, + { + "x": 59.27, + "y": 94.83, + "speed": 5.26, + "time": 2.22, + "theta": -0.01, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 3 + }, + { + "x": 58.45, + "y": 91.53, + "speed": 14.26, + "time": 2.46, + "theta": -4.64, + "omega": -38.77, + "vx": -3.45, + "vy": -13.83, + "splineNum": 3 + }, + { + "x": 56.33, + "y": 89.84, + "speed": 19.88, + "time": 2.6, + "theta": -11.4, + "omega": -60.82, + "vx": -15.56, + "vy": -12.38, + "splineNum": 3 + }, + { + "x": 53.44, + "y": 89.14, + "speed": 31.47, + "time": 2.69, + "theta": -17.88, + "omega": -76.17, + "vx": -30.56, + "vy": -7.49, + "splineNum": 3 + }, + { + "x": 50.3, + "y": 88.75, + "speed": 31.47, + "time": 2.79, + "theta": -26.37, + "omega": -239.77, + "vx": -31.24, + "vy": -3.81, + "splineNum": 3 + }, + { + "x": 47.41, + "y": 88.05, + "speed": 19.88, + "time": 2.94, + "theta": -42.03, + "omega": -215.49, + "vx": -19.31, + "vy": -4.73, + "splineNum": 3 + }, + { + "x": 45.29, + "y": 86.36, + "speed": 14.26, + "time": 3.13, + "theta": -67.07, + "omega": -184.73, + "vx": -11.16, + "vy": -8.87, + "splineNum": 3 + }, + { + "x": 44.47, + "y": 83.06, + "speed": 29.74, + "time": 3.24, + "theta": -85.03, + "omega": -166.14, + "vx": -7.2, + "vy": -28.85, + "splineNum": 3 + }, + { + "x": 44.47, + "y": 83.06, + "speed": 29.74, + "time": 3.24, + "theta": -85.03, + "omega": -166.14, + "vx": -29.74, + "vy": 0, + "splineNum": 3 + }, + { + "x": 44.41, + "y": 80.96, + "speed": 36.12, + "time": 3.3, + "theta": -84.42, + "omega": 21.05, + "vx": -1.09, + "vy": -36.1, + "splineNum": 4 + }, + { + "x": 44.33, + "y": 78.86, + "speed": 34.99, + "time": 3.36, + "theta": -82.5, + "omega": 42.81, + "vx": -1.2, + "vy": -34.97, + "splineNum": 4 + }, + { + "x": 44.42, + "y": 76.82, + "speed": 28.58, + "time": 3.43, + "theta": -78.53, + "omega": 68.6, + "vx": 1.22, + "vy": -28.55, + "splineNum": 4 + }, + { + "x": 44.84, + "y": 74.93, + "speed": 20.71, + "time": 3.53, + "theta": -70.51, + "omega": 102.5, + "vx": 4.42, + "vy": -20.23, + "splineNum": 4 + }, + { + "x": 45.75, + "y": 73.24, + "speed": 17.4, + "time": 3.64, + "theta": -57.05, + "omega": 364.06, + "vx": 8.27, + "vy": -15.31, + "splineNum": 4 + }, + { + "x": 47.32, + "y": 71.84, + "speed": 22.41, + "time": 3.73, + "theta": -42.1, + "omega": 330.08, + "vx": 16.74, + "vy": -14.9, + "splineNum": 4 + }, + { + "x": 49.72, + "y": 70.8, + "speed": 12.32, + "time": 3.94, + "theta": 3.54, + "omega": 253.17, + "vx": 11.3, + "vy": -4.91, + "splineNum": 4 + }, + { + "x": 49.72, + "y": 70.8, + "speed": 12.32, + "time": 3.94, + "theta": 3.54, + "omega": 253.17, + "vx": 12.32, + "vy": 0, + "splineNum": 4 + }, + { + "x": 50.8, + "y": 70.65, + "speed": 12.25, + "time": 4.03, + "theta": 3.39, + "omega": -3.36, + "vx": 12.14, + "vy": -1.63, + "splineNum": 5 + }, + { + "x": 51.85, + "y": 70.79, + "speed": 19, + "time": 4.09, + "theta": 3.15, + "omega": -5.45, + "vx": 18.84, + "vy": 2.47, + "splineNum": 5 + }, + { + "x": 52.87, + "y": 71.1, + "speed": 23.97, + "time": 4.13, + "theta": 2.87, + "omega": -7.13, + "vx": 22.96, + "vy": 6.88, + "splineNum": 5 + }, + { + "x": 53.89, + "y": 71.46, + "speed": 23.97, + "time": 4.18, + "theta": 2.51, + "omega": -23.83, + "vx": 22.57, + "vy": 8.07, + "splineNum": 5 + }, + { + "x": 54.91, + "y": 71.77, + "speed": 19, + "time": 4.23, + "theta": 1.95, + "omega": -21.72, + "vx": 18.2, + "vy": 5.45, + "splineNum": 5 + }, + { + "x": 55.96, + "y": 71.91, + "speed": 12.25, + "time": 4.32, + "theta": 0.87, + "omega": -18.47, + "vx": 12.14, + "vy": 1.59, + "splineNum": 5 + }, + { + "x": 57.04, + "y": 71.76, + "speed": 19.2, + "time": 4.38, + "theta": 0, + "omega": -16.33, + "vx": 19.02, + "vy": -2.55, + "splineNum": 5 + } + ] + }, + { + "name": "Goal8ToGoal7", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal8", + "omega": 0, + "angle": 0, + "spline_angle": -179.99, + "x": 57.04, + "y": 71.76, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 0, + "spline_angle": -1.79, + "x": 46.54, + "y": 71.76, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": -1.79, + "x": 41.69, + "y": 71.7, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -180, + "spline_angle": -131.88, + "x": 31.63, + "y": 69, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -90.02, + "spline_angle": 135.12, + "x": 32.35, + "y": 56.07, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -36.59, + "spline_angle": 113.16, + "x": 58.79, + "y": 46.62, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 0, + "spline_angle": -96.16, + "x": 59.9, + "y": 27.84, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -45, + "spline_angle": 113.16, + "x": 56.78, + "y": 20.67, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal7", + "omega": 0, + "angle": -45, + "spline_angle": 113.16, + "x": 62.36, + "y": 14.38, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": 57.04, + "y": 71.76, + "speed": 41.9, + "time": 0, + "theta": 0, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 55.54, + "y": 71.75, + "speed": 45.34, + "time": 0.03, + "theta": 0, + "omega": 0, + "vx": -45.34, + "vy": -0.18, + "splineNum": 0 + }, + { + "x": 54.04, + "y": 71.74, + "speed": 48.53, + "time": 0.06, + "theta": 0, + "omega": 0, + "vx": -48.53, + "vy": -0.44, + "splineNum": 0 + }, + { + "x": 52.54, + "y": 71.73, + "speed": 50, + "time": 0.09, + "theta": 0, + "omega": 0, + "vx": -50, + "vy": -0.51, + "splineNum": 0 + }, + { + "x": 51.04, + "y": 71.71, + "speed": 50, + "time": 0.12, + "theta": 0, + "omega": 0, + "vx": -50, + "vy": -0.38, + "splineNum": 0 + }, + { + "x": 49.54, + "y": 71.71, + "speed": 48.54, + "time": 0.15, + "theta": 0, + "omega": 0, + "vx": -48.54, + "vy": -0.06, + "splineNum": 0 + }, + { + "x": 48.04, + "y": 71.73, + "speed": 45.34, + "time": 0.19, + "theta": 0, + "omega": 0, + "vx": -45.34, + "vy": 0.41, + "splineNum": 0 + }, + { + "x": 46.54, + "y": 71.76, + "speed": 41.9, + "time": 0.22, + "theta": 0, + "omega": 0, + "vx": -41.89, + "vy": 0.96, + "splineNum": 0 + }, + { + "x": 46.54, + "y": 71.76, + "speed": 41.9, + "time": 0.22, + "theta": 0, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": 45.85, + "y": 71.77, + "speed": 43.52, + "time": 0.24, + "theta": 1.93, + "omega": 241.85, + "vx": -43.52, + "vy": 0.62, + "splineNum": 1 + }, + { + "x": 45.15, + "y": 71.76, + "speed": 45.09, + "time": 0.26, + "theta": 7.44, + "omega": 475.22, + "vx": -45.08, + "vy": -0.56, + "splineNum": 1 + }, + { + "x": 44.46, + "y": 71.74, + "speed": 46.6, + "time": 0.27, + "theta": 16.18, + "omega": 701.06, + "vx": -46.58, + "vy": -1.32, + "splineNum": 1 + }, + { + "x": 43.77, + "y": 71.72, + "speed": 46.6, + "time": 0.28, + "theta": 28.29, + "omega": 2379.68, + "vx": -46.57, + "vy": -1.57, + "splineNum": 1 + }, + { + "x": 43.08, + "y": 71.7, + "speed": 45.09, + "time": 0.3, + "theta": 44.33, + "omega": 2146.27, + "vx": -45.07, + "vy": -1.28, + "splineNum": 1 + }, + { + "x": 42.38, + "y": 71.69, + "speed": 43.52, + "time": 0.32, + "theta": 64.73, + "omega": 1904.51, + "vx": -43.52, + "vy": -0.54, + "splineNum": 1 + }, + { + "x": 41.69, + "y": 71.7, + "speed": 41.9, + "time": 0.33, + "theta": 90, + "omega": 1653.29, + "vx": -41.9, + "vy": 0.6, + "splineNum": 1 + }, + { + "x": 41.69, + "y": 71.7, + "speed": 41.9, + "time": 0.33, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 2 + }, + { + "x": 40.14, + "y": 71.75, + "speed": 41.5, + "time": 0.37, + "theta": 90.27, + "omega": 14.19, + "vx": -41.48, + "vy": 1.28, + "splineNum": 2 + }, + { + "x": 38.59, + "y": 71.75, + "speed": 37.6, + "time": 0.41, + "theta": 91.17, + "omega": 29.73, + "vx": -37.6, + "vy": 0.15, + "splineNum": 2 + }, + { + "x": 37.08, + "y": 71.66, + "speed": 33.32, + "time": 0.46, + "theta": 92.91, + "omega": 46.98, + "vx": -33.25, + "vy": -2.14, + "splineNum": 2 + }, + { + "x": 35.61, + "y": 71.39, + "speed": 28.49, + "time": 0.51, + "theta": 95.9, + "omega": 66.85, + "vx": -28.04, + "vy": -5.01, + "splineNum": 2 + }, + { + "x": 34.2, + "y": 70.9, + "speed": 23.48, + "time": 0.57, + "theta": 100.91, + "omega": 90.92, + "vx": -22.18, + "vy": -7.7, + "splineNum": 2 + }, + { + "x": 32.87, + "y": 70.13, + "speed": 18.86, + "time": 0.65, + "theta": 109.61, + "omega": 121.9, + "vx": -16.29, + "vy": -9.51, + "splineNum": 2 + }, + { + "x": 31.63, + "y": 69, + "speed": 4.56, + "time": 1.02, + "theta": 180, + "omega": 261.14, + "vx": -3.37, + "vy": -3.07, + "splineNum": 2 + }, + { + "x": 31.63, + "y": 69, + "speed": 4.56, + "time": 1.02, + "theta": 180, + "omega": 261.14, + "vx": 4.56, + "vy": 0, + "splineNum": 2 + }, + { + "x": 30.17, + "y": 67.07, + "speed": 22.48, + "time": 1.13, + "theta": -178.22, + "omega": 33.09, + "vx": -13.55, + "vy": -17.94, + "splineNum": 3 + }, + { + "x": 29.27, + "y": 65.16, + "speed": 24.12, + "time": 1.22, + "theta": -174.16, + "omega": 59.89, + "vx": -10.31, + "vy": -21.8, + "splineNum": 3 + }, + { + "x": 28.91, + "y": 63.29, + "speed": 20.74, + "time": 1.31, + "theta": -167.35, + "omega": 88.14, + "vx": -3.95, + "vy": -20.36, + "splineNum": 3 + }, + { + "x": 29.06, + "y": 61.45, + "speed": 22.08, + "time": 1.39, + "theta": -158.88, + "omega": 113.87, + "vx": 1.79, + "vy": -22, + "splineNum": 3 + }, + { + "x": 29.7, + "y": 59.63, + "speed": 28.23, + "time": 1.46, + "theta": -150.4, + "omega": 335.27, + "vx": 9.37, + "vy": -26.63, + "splineNum": 3 + }, + { + "x": 30.8, + "y": 57.84, + "speed": 23.82, + "time": 1.55, + "theta": -137.28, + "omega": 308.13, + "vx": 12.51, + "vy": -20.27, + "splineNum": 3 + }, + { + "x": 32.35, + "y": 56.07, + "speed": 9.87, + "time": 1.79, + "theta": -90.02, + "omega": 235.05, + "vx": 6.5, + "vy": -7.42, + "splineNum": 3 + }, + { + "x": 32.35, + "y": 56.07, + "speed": 9.87, + "time": 1.79, + "theta": -90.02, + "omega": 235.05, + "vx": 9.87, + "vy": 0, + "splineNum": 3 + }, + { + "x": 35.37, + "y": 54.09, + "speed": 28.63, + "time": 1.91, + "theta": -89.01, + "omega": 16, + "vx": 23.93, + "vy": -15.72, + "splineNum": 4 + }, + { + "x": 38.81, + "y": 53.29, + "speed": 39.07, + "time": 2, + "theta": -87.05, + "omega": 27.46, + "vx": 38.07, + "vy": -8.77, + "splineNum": 4 + }, + { + "x": 42.51, + "y": 53.21, + "speed": 47.6, + "time": 2.08, + "theta": -84.53, + "omega": 37.32, + "vx": 47.59, + "vy": -1.08, + "splineNum": 4 + }, + { + "x": 46.29, + "y": 53.35, + "speed": 48.38, + "time": 2.16, + "theta": -81.23, + "omega": 47.23, + "vx": 48.35, + "vy": 1.85, + "splineNum": 4 + }, + { + "x": 49.98, + "y": 53.25, + "speed": 40.04, + "time": 2.25, + "theta": -76.33, + "omega": 173.89, + "vx": 40.02, + "vy": -1.15, + "splineNum": 4 + }, + { + "x": 53.41, + "y": 52.41, + "speed": 29.95, + "time": 2.37, + "theta": -68.51, + "omega": 158.96, + "vx": 29.1, + "vy": -7.11, + "splineNum": 4 + }, + { + "x": 56.4, + "y": 50.36, + "speed": 30.3, + "time": 2.49, + "theta": -58.76, + "omega": 143.77, + "vx": 25.01, + "vy": -17.11, + "splineNum": 4 + }, + { + "x": 58.79, + "y": 46.62, + "speed": 20.57, + "time": 2.71, + "theta": -36.59, + "omega": 116.4, + "vx": 11.07, + "vy": -17.33, + "splineNum": 4 + }, + { + "x": 59.71, + "y": 43.98, + "speed": 31.34, + "time": 2.79, + "theta": -35.75, + "omega": 18.9, + "vx": 10.35, + "vy": -29.58, + "splineNum": 5 + }, + { + "x": 60.28, + "y": 41.32, + "speed": 39.06, + "time": 2.86, + "theta": -33.92, + "omega": 33.65, + "vx": 8.09, + "vy": -38.21, + "splineNum": 5 + }, + { + "x": 60.54, + "y": 38.65, + "speed": 45.43, + "time": 2.92, + "theta": -31.55, + "omega": 46.21, + "vx": 4.5, + "vy": -45.2, + "splineNum": 5 + }, + { + "x": 60.57, + "y": 35.96, + "speed": 44.44, + "time": 2.98, + "theta": -28.37, + "omega": 59.04, + "vx": 0.54, + "vy": -44.44, + "splineNum": 5 + }, + { + "x": 60.44, + "y": 33.26, + "speed": 37.87, + "time": 3.06, + "theta": -23.61, + "omega": 174.93, + "vx": -1.93, + "vy": -37.82, + "splineNum": 5 + }, + { + "x": 60.19, + "y": 30.55, + "speed": 29.84, + "time": 3.15, + "theta": -15.98, + "omega": 155.62, + "vx": -2.7, + "vy": -29.72, + "splineNum": 5 + }, + { + "x": 59.9, + "y": 27.84, + "speed": 18.59, + "time": 3.29, + "theta": 0, + "omega": 124.55, + "vx": -1.98, + "vy": -18.49, + "splineNum": 5 + }, + { + "x": 59.9, + "y": 27.84, + "speed": 18.59, + "time": 3.29, + "theta": 0, + "omega": 124.55, + "vx": 16, + "vy": -8, + "splineNum": 5 + }, + { + "x": 59.56, + "y": 26.77, + "speed": 11.01, + "time": 3.4, + "theta": -0.34, + "omega": -6.61, + "vx": -3.37, + "vy": -10.48, + "splineNum": 6 + }, + { + "x": 58.89, + "y": 25.84, + "speed": 18.7, + "time": 3.46, + "theta": -0.86, + "omega": -10.57, + "vx": -10.88, + "vy": -15.21, + "splineNum": 6 + }, + { + "x": 58.08, + "y": 24.98, + "speed": 23.55, + "time": 3.51, + "theta": -1.48, + "omega": -13.84, + "vx": -16.14, + "vy": -17.15, + "splineNum": 6 + }, + { + "x": 57.29, + "y": 24.1, + "speed": 17.86, + "time": 3.57, + "theta": -2.53, + "omega": -18.12, + "vx": -11.97, + "vy": -13.25, + "splineNum": 6 + }, + { + "x": 56.69, + "y": 23.14, + "speed": 9.65, + "time": 3.69, + "theta": -5.09, + "omega": -25.7, + "vx": -5.08, + "vy": -8.2, + "splineNum": 6 + }, + { + "x": 56.47, + "y": 22.02, + "speed": 8.96, + "time": 3.82, + "theta": -8.9, + "omega": -33.97, + "vx": -1.78, + "vy": -8.79, + "splineNum": 6 + }, + { + "x": 56.78, + "y": 20.67, + "speed": 2.12, + "time": 4.47, + "theta": -45, + "omega": -76.39, + "vx": 0.48, + "vy": -2.07, + "splineNum": 6 + }, + { + "x": 56.78, + "y": 20.67, + "speed": 2.12, + "time": 4.47, + "theta": -45, + "omega": -76.39, + "vx": 0, + "vy": -2, + "splineNum": 6 + }, + { + "x": 57.39, + "y": 19.61, + "speed": 15.8, + "time": 4.55, + "theta": -45, + "omega": 0, + "vx": 7.91, + "vy": -13.68, + "splineNum": 7 + }, + { + "x": 58.19, + "y": 18.71, + "speed": 22.13, + "time": 4.6, + "theta": -45, + "omega": 0, + "vx": 14.69, + "vy": -16.56, + "splineNum": 7 + }, + { + "x": 59.1, + "y": 17.91, + "speed": 27.05, + "time": 4.65, + "theta": -45, + "omega": 0, + "vx": 20.28, + "vy": -17.91, + "splineNum": 7 + }, + { + "x": 60.04, + "y": 17.14, + "speed": 28.48, + "time": 4.69, + "theta": -45, + "omega": 0, + "vx": 22.08, + "vy": -17.98, + "splineNum": 7 + }, + { + "x": 60.95, + "y": 16.34, + "speed": 23.85, + "time": 4.74, + "theta": -45, + "omega": 0, + "vx": 17.88, + "vy": -15.79, + "splineNum": 7 + }, + { + "x": 61.75, + "y": 15.44, + "speed": 18.13, + "time": 4.81, + "theta": -45, + "omega": 0, + "vx": 12.03, + "vy": -13.56, + "splineNum": 7 + }, + { + "x": 62.36, + "y": 14.38, + "speed": 12.65, + "time": 4.9, + "theta": -45, + "omega": 0, + "vx": 6.34, + "vy": -10.95, + "splineNum": 7 + } + ] + }, + { + "name": "Goal7ToGoal4", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal7", + "omega": 0, + "angle": -45, + "spline_angle": 127.88, + "x": 62.36, + "y": 14.38, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -45, + "spline_angle": 97.15, + "x": 57.2, + "y": 18.46, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": 177.35, + "x": 48.45, + "y": 23.71, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": 177.35, + "x": 36.99, + "y": 23.71, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -90, + "spline_angle": -11.62, + "x": 14.4, + "y": 27.53, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -90, + "spline_angle": -132.62, + "x": 2.78, + "y": 25.62, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": 62.36, + "y": 14.38, + "speed": 17.4, + "time": 0, + "theta": -45, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 61.66, + "y": 15.01, + "speed": 10.69, + "time": 0.09, + "theta": -45, + "omega": 0, + "vx": -7.98, + "vy": 7.12, + "splineNum": 0 + }, + { + "x": 60.8, + "y": 15.43, + "speed": 17.5, + "time": 0.14, + "theta": -45, + "omega": 0, + "vx": -15.68, + "vy": 7.79, + "splineNum": 0 + }, + { + "x": 59.87, + "y": 15.77, + "speed": 21.51, + "time": 0.19, + "theta": -45, + "omega": 0, + "vx": -20.21, + "vy": 7.36, + "splineNum": 0 + }, + { + "x": 58.96, + "y": 16.13, + "speed": 16.32, + "time": 0.25, + "theta": -45, + "omega": 0, + "vx": -15.17, + "vy": 6, + "splineNum": 0 + }, + { + "x": 58.15, + "y": 16.63, + "speed": 8.77, + "time": 0.36, + "theta": -45, + "omega": 0, + "vx": -7.48, + "vy": 4.58, + "splineNum": 0 + }, + { + "x": 57.53, + "y": 17.37, + "speed": 7.99, + "time": 0.48, + "theta": -45, + "omega": 0, + "vx": -5.11, + "vy": 6.14, + "splineNum": 0 + }, + { + "x": 57.2, + "y": 18.46, + "speed": 3.19, + "time": 0.84, + "theta": -45, + "omega": 0, + "vx": -0.93, + "vy": 3.05, + "splineNum": 0 + }, + { + "x": 57.2, + "y": 18.46, + "speed": 3.19, + "time": 0.84, + "theta": -45, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": 56.7, + "y": 20.46, + "speed": 18.09, + "time": 0.95, + "theta": -50.82, + "omega": -102.08, + "vx": -4.37, + "vy": 17.55, + "splineNum": 1 + }, + { + "x": 55.84, + "y": 21.86, + "speed": 13.22, + "time": 1.07, + "theta": -70.4, + "omega": -213.17, + "vx": -6.94, + "vy": 11.26, + "splineNum": 1 + }, + { + "x": 54.68, + "y": 22.77, + "speed": 14.73, + "time": 1.17, + "theta": -96.11, + "omega": -680.54, + "vx": -11.6, + "vy": 9.07, + "splineNum": 1 + }, + { + "x": 53.3, + "y": 23.29, + "speed": 22.65, + "time": 1.24, + "theta": -117.79, + "omega": -622.05, + "vx": -21.18, + "vy": 8.02, + "splineNum": 1 + }, + { + "x": 51.75, + "y": 23.55, + "speed": 28.75, + "time": 1.29, + "theta": -138.79, + "omega": -573.29, + "vx": -28.36, + "vy": 4.72, + "splineNum": 1 + }, + { + "x": 50.11, + "y": 23.65, + "speed": 33.98, + "time": 1.34, + "theta": -159.62, + "omega": -530.07, + "vx": -33.92, + "vy": 2.12, + "splineNum": 1 + }, + { + "x": 48.45, + "y": 23.71, + "speed": 38.57, + "time": 1.38, + "theta": -180, + "omega": -491.46, + "vx": -38.55, + "vy": 1.39, + "splineNum": 1 + }, + { + "x": 48.45, + "y": 23.71, + "speed": 38.57, + "time": 1.38, + "theta": 180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 2 + }, + { + "x": 46.81, + "y": 23.76, + "speed": 42.61, + "time": 1.42, + "theta": 180, + "omega": 0, + "vx": -42.59, + "vy": 1.21, + "splineNum": 2 + }, + { + "x": 45.18, + "y": 23.76, + "speed": 46.29, + "time": 1.46, + "theta": 180, + "omega": 0, + "vx": -46.29, + "vy": 0, + "splineNum": 2 + }, + { + "x": 43.54, + "y": 23.73, + "speed": 49.7, + "time": 1.49, + "theta": 180, + "omega": 0, + "vx": -49.7, + "vy": -0.84, + "splineNum": 2 + }, + { + "x": 41.9, + "y": 23.69, + "speed": 50, + "time": 1.52, + "theta": 180, + "omega": 0, + "vx": -49.99, + "vy": -1.13, + "splineNum": 2 + }, + { + "x": 40.26, + "y": 23.66, + "speed": 49.1, + "time": 1.56, + "theta": 180, + "omega": 0, + "vx": -49.09, + "vy": -0.83, + "splineNum": 2 + }, + { + "x": 38.63, + "y": 23.66, + "speed": 45.64, + "time": 1.59, + "theta": 180, + "omega": 0, + "vx": -45.64, + "vy": 0, + "splineNum": 2 + }, + { + "x": 36.99, + "y": 23.71, + "speed": 41.9, + "time": 1.63, + "theta": 180, + "omega": 0, + "vx": -41.88, + "vy": 1.19, + "splineNum": 2 + }, + { + "x": 36.99, + "y": 23.71, + "speed": 41.9, + "time": 1.63, + "theta": 180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 3 + }, + { + "x": 33.71, + "y": 23.95, + "speed": 49.12, + "time": 1.7, + "theta": 181.7, + "omega": 50.68, + "vx": -48.99, + "vy": 3.63, + "splineNum": 3 + }, + { + "x": 30.46, + "y": 24.35, + "speed": 50, + "time": 1.77, + "theta": 186.64, + "omega": 100.29, + "vx": -49.62, + "vy": 6.12, + "splineNum": 3 + }, + { + "x": 27.23, + "y": 24.88, + "speed": 50, + "time": 1.83, + "theta": 194.83, + "omega": 149.86, + "vx": -49.35, + "vy": 8.01, + "splineNum": 3 + }, + { + "x": 24.01, + "y": 25.49, + "speed": 50, + "time": 1.9, + "theta": 206.26, + "omega": 538.94, + "vx": -49.11, + "vy": 9.38, + "splineNum": 3 + }, + { + "x": 20.81, + "y": 26.16, + "speed": 50, + "time": 1.96, + "theta": 220.95, + "omega": 489.34, + "vx": -48.94, + "vy": 10.22, + "splineNum": 3 + }, + { + "x": 17.6, + "y": 26.85, + "speed": 45.6, + "time": 2.03, + "theta": 240.8, + "omega": 434.93, + "vx": -44.57, + "vy": 9.61, + "splineNum": 3 + }, + { + "x": 14.4, + "y": 27.53, + "speed": 37.73, + "time": 2.12, + "theta": 270, + "omega": 369.19, + "vx": -36.92, + "vy": 7.81, + "splineNum": 3 + }, + { + "x": 14.4, + "y": 27.53, + "speed": 37.73, + "time": 2.12, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 4 + }, + { + "x": 12.64, + "y": 27.88, + "speed": 41.83, + "time": 2.16, + "theta": -90, + "omega": 0, + "vx": -41.02, + "vy": 8.22, + "splineNum": 4 + }, + { + "x": 10.89, + "y": 28.16, + "speed": 37.35, + "time": 2.21, + "theta": -90, + "omega": 0, + "vx": -36.88, + "vy": 5.9, + "splineNum": 4 + }, + { + "x": 9.16, + "y": 28.29, + "speed": 32.39, + "time": 2.26, + "theta": -90, + "omega": 0, + "vx": -32.31, + "vy": 2.35, + "splineNum": 4 + }, + { + "x": 7.47, + "y": 28.18, + "speed": 26.67, + "time": 2.33, + "theta": -90, + "omega": 0, + "vx": -26.61, + "vy": -1.74, + "splineNum": 4 + }, + { + "x": 5.84, + "y": 27.75, + "speed": 22.77, + "time": 2.4, + "theta": -90, + "omega": 0, + "vx": -22.03, + "vy": -5.76, + "splineNum": 4 + }, + { + "x": 4.27, + "y": 26.93, + "speed": 24.03, + "time": 2.48, + "theta": -90, + "omega": 0, + "vx": -21.27, + "vy": -11.19, + "splineNum": 4 + }, + { + "x": 2.78, + "y": 25.62, + "speed": 20.88, + "time": 2.57, + "theta": -90, + "omega": 0, + "vx": -15.71, + "vy": -13.75, + "splineNum": 4 + }, + { + "x": 2.78, + "y": 25.62, + "speed": 20.88, + "time": 2.57, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 5 + }, + { + "x": 1.52, + "y": 23.95, + "speed": 29.24, + "time": 2.64, + "theta": -90, + "omega": 0, + "vx": -17.61, + "vy": -23.34, + "splineNum": 5 + }, + { + "x": 0.66, + "y": 22.18, + "speed": 33.83, + "time": 2.7, + "theta": -90, + "omega": 0, + "vx": -14.77, + "vy": -30.44, + "splineNum": 5 + }, + { + "x": 0.13, + "y": 20.34, + "speed": 39.09, + "time": 2.75, + "theta": -90, + "omega": 0, + "vx": -10.79, + "vy": -37.57, + "splineNum": 5 + }, + { + "x": -0.15, + "y": 18.44, + "speed": 43.72, + "time": 2.79, + "theta": -90, + "omega": 0, + "vx": -6.32, + "vy": -43.26, + "splineNum": 5 + }, + { + "x": -0.25, + "y": 16.5, + "speed": 47.96, + "time": 2.83, + "theta": -90, + "omega": 0, + "vx": -2.55, + "vy": -47.89, + "splineNum": 5 + }, + { + "x": -0.25, + "y": 14.54, + "speed": 46.36, + "time": 2.88, + "theta": -90, + "omega": 0, + "vx": -0.14, + "vy": -46.36, + "splineNum": 5 + }, + { + "x": -0.24, + "y": 12.57, + "speed": 41.9, + "time": 2.92, + "theta": -90, + "omega": 0, + "vx": 0.31, + "vy": -41.9, + "splineNum": 5 + } + ] + }, + { + "name": "Goal4ToGoal5", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -90, + "spline_angle": 96.27, + "x": -0.56, + "y": 23.55, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 89.98, + "x": -0.56, + "y": 32.78, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal5", + "omega": 0, + "angle": 90, + "spline_angle": 89.98, + "x": 0.24, + "y": 60.94, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -0.24, + "y": 12.57, + "speed": 41.9, + "time": 0, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -0.24, + "y": 14.14, + "speed": 45.49, + "time": 0.03, + "theta": -90, + "omega": 0, + "vx": 0.11, + "vy": 45.49, + "splineNum": 0 + }, + { + "x": -0.23, + "y": 15.71, + "speed": 48.82, + "time": 0.07, + "theta": -90, + "omega": 0, + "vx": 0.11, + "vy": 48.82, + "splineNum": 0 + }, + { + "x": -0.24, + "y": 17.28, + "speed": 50, + "time": 0.1, + "theta": -90, + "omega": 0, + "vx": -0.2, + "vy": 50, + "splineNum": 0 + }, + { + "x": -0.27, + "y": 18.85, + "speed": 50, + "time": 0.13, + "theta": -90, + "omega": 0, + "vx": -0.83, + "vy": 49.99, + "splineNum": 0 + }, + { + "x": -0.32, + "y": 20.42, + "speed": 48.83, + "time": 0.16, + "theta": -90, + "omega": 0, + "vx": -1.73, + "vy": 48.8, + "splineNum": 0 + }, + { + "x": -0.42, + "y": 21.98, + "speed": 45.5, + "time": 0.2, + "theta": -90, + "omega": 0, + "vx": -2.75, + "vy": 45.41, + "splineNum": 0 + }, + { + "x": -0.56, + "y": 23.55, + "speed": 41.9, + "time": 0.23, + "theta": -90, + "omega": 0, + "vx": -3.84, + "vy": 41.72, + "splineNum": 0 + }, + { + "x": -0.56, + "y": 23.55, + "speed": 41.9, + "time": 0.23, + "theta": -90, + "omega": 0, + "vx": -1.33, + "vy": 42.67, + "splineNum": 0 + }, + { + "x": -0.67, + "y": 24.87, + "speed": 40.17, + "time": 0.27, + "theta": -89.29, + "omega": 42.83, + "vx": -3.23, + "vy": 40.04, + "splineNum": 1 + }, + { + "x": -0.71, + "y": 26.19, + "speed": 36.74, + "time": 0.3, + "theta": -86.92, + "omega": 89.52, + "vx": -1.16, + "vy": 36.72, + "splineNum": 1 + }, + { + "x": -0.7, + "y": 27.51, + "speed": 32.95, + "time": 0.34, + "theta": -82.3, + "omega": 141.56, + "vx": 0.14, + "vy": 32.95, + "splineNum": 1 + }, + { + "x": -0.67, + "y": 28.82, + "speed": 28.67, + "time": 0.39, + "theta": -74.41, + "omega": 201.38, + "vx": 0.77, + "vy": 28.66, + "splineNum": 1 + }, + { + "x": -0.62, + "y": 30.14, + "speed": 23.63, + "time": 0.44, + "theta": -61.13, + "omega": 274, + "vx": 0.85, + "vy": 23.61, + "splineNum": 1 + }, + { + "x": -0.58, + "y": 31.46, + "speed": 17.16, + "time": 0.52, + "theta": -36.22, + "omega": 994.4, + "vx": 0.54, + "vy": 17.15, + "splineNum": 1 + }, + { + "x": -0.56, + "y": 32.78, + "speed": 5.53, + "time": 0.76, + "theta": 90, + "omega": 684.2, + "vx": 0.08, + "vy": 5.53, + "splineNum": 1 + }, + { + "x": -0.56, + "y": 32.78, + "speed": 5.53, + "time": 0.76, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 2 + }, + { + "x": -0.52, + "y": 36.3, + "speed": 27.11, + "time": 0.89, + "theta": 90, + "omega": 0, + "vx": 0.27, + "vy": 27.11, + "splineNum": 2 + }, + { + "x": -0.43, + "y": 39.82, + "speed": 37.94, + "time": 0.98, + "theta": 90, + "omega": 0, + "vx": 0.98, + "vy": 37.92, + "splineNum": 2 + }, + { + "x": -0.31, + "y": 43.34, + "speed": 46.3, + "time": 1.06, + "theta": 90, + "omega": 0, + "vx": 1.68, + "vy": 46.27, + "splineNum": 2 + }, + { + "x": -0.16, + "y": 46.86, + "speed": 50, + "time": 1.13, + "theta": 90, + "omega": 0, + "vx": 2.08, + "vy": 49.96, + "splineNum": 2 + }, + { + "x": -0.01, + "y": 50.38, + "speed": 50, + "time": 1.2, + "theta": 90, + "omega": 0, + "vx": 2.08, + "vy": 49.96, + "splineNum": 2 + }, + { + "x": 0.11, + "y": 53.9, + "speed": 50, + "time": 1.27, + "theta": 90, + "omega": 0, + "vx": 1.81, + "vy": 49.97, + "splineNum": 2 + }, + { + "x": 0.2, + "y": 57.42, + "speed": 49.6, + "time": 1.34, + "theta": 90, + "omega": 0, + "vx": 1.28, + "vy": 49.58, + "splineNum": 2 + }, + { + "x": 0.24, + "y": 60.94, + "speed": 41.9, + "time": 1.42, + "theta": 90, + "omega": 0, + "vx": 0.42, + "vy": 41.9, + "splineNum": 2 + } + ] + }, + { + "name": "Goal4ToDeploy4", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + }, + { + "name": "Deploy4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": 0, + "y": 24.12, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -0.24, + "y": 12.57, + "speed": 41.9, + "time": 0, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -0.23, + "y": 14.22, + "speed": 45.67, + "time": 0.04, + "theta": -90, + "omega": 0, + "vx": 0.38, + "vy": 45.67, + "splineNum": 0 + }, + { + "x": -0.19, + "y": 15.87, + "speed": 49.15, + "time": 0.07, + "theta": -90, + "omega": 0, + "vx": 1.02, + "vy": 49.14, + "splineNum": 0 + }, + { + "x": -0.15, + "y": 17.52, + "speed": 50, + "time": 0.1, + "theta": -90, + "omega": 0, + "vx": 1.41, + "vy": 49.98, + "splineNum": 0 + }, + { + "x": -0.09, + "y": 19.17, + "speed": 50, + "time": 0.14, + "theta": -90, + "omega": 0, + "vx": 1.54, + "vy": 49.98, + "splineNum": 0 + }, + { + "x": -0.05, + "y": 20.82, + "speed": 49.15, + "time": 0.17, + "theta": -90, + "omega": 0, + "vx": 1.39, + "vy": 49.13, + "splineNum": 0 + }, + { + "x": -0.01, + "y": 22.47, + "speed": 45.67, + "time": 0.21, + "theta": -90, + "omega": 0, + "vx": 0.95, + "vy": 45.66, + "splineNum": 0 + }, + { + "x": 0, + "y": 24.12, + "speed": 41.9, + "time": 0.24, + "theta": -90, + "omega": 0, + "vx": 0.35, + "vy": 41.9, + "splineNum": 0 + }, + { + "x": 0, + "y": 24.12, + "speed": 41.9, + "time": 0.24, + "theta": -90, + "omega": 0, + "vx": 0.33, + "vy": 42.67, + "splineNum": 0 + } + ] + }, + { + "name": "Deploy4ToGoal4", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Deploy4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": 0, + "y": 24.12, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": 0, + "y": 24.12, + "speed": 41.9, + "time": 0, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -0.01, + "y": 22.47, + "speed": 45.67, + "time": 0.04, + "theta": -90, + "omega": 0, + "vx": -0.38, + "vy": -45.67, + "splineNum": 0 + }, + { + "x": -0.05, + "y": 20.82, + "speed": 49.15, + "time": 0.07, + "theta": -90, + "omega": 0, + "vx": -1.02, + "vy": -49.14, + "splineNum": 0 + }, + { + "x": -0.09, + "y": 19.17, + "speed": 50, + "time": 0.1, + "theta": -90, + "omega": 0, + "vx": -1.41, + "vy": -49.98, + "splineNum": 0 + }, + { + "x": -0.15, + "y": 17.52, + "speed": 50, + "time": 0.14, + "theta": -90, + "omega": 0, + "vx": -1.54, + "vy": -49.98, + "splineNum": 0 + }, + { + "x": -0.19, + "y": 15.87, + "speed": 49.15, + "time": 0.17, + "theta": -90, + "omega": 0, + "vx": -1.39, + "vy": -49.13, + "splineNum": 0 + }, + { + "x": -0.23, + "y": 14.22, + "speed": 45.67, + "time": 0.21, + "theta": -90, + "omega": 0, + "vx": -0.95, + "vy": -45.66, + "splineNum": 0 + }, + { + "x": -0.24, + "y": 12.57, + "speed": 41.9, + "time": 0.24, + "theta": -90, + "omega": 0, + "vx": -0.35, + "vy": -41.9, + "splineNum": 0 + }, + { + "x": -0.24, + "y": 12.57, + "speed": 41.9, + "time": 0.24, + "theta": -90, + "omega": 0, + "vx": -0.5, + "vy": -32, + "splineNum": 0 + } + ] + }, + { + "name": "Goal1ToDeploy1", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -55.25, + "y": 16.43, + "shared": true, + "speed": 41.9 + }, + { + "name": "Deploy1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -52.32, + "y": 18.69, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -55.25, + "y": 16.43, + "speed": 22.62, + "time": 0, + "theta": -135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -54.86, + "y": 16.79, + "speed": 20.14, + "time": 0.03, + "theta": -135, + "omega": 0, + "vx": 14.93, + "vy": 13.52, + "splineNum": 0 + }, + { + "x": -54.44, + "y": 17.11, + "speed": 22.62, + "time": 0.05, + "theta": -135, + "omega": 0, + "vx": 17.91, + "vy": 13.81, + "splineNum": 0 + }, + { + "x": -54, + "y": 17.41, + "speed": 24.85, + "time": 0.07, + "theta": -135, + "omega": 0, + "vx": 20.37, + "vy": 14.23, + "splineNum": 0 + }, + { + "x": -53.57, + "y": 17.71, + "speed": 24.85, + "time": 0.09, + "theta": -135, + "omega": 0, + "vx": 20.59, + "vy": 13.9, + "splineNum": 0 + }, + { + "x": -53.13, + "y": 18.01, + "speed": 22.62, + "time": 0.12, + "theta": -135, + "omega": 0, + "vx": 18.54, + "vy": 12.95, + "splineNum": 0 + }, + { + "x": -52.71, + "y": 18.33, + "speed": 20.14, + "time": 0.14, + "theta": -135, + "omega": 0, + "vx": 15.95, + "vy": 12.3, + "splineNum": 0 + }, + { + "x": -52.32, + "y": 18.69, + "speed": 22.62, + "time": 0.17, + "theta": -135, + "omega": 0, + "vx": 16.77, + "vy": 15.19, + "splineNum": 0 + } + ] + }, + { + "name": "Deploy1ToGoal1", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Deploy1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -52.32, + "y": 18.69, + "shared": true, + "speed": 41.9 + }, + { + "name": "Goal1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -55.25, + "y": 16.43, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -52.32, + "y": 18.69, + "speed": 22.62, + "time": 0, + "theta": -135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -52.71, + "y": 18.33, + "speed": 20.14, + "time": 0.03, + "theta": -135, + "omega": 0, + "vx": -14.93, + "vy": -13.52, + "splineNum": 0 + }, + { + "x": -53.13, + "y": 18.01, + "speed": 22.62, + "time": 0.05, + "theta": -135, + "omega": 0, + "vx": -17.91, + "vy": -13.81, + "splineNum": 0 + }, + { + "x": -53.57, + "y": 17.71, + "speed": 24.85, + "time": 0.07, + "theta": -135, + "omega": 0, + "vx": -20.37, + "vy": -14.23, + "splineNum": 0 + }, + { + "x": -54, + "y": 17.41, + "speed": 24.85, + "time": 0.09, + "theta": -135, + "omega": 0, + "vx": -20.59, + "vy": -13.9, + "splineNum": 0 + }, + { + "x": -54.44, + "y": 17.11, + "speed": 22.62, + "time": 0.12, + "theta": -135, + "omega": 0, + "vx": -18.54, + "vy": -12.95, + "splineNum": 0 + }, + { + "x": -54.86, + "y": 16.79, + "speed": 20.14, + "time": 0.14, + "theta": -135, + "omega": 0, + "vx": -15.95, + "vy": -12.3, + "splineNum": 0 + }, + { + "x": -55.25, + "y": 16.43, + "speed": 22.62, + "time": 0.17, + "theta": -135, + "omega": 0, + "vx": -16.77, + "vy": -15.19, + "splineNum": 0 + } + ] + }, + { + "name": "DeployWall1ToGoal1", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "DeployWall1", + "omega": 0, + "angle": 90, + "spline_angle": 88.38, + "x": -36.52, + "y": 9.85, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 101.35, + "spline_angle": 97.52, + "x": -36.86, + "y": 19.54, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -47.74, + "y": 23.61, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -55.25, + "y": 16.43, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -36.52, + "y": 9.85, + "speed": 41.9, + "time": 0, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -36.49, + "y": 11.24, + "speed": 41.08, + "time": 0.03, + "theta": 90.04, + "omega": 2.27, + "vx": 0.96, + "vy": 41.07, + "splineNum": 0 + }, + { + "x": -36.47, + "y": 12.62, + "speed": 37.55, + "time": 0.07, + "theta": 90.17, + "omega": 4.75, + "vx": 0.4, + "vy": 37.55, + "splineNum": 0 + }, + { + "x": -36.48, + "y": 14.01, + "speed": 33.66, + "time": 0.11, + "theta": 90.42, + "omega": 7.52, + "vx": -0.21, + "vy": 33.66, + "splineNum": 0 + }, + { + "x": -36.52, + "y": 15.39, + "speed": 29.26, + "time": 0.16, + "theta": 90.85, + "omega": 10.71, + "vx": -0.79, + "vy": 29.25, + "splineNum": 0 + }, + { + "x": -36.59, + "y": 16.78, + "speed": 24.06, + "time": 0.22, + "theta": 91.58, + "omega": 14.58, + "vx": -1.25, + "vy": 24.03, + "splineNum": 0 + }, + { + "x": -36.7, + "y": 18.16, + "speed": 17.37, + "time": 0.3, + "theta": 92.96, + "omega": 58.2, + "vx": -1.4, + "vy": 17.31, + "splineNum": 0 + }, + { + "x": -36.86, + "y": 19.54, + "speed": 4.89, + "time": 0.58, + "theta": 101.35, + "omega": 39.07, + "vx": -0.55, + "vy": 4.85, + "splineNum": 0 + }, + { + "x": -36.86, + "y": 19.54, + "speed": 4.89, + "time": 0.58, + "theta": 101.35, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": -37.46, + "y": 22.68, + "speed": 25.77, + "time": 0.71, + "theta": 103.75, + "omega": 38.65, + "vx": -4.8, + "vy": 25.32, + "splineNum": 1 + }, + { + "x": -38.33, + "y": 25.07, + "speed": 22.79, + "time": 0.82, + "theta": 110.01, + "omega": 73.41, + "vx": -7.85, + "vy": 21.4, + "splineNum": 1 + }, + { + "x": -39.52, + "y": 26.65, + "speed": 11.2, + "time": 0.99, + "theta": 127.75, + "omega": 128.17, + "vx": -6.72, + "vy": 8.96, + "splineNum": 1 + }, + { + "x": -41.02, + "y": 27.35, + "speed": 9.6, + "time": 1.17, + "theta": 154.63, + "omega": 372.71, + "vx": -8.71, + "vy": 4.05, + "splineNum": 1 + }, + { + "x": -42.88, + "y": 27.12, + "speed": 17.63, + "time": 1.27, + "theta": 175.74, + "omega": 339.64, + "vx": -17.49, + "vy": -2.19, + "splineNum": 1 + }, + { + "x": -45.11, + "y": 25.89, + "speed": 28.64, + "time": 1.36, + "theta": 196.11, + "omega": 311.97, + "vx": -25.09, + "vy": -13.8, + "splineNum": 1 + }, + { + "x": -47.74, + "y": 23.61, + "speed": 31.33, + "time": 1.47, + "theta": 225, + "omega": 277.4, + "vx": -23.64, + "vy": -20.55, + "splineNum": 1 + }, + { + "x": -47.74, + "y": 23.61, + "speed": 31.33, + "time": 1.47, + "theta": 225, + "omega": 277.4, + "vx": -31.33, + "vy": 0, + "splineNum": 1 + }, + { + "x": -48.8, + "y": 22.57, + "speed": 35.75, + "time": 1.51, + "theta": -135, + "omega": 0, + "vx": -25.5, + "vy": -25.06, + "splineNum": 2 + }, + { + "x": -49.87, + "y": 21.54, + "speed": 39.69, + "time": 1.55, + "theta": -135, + "omega": 0, + "vx": -28.69, + "vy": -27.43, + "splineNum": 2 + }, + { + "x": -50.95, + "y": 20.53, + "speed": 43.27, + "time": 1.59, + "theta": -135, + "omega": 0, + "vx": -31.52, + "vy": -29.64, + "splineNum": 2 + }, + { + "x": -52.04, + "y": 19.51, + "speed": 46.57, + "time": 1.62, + "theta": -135, + "omega": 0, + "vx": -34.01, + "vy": -31.81, + "splineNum": 2 + }, + { + "x": -53.12, + "y": 18.5, + "speed": 48.47, + "time": 1.65, + "theta": -135, + "omega": 0, + "vx": -35.31, + "vy": -33.2, + "splineNum": 2 + }, + { + "x": -54.19, + "y": 17.47, + "speed": 45.3, + "time": 1.68, + "theta": -135, + "omega": 0, + "vx": -32.75, + "vy": -31.31, + "splineNum": 2 + }, + { + "x": -55.25, + "y": 16.43, + "speed": 41.9, + "time": 1.72, + "theta": -135, + "omega": 0, + "vx": -29.88, + "vy": -29.37, + "splineNum": 2 + } + ] + }, + { + "name": "Goal4ToGoal1", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -102.53, + "spline_angle": 90, + "x": -1.35, + "y": 24.18, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -78.51, + "spline_angle": 180, + "x": -10.1, + "y": 28.32, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -169.66, + "spline_angle": -178.12, + "x": -23.79, + "y": 25.46, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -159.52, + "spline_angle": -159.52, + "x": -42.72, + "y": 21.16, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -135, + "spline_angle": -153.43, + "x": -52.32, + "y": 17.16, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal1", + "omega": 0, + "angle": -135, + "spline_angle": -135, + "x": -55.25, + "y": 16.43, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -0.24, + "y": 12.57, + "speed": 41.9, + "time": 0, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -0.3, + "y": 14.24, + "speed": 45.13, + "time": 0.04, + "theta": -90.05, + "omega": -2.56, + "vx": -1.65, + "vy": 45.1, + "splineNum": 0 + }, + { + "x": -0.46, + "y": 15.9, + "speed": 41.27, + "time": 0.08, + "theta": -90.21, + "omega": -5.35, + "vx": -3.92, + "vy": 41.09, + "splineNum": 0 + }, + { + "x": -0.68, + "y": 17.55, + "speed": 37.01, + "time": 0.12, + "theta": -90.52, + "omega": -8.46, + "vx": -4.81, + "vy": 36.7, + "splineNum": 0 + }, + { + "x": -0.91, + "y": 19.2, + "speed": 32.19, + "time": 0.17, + "theta": -91.05, + "omega": -12.04, + "vx": -4.56, + "vy": 31.87, + "splineNum": 0 + }, + { + "x": -1.13, + "y": 20.85, + "speed": 26.51, + "time": 0.24, + "theta": -91.94, + "omega": -16.39, + "vx": -3.45, + "vy": 26.29, + "splineNum": 0 + }, + { + "x": -1.29, + "y": 22.51, + "speed": 19.23, + "time": 0.32, + "theta": -93.62, + "omega": -60.86, + "vx": -1.83, + "vy": 19.14, + "splineNum": 0 + }, + { + "x": -1.35, + "y": 24.18, + "speed": 6, + "time": 0.6, + "theta": -102.53, + "omega": -41.62, + "vx": -0.22, + "vy": 5.99, + "splineNum": 0 + }, + { + "x": -1.35, + "y": 24.18, + "speed": 6, + "time": 0.6, + "theta": -102.53, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": -1.65, + "y": 26.78, + "speed": 17.31, + "time": 0.75, + "theta": -101.8, + "omega": 9.68, + "vx": -1.96, + "vy": 17.2, + "splineNum": 1 + }, + { + "x": -2.46, + "y": 28.3, + "speed": 8.31, + "time": 0.96, + "theta": -98.43, + "omega": 22.91, + "vx": -3.93, + "vy": 7.32, + "splineNum": 1 + }, + { + "x": -3.67, + "y": 28.98, + "speed": 9.67, + "time": 1.1, + "theta": -94.48, + "omega": 78.76, + "vx": -8.44, + "vy": 4.72, + "splineNum": 1 + }, + { + "x": -5.16, + "y": 29.07, + "speed": 19.79, + "time": 1.18, + "theta": -91.89, + "omega": 73.95, + "vx": -19.75, + "vy": 1.19, + "splineNum": 1 + }, + { + "x": -6.8, + "y": 28.82, + "speed": 26.92, + "time": 1.24, + "theta": -89.48, + "omega": 69.99, + "vx": -26.62, + "vy": -3.99, + "splineNum": 1 + }, + { + "x": -8.49, + "y": 28.49, + "speed": 21.1, + "time": 1.32, + "theta": -85.94, + "omega": 64.78, + "vx": -20.7, + "vy": -4.08, + "splineNum": 1 + }, + { + "x": -10.1, + "y": 28.32, + "speed": 11.04, + "time": 1.47, + "theta": -78.51, + "omega": 55.42, + "vx": -10.98, + "vy": -1.14, + "splineNum": 1 + }, + { + "x": -10.1, + "y": 28.32, + "speed": 11.04, + "time": 1.47, + "theta": -78.51, + "omega": 55.42, + "vx": -11.04, + "vy": 0, + "splineNum": 1 + }, + { + "x": -12.11, + "y": 28.17, + "speed": 22.91, + "time": 1.56, + "theta": -83.11, + "omega": -104.69, + "vx": -22.85, + "vy": -1.71, + "splineNum": 2 + }, + { + "x": -14.07, + "y": 27.78, + "speed": 30.41, + "time": 1.62, + "theta": -92.56, + "omega": -182.89, + "vx": -29.82, + "vy": -5.93, + "splineNum": 2 + }, + { + "x": -16, + "y": 27.24, + "speed": 36.4, + "time": 1.68, + "theta": -104.42, + "omega": -683.24, + "vx": -35.07, + "vy": -9.76, + "splineNum": 2 + }, + { + "x": -17.92, + "y": 26.65, + "speed": 41.55, + "time": 1.73, + "theta": -117.81, + "omega": -625.75, + "vx": -39.7, + "vy": -12.27, + "splineNum": 2 + }, + { + "x": -19.84, + "y": 26.09, + "speed": 46.12, + "time": 1.77, + "theta": -132.22, + "omega": -574.05, + "vx": -44.31, + "vy": -12.8, + "splineNum": 2 + }, + { + "x": -21.79, + "y": 25.67, + "speed": 46.45, + "time": 1.81, + "theta": -148.7, + "omega": -522.85, + "vx": -45.37, + "vy": -9.94, + "splineNum": 2 + }, + { + "x": -23.79, + "y": 25.46, + "speed": 41.9, + "time": 1.86, + "theta": -169.66, + "omega": -465.8, + "vx": -41.68, + "vy": -4.32, + "splineNum": 2 + }, + { + "x": -23.79, + "y": 25.46, + "speed": 41.9, + "time": 1.86, + "theta": -169.66, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 3 + }, + { + "x": -26.59, + "y": 25.27, + "speed": 48.14, + "time": 1.92, + "theta": -169.61, + "omega": 1.55, + "vx": -48.03, + "vy": -3.2, + "splineNum": 3 + }, + { + "x": -29.35, + "y": 24.91, + "speed": 50, + "time": 1.97, + "theta": -169.49, + "omega": 3.02, + "vx": -49.58, + "vy": -6.48, + "splineNum": 3 + }, + { + "x": -32.08, + "y": 24.4, + "speed": 47.61, + "time": 2.03, + "theta": -169.27, + "omega": 4.57, + "vx": -46.78, + "vy": -8.86, + "splineNum": 3 + }, + { + "x": -34.78, + "y": 23.74, + "speed": 41.37, + "time": 2.1, + "theta": -168.9, + "omega": 6.34, + "vx": -40.21, + "vy": -9.74, + "splineNum": 3 + }, + { + "x": -37.44, + "y": 22.97, + "speed": 34, + "time": 2.18, + "theta": -168.29, + "omega": 8.51, + "vx": -32.67, + "vy": -9.42, + "splineNum": 3 + }, + { + "x": -40.09, + "y": 22.11, + "speed": 24.48, + "time": 2.3, + "theta": -167.16, + "omega": 11.52, + "vx": -23.26, + "vy": -7.62, + "splineNum": 3 + }, + { + "x": -42.72, + "y": 21.16, + "speed": 6.35, + "time": 2.74, + "theta": -159.52, + "omega": 23.18, + "vx": -5.97, + "vy": -2.15, + "splineNum": 3 + }, + { + "x": -42.72, + "y": 21.16, + "speed": 6.35, + "time": 2.74, + "theta": -159.52, + "omega": 23.18, + "vx": 0, + "vy": -8, + "splineNum": 3 + }, + { + "x": -44.11, + "y": 20.64, + "speed": 18.38, + "time": 2.82, + "theta": -159.4, + "omega": 3.07, + "vx": -17.2, + "vy": -6.45, + "splineNum": 4 + }, + { + "x": -45.5, + "y": 20.11, + "speed": 25.2, + "time": 2.88, + "theta": -159.15, + "omega": 5.32, + "vx": -23.54, + "vy": -8.98, + "splineNum": 4 + }, + { + "x": -46.88, + "y": 19.57, + "speed": 30.53, + "time": 2.92, + "theta": -158.84, + "omega": 7.17, + "vx": -28.42, + "vy": -11.15, + "splineNum": 4 + }, + { + "x": -48.26, + "y": 19, + "speed": 29.93, + "time": 2.97, + "theta": -158.44, + "omega": 9.05, + "vx": -27.72, + "vy": -11.3, + "splineNum": 4 + }, + { + "x": -49.63, + "y": 18.42, + "speed": 24.47, + "time": 3.03, + "theta": -157.82, + "omega": 11.36, + "vx": -22.5, + "vy": -9.62, + "splineNum": 4 + }, + { + "x": -50.98, + "y": 17.81, + "speed": 17.36, + "time": 3.12, + "theta": -156.71, + "omega": 14.61, + "vx": -15.82, + "vy": -7.16, + "splineNum": 4 + }, + { + "x": -52.32, + "y": 17.16, + "speed": 1.98, + "time": 3.87, + "theta": -135, + "omega": 43.17, + "vx": -1.78, + "vy": -0.86, + "splineNum": 4 + }, + { + "x": -52.32, + "y": 17.16, + "speed": 1.98, + "time": 3.87, + "theta": -135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 5 + }, + { + "x": -52.73, + "y": 17.02, + "speed": 6.59, + "time": 3.94, + "theta": -135, + "omega": 0, + "vx": -6.23, + "vy": -2.16, + "splineNum": 5 + }, + { + "x": -53.16, + "y": 16.96, + "speed": 11.41, + "time": 3.97, + "theta": -135, + "omega": 0, + "vx": -11.3, + "vy": -1.55, + "splineNum": 5 + }, + { + "x": -53.6, + "y": 16.94, + "speed": 14.67, + "time": 4, + "theta": -135, + "omega": 0, + "vx": -14.66, + "vy": -0.61, + "splineNum": 5 + }, + { + "x": -54.04, + "y": 16.92, + "speed": 11.28, + "time": 4.04, + "theta": -135, + "omega": 0, + "vx": -11.27, + "vy": -0.51, + "splineNum": 5 + }, + { + "x": -54.47, + "y": 16.86, + "speed": 6.37, + "time": 4.11, + "theta": -135, + "omega": 0, + "vx": -6.3, + "vy": -0.93, + "splineNum": 5 + }, + { + "x": -54.87, + "y": 16.71, + "speed": 4.75, + "time": 4.2, + "theta": -135, + "omega": 0, + "vx": -4.46, + "vy": -1.64, + "splineNum": 5 + }, + { + "x": -55.25, + "y": 16.43, + "speed": 10.77, + "time": 4.25, + "theta": -135, + "omega": 0, + "vx": -8.66, + "vy": -6.41, + "splineNum": 5 + } + ] + }, + { + "name": "Goal7ToGoal5", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal7", + "omega": 0, + "angle": -45, + "spline_angle": 134.17, + "x": 62.36, + "y": 14.38, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -75, + "spline_angle": 106.69, + "x": 55.04, + "y": 19.88, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -165, + "spline_angle": -173.19, + "x": 46.38, + "y": 26.16, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -180, + "spline_angle": -173.19, + "x": 31.43, + "y": 22.42, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 134.97, + "x": 10.53, + "y": 25.14, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 104.06, + "x": 1.7, + "y": 36.35, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 90.01, + "x": 0.51, + "y": 47.23, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal5", + "omega": 0, + "angle": 90, + "spline_angle": 89.98, + "x": 0.24, + "y": 60.94, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": 62.36, + "y": 14.38, + "speed": 26.44, + "time": 0, + "theta": -45, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 61.33, + "y": 15.19, + "speed": 20.91, + "time": 0.06, + "theta": -45.14, + "omega": -4.62, + "vx": -16.4, + "vy": 12.98, + "splineNum": 0 + }, + { + "x": 60.16, + "y": 15.8, + "speed": 26.51, + "time": 0.11, + "theta": -45.47, + "omega": -8.32, + "vx": -23.51, + "vy": 12.24, + "splineNum": 0 + }, + { + "x": 58.92, + "y": 16.33, + "speed": 28.14, + "time": 0.16, + "theta": -45.95, + "omega": -11.86, + "vx": -25.89, + "vy": 11.01, + "splineNum": 0 + }, + { + "x": 57.7, + "y": 16.89, + "speed": 22.89, + "time": 0.22, + "theta": -46.77, + "omega": -16.18, + "vx": -20.81, + "vy": 9.52, + "splineNum": 0 + }, + { + "x": 56.59, + "y": 17.59, + "speed": 16.17, + "time": 0.3, + "theta": -48.33, + "omega": -22.18, + "vx": -13.67, + "vy": 8.63, + "splineNum": 0 + }, + { + "x": 55.68, + "y": 18.55, + "speed": 13.31, + "time": 0.4, + "theta": -50.9, + "omega": -29.54, + "vx": -9.19, + "vy": 9.63, + "splineNum": 0 + }, + { + "x": 55.04, + "y": 19.88, + "speed": 2.94, + "time": 0.9, + "theta": -75, + "omega": -66.58, + "vx": -1.27, + "vy": 2.66, + "splineNum": 0 + }, + { + "x": 55.04, + "y": 19.88, + "speed": 2.94, + "time": 0.9, + "theta": -75, + "omega": -66.58, + "vx": 0, + "vy": 2.91, + "splineNum": 0 + }, + { + "x": 54.41, + "y": 21.61, + "speed": 19.42, + "time": 1, + "theta": -77.63, + "omega": -55.4, + "vx": -6.66, + "vy": 18.24, + "splineNum": 1 + }, + { + "x": 53.6, + "y": 23.11, + "speed": 26.63, + "time": 1.06, + "theta": -82.34, + "omega": -92.6, + "vx": -12.63, + "vy": 23.45, + "splineNum": 1 + }, + { + "x": 52.61, + "y": 24.34, + "speed": 20.8, + "time": 1.14, + "theta": -91.08, + "omega": -137.05, + "vx": -13.06, + "vy": 16.18, + "splineNum": 1 + }, + { + "x": 51.41, + "y": 25.28, + "speed": 18.75, + "time": 1.22, + "theta": -104.2, + "omega": -463.7, + "vx": -14.73, + "vy": 11.6, + "splineNum": 1 + }, + { + "x": 49.98, + "y": 25.92, + "speed": 20.34, + "time": 1.29, + "theta": -120.11, + "omega": -418.86, + "vx": -18.58, + "vy": 8.27, + "splineNum": 1 + }, + { + "x": 48.31, + "y": 26.22, + "speed": 26.14, + "time": 1.36, + "theta": -136.23, + "omega": -380.97, + "vx": -25.73, + "vy": 4.63, + "splineNum": 1 + }, + { + "x": 46.38, + "y": 26.16, + "speed": 19.86, + "time": 1.46, + "theta": -165, + "omega": -324.19, + "vx": -19.85, + "vy": -0.61, + "splineNum": 1 + }, + { + "x": 46.38, + "y": 26.16, + "speed": 19.86, + "time": 1.46, + "theta": -165, + "omega": -324.19, + "vx": 19.86, + "vy": 0, + "splineNum": 1 + }, + { + "x": 44.2, + "y": 25.79, + "speed": 28.91, + "time": 1.53, + "theta": -165.51, + "omega": -13.44, + "vx": -28.51, + "vy": -4.82, + "splineNum": 2 + }, + { + "x": 42.07, + "y": 25.26, + "speed": 35.73, + "time": 1.59, + "theta": -166.68, + "omega": -24.28, + "vx": -34.66, + "vy": -8.67, + "splineNum": 2 + }, + { + "x": 39.96, + "y": 24.62, + "speed": 41.44, + "time": 1.65, + "theta": -168.22, + "omega": -33.64, + "vx": -39.69, + "vy": -11.92, + "splineNum": 2 + }, + { + "x": 37.85, + "y": 23.96, + "speed": 46.46, + "time": 1.69, + "theta": -170.01, + "omega": -103.32, + "vx": -44.28, + "vy": -14.05, + "splineNum": 2 + }, + { + "x": 35.74, + "y": 23.32, + "speed": 44.14, + "time": 1.74, + "theta": -172.33, + "omega": -94.53, + "vx": -42.27, + "vy": -12.7, + "splineNum": 2 + }, + { + "x": 33.61, + "y": 22.79, + "speed": 38.83, + "time": 1.8, + "theta": -175.49, + "omega": -84.56, + "vx": -37.67, + "vy": -9.42, + "splineNum": 2 + }, + { + "x": 31.43, + "y": 22.42, + "speed": 32.65, + "time": 1.87, + "theta": -180, + "omega": -72.66, + "vx": -32.2, + "vy": -5.45, + "splineNum": 2 + }, + { + "x": 31.43, + "y": 22.42, + "speed": 32.65, + "time": 1.87, + "theta": -180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 3 + }, + { + "x": 28.34, + "y": 21.97, + "speed": 41.13, + "time": 1.95, + "theta": -182.02, + "omega": -53.11, + "vx": -40.7, + "vy": -5.91, + "splineNum": 3 + }, + { + "x": 25.24, + "y": 21.49, + "speed": 48.16, + "time": 2.01, + "theta": -186.96, + "omega": -98.62, + "vx": -47.58, + "vy": -7.45, + "splineNum": 3 + }, + { + "x": 22.16, + "y": 21.15, + "speed": 50, + "time": 2.07, + "theta": -194.41, + "omega": -141.89, + "vx": -49.71, + "vy": -5.36, + "splineNum": 3 + }, + { + "x": 19.12, + "y": 21.16, + "speed": 46.63, + "time": 2.14, + "theta": -205.13, + "omega": -521.84, + "vx": -46.62, + "vy": 0.16, + "splineNum": 3 + }, + { + "x": 16.16, + "y": 21.71, + "speed": 39.64, + "time": 2.21, + "theta": -221.4, + "omega": -468.71, + "vx": -38.99, + "vy": 7.12, + "splineNum": 3 + }, + { + "x": 13.28, + "y": 22.97, + "speed": 39.39, + "time": 2.29, + "theta": -242.77, + "omega": -413.07, + "vx": -36.06, + "vy": 15.85, + "splineNum": 3 + }, + { + "x": 10.53, + "y": 25.14, + "speed": 41.9, + "time": 2.38, + "theta": -270, + "omega": -354.6, + "vx": -32.9, + "vy": 25.94, + "splineNum": 3 + }, + { + "x": 10.53, + "y": 25.14, + "speed": 41.9, + "time": 2.38, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 4 + }, + { + "x": 9.04, + "y": 26.56, + "speed": 46.56, + "time": 2.42, + "theta": 90, + "omega": 0, + "vx": -33.66, + "vy": 32.17, + "splineNum": 4 + }, + { + "x": 7.52, + "y": 27.96, + "speed": 50, + "time": 2.46, + "theta": 90, + "omega": 0, + "vx": -36.82, + "vy": 33.83, + "splineNum": 4 + }, + { + "x": 6.03, + "y": 29.38, + "speed": 50, + "time": 2.5, + "theta": 90, + "omega": 0, + "vx": -36.14, + "vy": 34.55, + "splineNum": 4 + }, + { + "x": 4.64, + "y": 30.88, + "speed": 46.88, + "time": 2.55, + "theta": 90, + "omega": 0, + "vx": -31.88, + "vy": 34.36, + "splineNum": 4 + }, + { + "x": 3.41, + "y": 32.51, + "speed": 42.3, + "time": 2.6, + "theta": 90, + "omega": 0, + "vx": -25.5, + "vy": 33.76, + "splineNum": 4 + }, + { + "x": 2.41, + "y": 34.31, + "speed": 37.1, + "time": 2.65, + "theta": 90, + "omega": 0, + "vx": -18, + "vy": 32.44, + "splineNum": 4 + }, + { + "x": 1.7, + "y": 36.35, + "speed": 41.9, + "time": 2.7, + "theta": 90, + "omega": 0, + "vx": -13.8, + "vy": 39.56, + "splineNum": 4 + }, + { + "x": 1.7, + "y": 36.35, + "speed": 41.9, + "time": 2.7, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 5 + }, + { + "x": 1.35, + "y": 37.88, + "speed": 43.48, + "time": 2.74, + "theta": 90, + "omega": 0, + "vx": -9.6, + "vy": 42.41, + "splineNum": 5 + }, + { + "x": 1.07, + "y": 39.43, + "speed": 39.71, + "time": 2.78, + "theta": 90, + "omega": 0, + "vx": -7.08, + "vy": 39.08, + "splineNum": 5 + }, + { + "x": 0.86, + "y": 40.98, + "speed": 35.56, + "time": 2.82, + "theta": 90, + "omega": 0, + "vx": -4.93, + "vy": 35.21, + "splineNum": 5 + }, + { + "x": 0.7, + "y": 42.53, + "speed": 30.85, + "time": 2.87, + "theta": 90, + "omega": 0, + "vx": -3.14, + "vy": 30.69, + "splineNum": 5 + }, + { + "x": 0.59, + "y": 44.09, + "speed": 25.27, + "time": 2.93, + "theta": 90, + "omega": 0, + "vx": -1.73, + "vy": 25.21, + "splineNum": 5 + }, + { + "x": 0.53, + "y": 45.66, + "speed": 18.03, + "time": 3.02, + "theta": 90, + "omega": 0, + "vx": -0.7, + "vy": 18.02, + "splineNum": 5 + }, + { + "x": 0.51, + "y": 47.23, + "speed": 3.3, + "time": 3.5, + "theta": 90, + "omega": 0, + "vx": -0.04, + "vy": 3.3, + "splineNum": 5 + }, + { + "x": 0.51, + "y": 47.23, + "speed": 3.3, + "time": 3.5, + "theta": 90, + "omega": 0, + "vx": -3.3, + "vy": 0, + "splineNum": 5 + }, + { + "x": 0.49, + "y": 49.19, + "speed": 20.07, + "time": 3.59, + "theta": 90, + "omega": 0, + "vx": -0.16, + "vy": 20.07, + "splineNum": 6 + }, + { + "x": 0.46, + "y": 51.15, + "speed": 28.19, + "time": 3.66, + "theta": 90, + "omega": 0, + "vx": -0.56, + "vy": 28.18, + "splineNum": 6 + }, + { + "x": 0.4, + "y": 53.11, + "speed": 34.44, + "time": 3.72, + "theta": 90, + "omega": 0, + "vx": -0.93, + "vy": 34.43, + "splineNum": 6 + }, + { + "x": 0.35, + "y": 55.06, + "speed": 39.73, + "time": 3.77, + "theta": 90, + "omega": 0, + "vx": -1.17, + "vy": 39.71, + "splineNum": 6 + }, + { + "x": 0.29, + "y": 57.02, + "speed": 44.38, + "time": 3.81, + "theta": 90, + "omega": 0, + "vx": -1.19, + "vy": 44.37, + "splineNum": 6 + }, + { + "x": 0.25, + "y": 58.98, + "speed": 46.34, + "time": 3.86, + "theta": 90, + "omega": 0, + "vx": -0.91, + "vy": 46.33, + "splineNum": 6 + }, + { + "x": 0.24, + "y": 60.94, + "speed": 41.9, + "time": 3.9, + "theta": 90, + "omega": 0, + "vx": -0.31, + "vy": 41.9, + "splineNum": 6 + } + ] + }, + { + "name": "DeployWall2ToGoal4", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "DeployWall2", + "omega": 0, + "angle": -90, + "spline_angle": 90, + "x": -16.89, + "y": 13.66, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -90, + "spline_angle": 179.94, + "x": -8.66, + "y": 23.1, + "shared": false, + "speed": 41.9 + }, + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + } + ], + "points": [ + { + "x": -16.89, + "y": 13.66, + "speed": 41.24, + "time": 0, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -16.77, + "y": 15.93, + "speed": 35.3, + "time": 0.06, + "theta": -90, + "omega": 0, + "vx": 1.9, + "vy": 35.25, + "splineNum": 0 + }, + { + "x": -16.37, + "y": 17.95, + "speed": 28.87, + "time": 0.14, + "theta": -90, + "omega": 0, + "vx": 5.55, + "vy": 28.33, + "splineNum": 0 + }, + { + "x": -15.65, + "y": 19.7, + "speed": 21.34, + "time": 0.22, + "theta": -90, + "omega": 0, + "vx": 8.1, + "vy": 19.74, + "splineNum": 0 + }, + { + "x": -14.57, + "y": 21.13, + "speed": 18.15, + "time": 0.32, + "theta": -90, + "omega": 0, + "vx": 10.97, + "vy": 14.46, + "splineNum": 0 + }, + { + "x": -13.07, + "y": 22.2, + "speed": 20.25, + "time": 0.41, + "theta": -90, + "omega": 0, + "vx": 16.48, + "vy": 11.77, + "splineNum": 0 + }, + { + "x": -11.12, + "y": 22.87, + "speed": 28.69, + "time": 0.49, + "theta": -90, + "omega": 0, + "vx": 27.14, + "vy": 9.3, + "splineNum": 0 + }, + { + "x": -8.66, + "y": 23.1, + "speed": 36.29, + "time": 0.55, + "theta": -90, + "omega": 0, + "vx": 36.13, + "vy": 3.38, + "splineNum": 0 + }, + { + "x": -8.66, + "y": 23.1, + "speed": 36.29, + "time": 0.55, + "theta": -90, + "omega": 0, + "vx": 36.29, + "vy": 0, + "splineNum": 0 + }, + { + "x": -5.93, + "y": 22.82, + "speed": 28.43, + "time": 0.65, + "theta": -90, + "omega": 0, + "vx": 28.28, + "vy": -2.94, + "splineNum": 1 + }, + { + "x": -3.85, + "y": 22.02, + "speed": 19.64, + "time": 0.76, + "theta": -90, + "omega": 0, + "vx": 18.34, + "vy": -7.05, + "splineNum": 1 + }, + { + "x": -2.33, + "y": 20.76, + "speed": 18.59, + "time": 0.87, + "theta": -90, + "omega": 0, + "vx": 14.35, + "vy": -11.82, + "splineNum": 1 + }, + { + "x": -1.29, + "y": 19.13, + "speed": 24.09, + "time": 0.95, + "theta": -90, + "omega": 0, + "vx": 12.9, + "vy": -20.34, + "splineNum": 1 + }, + { + "x": -0.65, + "y": 17.17, + "speed": 31.49, + "time": 1.02, + "theta": -90, + "omega": 0, + "vx": 9.78, + "vy": -29.93, + "splineNum": 1 + }, + { + "x": -0.33, + "y": 14.97, + "speed": 37.92, + "time": 1.07, + "theta": -90, + "omega": 0, + "vx": 5.48, + "vy": -37.52, + "splineNum": 1 + }, + { + "x": -0.24, + "y": 12.57, + "speed": 35.42, + "time": 1.14, + "theta": -90, + "omega": 0, + "vx": 1.31, + "vy": -35.39, + "splineNum": 1 + }, + { + "x": -0.24, + "y": 12.57, + "speed": 35.42, + "time": 1.14, + "theta": -90, + "omega": 0, + "vx": -8, + "vy": -24, + "splineNum": 1 + } + ] + }, + { + "name": "V2-Goal4ToGoal1", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "Goal4", + "omega": 0, + "angle": -90, + "spline_angle": 89.98, + "x": -0.24, + "y": 12.57, + "shared": true, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -102.53, + "spline_angle": 90, + "x": -1.35, + "y": 24.18, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": -75, + "spline_angle": -142.88, + "x": -10.1, + "y": 28.32, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": 14.05, + "x": -24.23, + "y": 19.12, + "shared": false, + "speed": 41.9 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": 160.88, + "x": -43.85, + "y": 21.97, + "shared": false, + "speed": 40 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": -177.9, + "x": -62.97, + "y": 34.21, + "shared": false, + "speed": 5 + }, + { + "name": "wp", + "omega": 0, + "angle": -135, + "spline_angle": 79.17, + "x": -54.08, + "y": 15.6, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -135, + "spline_angle": 59.02, + "x": -60.96, + "y": 6.88, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": -0.24, + "y": 12.57, + "speed": 41.9, + "time": 0, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -0.3, + "y": 14.24, + "speed": 45.14, + "time": 0.04, + "theta": -90.05, + "omega": -2.59, + "vx": -1.65, + "vy": 45.11, + "splineNum": 0 + }, + { + "x": -0.46, + "y": 15.9, + "speed": 41.28, + "time": 0.08, + "theta": -90.21, + "omega": -5.42, + "vx": -3.93, + "vy": 41.1, + "splineNum": 0 + }, + { + "x": -0.68, + "y": 17.55, + "speed": 37.03, + "time": 0.12, + "theta": -90.52, + "omega": -8.57, + "vx": -4.82, + "vy": 36.71, + "splineNum": 0 + }, + { + "x": -0.91, + "y": 19.2, + "speed": 32.21, + "time": 0.17, + "theta": -91.06, + "omega": -12.2, + "vx": -4.56, + "vy": 31.88, + "splineNum": 0 + }, + { + "x": -1.13, + "y": 20.85, + "speed": 26.53, + "time": 0.24, + "theta": -91.97, + "omega": -16.61, + "vx": -3.45, + "vy": 26.31, + "splineNum": 0 + }, + { + "x": -1.29, + "y": 22.51, + "speed": 19.26, + "time": 0.32, + "theta": -93.67, + "omega": -61.14, + "vx": -1.83, + "vy": 19.17, + "splineNum": 0 + }, + { + "x": -1.35, + "y": 24.18, + "speed": 6.08, + "time": 0.6, + "theta": -102.53, + "omega": -41.91, + "vx": -0.22, + "vy": 6.08, + "splineNum": 0 + }, + { + "x": -1.35, + "y": 24.18, + "speed": 6.08, + "time": 0.6, + "theta": -102.53, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": -1.54, + "y": 27.01, + "speed": 24.56, + "time": 0.71, + "theta": -102.03, + "omega": 8.68, + "vx": -1.67, + "vy": 24.51, + "splineNum": 1 + }, + { + "x": -2.11, + "y": 29.04, + "speed": 15.38, + "time": 0.85, + "theta": -100.13, + "omega": 19.01, + "vx": -4.15, + "vy": 14.81, + "splineNum": 1 + }, + { + "x": -3.04, + "y": 30.3, + "speed": 8.27, + "time": 1.04, + "theta": -95.16, + "omega": 95.47, + "vx": -4.9, + "vy": 6.66, + "splineNum": 1 + }, + { + "x": -4.32, + "y": 30.83, + "speed": 9.1, + "time": 1.19, + "theta": -89.22, + "omega": 84.01, + "vx": -8.4, + "vy": 3.49, + "splineNum": 1 + }, + { + "x": -5.93, + "y": 30.66, + "speed": 18.33, + "time": 1.28, + "theta": -84.96, + "omega": 77.35, + "vx": -18.23, + "vy": -1.96, + "splineNum": 1 + }, + { + "x": -7.86, + "y": 29.81, + "speed": 27.53, + "time": 1.36, + "theta": -80.8, + "omega": 71.58, + "vx": -25.21, + "vy": -11.07, + "splineNum": 1 + }, + { + "x": -10.1, + "y": 28.32, + "speed": 28.18, + "time": 1.45, + "theta": -75, + "omega": 64.39, + "vx": -23.44, + "vy": -15.64, + "splineNum": 1 + }, + { + "x": -10.1, + "y": 28.32, + "speed": 28.18, + "time": 1.45, + "theta": -75, + "omega": 64.39, + "vx": -28.18, + "vy": 0, + "splineNum": 1 + }, + { + "x": -11.99, + "y": 26.82, + "speed": 35.75, + "time": 1.52, + "theta": -76.5, + "omega": -44.24, + "vx": -27.99, + "vy": -22.23, + "splineNum": 2 + }, + { + "x": -13.86, + "y": 25.26, + "speed": 41.99, + "time": 1.58, + "theta": -80.14, + "omega": -82, + "vx": -32.24, + "vy": -26.9, + "splineNum": 2 + }, + { + "x": -15.73, + "y": 23.73, + "speed": 46.5, + "time": 1.63, + "theta": -85.3, + "omega": -116.06, + "vx": -35.97, + "vy": -29.47, + "splineNum": 2 + }, + { + "x": -17.66, + "y": 22.28, + "speed": 40.98, + "time": 1.69, + "theta": -93.27, + "omega": -154.57, + "vx": -32.77, + "vy": -24.61, + "splineNum": 2 + }, + { + "x": -19.69, + "y": 20.98, + "speed": 34.61, + "time": 1.76, + "theta": -105.61, + "omega": -540.94, + "vx": -29.17, + "vy": -18.62, + "splineNum": 2 + }, + { + "x": -21.87, + "y": 19.91, + "speed": 26.7, + "time": 1.85, + "theta": -126.49, + "omega": -481.55, + "vx": -23.94, + "vy": -11.83, + "splineNum": 2 + }, + { + "x": -24.23, + "y": 19.12, + "speed": 14.66, + "time": 2.02, + "theta": -180, + "omega": -370.5, + "vx": -13.91, + "vy": -4.62, + "splineNum": 2 + }, + { + "x": -24.23, + "y": 19.12, + "speed": 14.66, + "time": 2.02, + "theta": -180, + "omega": -370.5, + "vx": -16, + "vy": 0, + "splineNum": 2 + }, + { + "x": -27.17, + "y": 18.62, + "speed": 28.47, + "time": 2.12, + "theta": 180, + "omega": 0, + "vx": -28.06, + "vy": -4.82, + "splineNum": 3 + }, + { + "x": -30.04, + "y": 18.54, + "speed": 37.22, + "time": 2.2, + "theta": 180, + "omega": 0, + "vx": -37.21, + "vy": -0.97, + "splineNum": 3 + }, + { + "x": -32.86, + "y": 18.82, + "speed": 44.18, + "time": 2.27, + "theta": 180, + "omega": 0, + "vx": -43.97, + "vy": 4.34, + "splineNum": 3 + }, + { + "x": -35.64, + "y": 19.38, + "speed": 46.38, + "time": 2.33, + "theta": 180, + "omega": 0, + "vx": -45.48, + "vy": 9.11, + "splineNum": 3 + }, + { + "x": -38.39, + "y": 20.14, + "speed": 39.75, + "time": 2.4, + "theta": 180, + "omega": 0, + "vx": -38.31, + "vy": 10.59, + "splineNum": 3 + }, + { + "x": -41.12, + "y": 21.03, + "speed": 31.71, + "time": 2.49, + "theta": 180, + "omega": 0, + "vx": -30.15, + "vy": 9.81, + "splineNum": 3 + }, + { + "x": -43.85, + "y": 21.97, + "speed": 20.71, + "time": 2.63, + "theta": 180, + "omega": 0, + "vx": -19.57, + "vy": 6.77, + "splineNum": 3 + }, + { + "x": -43.85, + "y": 21.97, + "speed": 20.71, + "time": 2.63, + "theta": 180, + "omega": 0, + "vx": -20.71, + "vy": 0, + "splineNum": 3 + }, + { + "x": -46.74, + "y": 23.47, + "speed": 32.87, + "time": 2.73, + "theta": 180, + "omega": 0, + "vx": -29.18, + "vy": 15.12, + "splineNum": 4 + }, + { + "x": -49.25, + "y": 25.57, + "speed": 41.64, + "time": 2.81, + "theta": 180, + "omega": 0, + "vx": -31.9, + "vy": 26.77, + "splineNum": 4 + }, + { + "x": -51.57, + "y": 27.96, + "speed": 49, + "time": 2.87, + "theta": 180, + "omega": 0, + "vx": -34.09, + "vy": 35.19, + "splineNum": 4 + }, + { + "x": -53.9, + "y": 30.34, + "speed": 45.29, + "time": 2.95, + "theta": 180, + "omega": 0, + "vx": -31.74, + "vy": 32.3, + "splineNum": 4 + }, + { + "x": -56.44, + "y": 32.38, + "speed": 37.4, + "time": 3.04, + "theta": 180, + "omega": 0, + "vx": -29.18, + "vy": 23.39, + "splineNum": 4 + }, + { + "x": -59.4, + "y": 33.77, + "speed": 27.28, + "time": 3.15, + "theta": 180, + "omega": 0, + "vx": -24.68, + "vy": 11.64, + "splineNum": 4 + }, + { + "x": -62.97, + "y": 34.21, + "speed": 5, + "time": 3.87, + "theta": 180, + "omega": 0, + "vx": -4.96, + "vy": 0.61, + "splineNum": 4 + }, + { + "x": -62.97, + "y": 34.21, + "speed": 5, + "time": 3.87, + "theta": 180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 5 + }, + { + "x": -59.14, + "y": 34.14, + "speed": 28.14, + "time": 4.01, + "theta": 180.81, + "omega": 11.9, + "vx": 28.14, + "vy": -0.54, + "splineNum": 5 + }, + { + "x": -56.2, + "y": 33.63, + "speed": 29.61, + "time": 4.11, + "theta": 182.45, + "omega": 20.68, + "vx": 29.18, + "vy": -5.01, + "splineNum": 5 + }, + { + "x": -54.07, + "y": 32.75, + "speed": 20.36, + "time": 4.22, + "theta": 185.36, + "omega": 30.59, + "vx": 18.8, + "vy": -7.8, + "splineNum": 5 + }, + { + "x": -52.63, + "y": 31.53, + "speed": 15.2, + "time": 4.35, + "theta": 189.82, + "omega": 41.41, + "vx": 11.59, + "vy": -9.83, + "splineNum": 5 + }, + { + "x": -51.79, + "y": 30.03, + "speed": 16.79, + "time": 4.45, + "theta": 194.53, + "omega": 126.94, + "vx": 8.19, + "vy": -14.65, + "splineNum": 5 + }, + { + "x": -51.45, + "y": 28.29, + "speed": 25.2, + "time": 4.52, + "theta": 198.29, + "omega": 120.79, + "vx": 4.91, + "vy": -24.71, + "splineNum": 5 + }, + { + "x": -51.49, + "y": 26.36, + "speed": 31.94, + "time": 4.58, + "theta": 201.86, + "omega": 115.52, + "vx": -0.79, + "vy": -31.93, + "splineNum": 5 + }, + { + "x": -51.83, + "y": 24.29, + "speed": 37.94, + "time": 4.64, + "theta": 205.41, + "omega": 110.7, + "vx": -6.15, + "vy": -37.44, + "splineNum": 5 + }, + { + "x": -52.36, + "y": 22.13, + "speed": 43.4, + "time": 4.69, + "theta": 208.93, + "omega": 106.22, + "vx": -10.35, + "vy": -42.15, + "splineNum": 5 + }, + { + "x": -52.98, + "y": 19.93, + "speed": 40.72, + "time": 4.74, + "theta": 213.06, + "omega": 101.32, + "vx": -11.03, + "vy": -39.2, + "splineNum": 5 + }, + { + "x": -53.59, + "y": 17.74, + "speed": 34.69, + "time": 4.81, + "theta": 218.23, + "omega": 95.59, + "vx": -9.24, + "vy": -33.43, + "splineNum": 5 + }, + { + "x": -54.08, + "y": 15.6, + "speed": 27.64, + "time": 4.89, + "theta": 225, + "omega": 88.65, + "vx": -6.19, + "vy": -26.94, + "splineNum": 5 + }, + { + "x": -54.61, + "y": 13.99, + "speed": 20.64, + "time": 4.97, + "theta": -135, + "omega": 0, + "vx": -6.44, + "vy": -19.61, + "splineNum": 6 + }, + { + "x": -55.45, + "y": 12.64, + "speed": 27.3, + "time": 5.03, + "theta": -135, + "omega": 0, + "vx": -14.42, + "vy": -23.18, + "splineNum": 6 + }, + { + "x": -56.51, + "y": 11.46, + "speed": 32.61, + "time": 5.08, + "theta": -135, + "omega": 0, + "vx": -21.77, + "vy": -24.28, + "splineNum": 6 + }, + { + "x": -57.69, + "y": 10.37, + "speed": 37.21, + "time": 5.12, + "theta": -135, + "omega": 0, + "vx": -27.34, + "vy": -25.24, + "splineNum": 6 + }, + { + "x": -58.89, + "y": 9.29, + "speed": 38.16, + "time": 5.16, + "theta": -135, + "omega": 0, + "vx": -28.44, + "vy": -25.44, + "splineNum": 6 + }, + { + "x": -60.02, + "y": 8.16, + "speed": 33.72, + "time": 5.21, + "theta": -135, + "omega": 0, + "vx": -23.7, + "vy": -23.99, + "splineNum": 6 + }, + { + "x": -60.96, + "y": 6.88, + "speed": 38.14, + "time": 5.25, + "theta": -135, + "omega": 0, + "vx": -22.7, + "vy": -30.64, + "splineNum": 6 + } + ] + }, + { + "name": "V2-Goal1ToGoal2", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": -135, + "spline_angle": 37.87, + "x": -60.96, + "y": 9.73, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": 0, + "angle": -165, + "spline_angle": 43.29, + "x": -38.9, + "y": 31.34, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 67.84, + "spline_angle": 68.3, + "x": -25.7, + "y": 55.53, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 89.95, + "spline_angle": 84.05, + "x": -23.47, + "y": 83.21, + "shared": false, + "speed": 5 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": -176.28, + "x": -39.54, + "y": 70.33, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": 3.51, + "x": -59.59, + "y": 70.17, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": -60.96, + "y": 9.73, + "speed": 0, + "time": 0, + "theta": -135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -57.97, + "y": 12.2, + "speed": 27.84, + "time": 0.14, + "theta": -136.13, + "omega": -16.21, + "vx": 21.47, + "vy": 17.71, + "splineNum": 0 + }, + { + "x": -55.12, + "y": 14.8, + "speed": 39.34, + "time": 0.24, + "theta": -138.28, + "omega": -27.64, + "vx": 29.07, + "vy": 26.5, + "splineNum": 0 + }, + { + "x": -52.36, + "y": 17.5, + "speed": 48.16, + "time": 0.32, + "theta": -140.87, + "omega": -36.97, + "vx": 34.37, + "vy": 33.74, + "splineNum": 0 + }, + { + "x": -49.67, + "y": 20.27, + "speed": 50, + "time": 0.39, + "theta": -144.07, + "omega": -121.21, + "vx": 34.81, + "vy": 35.89, + "splineNum": 0 + }, + { + "x": -47.02, + "y": 23.08, + "speed": 50, + "time": 0.47, + "theta": -147.97, + "omega": -112.21, + "vx": 34.39, + "vy": 36.3, + "splineNum": 0 + }, + { + "x": -44.36, + "y": 25.88, + "speed": 50, + "time": 0.55, + "theta": -152.57, + "omega": -103.21, + "vx": 34.41, + "vy": 36.28, + "splineNum": 0 + }, + { + "x": -41.66, + "y": 28.65, + "speed": 50, + "time": 0.63, + "theta": -157.85, + "omega": -94.22, + "vx": 34.89, + "vy": 35.82, + "splineNum": 0 + }, + { + "x": -38.9, + "y": 31.34, + "speed": 42.26, + "time": 0.72, + "theta": -165, + "omega": -83.59, + "vx": 30.26, + "vy": 29.5, + "splineNum": 0 + }, + { + "x": -36.45, + "y": 33.93, + "speed": 49.99, + "time": 0.79, + "theta": -167.09, + "omega": -58.59, + "vx": 34.33, + "vy": 36.33, + "splineNum": 1 + }, + { + "x": -34.35, + "y": 36.71, + "speed": 50, + "time": 0.86, + "theta": -173.16, + "omega": -115.86, + "vx": 30.18, + "vy": 39.86, + "splineNum": 1 + }, + { + "x": -32.53, + "y": 39.64, + "speed": 50, + "time": 0.93, + "theta": -183.11, + "omega": -172.58, + "vx": 26.33, + "vy": 42.51, + "splineNum": 1 + }, + { + "x": -30.95, + "y": 42.7, + "speed": 50, + "time": 1, + "theta": -196.96, + "omega": -685.29, + "vx": 23.06, + "vy": 44.36, + "splineNum": 1 + }, + { + "x": -29.53, + "y": 45.85, + "speed": 50, + "time": 1.07, + "theta": -214.76, + "omega": -628.48, + "vx": 20.55, + "vy": 45.58, + "splineNum": 1 + }, + { + "x": -28.22, + "y": 49.06, + "speed": 50, + "time": 1.14, + "theta": -236.56, + "omega": -571.48, + "vx": 18.88, + "vy": 46.3, + "splineNum": 1 + }, + { + "x": -26.96, + "y": 52.29, + "speed": 50, + "time": 1.2, + "theta": -262.38, + "omega": -514.37, + "vx": 18.07, + "vy": 46.62, + "splineNum": 1 + }, + { + "x": -25.7, + "y": 55.53, + "speed": 50, + "time": 1.27, + "theta": -292.16, + "omega": -457.26, + "vx": 18.15, + "vy": 46.59, + "splineNum": 1 + }, + { + "x": -24.62, + "y": 58.93, + "speed": 50, + "time": 1.35, + "theta": 67.91, + "omega": 1.95, + "vx": 15.21, + "vy": 47.63, + "splineNum": 2 + }, + { + "x": -23.98, + "y": 62.36, + "speed": 50, + "time": 1.42, + "theta": 68.11, + "omega": 3.85, + "vx": 9.16, + "vy": 49.15, + "splineNum": 2 + }, + { + "x": -23.67, + "y": 65.81, + "speed": 50, + "time": 1.48, + "theta": 68.44, + "omega": 5.75, + "vx": 4.35, + "vy": 49.81, + "splineNum": 2 + }, + { + "x": -23.6, + "y": 69.29, + "speed": 50, + "time": 1.55, + "theta": 68.91, + "omega": 7.65, + "vx": 1.03, + "vy": 49.99, + "splineNum": 2 + }, + { + "x": -23.65, + "y": 72.78, + "speed": 45.97, + "time": 1.63, + "theta": 69.57, + "omega": 9.72, + "vx": -0.67, + "vy": 45.96, + "splineNum": 2 + }, + { + "x": -23.72, + "y": 76.27, + "speed": 37.62, + "time": 1.72, + "theta": 70.59, + "omega": 12.25, + "vx": -0.72, + "vy": 37.62, + "splineNum": 2 + }, + { + "x": -23.69, + "y": 79.75, + "speed": 26.82, + "time": 1.85, + "theta": 72.41, + "omega": 15.79, + "vx": 0.19, + "vy": 26.82, + "splineNum": 2 + }, + { + "x": -23.47, + "y": 83.21, + "speed": 5, + "time": 2.55, + "theta": 89.95, + "omega": 34.74, + "vx": 0.32, + "vy": 4.99, + "splineNum": 2 + }, + { + "x": -24.24, + "y": 79.47, + "speed": 28.1, + "time": 2.68, + "theta": 94.79, + "omega": 71.22, + "vx": -5.66, + "vy": -27.52, + "splineNum": 3 + }, + { + "x": -25.64, + "y": 76.5, + "speed": 34.96, + "time": 2.78, + "theta": 103.76, + "omega": 120.27, + "vx": -14.9, + "vy": -31.63, + "splineNum": 3 + }, + { + "x": -27.59, + "y": 74.23, + "speed": 34.21, + "time": 2.86, + "theta": 116.29, + "omega": 448.07, + "vx": -22.3, + "vy": -25.94, + "splineNum": 3 + }, + { + "x": -30.02, + "y": 72.57, + "speed": 41.74, + "time": 2.93, + "theta": 129.34, + "omega": 411.06, + "vx": -34.46, + "vy": -23.55, + "splineNum": 3 + }, + { + "x": -32.87, + "y": 71.42, + "speed": 48.55, + "time": 3, + "theta": 143.24, + "omega": 377.91, + "vx": -45.04, + "vy": -18.12, + "splineNum": 3 + }, + { + "x": -36.07, + "y": 70.7, + "speed": 50, + "time": 3.06, + "theta": 159.84, + "omega": 343.62, + "vx": -48.79, + "vy": -10.95, + "splineNum": 3 + }, + { + "x": -39.54, + "y": 70.33, + "speed": 50, + "time": 3.13, + "theta": 180, + "omega": 307.07, + "vx": -49.71, + "vy": -5.37, + "splineNum": 3 + }, + { + "x": -39.54, + "y": 70.33, + "speed": 50, + "time": 3.13, + "theta": 180, + "omega": 307.07, + "vx": 50, + "vy": 0, + "splineNum": 3 + }, + { + "x": -42.4, + "y": 70.21, + "speed": 50, + "time": 3.19, + "theta": 180, + "omega": 0, + "vx": -49.95, + "vy": -2.17, + "splineNum": 4 + }, + { + "x": -45.27, + "y": 70.18, + "speed": 50, + "time": 3.25, + "theta": 180, + "omega": 0, + "vx": -50, + "vy": -0.45, + "splineNum": 4 + }, + { + "x": -48.13, + "y": 70.21, + "speed": 50, + "time": 3.31, + "theta": 180, + "omega": 0, + "vx": -50, + "vy": 0.59, + "splineNum": 4 + }, + { + "x": -51, + "y": 70.27, + "speed": 50, + "time": 3.36, + "theta": 180, + "omega": 0, + "vx": -49.99, + "vy": 0.95, + "splineNum": 4 + }, + { + "x": -53.86, + "y": 70.3, + "speed": 50, + "time": 3.42, + "theta": 180, + "omega": 0, + "vx": -50, + "vy": 0.64, + "splineNum": 4 + }, + { + "x": -56.73, + "y": 70.29, + "speed": 50, + "time": 3.48, + "theta": 180, + "omega": 0, + "vx": -50, + "vy": -0.35, + "splineNum": 4 + }, + { + "x": -59.59, + "y": 70.17, + "speed": 50, + "time": 3.53, + "theta": 180, + "omega": 0, + "vx": -49.96, + "vy": -2.01, + "splineNum": 4 + } + ] + }, + { + "name": "V2-Goal2ToGoal3", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": 180, + "spline_angle": 0, + "x": -57.77, + "y": 71.44, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": 0, + "angle": -137.41, + "spline_angle": 0, + "x": -45.36, + "y": 71.27, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -179.04, + "spline_angle": 99.9, + "x": -36.64, + "y": 86.53, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 90.07, + "x": -38.65, + "y": 106.65, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 90.02, + "x": -37.98, + "y": 124.76, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": -157.65, + "x": -52.91, + "y": 104.3, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 180, + "spline_angle": 4.39, + "x": -69.93, + "y": 102.94, + "shared": false, + "speed": 10 + }, + { + "name": "wp", + "omega": 0, + "angle": 135, + "spline_angle": 114.75, + "x": -55.29, + "y": 119.33, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 135, + "spline_angle": 139.34, + "x": -65.99, + "y": 131.13, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": -57.77, + "y": 71.44, + "speed": 0, + "time": 0, + "theta": 180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -56, + "y": 71.43, + "speed": 18.83, + "time": 0.09, + "theta": 182.56, + "omega": 54.28, + "vx": 18.83, + "vy": -0.1, + "splineNum": 0 + }, + { + "x": -54.22, + "y": 71.41, + "speed": 26.63, + "time": 0.16, + "theta": 187.45, + "omega": 92.66, + "vx": 26.63, + "vy": -0.36, + "splineNum": 0 + }, + { + "x": -52.45, + "y": 71.37, + "speed": 32.62, + "time": 0.22, + "theta": 193.34, + "omega": 319.2, + "vx": 32.61, + "vy": -0.61, + "splineNum": 0 + }, + { + "x": -50.68, + "y": 71.34, + "speed": 37.66, + "time": 0.26, + "theta": 199.81, + "omega": 292.06, + "vx": 37.65, + "vy": -0.77, + "splineNum": 0 + }, + { + "x": -48.91, + "y": 71.3, + "speed": 42.11, + "time": 0.3, + "theta": 206.69, + "omega": 267.78, + "vx": 42.1, + "vy": -0.79, + "splineNum": 0 + }, + { + "x": -47.13, + "y": 71.28, + "speed": 46.13, + "time": 0.34, + "theta": 213.86, + "omega": 245.62, + "vx": 46.12, + "vy": -0.63, + "splineNum": 0 + }, + { + "x": -45.36, + "y": 71.27, + "speed": 42.55, + "time": 0.38, + "theta": 222.59, + "omega": 221.6, + "vx": 42.55, + "vy": -0.23, + "splineNum": 0 + }, + { + "x": -45.36, + "y": 71.27, + "speed": 42.55, + "time": 0.38, + "theta": -137.41, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 1 + }, + { + "x": -41.54, + "y": 71.62, + "speed": 32.31, + "time": 0.5, + "theta": -138.47, + "omega": -17.8, + "vx": 32.17, + "vy": 2.93, + "splineNum": 1 + }, + { + "x": -38.83, + "y": 72.6, + "speed": 21.62, + "time": 0.64, + "theta": -142.17, + "omega": -37.79, + "vx": 20.32, + "vy": 7.37, + "splineNum": 1 + }, + { + "x": -37.07, + "y": 74.12, + "speed": 17.32, + "time": 0.77, + "theta": -148.61, + "omega": -165.51, + "vx": 13.12, + "vy": 11.31, + "splineNum": 1 + }, + { + "x": -36.08, + "y": 76.09, + "speed": 22.39, + "time": 0.87, + "theta": -155.03, + "omega": -150.77, + "vx": 10.03, + "vy": 20.02, + "splineNum": 1 + }, + { + "x": -35.71, + "y": 78.41, + "speed": 31.16, + "time": 0.94, + "theta": -160.93, + "omega": -139.47, + "vx": 4.92, + "vy": 30.77, + "splineNum": 1 + }, + { + "x": -35.79, + "y": 80.98, + "speed": 38.55, + "time": 1.01, + "theta": -166.88, + "omega": -129.45, + "vx": -1.19, + "vy": 38.53, + "splineNum": 1 + }, + { + "x": -36.15, + "y": 83.72, + "speed": 45.15, + "time": 1.07, + "theta": -172.92, + "omega": -120.28, + "vx": -5.96, + "vy": 44.76, + "splineNum": 1 + }, + { + "x": -36.64, + "y": 86.53, + "speed": 50, + "time": 1.13, + "theta": -179.04, + "omega": -111.73, + "vx": -8.51, + "vy": 49.27, + "splineNum": 1 + }, + { + "x": -37.12, + "y": 89.39, + "speed": 50, + "time": 1.19, + "theta": -180.9, + "omega": -64.25, + "vx": -8.23, + "vy": 49.32, + "splineNum": 2 + }, + { + "x": -37.55, + "y": 92.25, + "speed": 50, + "time": 1.25, + "theta": -186.47, + "omega": -128.43, + "vx": -7.41, + "vy": 49.45, + "splineNum": 2 + }, + { + "x": -37.92, + "y": 95.11, + "speed": 50, + "time": 1.3, + "theta": -195.75, + "omega": -192.57, + "vx": -6.42, + "vy": 49.59, + "splineNum": 2 + }, + { + "x": -38.22, + "y": 97.98, + "speed": 50, + "time": 1.36, + "theta": -208.73, + "omega": -641.92, + "vx": -5.28, + "vy": 49.72, + "splineNum": 2 + }, + { + "x": -38.45, + "y": 100.86, + "speed": 50, + "time": 1.42, + "theta": -225.41, + "omega": -577.8, + "vx": -3.98, + "vy": 49.84, + "splineNum": 2 + }, + { + "x": -38.6, + "y": 103.75, + "speed": 50, + "time": 1.48, + "theta": -245.82, + "omega": -513.62, + "vx": -2.52, + "vy": 49.94, + "splineNum": 2 + }, + { + "x": -38.65, + "y": 106.65, + "speed": 50, + "time": 1.53, + "theta": -270, + "omega": -449.3, + "vx": -0.91, + "vy": 49.99, + "splineNum": 2 + }, + { + "x": -38.65, + "y": 106.65, + "speed": 50, + "time": 1.53, + "theta": -270, + "omega": -449.3, + "vx": -50, + "vy": 0, + "splineNum": 2 + }, + { + "x": -38.62, + "y": 109.24, + "speed": 50, + "time": 1.59, + "theta": 90, + "omega": 0, + "vx": 0.67, + "vy": 50, + "splineNum": 3 + }, + { + "x": -38.52, + "y": 111.83, + "speed": 50, + "time": 1.64, + "theta": 90, + "omega": 0, + "vx": 1.84, + "vy": 49.97, + "splineNum": 3 + }, + { + "x": -38.39, + "y": 114.41, + "speed": 45.86, + "time": 1.69, + "theta": 90, + "omega": 0, + "vx": 2.33, + "vy": 45.8, + "splineNum": 3 + }, + { + "x": -38.25, + "y": 117, + "speed": 39.81, + "time": 1.76, + "theta": 90, + "omega": 0, + "vx": 2.21, + "vy": 39.75, + "splineNum": 3 + }, + { + "x": -38.11, + "y": 119.58, + "speed": 32.67, + "time": 1.84, + "theta": 90, + "omega": 0, + "vx": 1.66, + "vy": 32.63, + "splineNum": 3 + }, + { + "x": -38.02, + "y": 122.17, + "speed": 23.44, + "time": 1.95, + "theta": 90, + "omega": 0, + "vx": 0.87, + "vy": 23.42, + "splineNum": 3 + }, + { + "x": -37.98, + "y": 124.76, + "speed": 5.62, + "time": 2.41, + "theta": 90, + "omega": 0, + "vx": 0.08, + "vy": 5.62, + "splineNum": 3 + }, + { + "x": -37.98, + "y": 124.76, + "speed": 5.62, + "time": 2.41, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 5.33, + "splineNum": 3 + }, + { + "x": -38.24, + "y": 121.03, + "speed": 27.9, + "time": 2.54, + "theta": 94.09, + "omega": 61.12, + "vx": -1.98, + "vy": -27.83, + "splineNum": 4 + }, + { + "x": -39.02, + "y": 117.68, + "speed": 38.3, + "time": 2.63, + "theta": 101.42, + "omega": 102.14, + "vx": -8.66, + "vy": -37.31, + "splineNum": 4 + }, + { + "x": -40.29, + "y": 114.69, + "speed": 46.01, + "time": 2.7, + "theta": 109.79, + "omega": 134.41, + "vx": -17.88, + "vy": -42.4, + "splineNum": 4 + }, + { + "x": -42.01, + "y": 112.02, + "speed": 50, + "time": 2.77, + "theta": 119.23, + "omega": 409.98, + "vx": -27.14, + "vy": -41.99, + "splineNum": 4 + }, + { + "x": -44.16, + "y": 109.67, + "speed": 50, + "time": 2.83, + "theta": 130.56, + "omega": 380.89, + "vx": -33.76, + "vy": -36.88, + "splineNum": 4 + }, + { + "x": -46.71, + "y": 107.62, + "speed": 50, + "time": 2.9, + "theta": 144.16, + "omega": 350.96, + "vx": -38.93, + "vy": -31.37, + "splineNum": 4 + }, + { + "x": -49.64, + "y": 105.83, + "speed": 50, + "time": 2.97, + "theta": 160.48, + "omega": 319.67, + "vx": -42.69, + "vy": -26.03, + "splineNum": 4 + }, + { + "x": -52.91, + "y": 104.3, + "speed": 50, + "time": 3.04, + "theta": 180, + "omega": 286.68, + "vx": -45.28, + "vy": -21.2, + "splineNum": 4 + }, + { + "x": -55.3, + "y": 103.53, + "speed": 50, + "time": 3.09, + "theta": 180, + "omega": 0, + "vx": -47.59, + "vy": -15.32, + "splineNum": 5 + }, + { + "x": -57.71, + "y": 103.11, + "speed": 50, + "time": 3.14, + "theta": 180, + "omega": 0, + "vx": -49.26, + "vy": -8.56, + "splineNum": 5 + }, + { + "x": -60.14, + "y": 102.95, + "speed": 45.36, + "time": 3.19, + "theta": 180, + "omega": 0, + "vx": -45.26, + "vy": -3.07, + "splineNum": 5 + }, + { + "x": -62.59, + "y": 102.94, + "speed": 39.61, + "time": 3.25, + "theta": 180, + "omega": 0, + "vx": -39.61, + "vy": -0.08, + "splineNum": 5 + }, + { + "x": -65.04, + "y": 103, + "speed": 32.84, + "time": 3.33, + "theta": 180, + "omega": 0, + "vx": -32.83, + "vy": 0.8, + "splineNum": 5 + }, + { + "x": -67.49, + "y": 103.03, + "speed": 24.25, + "time": 3.43, + "theta": 180, + "omega": 0, + "vx": -24.25, + "vy": 0.3, + "splineNum": 5 + }, + { + "x": -69.93, + "y": 102.94, + "speed": 10, + "time": 3.67, + "theta": 180, + "omega": 0, + "vx": -9.99, + "vy": -0.38, + "splineNum": 5 + }, + { + "x": -69.93, + "y": 102.94, + "speed": 10, + "time": 3.67, + "theta": 180, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 6 + }, + { + "x": -66.08, + "y": 103.18, + "speed": 29.53, + "time": 3.8, + "theta": 179.17, + "omega": -12.77, + "vx": 29.47, + "vy": 1.86, + "splineNum": 6 + }, + { + "x": -62.29, + "y": 103.48, + "speed": 40.4, + "time": 3.9, + "theta": 177.53, + "omega": -21.97, + "vx": 40.28, + "vy": 3.17, + "splineNum": 6 + }, + { + "x": -58.82, + "y": 104.06, + "speed": 34.57, + "time": 4, + "theta": 174.79, + "omega": -31.91, + "vx": 34.09, + "vy": 5.74, + "splineNum": 6 + }, + { + "x": -55.93, + "y": 105.16, + "speed": 24.01, + "time": 4.13, + "theta": 169.86, + "omega": -44.5, + "vx": 22.44, + "vy": 8.53, + "splineNum": 6 + }, + { + "x": -53.87, + "y": 107.01, + "speed": 17.08, + "time": 4.29, + "theta": 161.38, + "omega": -127.23, + "vx": 12.71, + "vy": 11.41, + "splineNum": 6 + }, + { + "x": -52.91, + "y": 109.83, + "speed": 25.03, + "time": 4.41, + "theta": 153.5, + "omega": -115.59, + "vx": 8.08, + "vy": 23.69, + "splineNum": 6 + }, + { + "x": -53.29, + "y": 113.86, + "speed": 37.9, + "time": 4.52, + "theta": 145.25, + "omega": -105.15, + "vx": -3.63, + "vy": 37.72, + "splineNum": 6 + }, + { + "x": -55.29, + "y": 119.33, + "speed": 50, + "time": 4.63, + "theta": 135, + "omega": -93.78, + "vx": -17.15, + "vy": 46.97, + "splineNum": 6 + }, + { + "x": -56.4, + "y": 121.39, + "speed": 50, + "time": 4.68, + "theta": 135, + "omega": 0, + "vx": -23.75, + "vy": 44, + "splineNum": 7 + }, + { + "x": -57.72, + "y": 123.27, + "speed": 50, + "time": 4.73, + "theta": 135, + "omega": 0, + "vx": -28.71, + "vy": 40.94, + "splineNum": 7 + }, + { + "x": -59.2, + "y": 125, + "speed": 50, + "time": 4.77, + "theta": 135, + "omega": 0, + "vx": -32.53, + "vy": 37.97, + "splineNum": 7 + }, + { + "x": -60.81, + "y": 126.61, + "speed": 50, + "time": 4.82, + "theta": 135, + "omega": 0, + "vx": -35.26, + "vy": 35.45, + "splineNum": 7 + }, + { + "x": -62.5, + "y": 128.15, + "speed": 50, + "time": 4.86, + "theta": 135, + "omega": 0, + "vx": -37.02, + "vy": 33.6, + "splineNum": 7 + }, + { + "x": -64.24, + "y": 129.64, + "speed": 50, + "time": 4.91, + "theta": 135, + "omega": 0, + "vx": -37.94, + "vy": 32.57, + "splineNum": 7 + }, + { + "x": -65.99, + "y": 131.13, + "speed": 50, + "time": 4.95, + "theta": 135, + "omega": 0, + "vx": -38.1, + "vy": 32.38, + "splineNum": 7 + } + ] + }, + { + "name": "V2-Goal3ToGoal6", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": 135, + "spline_angle": -43.83, + "x": -60.12, + "y": 132.31, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": 0, + "angle": 104.92, + "spline_angle": -35.51, + "x": -40.65, + "y": 109.95, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -38.66, + "spline_angle": -35.51, + "x": -25.06, + "y": 99.13, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 0, + "spline_angle": -176.95, + "x": 1.67, + "y": 93.56, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 94.76, + "x": 10.74, + "y": 104.38, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 94.76, + "x": -5.97, + "y": 120.76, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 94.76, + "x": -5.81, + "y": 133.49, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": -60.12, + "y": 132.31, + "speed": 0, + "time": 0, + "theta": 135, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -57.57, + "y": 129.62, + "speed": 27.24, + "time": 0.14, + "theta": 133.81, + "omega": -17.54, + "vx": 18.74, + "vy": -19.76, + "splineNum": 0 + }, + { + "x": -55.22, + "y": 126.75, + "speed": 38.52, + "time": 0.23, + "theta": 131.52, + "omega": -29.93, + "vx": 24.37, + "vy": -29.82, + "splineNum": 0 + }, + { + "x": -52.99, + "y": 123.77, + "speed": 47.19, + "time": 0.31, + "theta": 128.76, + "omega": -40.07, + "vx": 28.27, + "vy": -37.78, + "splineNum": 0 + }, + { + "x": -50.8, + "y": 120.77, + "speed": 50, + "time": 0.39, + "theta": 125.43, + "omega": -126.38, + "vx": 29.47, + "vy": -40.39, + "splineNum": 0 + }, + { + "x": -48.56, + "y": 117.81, + "speed": 50, + "time": 0.46, + "theta": 121.38, + "omega": -116.81, + "vx": 30.21, + "vy": -39.84, + "splineNum": 0 + }, + { + "x": -46.18, + "y": 114.97, + "speed": 50, + "time": 0.53, + "theta": 116.64, + "omega": -107.26, + "vx": 32.14, + "vy": -38.3, + "splineNum": 0 + }, + { + "x": -43.57, + "y": 112.32, + "speed": 50, + "time": 0.61, + "theta": 111.18, + "omega": -97.7, + "vx": 35.11, + "vy": -35.6, + "splineNum": 0 + }, + { + "x": -40.65, + "y": 109.95, + "speed": 50, + "time": 0.68, + "theta": 104.92, + "omega": -88.01, + "vx": 38.79, + "vy": -31.55, + "splineNum": 0 + }, + { + "x": -38.44, + "y": 108.39, + "speed": 50, + "time": 0.74, + "theta": 101.99, + "omega": -108.09, + "vx": 40.85, + "vy": -28.84, + "splineNum": 1 + }, + { + "x": -36.21, + "y": 106.84, + "speed": 50, + "time": 0.79, + "theta": 93.2, + "omega": -216.17, + "vx": 41.08, + "vy": -28.51, + "splineNum": 1 + }, + { + "x": -33.97, + "y": 105.31, + "speed": 50, + "time": 0.85, + "theta": 78.55, + "omega": -324.25, + "vx": 41.21, + "vy": -28.31, + "splineNum": 1 + }, + { + "x": -31.74, + "y": 103.77, + "speed": 50, + "time": 0.9, + "theta": 58.04, + "omega": -1080.85, + "vx": 41.26, + "vy": -28.25, + "splineNum": 1 + }, + { + "x": -29.5, + "y": 102.24, + "speed": 50, + "time": 0.95, + "theta": 31.66, + "omega": -972.76, + "vx": 41.21, + "vy": -28.31, + "splineNum": 1 + }, + { + "x": -27.27, + "y": 100.69, + "speed": 50, + "time": 1.01, + "theta": -0.57, + "omega": -864.68, + "vx": 41.08, + "vy": -28.51, + "splineNum": 1 + }, + { + "x": -25.06, + "y": 99.13, + "speed": 50, + "time": 1.06, + "theta": -38.66, + "omega": -756.59, + "vx": 40.85, + "vy": -28.84, + "splineNum": 1 + }, + { + "x": -25.06, + "y": 99.13, + "speed": 50, + "time": 1.06, + "theta": -38.66, + "omega": -756.59, + "vx": 32, + "vy": 0, + "splineNum": 1 + }, + { + "x": -21.97, + "y": 97.21, + "speed": 50, + "time": 1.14, + "theta": -38.04, + "omega": 17.01, + "vx": 42.47, + "vy": -26.39, + "splineNum": 2 + }, + { + "x": -18.79, + "y": 95.75, + "speed": 50, + "time": 1.21, + "theta": -36.28, + "omega": 33.4, + "vx": 45.45, + "vy": -20.84, + "splineNum": 2 + }, + { + "x": -15.52, + "y": 94.7, + "speed": 50, + "time": 1.27, + "theta": -33.43, + "omega": 49.46, + "vx": 47.58, + "vy": -15.37, + "splineNum": 2 + }, + { + "x": -12.19, + "y": 93.99, + "speed": 50, + "time": 1.34, + "theta": -29.51, + "omega": 65.44, + "vx": 48.92, + "vy": -10.35, + "splineNum": 2 + }, + { + "x": -8.78, + "y": 93.58, + "speed": 50, + "time": 1.41, + "theta": -24.48, + "omega": 187.57, + "vx": 49.64, + "vy": -6.01, + "splineNum": 2 + }, + { + "x": -5.33, + "y": 93.41, + "speed": 50, + "time": 1.48, + "theta": -18.29, + "omega": 171.4, + "vx": 49.94, + "vy": -2.5, + "splineNum": 2 + }, + { + "x": -1.85, + "y": 93.42, + "speed": 48.76, + "time": 1.55, + "theta": -10.7, + "omega": 154.65, + "vx": 48.76, + "vy": 0.16, + "splineNum": 2 + }, + { + "x": 1.67, + "y": 93.56, + "speed": 40.91, + "time": 1.64, + "theta": 0, + "omega": 134.52, + "vx": 40.87, + "vy": 1.64, + "splineNum": 2 + }, + { + "x": 4.37, + "y": 93.93, + "speed": 33.59, + "time": 1.72, + "theta": 1.75, + "omega": 43.07, + "vx": 33.28, + "vy": 4.54, + "splineNum": 3 + }, + { + "x": 6.58, + "y": 94.71, + "speed": 25.69, + "time": 1.81, + "theta": 7.87, + "omega": 91.44, + "vx": 24.22, + "vy": 8.59, + "splineNum": 3 + }, + { + "x": 8.3, + "y": 95.89, + "speed": 21.16, + "time": 1.91, + "theta": 19.53, + "omega": 143.99, + "vx": 17.46, + "vy": 11.95, + "splineNum": 3 + }, + { + "x": 9.57, + "y": 97.47, + "speed": 22.17, + "time": 2, + "theta": 34.83, + "omega": 425.94, + "vx": 13.9, + "vy": 17.27, + "splineNum": 3 + }, + { + "x": 10.39, + "y": 99.41, + "speed": 28.81, + "time": 2.07, + "theta": 50.35, + "omega": 387.04, + "vx": 11.15, + "vy": 26.56, + "splineNum": 3 + }, + { + "x": 10.77, + "y": 101.72, + "speed": 36.03, + "time": 2.14, + "theta": 66.49, + "omega": 352.54, + "vx": 5.93, + "vy": 35.54, + "splineNum": 3 + }, + { + "x": 10.74, + "y": 104.38, + "speed": 32.51, + "time": 2.22, + "theta": 90, + "omega": 309.12, + "vx": -0.39, + "vy": 32.51, + "splineNum": 3 + }, + { + "x": 10.74, + "y": 104.38, + "speed": 32.51, + "time": 2.22, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 4 + }, + { + "x": 9.59, + "y": 107.98, + "speed": 22.19, + "time": 2.39, + "theta": 90, + "omega": 0, + "vx": -6.75, + "vy": 21.14, + "splineNum": 4 + }, + { + "x": 7.2, + "y": 110.32, + "speed": 33.58, + "time": 2.49, + "theta": 90, + "omega": 0, + "vx": -23.98, + "vy": 23.51, + "splineNum": 4 + }, + { + "x": 4.07, + "y": 111.9, + "speed": 42.77, + "time": 2.57, + "theta": 90, + "omega": 0, + "vx": -38.16, + "vy": 19.3, + "splineNum": 4 + }, + { + "x": 0.7, + "y": 113.24, + "speed": 42.77, + "time": 2.66, + "theta": 90, + "omega": 0, + "vx": -39.79, + "vy": 15.68, + "splineNum": 4 + }, + { + "x": -2.43, + "y": 114.82, + "speed": 33.58, + "time": 2.76, + "theta": 90, + "omega": 0, + "vx": -29.97, + "vy": 15.16, + "splineNum": 4 + }, + { + "x": -4.82, + "y": 117.16, + "speed": 22.19, + "time": 2.91, + "theta": 90, + "omega": 0, + "vx": -15.85, + "vy": 15.54, + "splineNum": 4 + }, + { + "x": -5.97, + "y": 120.76, + "speed": 35.34, + "time": 3.02, + "theta": 90, + "omega": 0, + "vx": -10.75, + "vy": 33.66, + "splineNum": 4 + }, + { + "x": -5.97, + "y": 120.76, + "speed": 35.34, + "time": 3.02, + "theta": 90, + "omega": 0, + "vx": -35.34, + "vy": 0, + "splineNum": 4 + }, + { + "x": -6.05, + "y": 122.58, + "speed": 40.16, + "time": 3.06, + "theta": 90, + "omega": 0, + "vx": -1.85, + "vy": 40.12, + "splineNum": 5 + }, + { + "x": -6.03, + "y": 124.4, + "speed": 44.46, + "time": 3.11, + "theta": 90, + "omega": 0, + "vx": 0.56, + "vy": 44.46, + "splineNum": 5 + }, + { + "x": -5.94, + "y": 126.22, + "speed": 48.38, + "time": 3.14, + "theta": 90, + "omega": 0, + "vx": 2.31, + "vy": 48.33, + "splineNum": 5 + }, + { + "x": -5.84, + "y": 128.03, + "speed": 50, + "time": 3.18, + "theta": 90, + "omega": 0, + "vx": 2.97, + "vy": 49.91, + "splineNum": 5 + }, + { + "x": -5.75, + "y": 129.85, + "speed": 50, + "time": 3.22, + "theta": 90, + "omega": 0, + "vx": 2.39, + "vy": 49.94, + "splineNum": 5 + }, + { + "x": -5.73, + "y": 131.67, + "speed": 50, + "time": 3.25, + "theta": 90, + "omega": 0, + "vx": 0.63, + "vy": 50, + "splineNum": 5 + }, + { + "x": -5.81, + "y": 133.49, + "speed": 50, + "time": 3.29, + "theta": 90, + "omega": 0, + "vx": -2.3, + "vy": 49.95, + "splineNum": 5 + } + ] + }, + { + "name": "V2-Goal6ToGoal9", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": 90, + "spline_angle": -92.82, + "x": -5.17, + "y": 129.67, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": 0, + "angle": 120, + "spline_angle": 127.72, + "x": -2.63, + "y": 119.33, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 53.81, + "spline_angle": 43.48, + "x": 8.83, + "y": 122.2, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -11.86, + "spline_angle": 0, + "x": 17.74, + "y": 126.02, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -20.18, + "spline_angle": 150.51, + "x": 38.9, + "y": 122.51, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -0.02, + "spline_angle": 162.58, + "x": 62.13, + "y": 108.35, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 45, + "spline_angle": 72.3, + "x": 51.15, + "y": 129.83, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 45, + "spline_angle": -122.24, + "x": 58.31, + "y": 139.7, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": -5.17, + "y": 129.67, + "speed": 0, + "time": 0, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": -5.21, + "y": 128.09, + "speed": 17.76, + "time": 0.09, + "theta": 90.62, + "omega": 13.98, + "vx": -0.47, + "vy": -17.75, + "splineNum": 0 + }, + { + "x": -5.16, + "y": 126.54, + "speed": 25.03, + "time": 0.15, + "theta": 91.79, + "omega": 23.76, + "vx": 0.8, + "vy": -25.01, + "splineNum": 0 + }, + { + "x": -4.99, + "y": 125.01, + "speed": 30.55, + "time": 0.2, + "theta": 93.19, + "omega": 31.67, + "vx": 3.32, + "vy": -30.37, + "splineNum": 0 + }, + { + "x": -4.68, + "y": 123.52, + "speed": 31.46, + "time": 0.25, + "theta": 94.9, + "omega": 39.29, + "vx": 6.42, + "vy": -30.8, + "splineNum": 0 + }, + { + "x": -4.2, + "y": 122.08, + "speed": 26.16, + "time": 0.31, + "theta": 97.46, + "omega": 48.47, + "vx": 8.23, + "vy": -24.83, + "splineNum": 0 + }, + { + "x": -3.53, + "y": 120.68, + "speed": 19.33, + "time": 0.39, + "theta": 101.87, + "omega": 133.25, + "vx": 8.4, + "vy": -17.4, + "splineNum": 0 + }, + { + "x": -2.63, + "y": 119.33, + "speed": 7.06, + "time": 0.62, + "theta": 120, + "omega": 97.19, + "vx": 3.92, + "vy": -5.88, + "splineNum": 0 + }, + { + "x": -2.63, + "y": 119.33, + "speed": 7.06, + "time": 0.62, + "theta": 120, + "omega": 97.19, + "vx": 7.06, + "vy": 0, + "splineNum": 0 + }, + { + "x": -0.28, + "y": 116.88, + "speed": 22.86, + "time": 0.77, + "theta": 117.62, + "omega": -32.05, + "vx": 15.84, + "vy": -16.48, + "splineNum": 1 + }, + { + "x": 1.69, + "y": 115.96, + "speed": 9.96, + "time": 0.98, + "theta": 105.47, + "omega": -79.2, + "vx": 9.02, + "vy": -4.22, + "splineNum": 1 + }, + { + "x": 3.37, + "y": 116.22, + "speed": 10.92, + "time": 1.14, + "theta": 90.58, + "omega": -225.36, + "vx": 10.79, + "vy": 1.68, + "splineNum": 1 + }, + { + "x": 4.83, + "y": 117.32, + "speed": 22.03, + "time": 1.22, + "theta": 80.47, + "omega": -207.43, + "vx": 17.62, + "vy": 13.22, + "splineNum": 1 + }, + { + "x": 6.17, + "y": 118.91, + "speed": 30.03, + "time": 1.29, + "theta": 70.9, + "omega": -192.47, + "vx": 19.34, + "vy": 22.97, + "splineNum": 1 + }, + { + "x": 7.48, + "y": 120.65, + "speed": 36.56, + "time": 1.35, + "theta": 61.85, + "omega": -179.63, + "vx": 21.91, + "vy": 29.27, + "splineNum": 1 + }, + { + "x": 8.83, + "y": 122.2, + "speed": 41.81, + "time": 1.4, + "theta": 53.81, + "omega": -169.03, + "vx": 27.53, + "vy": 31.46, + "splineNum": 1 + }, + { + "x": 8.83, + "y": 122.2, + "speed": 41.81, + "time": 1.4, + "theta": 53.81, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 2 + }, + { + "x": 9.93, + "y": 123.16, + "speed": 44.83, + "time": 1.43, + "theta": 52.78, + "omega": -63.43, + "vx": 33.75, + "vy": 29.5, + "splineNum": 2 + }, + { + "x": 11.07, + "y": 123.99, + "speed": 41.54, + "time": 1.47, + "theta": 49.47, + "omega": -130.22, + "vx": 33.58, + "vy": 24.44, + "splineNum": 2 + }, + { + "x": 12.28, + "y": 124.7, + "speed": 38.03, + "time": 1.5, + "theta": 43.37, + "omega": -201.91, + "vx": 32.82, + "vy": 19.2, + "splineNum": 2 + }, + { + "x": 13.54, + "y": 125.26, + "speed": 35.54, + "time": 1.54, + "theta": 34.02, + "omega": -734.94, + "vx": 32.46, + "vy": 14.48, + "splineNum": 2 + }, + { + "x": 14.87, + "y": 125.68, + "speed": 34.76, + "time": 1.58, + "theta": 21.32, + "omega": -656.72, + "vx": 33.19, + "vy": 10.35, + "splineNum": 2 + }, + { + "x": 16.27, + "y": 125.93, + "speed": 35.72, + "time": 1.62, + "theta": 5.61, + "omega": -579.04, + "vx": 35.14, + "vy": 6.42, + "splineNum": 2 + }, + { + "x": 17.74, + "y": 126.02, + "speed": 39.63, + "time": 1.66, + "theta": -11.86, + "omega": -506.48, + "vx": 39.56, + "vy": 2.35, + "splineNum": 2 + }, + { + "x": 17.74, + "y": 126.02, + "speed": 39.63, + "time": 1.66, + "theta": -11.86, + "omega": -506.48, + "vx": 39.63, + "vy": 0, + "splineNum": 2 + }, + { + "x": 20.85, + "y": 126.02, + "speed": 46.81, + "time": 1.73, + "theta": -11.93, + "omega": -2.01, + "vx": 46.81, + "vy": 0.03, + "splineNum": 3 + }, + { + "x": 23.95, + "y": 125.98, + "speed": 50, + "time": 1.79, + "theta": -12.11, + "omega": -3.89, + "vx": 50, + "vy": -0.69, + "splineNum": 3 + }, + { + "x": 27.02, + "y": 125.82, + "speed": 50, + "time": 1.85, + "theta": -12.41, + "omega": -5.75, + "vx": 49.93, + "vy": -2.61, + "splineNum": 3 + }, + { + "x": 30.07, + "y": 125.46, + "speed": 44.65, + "time": 1.92, + "theta": -12.87, + "omega": -7.83, + "vx": 44.36, + "vy": -5.15, + "splineNum": 3 + }, + { + "x": 33.08, + "y": 124.84, + "speed": 37.16, + "time": 2, + "theta": -13.62, + "omega": -10.33, + "vx": 36.39, + "vy": -7.51, + "splineNum": 3 + }, + { + "x": 36.02, + "y": 123.88, + "speed": 27.58, + "time": 2.11, + "theta": -14.98, + "omega": -31.16, + "vx": 26.22, + "vy": -8.55, + "splineNum": 3 + }, + { + "x": 38.9, + "y": 122.51, + "speed": 11.09, + "time": 2.4, + "theta": -20.18, + "omega": -22.45, + "vx": 10, + "vy": -4.78, + "splineNum": 3 + }, + { + "x": 38.9, + "y": 122.51, + "speed": 11.09, + "time": 2.4, + "theta": -20.18, + "omega": -22.45, + "vx": 11.09, + "vy": 0, + "splineNum": 3 + }, + { + "x": 42.21, + "y": 120.47, + "speed": 30, + "time": 2.53, + "theta": -19.29, + "omega": 13.78, + "vx": 25.52, + "vy": -15.78, + "splineNum": 4 + }, + { + "x": 45.4, + "y": 118.24, + "speed": 40.98, + "time": 2.63, + "theta": -17.5, + "omega": 23.88, + "vx": 33.61, + "vy": -23.44, + "splineNum": 4 + }, + { + "x": 48.55, + "y": 115.94, + "speed": 49.59, + "time": 2.7, + "theta": -15.29, + "omega": 32.25, + "vx": 40.08, + "vy": -29.2, + "splineNum": 4 + }, + { + "x": 51.73, + "y": 113.69, + "speed": 50, + "time": 2.78, + "theta": -12.46, + "omega": 90.44, + "vx": 40.81, + "vy": -28.89, + "splineNum": 4 + }, + { + "x": 55.01, + "y": 111.6, + "speed": 50, + "time": 2.86, + "theta": -8.98, + "omega": 82.17, + "vx": 42.14, + "vy": -26.91, + "splineNum": 4 + }, + { + "x": 58.45, + "y": 109.78, + "speed": 50, + "time": 2.94, + "theta": -4.86, + "omega": 73.88, + "vx": 44.21, + "vy": -23.35, + "splineNum": 4 + }, + { + "x": 62.13, + "y": 108.35, + "speed": 50, + "time": 3.02, + "theta": -0.02, + "omega": 65.49, + "vx": 46.6, + "vy": -18.12, + "splineNum": 4 + }, + { + "x": 62.13, + "y": 108.35, + "speed": 50, + "time": 3.02, + "theta": -0.02, + "omega": 65.49, + "vx": -50, + "vy": 0, + "splineNum": 4 + }, + { + "x": 58.76, + "y": 109.64, + "speed": 50, + "time": 3.09, + "theta": 0.56, + "omega": 16.03, + "vx": -46.72, + "vy": 17.81, + "splineNum": 5 + }, + { + "x": 55.93, + "y": 111.2, + "speed": 48.43, + "time": 3.16, + "theta": 2.12, + "omega": 30.83, + "vx": -42.35, + "vy": 23.49, + "splineNum": 5 + }, + { + "x": 53.65, + "y": 113.05, + "speed": 41.94, + "time": 3.23, + "theta": 4.82, + "omega": 46.35, + "vx": -32.6, + "vy": 26.38, + "splineNum": 5 + }, + { + "x": 51.91, + "y": 115.17, + "speed": 36.9, + "time": 3.3, + "theta": 8.88, + "omega": 62.86, + "vx": -23.41, + "vy": 28.53, + "splineNum": 5 + }, + { + "x": 50.71, + "y": 117.56, + "speed": 37.35, + "time": 3.37, + "theta": 13.96, + "omega": 203.97, + "vx": -16.79, + "vy": 33.36, + "splineNum": 5 + }, + { + "x": 50.03, + "y": 120.23, + "speed": 43.31, + "time": 3.44, + "theta": 19.41, + "omega": 189.87, + "vx": -10.62, + "vy": 41.98, + "splineNum": 5 + }, + { + "x": 49.89, + "y": 123.16, + "speed": 49.63, + "time": 3.49, + "theta": 25.3, + "omega": 176.73, + "vx": -2.5, + "vy": 49.57, + "splineNum": 5 + }, + { + "x": 50.26, + "y": 126.36, + "speed": 47.45, + "time": 3.56, + "theta": 33.01, + "omega": 161.65, + "vx": 5.5, + "vy": 47.13, + "splineNum": 5 + }, + { + "x": 51.15, + "y": 129.83, + "speed": 39.18, + "time": 3.65, + "theta": 45, + "omega": 141.38, + "vx": 9.76, + "vy": 37.95, + "splineNum": 5 + }, + { + "x": 51.84, + "y": 131.48, + "speed": 34.32, + "time": 3.71, + "theta": 45, + "omega": 0, + "vx": 13.28, + "vy": 31.64, + "splineNum": 6 + }, + { + "x": 52.76, + "y": 132.97, + "speed": 39.08, + "time": 3.75, + "theta": 45, + "omega": 0, + "vx": 20.49, + "vy": 33.27, + "splineNum": 6 + }, + { + "x": 53.83, + "y": 134.34, + "speed": 43.31, + "time": 3.79, + "theta": 45, + "omega": 0, + "vx": 26.63, + "vy": 34.15, + "splineNum": 6 + }, + { + "x": 54.99, + "y": 135.65, + "speed": 47.18, + "time": 3.83, + "theta": 45, + "omega": 0, + "vx": 31.25, + "vy": 35.34, + "splineNum": 6 + }, + { + "x": 56.17, + "y": 136.95, + "speed": 50, + "time": 3.86, + "theta": 45, + "omega": 0, + "vx": 33.62, + "vy": 37.01, + "splineNum": 6 + }, + { + "x": 57.3, + "y": 138.28, + "speed": 50, + "time": 3.9, + "theta": 45, + "omega": 0, + "vx": 32.33, + "vy": 38.14, + "splineNum": 6 + }, + { + "x": 58.31, + "y": 139.7, + "speed": 50, + "time": 3.93, + "theta": 45, + "omega": 0, + "vx": 29.06, + "vy": 40.69, + "splineNum": 6 + } + ] + }, + { + "name": "V2-Goal9ToGoal8", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": 45, + "spline_angle": -131.76, + "x": 60.7, + "y": 133.97, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": 0, + "angle": 17.97, + "spline_angle": 50.22, + "x": 39.38, + "y": 110.74, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -105, + "spline_angle": 68.26, + "x": 29.67, + "y": 89.26, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": -90, + "spline_angle": 84.25, + "x": 26.65, + "y": 70.01, + "shared": false, + "speed": 5 + }, + { + "name": "wp", + "omega": 0, + "angle": 0, + "spline_angle": 177.2, + "x": 40.81, + "y": 77.65, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 0, + "spline_angle": 177.2, + "x": 67.06, + "y": 77.17, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": 60.7, + "y": 133.97, + "speed": 0, + "time": 0, + "theta": 45, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 58.05, + "y": 131.05, + "speed": 28.08, + "time": 0.14, + "theta": 43.96, + "omega": -14.85, + "vx": -18.88, + "vy": -20.78, + "splineNum": 0 + }, + { + "x": 55.36, + "y": 128.17, + "speed": 39.71, + "time": 0.24, + "theta": 41.96, + "omega": -25.35, + "vx": -27.08, + "vy": -29.04, + "splineNum": 0 + }, + { + "x": 52.65, + "y": 125.31, + "speed": 48.63, + "time": 0.32, + "theta": 39.56, + "omega": -33.92, + "vx": -33.42, + "vy": -35.32, + "splineNum": 0 + }, + { + "x": 49.94, + "y": 122.45, + "speed": 50, + "time": 0.4, + "theta": 36.56, + "omega": -108.98, + "vx": -34.42, + "vy": -36.27, + "splineNum": 0 + }, + { + "x": 47.24, + "y": 119.58, + "speed": 50, + "time": 0.48, + "theta": 32.9, + "omega": -100.64, + "vx": -34.26, + "vy": -36.42, + "splineNum": 0 + }, + { + "x": 44.57, + "y": 116.68, + "speed": 50, + "time": 0.56, + "theta": 28.58, + "omega": -92.3, + "vx": -33.89, + "vy": -36.76, + "splineNum": 0 + }, + { + "x": 41.94, + "y": 113.74, + "speed": 50, + "time": 0.64, + "theta": 23.61, + "omega": -83.96, + "vx": -33.3, + "vy": -37.3, + "splineNum": 0 + }, + { + "x": 39.38, + "y": 110.74, + "speed": 50, + "time": 0.71, + "theta": 17.97, + "omega": -75.62, + "vx": -32.48, + "vy": -38.01, + "splineNum": 0 + }, + { + "x": 37.35, + "y": 107.96, + "speed": 50, + "time": 0.78, + "theta": 15.38, + "omega": -75.31, + "vx": -29.47, + "vy": -40.39, + "splineNum": 1 + }, + { + "x": 35.68, + "y": 105.02, + "speed": 50, + "time": 0.85, + "theta": 7.78, + "omega": -149.35, + "vx": -24.68, + "vy": -43.49, + "splineNum": 1 + }, + { + "x": 34.29, + "y": 101.96, + "speed": 50, + "time": 0.92, + "theta": -4.76, + "omega": -223.08, + "vx": -20.75, + "vy": -45.49, + "splineNum": 1 + }, + { + "x": 33.07, + "y": 98.81, + "speed": 50, + "time": 0.99, + "theta": -22.3, + "omega": -740.81, + "vx": -17.99, + "vy": -46.65, + "splineNum": 1 + }, + { + "x": 31.96, + "y": 95.62, + "speed": 50, + "time": 1.05, + "theta": -44.88, + "omega": -666.79, + "vx": -16.5, + "vy": -47.2, + "splineNum": 1 + }, + { + "x": 30.85, + "y": 92.42, + "speed": 50, + "time": 1.12, + "theta": -72.47, + "omega": -592.76, + "vx": -16.34, + "vy": -47.25, + "splineNum": 1 + }, + { + "x": 29.67, + "y": 89.26, + "speed": 50, + "time": 1.19, + "theta": -105, + "omega": -518.87, + "vx": -17.5, + "vy": -46.84, + "splineNum": 1 + }, + { + "x": 29.67, + "y": 89.26, + "speed": 50, + "time": 1.19, + "theta": -105, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 2 + }, + { + "x": 28.76, + "y": 86.59, + "speed": 50, + "time": 1.25, + "theta": -104.95, + "omega": 1.71, + "vx": -16.1, + "vy": -47.34, + "splineNum": 2 + }, + { + "x": 28.11, + "y": 83.87, + "speed": 50, + "time": 1.3, + "theta": -104.81, + "omega": 3.41, + "vx": -11.7, + "vy": -48.61, + "splineNum": 2 + }, + { + "x": 27.65, + "y": 81.12, + "speed": 47.51, + "time": 1.36, + "theta": -104.56, + "omega": 5.18, + "vx": -7.77, + "vy": -46.87, + "splineNum": 2 + }, + { + "x": 27.34, + "y": 78.36, + "speed": 41.23, + "time": 1.43, + "theta": -104.14, + "omega": 7.23, + "vx": -4.67, + "vy": -40.96, + "splineNum": 2 + }, + { + "x": 27.1, + "y": 75.57, + "speed": 33.79, + "time": 1.51, + "theta": -103.44, + "omega": 9.73, + "vx": -2.82, + "vy": -33.67, + "splineNum": 2 + }, + { + "x": 26.89, + "y": 72.79, + "speed": 24.15, + "time": 1.63, + "theta": -102.11, + "omega": 13.24, + "vx": -1.81, + "vy": -24.08, + "splineNum": 2 + }, + { + "x": 26.65, + "y": 70.01, + "speed": 5, + "time": 2.18, + "theta": -90, + "omega": 30.16, + "vx": -0.44, + "vy": -4.98, + "splineNum": 2 + }, + { + "x": 26.65, + "y": 70.01, + "speed": 5, + "time": 2.18, + "theta": -90, + "omega": 30.16, + "vx": -4, + "vy": 0, + "splineNum": 2 + }, + { + "x": 27.41, + "y": 73.45, + "speed": 27, + "time": 2.31, + "theta": -86.37, + "omega": 55.69, + "vx": 5.81, + "vy": 26.36, + "splineNum": 3 + }, + { + "x": 28.78, + "y": 75.74, + "speed": 18.84, + "time": 2.46, + "theta": -74.16, + "omega": 116.32, + "vx": 9.68, + "vy": 16.17, + "splineNum": 3 + }, + { + "x": 30.65, + "y": 77.11, + "speed": 20.3, + "time": 2.57, + "theta": -58.08, + "omega": 389.48, + "vx": 16.39, + "vy": 11.98, + "splineNum": 3 + }, + { + "x": 32.91, + "y": 77.77, + "speed": 29.7, + "time": 2.65, + "theta": -43.68, + "omega": 355.68, + "vx": 28.51, + "vy": 8.33, + "splineNum": 3 + }, + { + "x": 35.43, + "y": 77.93, + "speed": 37.25, + "time": 2.72, + "theta": -29.2, + "omega": 326.69, + "vx": 37.17, + "vy": 2.44, + "splineNum": 3 + }, + { + "x": 38.11, + "y": 77.82, + "speed": 43.85, + "time": 2.78, + "theta": -14.5, + "omega": 300.63, + "vx": 43.81, + "vy": -1.83, + "splineNum": 3 + }, + { + "x": 40.81, + "y": 77.65, + "speed": 49.65, + "time": 2.83, + "theta": 0, + "omega": 277.31, + "vx": 49.55, + "vy": -3.16, + "splineNum": 3 + }, + { + "x": 40.81, + "y": 77.65, + "speed": 49.65, + "time": 2.83, + "theta": 0, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 4 + }, + { + "x": 44.56, + "y": 77.51, + "speed": 50, + "time": 2.91, + "theta": 0, + "omega": 0, + "vx": 49.97, + "vy": -1.85, + "splineNum": 4 + }, + { + "x": 48.31, + "y": 77.44, + "speed": 50, + "time": 2.98, + "theta": 0, + "omega": 0, + "vx": 49.99, + "vy": -0.91, + "splineNum": 4 + }, + { + "x": 52.06, + "y": 77.42, + "speed": 50, + "time": 3.06, + "theta": 0, + "omega": 0, + "vx": 50, + "vy": -0.35, + "splineNum": 4 + }, + { + "x": 55.81, + "y": 77.4, + "speed": 50, + "time": 3.13, + "theta": 0, + "omega": 0, + "vx": 50, + "vy": -0.16, + "splineNum": 4 + }, + { + "x": 59.56, + "y": 77.38, + "speed": 50, + "time": 3.21, + "theta": 0, + "omega": 0, + "vx": 50, + "vy": -0.35, + "splineNum": 4 + }, + { + "x": 63.31, + "y": 77.31, + "speed": 50, + "time": 3.28, + "theta": 0, + "omega": 0, + "vx": 49.99, + "vy": -0.91, + "splineNum": 4 + }, + { + "x": 67.06, + "y": 77.17, + "speed": 50, + "time": 3.36, + "theta": 0, + "omega": 0, + "vx": 49.97, + "vy": -1.85, + "splineNum": 4 + } + ] + }, + { + "name": "V2-Goal8ToGoal7", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": -1.32242845928212, + "angle": 0, + "spline_angle": 0, + "x": 52.75, + "y": 72.24, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": -1.32242845928212, + "angle": 45, + "spline_angle": 50.1, + "x": 38.74, + "y": 68.26, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": -1.32242845928212, + "angle": 0, + "spline_angle": 81.18, + "x": 37.15, + "y": 54.89, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": -1.32242845928212, + "angle": -90, + "spline_angle": -90.82, + "x": 36.2, + "y": 36.28, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": -1.32242845928212, + "angle": -90, + "spline_angle": -90.82, + "x": 35.72, + "y": 18.14, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": -1.32242845928212, + "angle": 0, + "spline_angle": 34.79, + "x": 46.54, + "y": 32.78, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": -1.32242845928212, + "angle": 0, + "spline_angle": -179.97, + "x": 66.11, + "y": 35.64, + "shared": false, + "speed": 10 + }, + { + "name": "wp", + "omega": -1.32242845928212, + "angle": -44.51, + "spline_angle": 84.43, + "x": 50.99, + "y": 25.14, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": -1.32242845928212, + "angle": -45, + "spline_angle": -30.95, + "x": 60.7, + "y": 11.14, + "shared": false, + "speed": 10 + } + ], + "points": [ + { + "x": 52.75, + "y": 72.24, + "speed": 0, + "time": 0, + "theta": 0, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 50.58, + "y": 72.26, + "speed": 20.82, + "time": 0.1, + "theta": 1.9, + "omega": 36.5, + "vx": -20.82, + "vy": 0.15, + "splineNum": 0 + }, + { + "x": 48.42, + "y": 72.24, + "speed": 29.41, + "time": 0.18, + "theta": 5.52, + "omega": 62.22, + "vx": -29.41, + "vy": -0.23, + "splineNum": 0 + }, + { + "x": 46.3, + "y": 72.09, + "speed": 35.92, + "time": 0.24, + "theta": 9.82, + "omega": 82.97, + "vx": -35.84, + "vy": -2.48, + "splineNum": 0 + }, + { + "x": 44.25, + "y": 71.72, + "speed": 37.33, + "time": 0.29, + "theta": 15.01, + "omega": 252.65, + "vx": -36.72, + "vy": -6.68, + "splineNum": 0 + }, + { + "x": 42.28, + "y": 71.02, + "speed": 31.24, + "time": 0.36, + "theta": 22.64, + "omega": 229.26, + "vx": -29.44, + "vy": -10.47, + "splineNum": 0 + }, + { + "x": 40.44, + "y": 69.9, + "speed": 30.56, + "time": 0.43, + "theta": 32.41, + "omega": 204.5, + "vx": -26.12, + "vy": -15.86, + "splineNum": 0 + }, + { + "x": 38.74, + "y": 68.26, + "speed": 30.78, + "time": 0.51, + "theta": 45, + "omega": 177.63, + "vx": -22.14, + "vy": -21.38, + "splineNum": 0 + }, + { + "x": 38.74, + "y": 68.26, + "speed": 30.78, + "time": 0.51, + "theta": 45, + "omega": 177.63, + "vx": -32, + "vy": 0, + "splineNum": 0 + }, + { + "x": 37.61, + "y": 66.46, + "speed": 22.84, + "time": 0.6, + "theta": 42.5, + "omega": -53.62, + "vx": -12.16, + "vy": -19.33, + "splineNum": 1 + }, + { + "x": 37.04, + "y": 64.59, + "speed": 27.41, + "time": 0.67, + "theta": 37.22, + "omega": -94.6, + "vx": -7.91, + "vy": -26.24, + "splineNum": 1 + }, + { + "x": 36.89, + "y": 62.67, + "speed": 33.71, + "time": 0.73, + "theta": 30.88, + "omega": -327.56, + "vx": -2.7, + "vy": -33.6, + "splineNum": 1 + }, + { + "x": 36.98, + "y": 60.72, + "speed": 39.07, + "time": 0.78, + "theta": 23.8, + "omega": -298.85, + "vx": 1.9, + "vy": -39.02, + "splineNum": 1 + }, + { + "x": 37.17, + "y": 58.76, + "speed": 43.81, + "time": 0.82, + "theta": 16.21, + "omega": -273.02, + "vx": 4.06, + "vy": -43.62, + "splineNum": 1 + }, + { + "x": 37.27, + "y": 56.81, + "speed": 48.06, + "time": 0.86, + "theta": 8.34, + "omega": -249.66, + "vx": 2.69, + "vy": -47.99, + "splineNum": 1 + }, + { + "x": 37.15, + "y": 54.89, + "speed": 50, + "time": 0.9, + "theta": 0, + "omega": -227.5, + "vx": -3.23, + "vy": -49.9, + "splineNum": 1 + }, + { + "x": 37.15, + "y": 54.89, + "speed": 50, + "time": 0.9, + "theta": 0, + "omega": -227.5, + "vx": -64, + "vy": 0, + "splineNum": 1 + }, + { + "x": 36.8, + "y": 52.24, + "speed": 50, + "time": 0.96, + "theta": -1.56, + "omega": -58.45, + "vx": -6.54, + "vy": -49.57, + "splineNum": 2 + }, + { + "x": 36.56, + "y": 49.59, + "speed": 50, + "time": 1.01, + "theta": -6.23, + "omega": -116.76, + "vx": -4.54, + "vy": -49.79, + "splineNum": 2 + }, + { + "x": 36.4, + "y": 46.93, + "speed": 50, + "time": 1.06, + "theta": -14, + "omega": -175.03, + "vx": -2.94, + "vy": -49.91, + "splineNum": 2 + }, + { + "x": 36.31, + "y": 44.27, + "speed": 50, + "time": 1.12, + "theta": -24.87, + "omega": -654.35, + "vx": -1.73, + "vy": -49.97, + "splineNum": 2 + }, + { + "x": 36.26, + "y": 41.61, + "speed": 48.37, + "time": 1.17, + "theta": -39.37, + "omega": -594.09, + "vx": -0.91, + "vy": -48.36, + "splineNum": 2 + }, + { + "x": 36.23, + "y": 38.94, + "speed": 42.51, + "time": 1.23, + "theta": -59.92, + "omega": -525.51, + "vx": -0.47, + "vy": -42.5, + "splineNum": 2 + }, + { + "x": 36.2, + "y": 36.28, + "speed": 35.69, + "time": 1.31, + "theta": -90, + "omega": -443.82, + "vx": -0.41, + "vy": -35.69, + "splineNum": 2 + }, + { + "x": 36.2, + "y": 36.28, + "speed": 35.69, + "time": 1.31, + "theta": -90, + "omega": -443.82, + "vx": -35.69, + "vy": 0, + "splineNum": 2 + }, + { + "x": 36.15, + "y": 33.69, + "speed": 42.34, + "time": 1.37, + "theta": -90, + "omega": 0, + "vx": -0.81, + "vy": -42.33, + "splineNum": 3 + }, + { + "x": 36.08, + "y": 31.1, + "speed": 48.07, + "time": 1.42, + "theta": -90, + "omega": 0, + "vx": -1.27, + "vy": -48.06, + "splineNum": 3 + }, + { + "x": 36, + "y": 28.51, + "speed": 45.76, + "time": 1.48, + "theta": -90, + "omega": 0, + "vx": -1.41, + "vy": -45.74, + "splineNum": 3 + }, + { + "x": 35.92, + "y": 25.91, + "speed": 39.7, + "time": 1.54, + "theta": -90, + "omega": 0, + "vx": -1.29, + "vy": -39.68, + "splineNum": 3 + }, + { + "x": 35.84, + "y": 23.32, + "speed": 32.52, + "time": 1.62, + "theta": -90, + "omega": 0, + "vx": -1.01, + "vy": -32.5, + "splineNum": 3 + }, + { + "x": 35.77, + "y": 20.73, + "speed": 23.21, + "time": 1.74, + "theta": -90, + "omega": 0, + "vx": -0.61, + "vy": -23.21, + "splineNum": 3 + }, + { + "x": 35.72, + "y": 18.14, + "speed": 4.52, + "time": 2.31, + "theta": -90, + "omega": 0, + "vx": -0.09, + "vy": -4.52, + "splineNum": 3 + }, + { + "x": 35.72, + "y": 18.14, + "speed": 4.52, + "time": 2.31, + "theta": -90, + "omega": 0, + "vx": 0, + "vy": -4, + "splineNum": 3 + }, + { + "x": 36.08, + "y": 21.11, + "speed": 24.87, + "time": 2.43, + "theta": -84.39, + "omega": 93.32, + "vx": 2.97, + "vy": 24.7, + "splineNum": 4 + }, + { + "x": 36.99, + "y": 23.67, + "speed": 34.09, + "time": 2.51, + "theta": -74.49, + "omega": 155.16, + "vx": 11.47, + "vy": 32.1, + "splineNum": 4 + }, + { + "x": 38.37, + "y": 25.89, + "speed": 41.04, + "time": 2.57, + "theta": -63.05, + "omega": 542.97, + "vx": 21.63, + "vy": 34.87, + "splineNum": 4 + }, + { + "x": 40.11, + "y": 27.83, + "speed": 46.97, + "time": 2.63, + "theta": -50.48, + "omega": 499.82, + "vx": 31.28, + "vy": 35.04, + "splineNum": 4 + }, + { + "x": 42.11, + "y": 29.58, + "speed": 50, + "time": 2.68, + "theta": -36.19, + "omega": 458.49, + "vx": 37.67, + "vy": 32.87, + "splineNum": 4 + }, + { + "x": 44.29, + "y": 31.21, + "speed": 50, + "time": 2.74, + "theta": -19.34, + "omega": 416.33, + "vx": 40.07, + "vy": 29.91, + "splineNum": 4 + }, + { + "x": 46.54, + "y": 32.78, + "speed": 50, + "time": 2.79, + "theta": 0, + "omega": 373.73, + "vx": 41.01, + "vy": 28.61, + "splineNum": 4 + }, + { + "x": 46.54, + "y": 32.78, + "speed": 50, + "time": 2.79, + "theta": 0, + "omega": 373.73, + "vx": -50, + "vy": 0, + "splineNum": 4 + }, + { + "x": 49.18, + "y": 34.26, + "speed": 48.02, + "time": 2.85, + "theta": 0, + "omega": 0, + "vx": 41.87, + "vy": 23.5, + "splineNum": 5 + }, + { + "x": 51.9, + "y": 35.18, + "speed": 50, + "time": 2.91, + "theta": 0, + "omega": 0, + "vx": 47.35, + "vy": 16.06, + "splineNum": 5 + }, + { + "x": 54.68, + "y": 35.67, + "speed": 48.85, + "time": 2.97, + "theta": 0, + "omega": 0, + "vx": 48.13, + "vy": 8.38, + "splineNum": 5 + }, + { + "x": 57.52, + "y": 35.84, + "speed": 42.66, + "time": 3.04, + "theta": 0, + "omega": 0, + "vx": 42.58, + "vy": 2.52, + "splineNum": 5 + }, + { + "x": 60.37, + "y": 35.81, + "speed": 35.32, + "time": 3.12, + "theta": 0, + "omega": 0, + "vx": 35.32, + "vy": -0.36, + "splineNum": 5 + }, + { + "x": 63.25, + "y": 35.7, + "speed": 25.94, + "time": 3.23, + "theta": 0, + "omega": 0, + "vx": 25.92, + "vy": -0.95, + "splineNum": 5 + }, + { + "x": 66.11, + "y": 35.64, + "speed": 10, + "time": 3.51, + "theta": 0, + "omega": 0, + "vx": 10, + "vy": -0.21, + "splineNum": 5 + }, + { + "x": 66.11, + "y": 35.64, + "speed": 10, + "time": 3.51, + "theta": 0, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 6 + }, + { + "x": 62.97, + "y": 35.55, + "speed": 26.99, + "time": 3.63, + "theta": -1.44, + "omega": -24.77, + "vx": -26.98, + "vy": -0.75, + "splineNum": 6 + }, + { + "x": 60.01, + "y": 35.21, + "speed": 36.4, + "time": 3.71, + "theta": -4.18, + "omega": -42.2, + "vx": -36.15, + "vy": -4.22, + "splineNum": 6 + }, + { + "x": 57.31, + "y": 34.48, + "speed": 35.63, + "time": 3.79, + "theta": -8.14, + "omega": -58.87, + "vx": -34.38, + "vy": -9.33, + "splineNum": 6 + }, + { + "x": 54.98, + "y": 33.23, + "speed": 27.2, + "time": 3.89, + "theta": -14.88, + "omega": -195.66, + "vx": -24.01, + "vy": -12.78, + "splineNum": 6 + }, + { + "x": 53.08, + "y": 31.35, + "speed": 27.09, + "time": 3.99, + "theta": -23.77, + "omega": -174.68, + "vx": -19.19, + "vy": -19.12, + "splineNum": 6 + }, + { + "x": 51.73, + "y": 28.69, + "speed": 36.47, + "time": 4.07, + "theta": -32.7, + "omega": -157.29, + "vx": -16.61, + "vy": -32.47, + "splineNum": 6 + }, + { + "x": 50.99, + "y": 25.14, + "speed": 39.24, + "time": 4.16, + "theta": -44.51, + "omega": -137.62, + "vx": -7.95, + "vy": -38.42, + "splineNum": 6 + }, + { + "x": 50.99, + "y": 25.14, + "speed": 39.24, + "time": 4.16, + "theta": -44.51, + "omega": -137.62, + "vx": -39.24, + "vy": 0, + "splineNum": 6 + }, + { + "x": 51.02, + "y": 22.2, + "speed": 34.61, + "time": 4.25, + "theta": -44.52, + "omega": -0.15, + "vx": 0.35, + "vy": -34.61, + "splineNum": 7 + }, + { + "x": 51.66, + "y": 19.68, + "speed": 31.19, + "time": 4.33, + "theta": -44.54, + "omega": -0.3, + "vx": 7.74, + "vy": -30.21, + "splineNum": 7 + }, + { + "x": 52.83, + "y": 17.53, + "speed": 35.15, + "time": 4.4, + "theta": -44.56, + "omega": -0.42, + "vx": 16.67, + "vy": -30.95, + "splineNum": 7 + }, + { + "x": 54.41, + "y": 15.66, + "speed": 40.66, + "time": 4.46, + "theta": -44.59, + "omega": -0.53, + "vx": 26.29, + "vy": -31.01, + "splineNum": 7 + }, + { + "x": 56.31, + "y": 14.02, + "speed": 33.92, + "time": 4.53, + "theta": -44.63, + "omega": -1.98, + "vx": 25.69, + "vy": -22.14, + "splineNum": 7 + }, + { + "x": 58.44, + "y": 12.54, + "speed": 25.12, + "time": 4.64, + "theta": -44.71, + "omega": -1.8, + "vx": 20.61, + "vy": -14.36, + "splineNum": 7 + }, + { + "x": 60.7, + "y": 11.14, + "speed": 10, + "time": 4.9, + "theta": -45, + "omega": -1.32, + "vx": 8.51, + "vy": -5.26, + "splineNum": 7 + }, + { + "x": 60.7, + "y": 11.14, + "speed": 10, + "time": 4.9, + "theta": -45, + "omega": -1.32, + "vx": 8, + "vy": -4, + "splineNum": 7 + } + ] + }, + { + "name": "V2-Goal7ToGoal5", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": -38.85, + "spline_angle": 126.08, + "x": 61.81, + "y": 11.62, + "shared": false, + "speed": 0 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": -3.7, + "x": 23.63, + "y": 21.32, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 162.65, + "spline_angle": 162.65, + "x": 0.08, + "y": 23.23, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 94.29, + "x": -5.17, + "y": 33.57, + "shared": false, + "speed": 50 + }, + { + "name": "wp", + "omega": 0, + "angle": 90, + "spline_angle": 94.27, + "x": -1.99, + "y": 63.96, + "shared": false, + "speed": 20 + } + ], + "points": [ + { + "x": 61.81, + "y": 11.62, + "speed": 0, + "time": 0, + "theta": -38.85, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 59.41, + "y": 14.48, + "speed": 27.33, + "time": 0.14, + "theta": -35.99, + "omega": 41.84, + "vx": -17.56, + "vy": 20.93, + "splineNum": 0 + }, + { + "x": 56.86, + "y": 16.74, + "speed": 37.8, + "time": 0.23, + "theta": -30.97, + "omega": 69.47, + "vx": -28.29, + "vy": 25.07, + "splineNum": 0 + }, + { + "x": 54.17, + "y": 18.47, + "speed": 45.47, + "time": 0.3, + "theta": -25.33, + "omega": 90.99, + "vx": -38.23, + "vy": 24.63, + "splineNum": 0 + }, + { + "x": 51.37, + "y": 19.74, + "speed": 50, + "time": 0.36, + "theta": -19.15, + "omega": 109.84, + "vx": -45.57, + "vy": 20.58, + "splineNum": 0 + }, + { + "x": 48.46, + "y": 20.61, + "speed": 50, + "time": 0.42, + "theta": -11.92, + "omega": 128.42, + "vx": -47.9, + "vy": 14.34, + "splineNum": 0 + }, + { + "x": 45.47, + "y": 21.15, + "speed": 50, + "time": 0.48, + "theta": -3.56, + "omega": 414.83, + "vx": -49.2, + "vy": 8.89, + "splineNum": 0 + }, + { + "x": 42.42, + "y": 21.43, + "speed": 50, + "time": 0.54, + "theta": 6.04, + "omega": 396.03, + "vx": -49.8, + "vy": 4.51, + "splineNum": 0 + }, + { + "x": 39.31, + "y": 21.51, + "speed": 50, + "time": 0.6, + "theta": 16.94, + "omega": 377, + "vx": -49.98, + "vy": 1.3, + "splineNum": 0 + }, + { + "x": 36.17, + "y": 21.46, + "speed": 50, + "time": 0.67, + "theta": 29.15, + "omega": 357.78, + "vx": -49.99, + "vy": -0.76, + "splineNum": 0 + }, + { + "x": 33.02, + "y": 21.35, + "speed": 50, + "time": 0.73, + "theta": 42.64, + "omega": 338.44, + "vx": -49.97, + "vy": -1.74, + "splineNum": 0 + }, + { + "x": 29.86, + "y": 21.25, + "speed": 50, + "time": 0.79, + "theta": 57.34, + "omega": 319.12, + "vx": -49.97, + "vy": -1.66, + "splineNum": 0 + }, + { + "x": 26.73, + "y": 21.21, + "speed": 50, + "time": 0.86, + "theta": 73.17, + "omega": 299.92, + "vx": -50, + "vy": -0.52, + "splineNum": 0 + }, + { + "x": 23.63, + "y": 21.32, + "speed": 50, + "time": 0.92, + "theta": 90, + "omega": 280.93, + "vx": -49.97, + "vy": 1.72, + "splineNum": 0 + }, + { + "x": 23.63, + "y": 21.32, + "speed": 50, + "time": 0.92, + "theta": 90, + "omega": 280.93, + "vx": -64, + "vy": 0, + "splineNum": 0 + }, + { + "x": 20.25, + "y": 21.46, + "speed": 50, + "time": 0.98, + "theta": 90.97, + "omega": 28.6, + "vx": -49.96, + "vy": 2.06, + "splineNum": 1 + }, + { + "x": 16.87, + "y": 21.5, + "speed": 50, + "time": 1.05, + "theta": 93.87, + "omega": 57.24, + "vx": -50, + "vy": 0.6, + "splineNum": 1 + }, + { + "x": 13.49, + "y": 21.53, + "speed": 50, + "time": 1.12, + "theta": 98.71, + "omega": 85.89, + "vx": -50, + "vy": 0.4, + "splineNum": 1 + }, + { + "x": 10.11, + "y": 21.63, + "speed": 50, + "time": 1.19, + "theta": 105.49, + "omega": 114.5, + "vx": -49.98, + "vy": 1.49, + "splineNum": 1 + }, + { + "x": 6.74, + "y": 21.89, + "speed": 43.96, + "time": 1.26, + "theta": 115.53, + "omega": 349, + "vx": -43.83, + "vy": 3.38, + "splineNum": 1 + }, + { + "x": 3.4, + "y": 22.39, + "speed": 35.44, + "time": 1.36, + "theta": 131.49, + "omega": 308.59, + "vx": -35.04, + "vy": 5.29, + "splineNum": 1 + }, + { + "x": 0.08, + "y": 23.23, + "speed": 23.91, + "time": 1.5, + "theta": 162.65, + "omega": 248, + "vx": -23.18, + "vy": 5.85, + "splineNum": 1 + }, + { + "x": 0.08, + "y": 23.23, + "speed": 23.91, + "time": 1.5, + "theta": 162.65, + "omega": 248, + "vx": -16, + "vy": 0, + "splineNum": 1 + }, + { + "x": -1.86, + "y": 24.1, + "speed": 20.58, + "time": 1.61, + "theta": 159.43, + "omega": -62.37, + "vx": -18.76, + "vy": 8.45, + "splineNum": 2 + }, + { + "x": -3.22, + "y": 25.27, + "speed": 17.52, + "time": 1.71, + "theta": 149.89, + "omega": -124.1, + "vx": -13.28, + "vy": 11.42, + "splineNum": 2 + }, + { + "x": -4.11, + "y": 26.68, + "speed": 20.74, + "time": 1.79, + "theta": 137.99, + "omega": -419.74, + "vx": -11.09, + "vy": 17.53, + "splineNum": 2 + }, + { + "x": -4.64, + "y": 28.27, + "speed": 27.66, + "time": 1.85, + "theta": 126.44, + "omega": -383.2, + "vx": -8.75, + "vy": 26.25, + "splineNum": 2 + }, + { + "x": -4.92, + "y": 29.98, + "speed": 33.36, + "time": 1.9, + "theta": 114.73, + "omega": -351.75, + "vx": -5.38, + "vy": 32.93, + "splineNum": 2 + }, + { + "x": -5.06, + "y": 31.77, + "speed": 38.36, + "time": 1.95, + "theta": 102.84, + "omega": -323.56, + "vx": -3.02, + "vy": 38.24, + "splineNum": 2 + }, + { + "x": -5.17, + "y": 33.57, + "speed": 39.69, + "time": 1.99, + "theta": 90, + "omega": -296.12, + "vx": -2.46, + "vy": 39.61, + "splineNum": 2 + }, + { + "x": -5.17, + "y": 33.57, + "speed": 39.69, + "time": 1.99, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 3 + }, + { + "x": -5.22, + "y": 37.42, + "speed": 48.42, + "time": 2.07, + "theta": 90, + "omega": 0, + "vx": -0.68, + "vy": 48.42, + "splineNum": 3 + }, + { + "x": -4.89, + "y": 41.22, + "speed": 50, + "time": 2.15, + "theta": 90, + "omega": 0, + "vx": 4.35, + "vy": 49.81, + "splineNum": 3 + }, + { + "x": -4.3, + "y": 45, + "speed": 50, + "time": 2.23, + "theta": 90, + "omega": 0, + "vx": 7.72, + "vy": 49.4, + "splineNum": 3 + }, + { + "x": -3.58, + "y": 48.77, + "speed": 50, + "time": 2.3, + "theta": 90, + "omega": 0, + "vx": 9.39, + "vy": 49.11, + "splineNum": 3 + }, + { + "x": -2.86, + "y": 52.53, + "speed": 50, + "time": 2.38, + "theta": 90, + "omega": 0, + "vx": 9.39, + "vy": 49.11, + "splineNum": 3 + }, + { + "x": -2.27, + "y": 56.31, + "speed": 43.97, + "time": 2.47, + "theta": 90, + "omega": 0, + "vx": 6.79, + "vy": 43.44, + "splineNum": 3 + }, + { + "x": -1.94, + "y": 60.11, + "speed": 34.19, + "time": 2.58, + "theta": 90, + "omega": 0, + "vx": 2.99, + "vy": 34.06, + "splineNum": 3 + }, + { + "x": -1.99, + "y": 63.96, + "speed": 20, + "time": 2.77, + "theta": 90, + "omega": 0, + "vx": -0.27, + "vy": 20, + "splineNum": 3 + } + ] + }, + { + "name": "V2-BackUp", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": 90, + "spline_angle": 93.98, + "x": 0.56, + "y": 65.71, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": 0, + "angle": 90, + "spline_angle": 93.27, + "x": 0.72, + "y": 42.16, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": 0.56, + "y": 65.71, + "speed": 0, + "time": 0, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 0.72, + "y": 62.35, + "speed": 25.95, + "time": 0.13, + "theta": 90, + "omega": 0, + "vx": 1.21, + "vy": -25.92, + "splineNum": 0 + }, + { + "x": 0.75, + "y": 58.98, + "speed": 36.69, + "time": 0.22, + "theta": 90, + "omega": 0, + "vx": 0.38, + "vy": -36.69, + "splineNum": 0 + }, + { + "x": 0.71, + "y": 55.62, + "speed": 44.94, + "time": 0.3, + "theta": 90, + "omega": 0, + "vx": -0.55, + "vy": -44.93, + "splineNum": 0 + }, + { + "x": 0.64, + "y": 52.25, + "speed": 50, + "time": 0.36, + "theta": 90, + "omega": 0, + "vx": -1.04, + "vy": -49.99, + "splineNum": 0 + }, + { + "x": 0.59, + "y": 48.89, + "speed": 50, + "time": 0.43, + "theta": 90, + "omega": 0, + "vx": -0.79, + "vy": -49.99, + "splineNum": 0 + }, + { + "x": 0.6, + "y": 45.52, + "speed": 50, + "time": 0.5, + "theta": 90, + "omega": 0, + "vx": 0.16, + "vy": -50, + "splineNum": 0 + }, + { + "x": 0.72, + "y": 42.16, + "speed": 50, + "time": 0.57, + "theta": 90, + "omega": 0, + "vx": 1.8, + "vy": -49.97, + "splineNum": 0 + } + ] + }, + { + "name": "V2-Forward", + "maxVel": 50, + "maxAccel": 100, + "k": 3, + "totalTime": 0, + "waypoints": [ + { + "name": "start", + "omega": 0, + "angle": 90, + "spline_angle": 85.97, + "x": 0.88, + "y": 55.69, + "shared": false, + "speed": 0 + }, + { + "name": "end", + "omega": 0, + "angle": 90, + "spline_angle": -91.3, + "x": 1.03, + "y": 70.64, + "shared": false, + "speed": 50 + } + ], + "points": [ + { + "x": 0.88, + "y": 55.69, + "speed": 0, + "time": 0, + "theta": 90, + "omega": 0, + "vx": 0, + "vy": 0, + "splineNum": 0 + }, + { + "x": 0.99, + "y": 57.82, + "speed": 20.68, + "time": 0.1, + "theta": 90, + "omega": 0, + "vx": 1.09, + "vy": 20.65, + "splineNum": 0 + }, + { + "x": 1.04, + "y": 59.96, + "speed": 29.24, + "time": 0.18, + "theta": 90, + "omega": 0, + "vx": 0.69, + "vy": 29.23, + "splineNum": 0 + }, + { + "x": 1.05, + "y": 62.1, + "speed": 35.8, + "time": 0.24, + "theta": 90, + "omega": 0, + "vx": 0.12, + "vy": 35.8, + "splineNum": 0 + }, + { + "x": 1.03, + "y": 64.23, + "speed": 41.34, + "time": 0.29, + "theta": 90, + "omega": 0, + "vx": -0.32, + "vy": 41.34, + "splineNum": 0 + }, + { + "x": 1.01, + "y": 66.37, + "speed": 46.22, + "time": 0.33, + "theta": 90, + "omega": 0, + "vx": -0.47, + "vy": 46.22, + "splineNum": 0 + }, + { + "x": 1, + "y": 68.5, + "speed": 50, + "time": 0.38, + "theta": 90, + "omega": 0, + "vx": -0.18, + "vy": 50, + "splineNum": 0 + }, + { + "x": 1.03, + "y": 70.64, + "speed": 50, + "time": 0.42, + "theta": 90, + "omega": 0, + "vx": 0.6, + "vy": 50, + "splineNum": 0 + } + ] + } + ] +} \ No newline at end of file diff --git a/project.pros b/project.pros new file mode 100644 index 00000000..77de5e1a --- /dev/null +++ b/project.pros @@ -0,0 +1,313 @@ +{ + "py/object": "pros.conductor.project.Project", + "py/state": { + "project_name": "ros1", + "target": "v5", + "templates": { + "kernel": { + "location": "/root/.config/pros/templates/kernel@3.7.3", + "metadata": { + "cold_addr": "58720256", + "cold_output": "bin/cold.package.bin", + "hot_addr": "125829120", + "hot_output": "bin/hot.package.bin", + "origin": "pros-mainline", + "output": "bin/monolith.bin" + }, + "name": "kernel", + "py/object": "pros.conductor.templates.local_template.LocalTemplate", + "supported_kernels": null, + "system_files": [ + "common.mk", + "include/display/lv_objx/lv_tileview.h", + "firmware/libm.a", + "include/display/lv_hal/lv_hal_indev.h", + "include/display/lv_objx/lv_bar.h", + "include/pros/ext_adi.h", + "include/display/lv_fonts/lv_font_builtin.h", + "include/display/lv_draw/lv_draw_rect.h", + "include/display/lv_misc/lv_anim.h", + "include/display/lv_misc/lv_font.h", + "include/display/lv_misc/lv_color.h", + "include/display/lv_themes/lv_theme_zen.h", + "include/display/lv_misc/lv_symbol_def.h", + "include/display/lv_objx/lv_cb.h", + "include/pros/misc.h", + "include/display/lv_misc/lv_task.h", + "include/display/lv_core/lv_obj.h", + "include/display/lv_themes/lv_themes.mk", + "include/pros/adi.hpp", + "include/display/lv_objx/lv_line.h", + "include/display/lv_objx/lv_gauge.h", + "include/display/lv_objx/lv_arc.h", + "include/display/lv_core/lv_lang.h", + "include/pros/colors.h", + "include/display/lv_objx/lv_ta.h", + "include/pros/gps.h", + "include/display/lv_objx/lv_lmeter.h", + "include/pros/optical.h", + "include/pros/screen.hpp", + "include/display/lv_hal/lv_hal.mk", + "include/pros/serial.h", + "include/pros/link.h", + "include/display/lv_hal/lv_hal.h", + "include/display/lv_objx/lv_btnm.h", + "include/display/lv_objx/lv_img.h", + "include/display/lv_objx/lv_label.h", + "include/display/lv_misc/lv_gc.h", + "include/display/lvgl.h", + "include/pros/adi.h", + "include/pros/optical.hpp", + "include/display/lv_objx/lv_sw.h", + "include/api.h", + "include/pros/llemu.hpp", + "include/display/lv_core/lv_style.h", + "include/pros/colors.hpp", + "firmware/v5.ld", + "include/display/lv_draw/lv_draw_vbasic.h", + "include/display/lv_misc/lv_fs.h", + "include/display/lv_objx/lv_page.h", + "include/display/lv_draw/lv_draw.mk", + "include/display/lv_objx/lv_calendar.h", + "include/display/lv_objx/lv_win.h", + "include/pros/rtos.h", + "include/display/lv_conf_checker.h", + "include/display/lv_themes/lv_theme_night.h", + "include/display/lv_objx/lv_cont.h", + "include/display/licence.txt", + "include/pros/api_legacy.h", + "include/display/lv_misc/lv_log.h", + "firmware/libc.a", + "include/pros/rtos.hpp", + "include/display/lv_objx/lv_roller.h", + "include/display/lv_draw/lv_draw_label.h", + "include/display/lv_objx/lv_spinbox.h", + "include/display/lv_misc/lv_mem.h", + "include/display/lv_objx/lv_led.h", + "include/display/lv_objx/lv_canvas.h", + "include/display/lv_misc/lv_circ.h", + "include/pros/screen.h", + "include/pros/apix.h", + "include/display/lv_objx/lv_objx.mk", + "include/display/lv_misc/lv_txt.h", + "include/display/lv_draw/lv_draw_line.h", + "include/display/lv_draw/lv_draw.h", + "include/display/lv_objx/lv_preload.h", + "include/display/lv_themes/lv_theme_material.h", + "include/pros/distance.hpp", + "include/pros/rotation.hpp", + "include/display/lv_themes/lv_theme.h", + "include/display/lv_misc/lv_area.h", + "firmware/libpros.a", + "include/pros/motors.hpp", + "include/display/lv_misc/lv_ufs.h", + "include/display/lv_misc/lv_math.h", + "include/display/lv_core/lv_group.h", + "include/display/lv_objx/lv_chart.h", + "include/display/lv_objx/lv_slider.h", + "include/display/lv_draw/lv_draw_triangle.h", + "include/display/lv_objx/lv_mbox.h", + "include/display/lv_hal/lv_hal_disp.h", + "include/pros/misc.hpp", + "include/display/lv_objx/lv_list.h", + "include/pros/serial.hpp", + "include/display/lv_objx/lv_imgbtn.h", + "include/pros/vision.h", + "include/display/lv_objx/lv_objx_templ.h", + "firmware/v5-hot.ld", + "include/display/lv_core/lv_indev.h", + "include/pros/llemu.h", + "include/pros/imu.h", + "include/display/README.md", + "include/pros/rotation.h", + "include/display/lv_version.h", + "include/pros/vision.hpp", + "include/display/lv_themes/lv_theme_nemo.h", + "include/display/lv_core/lv_vdb.h", + "include/display/lv_objx/lv_ddlist.h", + "include/display/lv_core/lv_core.mk", + "include/pros/imu.hpp", + "include/display/lv_misc/lv_ll.h", + "include/display/lv_draw/lv_draw_rbasic.h", + "include/display/lv_themes/lv_theme_mono.h", + "include/display/lv_fonts/lv_fonts.mk", + "include/display/lv_misc/lv_templ.h", + "include/display/lv_themes/lv_theme_templ.h", + "include/display/lv_themes/lv_theme_default.h", + "include/display/lv_objx/lv_btn.h", + "include/display/lv_conf.h", + "include/display/lv_core/lv_refr.h", + "include/pros/motors.h", + "include/display/lv_objx/lv_tabview.h", + "include/pros/gps.hpp", + "include/display/lv_hal/lv_hal_tick.h", + "include/pros/error.h", + "firmware/v5-common.ld", + "include/display/lv_draw/lv_draw_arc.h", + "include/display/lv_themes/lv_theme_alien.h", + "include/pros/distance.h", + "include/display/lv_objx/lv_table.h", + "include/display/lv_misc/lv_misc.mk", + "include/display/lv_draw/lv_draw_img.h", + "include/display/lv_objx/lv_kb.h", + "include/pros/link.hpp" + ], + "target": "v5", + "user_files": [ + ".gitignore", + "include/main.h", + "Makefile", + "src/main.cc", + "include/main.hpp", + "src/main.c", + "src/main.cpp", + "include/main.hh" + ], + "version": "3.7.3" + }, + "okapilib": { + "location": "/root/.config/pros/templates/okapilib@4.8.0", + "metadata": { + "origin": "pros-mainline" + }, + "name": "okapilib", + "py/object": "pros.conductor.templates.local_template.LocalTemplate", + "supported_kernels": "^3.3.1", + "system_files": [ + "include/okapi/api/odometry/odomMath.hpp", + "include/okapi/squiggles/physicalmodel/physicalmodel.hpp", + "include/okapi/api/chassis/model/threeEncoderXDriveModel.hpp", + "include/okapi/api/chassis/model/hDriveModel.hpp", + "include/okapi/api/chassis/model/readOnlyChassisModel.hpp", + "include/okapi/api/device/button/buttonBase.hpp", + "include/okapi/api/units/QAngularJerk.hpp", + "include/okapi/api/control/iterative/iterativeController.hpp", + "include/okapi/api/control/controllerInput.hpp", + "include/okapi/squiggles/math/quinticpolynomial.hpp", + "include/okapi/api/device/rotarysensor/continuousRotarySensor.hpp", + "include/okapi/api/control/async/asyncPositionController.hpp", + "include/okapi/api/filter/passthroughFilter.hpp", + "include/okapi/api/device/rotarysensor/rotarySensor.hpp", + "include/okapi/api/odometry/stateMode.hpp", + "include/okapi/impl/device/controller.hpp", + "include/okapi/api/units/QTime.hpp", + "include/okapi/api/control/util/controllerRunner.hpp", + "include/okapi/api/units/QTorque.hpp", + "include/okapi/impl/device/rotarysensor/IMU.hpp", + "include/okapi/api/control/util/pidTuner.hpp", + "include/okapi/impl/util/timeUtilFactory.hpp", + "include/okapi/api/device/motor/abstractMotor.hpp", + "include/okapi/impl/device/button/controllerButton.hpp", + "include/okapi/impl/device/rotarysensor/integratedEncoder.hpp", + "include/okapi/impl/device/rotarysensor/adiEncoder.hpp", + "include/okapi/api/filter/composableFilter.hpp", + "include/okapi/api/chassis/model/xDriveModel.hpp", + "include/okapi/squiggles/geometry/pose.hpp", + "include/okapi/api/odometry/twoEncoderOdometry.hpp", + "include/okapi/api/util/timeUtil.hpp", + "firmware/squiggles.mk", + "include/okapi/api/control/async/asyncPosPidController.hpp", + "include/okapi/impl/control/util/controllerRunnerFactory.hpp", + "include/okapi/impl/chassis/controller/chassisControllerBuilder.hpp", + "include/okapi/api/control/closedLoopController.hpp", + "include/okapi/squiggles/math/utils.hpp", + "include/okapi/api/control/async/asyncVelIntegratedController.hpp", + "include/okapi/api/units/QLength.hpp", + "include/okapi/impl/device/motor/motor.hpp", + "include/okapi/api/odometry/odometry.hpp", + "include/okapi/api/units/RQuantity.hpp", + "include/okapi/api/units/QArea.hpp", + "include/okapi/api/filter/filter.hpp", + "include/okapi/api/device/button/abstractButton.hpp", + "include/okapi/api/units/QPressure.hpp", + "include/okapi/api/control/async/asyncLinearMotionProfileController.hpp", + "include/okapi/api/control/util/flywheelSimulator.hpp", + "include/okapi/api/util/logging.hpp", + "include/okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp", + "include/okapi/api/filter/emaFilter.hpp", + "include/okapi/impl/device/controllerUtil.hpp", + "include/okapi/api/util/mathUtil.hpp", + "include/okapi/api/filter/averageFilter.hpp", + "include/okapi/api/control/iterative/iterativeVelocityController.hpp", + "include/okapi/api/odometry/point.hpp", + "include/okapi/api/control/async/asyncController.hpp", + "include/okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp", + "include/okapi/api/coreProsAPI.hpp", + "include/okapi/api/units/QSpeed.hpp", + "include/okapi/impl/control/util/pidTunerFactory.hpp", + "include/okapi/api/units/QAngle.hpp", + "include/okapi/api/control/async/asyncVelocityController.hpp", + "include/okapi/api/odometry/threeEncoderOdometry.hpp", + "include/okapi/api/filter/velMath.hpp", + "include/okapi/api/control/async/asyncPosIntegratedController.hpp", + "include/okapi/squiggles/constraints.hpp", + "include/okapi/api/filter/filteredControllerInput.hpp", + "include/okapi/api/chassis/controller/chassisControllerPid.hpp", + "include/okapi/api/control/iterative/iterativePositionController.hpp", + "include/okapi/api/control/offsettableControllerInput.hpp", + "include/okapi/squiggles/squiggles.hpp", + "include/okapi/api/units/QAngularSpeed.hpp", + "include/okapi/api/control/iterative/iterativePosPidController.hpp", + "include/okapi/squiggles/physicalmodel/tankmodel.hpp", + "include/okapi/impl/util/rate.hpp", + "include/okapi/api/filter/medianFilter.hpp", + "include/okapi/impl/device/rotarysensor/potentiometer.hpp", + "include/okapi/api/control/iterative/iterativeVelPidController.hpp", + "include/okapi/squiggles/geometry/profilepoint.hpp", + "include/okapi/impl/device/button/adiButton.hpp", + "include/okapi/impl/control/async/asyncVelControllerBuilder.hpp", + "include/okapi/api/filter/demaFilter.hpp", + "include/okapi/api/units/RQuantityName.hpp", + "include/okapi/api/control/util/pathfinderUtil.hpp", + "include/okapi/api/util/abstractTimer.hpp", + "include/okapi/api.hpp", + "include/okapi/impl/control/async/asyncPosControllerBuilder.hpp", + "include/okapi/api/chassis/controller/chassisScales.hpp", + "include/okapi/api/units/QMass.hpp", + "include/okapi/impl/device/rotarysensor/adiGyro.hpp", + "include/okapi/impl/util/configurableTimeUtilFactory.hpp", + "include/okapi/api/control/util/settledUtil.hpp", + "include/okapi/impl/control/iterative/iterativeControllerFactory.hpp", + "include/okapi/impl/util/timer.hpp", + "include/okapi/api/chassis/controller/defaultOdomChassisController.hpp", + "include/okapi/impl/device/motor/motorGroup.hpp", + "include/okapi/api/control/async/asyncWrapper.hpp", + "include/okapi/squiggles/io.hpp", + "include/okapi/api/filter/ekfFilter.hpp", + "include/okapi/api/control/async/asyncMotionProfileController.hpp", + "include/okapi/squiggles/geometry/controlvector.hpp", + "include/okapi/impl/device/distanceSensor.hpp", + "include/okapi/api/control/controllerOutput.hpp", + "include/okapi/api/units/QVolume.hpp", + "include/okapi/squiggles/spline.hpp", + "include/okapi/api/units/QJerk.hpp", + "include/okapi/api/chassis/controller/chassisController.hpp", + "include/okapi/squiggles/physicalmodel/passthroughmodel.hpp", + "include/okapi/api/units/QAngularAcceleration.hpp", + "include/okapi/api/chassis/controller/chassisControllerIntegrated.hpp", + "include/okapi/impl/device/adiUltrasonic.hpp", + "include/okapi/impl/device/opticalSensor.hpp", + "include/okapi/api/units/QForce.hpp", + "include/okapi/api/util/supplier.hpp", + "include/okapi/api/chassis/controller/odomChassisController.hpp", + "include/okapi/impl/filter/velMathFactory.hpp", + "include/okapi/api/control/iterative/iterativeMotorVelocityController.hpp", + "include/okapi/api/control/async/asyncVelPidController.hpp", + "include/okapi/api/odometry/odomState.hpp", + "include/okapi/api/chassis/model/chassisModel.hpp", + "include/okapi/api/units/QFrequency.hpp", + "include/okapi/impl/device/rotarysensor/rotationSensor.hpp", + "include/okapi/api/util/abstractRate.hpp", + "include/okapi/impl/device/motor/adiMotor.hpp", + "include/okapi/api/units/QAcceleration.hpp", + "include/okapi/api/chassis/model/skidSteerModel.hpp", + "firmware/okapilib.a" + ], + "target": "v5", + "user_files": [], + "version": "4.8.0" + } + }, + "upload_options": {} + } +} \ No newline at end of file diff --git a/pros/api.h b/pros/api.h new file mode 100644 index 00000000..718030d1 --- /dev/null +++ b/pros/api.h @@ -0,0 +1,80 @@ +/** + * \file api.h + * + * PROS API header provides high-level user functionality + * + * Contains declarations for use by typical VEX programmers using PROS. + * + * 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. + * 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/. + */ + +#ifndef _PROS_API_H_ +#define _PROS_API_H_ + +#ifdef __cplusplus +#include +#include +#include +#include +#include +#include +#include +#include +#else /* (not) __cplusplus */ +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* __cplusplus */ + +#define PROS_VERSION_MAJOR 3 +#define PROS_VERSION_MINOR 7 +#define PROS_VERSION_PATCH 3 +#define PROS_VERSION_STRING "3.7.3" + +#include "pros/adi.h" +#include "pros/colors.h" +#include "pros/distance.h" +#include "pros/error.h" +#include "pros/ext_adi.h" +#include "pros/gps.h" +#include "pros/imu.h" +#include "pros/link.h" +#include "pros/llemu.h" +#include "pros/misc.h" +#include "pros/motors.h" +#include "pros/optical.h" +#include "pros/rtos.h" +#include "pros/rotation.h" +#include "pros/screen.h" +#include "pros/vision.h" + +#ifdef __cplusplus +#include "pros/adi.hpp" +#include "pros/distance.hpp" +#include "pros/gps.hpp" +#include "pros/imu.hpp" +#include "pros/llemu.hpp" +#include "pros/misc.hpp" +#include "pros/motors.hpp" +#include "pros/optical.hpp" +#include "pros/rotation.hpp" +#include "pros/rtos.hpp" +#include "pros/screen.hpp" +#include "pros/vision.hpp" +#include "pros/link.hpp" +#endif + +#endif // _PROS_API_H_ diff --git a/pros/display/README.md b/pros/display/README.md new file mode 100644 index 00000000..afdfdeb5 --- /dev/null +++ b/pros/display/README.md @@ -0,0 +1,71 @@ +# Littlev Graphics Libraray + +![LittlevGL cover](http://www.gl.littlev.hu/home/main_cover_small.png) + +LittlevGL provides everything you need to create a Graphical User Interface (GUI) on embedded systems with easy-to-use graphical elements, beautiful visual effects and low memory footprint. + +Homepage: https://littlevgl.com + +### Table Of Content +* [Key features](#key-features) +* [Porting](#porting) +* [Project set-up](#project-set-up) +* [PC simulator](#pc-simulator) +* [Screenshots](#screenshots) +* [Contributing](#contributing) +* [Donate](#donate) + +## Key features +* Powerful building blocks buttons, charts, lists, sliders, images etc +* Advanced graphics with animations, anti-aliasing, opacity, smooth scrolling +* Various input devices touch pad, mouse, keyboard, encoder, buttons etc +* Multi language support with UTF-8 decoding +* Fully customizable graphical elements +* Hardware independent to use with any microcontroller or display +* Scalable to operate with few memory (50 kB Flash, 10 kB RAM) +* OS, External memory and GPU supported but not required +* Single frame buffer operation even with advances graphical effects +* Written in C for maximal compatibility +* Simulator to develop on PC without embedded hardware +* Tutorials, examples, themes for rapid development +* Documentation and API references online + +## Porting +In the most sime case you need 4 things: +1. Call `lv_tick_inc(1)` in every millisecods in a Timer or Task +2. Register a function which can **copy a pixel array** to an area of the screen +3. Register a function which can **read an input device**. (E.g. touch pad) +4. Call `lv_task_handler()` periodically in every few milliseconds +For more information visit https://littlevgl.com/porting + +## Project set-up +1. **Clone** or [Download](https://littlevgl.com/download) the lvgl repository: `git clone https://github.com/littlevgl/lvgl.git` +2. **Create project** with your preferred IDE and add the *lvgl* folder +3. Copy **lvgl/lv_conf_templ.h** as **lv_conf.h** next to the *lvgl* folder +4. In the lv_conf.h delete the first `#if 0` and its `#endif`. Let the default configurations at first. +5. In your *main.c*: #include "lvgl/lvgl.h" +6. In your *main function*: + * lvgl_init(); + * tick, display and input device initialization (see above) +7. To **test** create a label: `lv_obj_t * label = lv_label_create(lv_scr_act(), NULL);` +8. In the main *while(1)* call `lv_task_handler();` and make a few milliseconds delay (e.g. `my_delay_ms(5);`) +9. Compile the code and load it to your embedded hardware + +## PC Simulator +If you don't have got an embedded hardware you can test the graphics library in a PC simulator. The simulator uses [SDL2](https://www.libsdl.org/) to emulate a display on your monitor and a touch pad with your mouse. + +There is a pre-configured PC project for **Eclipse CDT** in this repository: https://github.com/littlevgl/pc_simulator + +## Screenshots +![TFT material](http://www.gl.littlev.hu/github_res/tft_material.png) +![TFT zen](http://www.gl.littlev.hu/github_res/tft_zen.png) +![TFT alien](http://www.gl.littlev.hu/github_res/tft_alien.png) +![TFT night](http://www.gl.littlev.hu/github_res/tft_night.png) + +## Contributing +See [CONTRIBUTING.md](https://github.com/littlevgl/lvgl/blob/master/docs/CONTRIBUTING.md) + +## Donate +If you are pleased with the graphics library, found it useful or be happy with the support you got, please help its further development: + +[![Donate](https://littlevgl.com/donate_dir/donate_btn.png)](https://littlevgl.com/donate) diff --git a/pros/display/licence.txt b/pros/display/licence.txt new file mode 100644 index 00000000..beaef1d2 --- /dev/null +++ b/pros/display/licence.txt @@ -0,0 +1,8 @@ +MIT licence +Copyright (c) 2016 Gábor Kiss-Vámosi + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/pros/display/lv_conf.h b/pros/display/lv_conf.h new file mode 100644 index 00000000..0b1a1626 --- /dev/null +++ b/pros/display/lv_conf.h @@ -0,0 +1,341 @@ +/** + * @file lv_conf.h + * + */ + +#ifndef LV_CONF_H +#define LV_CONF_H + +/*---------------- + * Dynamic memory + *----------------*/ + +/* Memory size which will be used by the library + * to store the graphical objects and other data */ +#define LV_MEM_CUSTOM \ + 1 /*1: use custom malloc/free, 0: use the built-in \ + lv_mem_alloc/lv_mem_free*/ +#if LV_MEM_CUSTOM == 0 +#define LV_MEM_SIZE \ + (32U * 1024U) /*Size memory used by `lv_mem_alloc` in bytes (>= 2kB)*/ +#define LV_MEM_ATTR /*Complier prefix for big array declaration*/ +#define LV_MEM_AUTO_DEFRAG 1 /*Automatically defrag on free*/ +#else /*LV_MEM_CUSTOM*/ +#define LV_MEM_CUSTOM_INCLUDE \ + "kapi.h" /*Header for the dynamic memory function*/ +#define LV_MEM_CUSTOM_ALLOC kmalloc /*Wrapper to malloc*/ +#define LV_MEM_CUSTOM_FREE kfree /*Wrapper to free*/ +#endif /*LV_MEM_CUSTOM*/ +#define LV_ENABLE_GC 0 + +/*=================== + Graphical settings + *===================*/ + +/* Horizontal and vertical resolution of the library.*/ +#define LV_HOR_RES (480) +#define LV_VER_RES (240) +#define LV_DPI 126 + +/* Size of VDB (Virtual Display Buffer: the internal graphics buffer). + * Required for buffered drawing, opacity and anti-aliasing + * VDB makes the double buffering, you don't need to deal with it! + * Typical size: ~1/10 screen */ +#define LV_VDB_SIZE \ + (LV_VER_RES * \ + LV_HOR_RES) /*Size of VDB in pixel count (1/10 screen size is good for \ + first)*/ +#define LV_VDB_ADR \ + 0 /*Place VDB to a specific address (e.g. in external RAM) (0: allocate \ + automatically into RAM)*/ + +/* Use two Virtual Display buffers (VDB) parallelize rendering and flushing + * (optional) + * The flushing should use DMA to write the frame buffer in the background*/ +#define LV_VDB_DOUBLE 0 /*1: Enable the use of 2 VDBs*/ +#define LV_VDB2_ADR \ + 0 /*Place VDB2 to a specific address (e.g. in external RAM) (0: allocate \ + automatically into RAM)*/ + +/* Enable anti-aliasing (lines, and radiuses will be smoothed) */ +#define LV_ANTIALIAS 1 /*1: Enable anti-aliasing*/ + +/*Screen refresh settings*/ +#define LV_REFR_PERIOD 40 /*Screen refresh period in milliseconds*/ +#define LV_INV_FIFO_SIZE 32 /*The average count of objects on a screen */ + +/*================= + Misc. setting + *=================*/ + +/*Input device settings*/ +#define LV_INDEV_READ_PERIOD 50 /*Input device read period in milliseconds*/ +#define LV_INDEV_POINT_MARKER \ + 0 /*Mark the pressed points (required: USE_LV_REAL_DRAW = 1)*/ +#define LV_INDEV_DRAG_LIMIT 10 /*Drag threshold in pixels */ +#define LV_INDEV_DRAG_THROW \ + 20 /*Drag throw slow-down in [%]. Greater value means faster slow-down */ +#define LV_INDEV_LONG_PRESS_TIME 400 /*Long press time in milliseconds*/ +#define LV_INDEV_LONG_PRESS_REP_TIME \ + 100 /*Repeated trigger period in long press [ms] */ + +/*Color settings*/ +#define LV_COLOR_DEPTH 32 /*Color depth: 1/8/16/24*/ +#define LV_COLOR_TRANSP \ + LV_COLOR_LIME /*Images pixels with this color will not be drawn (with chroma \ + keying)*/ + +/*Text settings*/ +#define LV_TXT_UTF8 1 /*Enable UTF-8 coded Unicode character usage */ +#define LV_TXT_BREAK_CHARS " ,.;:-_" /*Can break texts on these chars*/ +#define LV_TXT_LINE_BREAK_LONG_LEN 12 +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 + +/*Graphics feature usage*/ +#define USE_LV_ANIMATION 1 /*1: Enable all animations*/ +#define USE_LV_SHADOW 1 /*1: Enable shadows*/ +#define USE_LV_GROUP 1 /*1: Enable object groups (for keyboards)*/ +#define USE_LV_GPU 0 /*1: Enable GPU interface*/ +#define USE_LV_REAL_DRAW \ + 1 /*1: Enable function which draw directly to the frame buffer instead of \ + VDB (required if LV_VDB_SIZE = 0)*/ +#define USE_LV_FILESYSTEM 1 /*1: Enable file system (required by images*/ +#define USE_LV_MULTI_LANG 1 + +/*Compiler attributes*/ +#define LV_ATTRIBUTE_TICK_INC /* Define a custom attribute to tick increment \ + function */ +#define LV_ATTRIBUTE_TASK_HANDLER +#define LV_ATTRIBUTE_MEM_ALIGN +#define LV_COMPILER_VLA_SUPPORTED 1 +#define LV_COMPILER_NON_CONST_INIT_SUPPORTED 1 + +#define USE_LV_LOG 0 +/*================ + * THEME USAGE + *================*/ +#define LV_THEME_LIVE_UPDATE 1 +#define USE_LV_THEME_TEMPL 0 /*Just for test*/ +#define USE_LV_THEME_DEFAULT 0 /*Built mainly from the built-in styles. Consumes very few RAM*/ +#define USE_LV_THEME_ALIEN 1 /*Dark futuristic theme*/ +#define USE_LV_THEME_NIGHT 1 /*Dark elegant theme*/ +#define USE_LV_THEME_MONO 1 /*Mono color theme for monochrome displays*/ +#define USE_LV_THEME_MATERIAL 1 /*Flat theme with bold colors and light shadows*/ +#define USE_LV_THEME_ZEN 1 /*Peaceful, mainly light theme */ + +/*================== + * FONT USAGE + *===================*/ + +/* More info about fonts: https://littlevgl.com/basics#fonts + * To enable a built-in font use 1,2,4 or 8 values + * which will determine the bit-per-pixel */ +#define LV_FONT_DEFAULT \ + &lv_font_dejavu_20 /*Always set a default font from the built-in fonts*/ + +#define USE_LV_FONT_DEJAVU_10 4 +#define USE_LV_FONT_DEJAVU_10_LATIN_SUP 4 +#define USE_LV_FONT_DEJAVU_10_CYRILLIC 4 +#define USE_LV_FONT_SYMBOL_10 4 + +#define USE_LV_FONT_DEJAVU_20 4 +#define USE_LV_FONT_DEJAVU_20_LATIN_SUP 4 +#define USE_LV_FONT_DEJAVU_20_CYRILLIC 4 +#define USE_LV_FONT_SYMBOL_20 4 + +#define USE_LV_FONT_DEJAVU_30 0 +#define USE_LV_FONT_DEJAVU_30_LATIN_SUP 0 +#define USE_LV_FONT_DEJAVU_30_CYRILLIC 0 +#define USE_LV_FONT_SYMBOL_30 0 + +#define USE_LV_FONT_DEJAVU_40 0 +#define USE_LV_FONT_DEJAVU_40_LATIN_SUP 0 +#define USE_LV_FONT_DEJAVU_40_CYRILLIC 0 +#define USE_LV_FONT_SYMBOL_40 0 + +/* PROS adds the mono variant of DejaVu sans */ +#define USE_PROS_FONT_DEJAVU_MONO_10 4 +#define USE_PROS_FONT_DEJAVU_MONO_10_LATIN_SUP 4 + +#define USE_PROS_FONT_DEJAVU_MONO_20 4 +#define USE_PROS_FONT_DEJAVU_MONO_LATIN_SUP_20 4 + +#define USE_PROS_FONT_DEJAVU_MONO_30 0 +#define USE_PROS_FONT_DEJAVU_MONO_30_LATIN_SUP 0 + +#define USE_PROS_FONT_DEJAVU_MONO_40 0 +#define USE_PROS_FONT_DEJAVU_MONO_40_LATIN_SUP 0 + +/*=================== + * LV_OBJ SETTINGS + *==================*/ +#define LV_OBJ_FREE_NUM_TYPE \ + uint32_t /*Type of free number attribute (comment out disable free number)*/ +#define LV_OBJ_FREE_PTR 1 /*Enable the free pointer attribute*/ + +/*================== + * LV OBJ X USAGE + *================*/ +/* + * Documentation of the object types: https://littlevgl.com/object-types + */ + +/***************** + * Simple object + *****************/ + +/*Label (dependencies: -*/ +#define USE_LV_LABEL 1 +#if USE_LV_LABEL != 0 +#define LV_LABEL_SCROLL_SPEED \ + 25 /*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_SCROLL/ROLL' \ + mode*/ +#endif + +/*Image (dependencies: lv_label*/ +#define USE_LV_IMG 1 +#if USE_LV_IMG != 0 +# define LV_IMG_CF_INDEXED 1 +# define LV_IMG_CF_ALPHA 1 +#endif + +/*Line (dependencies: -*/ +#define USE_LV_LINE 1 +#define USE_LV_ARC 1 + +/******************* + * Container objects + *******************/ + +/*Container (dependencies: -*/ +#define USE_LV_CONT 1 + +/*Page (dependencies: lv_cont)*/ +#define USE_LV_PAGE 1 + +/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/ +#define USE_LV_WIN 1 + +/*Tab (dependencies: lv_page, lv_btnm)*/ +#define USE_LV_TABVIEW 1 +#if USE_LV_TABVIEW != 0 +#define LV_TABVIEW_ANIM_TIME \ + 300 /*Time of slide animation [ms] (0: no animation)*/ +#endif +#define USE_LV_TILEVIEW 1 +#if USE_LV_TILEVIEW +# define LV_TILEVIEW_ANIM_TIME 300 +#endif + + +/************************* + * Data visualizer objects + *************************/ + +/*Bar (dependencies: -)*/ +#define USE_LV_BAR 1 + +/*Line meter (dependencies: *;)*/ +#define USE_LV_LMETER 1 + +/*Gauge (dependencies:bar, lmeter)*/ +#define USE_LV_GAUGE 1 + +/*Chart (dependencies: -)*/ +#define USE_LV_CHART 1 + +#define USE_LV_TABLE 1 +#if USE_LV_TABLE +# define LV_TABLE_COL_MAX 12 +#endif + +/*LED (dependencies: -)*/ +#define USE_LV_LED 1 + +/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ +#define USE_LV_MBOX 1 + +/*Text area (dependencies: lv_label, lv_page)*/ +#define USE_LV_TA 1 +#if USE_LV_TA != 0 +#define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/ +#define LV_TA_PWD_SHOW_TIME 1500 /*ms*/ +#endif + +#define USE_LV_SPINBOX 1 +#define USE_LV_CALENDAR 1 + +#define USE_PRELOAD 1 +#if USE_LV_PRELOAD != 0 +# define LV_PRELOAD_DEF_ARC_LENGTH 60 +# define LV_PRELOAD_DEF_SPIN_TIME 1000 +# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC +#endif + +#define USE_LV_CANVAS 1 +/************************* + * User input objects + *************************/ + +/*Button (dependencies: lv_cont*/ +#define USE_LV_BTN 1 +#if USE_LV_BTN != 0 +# define LV_BTN_INK_EFFECT 1 +#endif + +#define USE_LV_IMGBTN 1 +#if USE_LV_IMGBTN +# define LV_IMGBTN_TILED 0 +#endif + +/*Button matrix (dependencies: -)*/ +#define USE_LV_BTNM 1 + +/*Keyboard (dependencies: lv_btnm)*/ +#define USE_LV_KB 1 + +/*Check box (dependencies: lv_btn, lv_label)*/ +#define USE_LV_CB 1 + +/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons + * ))*/ +#define USE_LV_LIST 1 +#if USE_LV_LIST != 0 +#define LV_LIST_FOCUS_TIME \ + 100 /*Default animation time of focusing to a list element [ms] (0: no \ + animation) */ +#endif + +/*Drop down list (dependencies: lv_page, lv_label)*/ +#define USE_LV_DDLIST 1 +#if USE_LV_DDLIST != 0 +#define LV_DDLIST_ANIM_TIME \ + 200 /*Open and close default animation time [ms] (0: no animation)*/ +#endif + +/*Roller (dependencies: lv_ddlist)*/ +#define USE_LV_ROLLER 1 +#if USE_LV_ROLLER != 0 +#define LV_ROLLER_ANIM_TIME \ + 200 /*Focus animation time [ms] (0: no \ + animation)*/ +#endif + +/*Slider (dependencies: lv_bar)*/ +#define USE_LV_SLIDER 1 + +/*Switch (dependencies: lv_slider)*/ +#define USE_LV_SW 1 + +#if LV_INDEV_DRAG_THROW <= 0 +#warning "LV_INDEV_DRAG_THROW must be greater than 0" +#undef LV_INDEV_DRAG_THROW +#define LV_INDEV_DRAG_THROW 1 +#endif + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +# define _CRT_SECURE_NO_WARNINGS +#endif +#include "display/lv_conf_checker.h" +#endif /*LV_CONF_H*/ diff --git a/pros/display/lv_conf_checker.h b/pros/display/lv_conf_checker.h new file mode 100644 index 00000000..3a8ead51 --- /dev/null +++ b/pros/display/lv_conf_checker.h @@ -0,0 +1,664 @@ +/** + * GENERATED FILE, DO NOT EDIT IT! + * @file lv_conf_checker.h + * Make sure all the defines of lv_conf.h have a default value +**/ + +#ifndef LV_CONF_CHECKER_H +#define LV_CONF_CHECKER_H +/*=================== + Dynamic memory + *===================*/ + +/* Memory size which will be used by the library + * to store the graphical objects and other data */ +#ifndef LV_MEM_CUSTOM +#define LV_MEM_CUSTOM 0 /*1: use custom malloc/free, 0: use the built-in lv_mem_alloc/lv_mem_free*/ +#endif +#if LV_MEM_CUSTOM == 0 +#ifndef LV_MEM_SIZE +# define LV_MEM_SIZE (64U * 1024U) /*Size memory used by `lv_mem_alloc` in bytes (>= 2kB)*/ +#endif +#ifndef LV_MEM_ATTR +# define LV_MEM_ATTR /*Complier prefix for big array declaration*/ +#endif +#ifndef LV_MEM_ADR +# define LV_MEM_ADR 0 /*Set an address for memory pool instead of allocation it as an array. Can be in external SRAM too.*/ +#endif +#ifndef LV_MEM_AUTO_DEFRAG +# define LV_MEM_AUTO_DEFRAG 1 /*Automatically defrag on free*/ +#endif +#else /*LV_MEM_CUSTOM*/ +#ifndef LV_MEM_CUSTOM_INCLUDE +# define LV_MEM_CUSTOM_INCLUDE /*Header for the dynamic memory function*/ +#endif +#ifndef LV_MEM_CUSTOM_ALLOC +# define LV_MEM_CUSTOM_ALLOC malloc /*Wrapper to malloc*/ +#endif +#ifndef LV_MEM_CUSTOM_FREE +# define LV_MEM_CUSTOM_FREE free /*Wrapper to free*/ +#endif +#endif /*LV_MEM_CUSTOM*/ + +/* Garbage Collector settings + * Used if lvgl is binded to higher language and the memory is managed by that language */ +#ifndef LV_ENABLE_GC +#define LV_ENABLE_GC 0 +#endif +#if LV_ENABLE_GC != 0 +#ifndef LV_MEM_CUSTOM_REALLOC +# define LV_MEM_CUSTOM_REALLOC your_realloc /*Wrapper to realloc*/ +#endif +#ifndef LV_MEM_CUSTOM_GET_SIZE +# define LV_MEM_CUSTOM_GET_SIZE your_mem_get_size /*Wrapper to lv_mem_get_size*/ +#endif +#ifndef LV_GC_INCLUDE +# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/ +#endif +#endif /* LV_ENABLE_GC */ + +/*=================== + Graphical settings + *===================*/ + +/* Horizontal and vertical resolution of the library.*/ +#ifndef LV_HOR_RES +#define LV_HOR_RES (480) +#endif +#ifndef LV_VER_RES +#define LV_VER_RES (320) +#endif + +/* Dot Per Inch: used to initialize default sizes. E.g. a button with width = LV_DPI / 2 -> half inch wide + * (Not so important, you can adjust it to modify default sizes and spaces)*/ +#ifndef LV_DPI +#define LV_DPI 100 +#endif + +/* Enable anti-aliasing (lines, and radiuses will be smoothed) */ +#ifndef LV_ANTIALIAS +#define LV_ANTIALIAS 1 /*1: Enable anti-aliasing*/ +#endif + +/*Screen refresh period in milliseconds*/ +#ifndef LV_REFR_PERIOD +#define LV_REFR_PERIOD 30 +#endif + +/*----------------- + * VDB settings + *----------------*/ + +/* VDB (Virtual Display Buffer) is an internal graphics buffer. + * The GUI will be drawn into this buffer first and then + * the buffer will be passed to your `disp_drv.disp_flush` function to + * copy it to your frame buffer. + * VDB is required for: buffered drawing, opacity, anti-aliasing and shadows + * Learn more: https://docs.littlevgl.com/#Drawing*/ + +/* Size of the VDB in pixels. Typical size: ~1/10 screen. Must be >= LV_HOR_RES + * Setting it to 0 will disable VDB and `disp_drv.disp_fill` and `disp_drv.disp_map` functions + * will be called to draw to the frame buffer directly*/ +#ifndef LV_VDB_SIZE +#define LV_VDB_SIZE ((LV_VER_RES * LV_HOR_RES) / 10) +#endif + + /* Bit-per-pixel of VDB. Useful for monochrome or non-standard color format displays. + * Special formats are handled with `disp_drv.vdb_wr`)*/ +#ifndef LV_VDB_PX_BPP +#define LV_VDB_PX_BPP LV_COLOR_SIZE /*LV_COLOR_SIZE comes from LV_COLOR_DEPTH below to set 8, 16 or 32 bit pixel size automatically */ +#endif + + /* Place VDB to a specific address (e.g. in external RAM) + * 0: allocate automatically into RAM + * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/ +#ifndef LV_VDB_ADR +#define LV_VDB_ADR 0 +#endif + +/* Use two Virtual Display buffers (VDB) to parallelize rendering and flushing + * The flushing should use DMA to write the frame buffer in the background */ +#ifndef LV_VDB_DOUBLE +#define LV_VDB_DOUBLE 0 +#endif + +/* Place VDB2 to a specific address (e.g. in external RAM) + * 0: allocate automatically into RAM + * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/ +#ifndef LV_VDB2_ADR +#define LV_VDB2_ADR 0 +#endif + +/* Using true double buffering in `disp_drv.disp_flush` you will always get the image of the whole screen. + * Your only task is to set the rendered image (`color_p` parameter) as frame buffer address or send it to your display. + * The best if you do in the blank period of you display to avoid tearing effect. + * Requires: + * - LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES + * - LV_VDB_DOUBLE = 1 + */ +#ifndef LV_VDB_TRUE_DOUBLE_BUFFERED +#define LV_VDB_TRUE_DOUBLE_BUFFERED 0 +#endif + +/*================= + Misc. setting + *=================*/ + +/*Input device settings*/ +#ifndef LV_INDEV_READ_PERIOD +#define LV_INDEV_READ_PERIOD 50 /*Input device read period in milliseconds*/ +#endif +#ifndef LV_INDEV_POINT_MARKER +#define LV_INDEV_POINT_MARKER 0 /*Mark the pressed points (required: USE_LV_REAL_DRAW = 1)*/ +#endif +#ifndef LV_INDEV_DRAG_LIMIT +#define LV_INDEV_DRAG_LIMIT 10 /*Drag threshold in pixels */ +#endif +#ifndef LV_INDEV_DRAG_THROW +#define LV_INDEV_DRAG_THROW 20 /*Drag throw slow-down in [%] (must be > 0). Greater value means faster slow-down */ +#endif +#ifndef LV_INDEV_LONG_PRESS_TIME +#define LV_INDEV_LONG_PRESS_TIME 400 /*Long press time in milliseconds*/ +#endif +#ifndef LV_INDEV_LONG_PRESS_REP_TIME +#define LV_INDEV_LONG_PRESS_REP_TIME 100 /*Repeated trigger period in long press [ms] */ +#endif + +/*Color settings*/ +#ifndef LV_COLOR_DEPTH +#define LV_COLOR_DEPTH 16 /*Color depth: 1/8/16/32*/ +#endif +#ifndef LV_COLOR_16_SWAP +#define LV_COLOR_16_SWAP 0 /*Swap the 2 bytes of RGB565 color. Useful if the display has a 8 bit interface (e.g. SPI)*/ +#endif +#ifndef LV_COLOR_SCREEN_TRANSP +#define LV_COLOR_SCREEN_TRANSP 0 /*1: Enable screen transparency. Useful for OSD or other overlapping GUIs. Requires ARGB8888 colors*/ +#endif +#ifndef LV_COLOR_TRANSP +#define LV_COLOR_TRANSP LV_COLOR_LIME /*Images pixels with this color will not be drawn (with chroma keying)*/ +#endif + +/*Text settings*/ +#ifndef LV_TXT_UTF8 +#define LV_TXT_UTF8 1 /*Enable UTF-8 coded Unicode character usage */ +#endif +#ifndef LV_TXT_BREAK_CHARS +#define LV_TXT_BREAK_CHARS " ,.;:-_" /*Can break texts on these chars*/ +#endif +#ifndef LV_TXT_LINE_BREAK_LONG_LEN +#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever "prettiest" */ +#endif +#ifndef LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */ +#endif +#ifndef LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 /* Minimum number of characters of a word to put on a line after a break */ +#endif + +/*Feature usage*/ +#ifndef USE_LV_ANIMATION +#define USE_LV_ANIMATION 1 /*1: Enable all animations*/ +#endif +#ifndef USE_LV_SHADOW +#define USE_LV_SHADOW 1 /*1: Enable shadows*/ +#endif +#ifndef USE_LV_GROUP +#define USE_LV_GROUP 1 /*1: Enable object groups (for keyboards)*/ +#endif +#ifndef USE_LV_GPU +#define USE_LV_GPU 1 /*1: Enable GPU interface*/ +#endif +#ifndef USE_LV_REAL_DRAW +#define USE_LV_REAL_DRAW 1 /*1: Enable function which draw directly to the frame buffer instead of VDB (required if LV_VDB_SIZE = 0)*/ +#endif +#ifndef USE_LV_FILESYSTEM +#define USE_LV_FILESYSTEM 1 /*1: Enable file system (might be required for images*/ +#endif +#ifndef USE_LV_MULTI_LANG +#define USE_LV_MULTI_LANG 0 /* Number of languages for labels to store (0: to disable this feature)*/ +#endif + +/*Compiler settings*/ +#ifndef LV_ATTRIBUTE_TICK_INC +#define LV_ATTRIBUTE_TICK_INC /* Define a custom attribute to `lv_tick_inc` function */ +#endif +#ifndef LV_ATTRIBUTE_TASK_HANDLER +#define LV_ATTRIBUTE_TASK_HANDLER /* Define a custom attribute to `lv_task_handler` function */ +#endif +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN /* With size optimization (-Os) the compiler might not align data to 4 or 8 byte boundary. This alignment will be explicitly applied where needed.*/ +#endif +#ifndef LV_COMPILER_VLA_SUPPORTED +#define LV_COMPILER_VLA_SUPPORTED 1 /* 1: Variable length array is supported*/ +#endif +#ifndef LV_COMPILER_NON_CONST_INIT_SUPPORTED +#define LV_COMPILER_NON_CONST_INIT_SUPPORTED 1 /* 1: Initialization with non constant values are supported */ +#endif + +/*HAL settings*/ +#ifndef LV_TICK_CUSTOM +#define LV_TICK_CUSTOM 0 /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */ +#endif +#if LV_TICK_CUSTOM == 1 +#ifndef LV_TICK_CUSTOM_INCLUDE +#define LV_TICK_CUSTOM_INCLUDE "something.h" /*Header for the sys time function*/ +#endif +#ifndef LV_TICK_CUSTOM_SYS_TIME_EXPR +#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current systime in ms*/ +#endif +#endif /*LV_TICK_CUSTOM*/ + + +/*Log settings*/ +#ifndef USE_LV_LOG +#define USE_LV_LOG 1 /*Enable/disable the log module*/ +#endif +#if USE_LV_LOG +/* How important log should be added: + * LV_LOG_LEVEL_TRACE A lot of logs to give detailed information + * LV_LOG_LEVEL_INFO Log important events + * LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't caused problem + * LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail + */ +#ifndef LV_LOG_LEVEL +# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN +#endif +/* 1: Print the log with 'printf'; 0: user need to register a callback*/ + +#ifndef LV_LOG_PRINTF +# define LV_LOG_PRINTF 0 +#endif +#endif /*USE_LV_LOG*/ + +/*================ + * THEME USAGE + *================*/ +#ifndef LV_THEME_LIVE_UPDATE +#define LV_THEME_LIVE_UPDATE 1 /*1: Allow theme switching at run time. Uses 8..10 kB of RAM*/ +#endif + +#ifndef USE_LV_THEME_TEMPL +#define USE_LV_THEME_TEMPL 0 /*Just for test*/ +#endif +#ifndef USE_LV_THEME_DEFAULT +#define USE_LV_THEME_DEFAULT 1 /*Built mainly from the built-in styles. Consumes very few RAM*/ +#endif +#ifndef USE_LV_THEME_ALIEN +#define USE_LV_THEME_ALIEN 1 /*Dark futuristic theme*/ +#endif +#ifndef USE_LV_THEME_NIGHT +#define USE_LV_THEME_NIGHT 1 /*Dark elegant theme*/ +#endif +#ifndef USE_LV_THEME_MONO +#define USE_LV_THEME_MONO 1 /*Mono color theme for monochrome displays*/ +#endif +#ifndef USE_LV_THEME_MATERIAL +#define USE_LV_THEME_MATERIAL 1 /*Flat theme with bold colors and light shadows*/ +#endif +#ifndef USE_LV_THEME_ZEN +#define USE_LV_THEME_ZEN 1 /*Peaceful, mainly light theme */ +#endif +#ifndef USE_LV_THEME_NEMO +#define USE_LV_THEME_NEMO 1 /*Water-like theme based on the movie "Finding Nemo"*/ +#endif + +/*================== + * FONT USAGE + *===================*/ + +/* More info about fonts: https://docs.littlevgl.com/#Fonts + * To enable a built-in font use 1,2,4 or 8 values + * which will determine the bit-per-pixel. Higher value means smoother fonts */ +#ifndef USE_LV_FONT_DEJAVU_10 +#define USE_LV_FONT_DEJAVU_10 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_10_LATIN_SUP +#define USE_LV_FONT_DEJAVU_10_LATIN_SUP 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_10_CYRILLIC +#define USE_LV_FONT_DEJAVU_10_CYRILLIC 4 +#endif +#ifndef USE_LV_FONT_SYMBOL_10 +#define USE_LV_FONT_SYMBOL_10 4 +#endif + +#ifndef USE_LV_FONT_DEJAVU_20 +#define USE_LV_FONT_DEJAVU_20 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_20_LATIN_SUP +#define USE_LV_FONT_DEJAVU_20_LATIN_SUP 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_20_CYRILLIC +#define USE_LV_FONT_DEJAVU_20_CYRILLIC 4 +#endif +#ifndef USE_LV_FONT_SYMBOL_20 +#define USE_LV_FONT_SYMBOL_20 4 +#endif + +#ifndef USE_LV_FONT_DEJAVU_30 +#define USE_LV_FONT_DEJAVU_30 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_30_LATIN_SUP +#define USE_LV_FONT_DEJAVU_30_LATIN_SUP 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_30_CYRILLIC +#define USE_LV_FONT_DEJAVU_30_CYRILLIC 4 +#endif +#ifndef USE_LV_FONT_SYMBOL_30 +#define USE_LV_FONT_SYMBOL_30 4 +#endif + +#ifndef USE_LV_FONT_DEJAVU_40 +#define USE_LV_FONT_DEJAVU_40 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_40_LATIN_SUP +#define USE_LV_FONT_DEJAVU_40_LATIN_SUP 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_40_CYRILLIC +#define USE_LV_FONT_DEJAVU_40_CYRILLIC 4 +#endif +#ifndef USE_LV_FONT_SYMBOL_40 +#define USE_LV_FONT_SYMBOL_40 4 +#endif + +#ifndef USE_LV_FONT_MONOSPACE_8 +#define USE_LV_FONT_MONOSPACE_8 1 +#endif + +/* Optionally declare your custom fonts here. + * You can use these fonts as default font too + * and they will be available globally. E.g. + * #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) \ + * LV_FONT_DECLARE(my_font_2) \ + */ +#ifndef LV_FONT_CUSTOM_DECLARE +#define LV_FONT_CUSTOM_DECLARE +#endif + + +#ifndef LV_FONT_DEFAULT +#define LV_FONT_DEFAULT &lv_font_dejavu_20 /*Always set a default font from the built-in fonts*/ +#endif + +/*=================== + * LV_OBJ SETTINGS + *==================*/ +#ifndef LV_OBJ_FREE_NUM_TYPE +#define LV_OBJ_FREE_NUM_TYPE uint32_t /*Type of free number attribute (comment out disable free number)*/ +#endif +#ifndef LV_OBJ_FREE_PTR +#define LV_OBJ_FREE_PTR 1 /*Enable the free pointer attribute*/ +#endif +#ifndef LV_OBJ_REALIGN +#define LV_OBJ_REALIGN 1 /*Enable `lv_obj_realaign()` based on `lv_obj_align()` parameters*/ +#endif + +/*================== + * LV OBJ X USAGE + *================*/ +/* + * Documentation of the object types: https://docs.littlevgl.com/#Object-types + */ + +/***************** + * Simple object + *****************/ + +/*Label (dependencies: -*/ +#ifndef USE_LV_LABEL +#define USE_LV_LABEL 1 +#endif +#if USE_LV_LABEL != 0 +#ifndef LV_LABEL_SCROLL_SPEED +# define LV_LABEL_SCROLL_SPEED 25 /*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_SCROLL/ROLL' mode*/ +#endif +#endif + +/*Image (dependencies: lv_label*/ +#ifndef USE_LV_IMG +#define USE_LV_IMG 1 +#endif +#if USE_LV_IMG != 0 +#ifndef LV_IMG_CF_INDEXED +# define LV_IMG_CF_INDEXED 1 /*Enable indexed (palette) images*/ +#endif +#ifndef LV_IMG_CF_ALPHA +# define LV_IMG_CF_ALPHA 1 /*Enable alpha indexed images*/ +#endif +#endif + +/*Line (dependencies: -*/ +#ifndef USE_LV_LINE +#define USE_LV_LINE 1 +#endif + +/*Arc (dependencies: -)*/ +#ifndef USE_LV_ARC +#define USE_LV_ARC 1 +#endif + +/******************* + * Container objects + *******************/ + +/*Container (dependencies: -*/ +#ifndef USE_LV_CONT +#define USE_LV_CONT 1 +#endif + +/*Page (dependencies: lv_cont)*/ +#ifndef USE_LV_PAGE +#define USE_LV_PAGE 1 +#endif + +/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/ +#ifndef USE_LV_WIN +#define USE_LV_WIN 1 +#endif + +/*Tab (dependencies: lv_page, lv_btnm)*/ +#ifndef USE_LV_TABVIEW +#define USE_LV_TABVIEW 1 +#endif +# if USE_LV_TABVIEW != 0 +#ifndef LV_TABVIEW_ANIM_TIME +# define LV_TABVIEW_ANIM_TIME 300 /*Time of slide animation [ms] (0: no animation)*/ +#endif +#endif + +/*Tileview (dependencies: lv_page) */ +#ifndef USE_LV_TILEVIEW +#define USE_LV_TILEVIEW 1 +#endif +#if USE_LV_TILEVIEW +#ifndef LV_TILEVIEW_ANIM_TIME +# define LV_TILEVIEW_ANIM_TIME 300 /*Time of slide animation [ms] (0: no animation)*/ +#endif +#endif + +/************************* + * Data visualizer objects + *************************/ + +/*Bar (dependencies: -)*/ +#ifndef USE_LV_BAR +#define USE_LV_BAR 1 +#endif + +/*Line meter (dependencies: *;)*/ +#ifndef USE_LV_LMETER +#define USE_LV_LMETER 1 +#endif + +/*Gauge (dependencies:lv_bar, lv_lmeter)*/ +#ifndef USE_LV_GAUGE +#define USE_LV_GAUGE 1 +#endif + +/*Chart (dependencies: -)*/ +#ifndef USE_LV_CHART +#define USE_LV_CHART 1 +#endif + +/*Table (dependencies: lv_label)*/ +#ifndef USE_LV_TABLE +#define USE_LV_TABLE 1 +#endif +#if USE_LV_TABLE +#ifndef LV_TABLE_COL_MAX +# define LV_TABLE_COL_MAX 12 +#endif +#endif + +/*LED (dependencies: -)*/ +#ifndef USE_LV_LED +#define USE_LV_LED 1 +#endif + +/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ +#ifndef USE_LV_MBOX +#define USE_LV_MBOX 1 +#endif + +/*Text area (dependencies: lv_label, lv_page)*/ +#ifndef USE_LV_TA +#define USE_LV_TA 1 +#endif +#if USE_LV_TA != 0 +#ifndef LV_TA_CURSOR_BLINK_TIME +# define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/ +#endif +#ifndef LV_TA_PWD_SHOW_TIME +# define LV_TA_PWD_SHOW_TIME 1500 /*ms*/ +#endif +#endif + +/*Spinbox (dependencies: lv_ta)*/ +#ifndef USE_LV_SPINBOX +#define USE_LV_SPINBOX 1 +#endif + +/*Calendar (dependencies: -)*/ +#ifndef USE_LV_CALENDAR +#define USE_LV_CALENDAR 1 +#endif + +/*Preload (dependencies: lv_arc)*/ +#ifndef USE_LV_PRELOAD +#define USE_LV_PRELOAD 1 +#endif +#if USE_LV_PRELOAD != 0 +#ifndef LV_PRELOAD_DEF_ARC_LENGTH +# define LV_PRELOAD_DEF_ARC_LENGTH 60 /*[deg]*/ +#endif +#ifndef LV_PRELOAD_DEF_SPIN_TIME +# define LV_PRELOAD_DEF_SPIN_TIME 1000 /*[ms]*/ +#endif +#ifndef LV_PRELOAD_DEF_ANIM +# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC +#endif +#endif + +/*Canvas (dependencies: lv_img)*/ +#ifndef USE_LV_CANVAS +#define USE_LV_CANVAS 1 +#endif +/************************* + * User input objects + *************************/ + +/*Button (dependencies: lv_cont*/ +#ifndef USE_LV_BTN +#define USE_LV_BTN 1 +#endif +#if USE_LV_BTN != 0 +#ifndef LV_BTN_INK_EFFECT +# define LV_BTN_INK_EFFECT 1 /*Enable button-state animations - draw a circle on click (dependencies: USE_LV_ANIMATION)*/ +#endif +#endif + +/*Image Button (dependencies: lv_btn*/ +#ifndef USE_LV_IMGBTN +#define USE_LV_IMGBTN 1 +#endif +#if USE_LV_IMGBTN +#ifndef LV_IMGBTN_TILED +# define LV_IMGBTN_TILED 0 /*1: The imgbtn requires left, mid and right parts and the width can be set freely*/ +#endif +#endif + +/*Button matrix (dependencies: -)*/ +#ifndef USE_LV_BTNM +#define USE_LV_BTNM 1 +#endif + +/*Keyboard (dependencies: lv_btnm)*/ +#ifndef USE_LV_KB +#define USE_LV_KB 1 +#endif + +/*Check box (dependencies: lv_btn, lv_label)*/ +#ifndef USE_LV_CB +#define USE_LV_CB 1 +#endif + +/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/ +#ifndef USE_LV_LIST +#define USE_LV_LIST 1 +#endif +#if USE_LV_LIST != 0 +#ifndef LV_LIST_FOCUS_TIME +# define LV_LIST_FOCUS_TIME 100 /*Default animation time of focusing to a list element [ms] (0: no animation) */ +#endif +#endif + +/*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/ +#ifndef USE_LV_DDLIST +#define USE_LV_DDLIST 1 +#endif +#if USE_LV_DDLIST != 0 +#ifndef LV_DDLIST_ANIM_TIME +# define LV_DDLIST_ANIM_TIME 200 /*Open and close default animation time [ms] (0: no animation)*/ +#endif +#endif + +/*Roller (dependencies: lv_ddlist)*/ +#ifndef USE_LV_ROLLER +#define USE_LV_ROLLER 1 +#endif +#if USE_LV_ROLLER != 0 +#ifndef LV_ROLLER_ANIM_TIME +# define LV_ROLLER_ANIM_TIME 200 /*Focus animation time [ms] (0: no animation)*/ +#endif +#endif + +/*Slider (dependencies: lv_bar)*/ +#ifndef USE_LV_SLIDER +#define USE_LV_SLIDER 1 +#endif + +/*Switch (dependencies: lv_slider)*/ +#ifndef USE_LV_SW +#define USE_LV_SW 1 +#endif + +/************************* + * Non-user section + *************************/ + +#if LV_INDEV_DRAG_THROW <= 0 +#warning "LV_INDEV_DRAG_THROW must be greater than 0" +#undef LV_INDEV_DRAG_THROW +#ifndef LV_INDEV_DRAG_THROW +#define LV_INDEV_DRAG_THROW 1 +#endif +#endif + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) /* Disable warnings for Visual Studio*/ +#ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS +#endif +#endif + + +#endif /*LV_CONF_CHECKER_H*/ diff --git a/pros/display/lv_core/lv_core.mk b/pros/display/lv_core/lv_core.mk new file mode 100644 index 00000000..9992e3fe --- /dev/null +++ b/pros/display/lv_core/lv_core.mk @@ -0,0 +1,12 @@ +CSRCS += lv_group.c +CSRCS += lv_indev.c +CSRCS += lv_obj.c +CSRCS += lv_refr.c +CSRCS += lv_style.c +CSRCS += lv_vdb.c +CSRCS += lv_lang.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_core +VPATH += :$(LVGL_DIR)/lvgl/lv_core + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_core" diff --git a/pros/display/lv_core/lv_group.h b/pros/display/lv_core/lv_group.h new file mode 100644 index 00000000..4fb6043b --- /dev/null +++ b/pros/display/lv_core/lv_group.h @@ -0,0 +1,247 @@ +/** + * @file lv_group.h + * + */ + +#ifndef LV_GROUP_H +#define LV_GROUP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include "lv_obj.h" + +/********************* + * DEFINES + *********************/ +/*Predefined keys to control the focused object via lv_group_send(group, c)*/ +/*For compatibility in signal function define the keys regardless to LV_GROUP*/ +#define LV_GROUP_KEY_UP 17 /*0x11*/ +#define LV_GROUP_KEY_DOWN 18 /*0x12*/ +#define LV_GROUP_KEY_RIGHT 19 /*0x13*/ +#define LV_GROUP_KEY_LEFT 20 /*0x14*/ +#define LV_GROUP_KEY_ESC 27 /*0x1B*/ +#define LV_GROUP_KEY_DEL 127 /*0x7F*/ +#define LV_GROUP_KEY_BACKSPACE 8 /*0x08*/ +#define LV_GROUP_KEY_ENTER 10 /*0x0A, '\n'*/ +#define LV_GROUP_KEY_NEXT 9 /*0x09, '\t'*/ +#define LV_GROUP_KEY_PREV 11 /*0x0B, '*/ + +#if USE_LV_GROUP != 0 +/********************** + * TYPEDEFS + **********************/ +struct _lv_group_t; + +typedef void (*lv_group_style_mod_func_t)(lv_style_t *); +typedef void (*lv_group_focus_cb_t)(struct _lv_group_t *); + +typedef struct _lv_group_t +{ + lv_ll_t obj_ll; /*Linked list to store the objects in the group */ + lv_obj_t ** obj_focus; /*The object in focus*/ + lv_group_style_mod_func_t style_mod; /*A function which modifies the style of the focused object*/ + lv_group_style_mod_func_t style_mod_edit;/*A function which modifies the style of the focused object*/ + lv_group_focus_cb_t focus_cb; /*A function to call when a new object is focused (optional)*/ + lv_style_t style_tmp; /*Stores the modified style of the focused object */ + uint8_t frozen :1; /*1: can't focus to new object*/ + uint8_t editing :1; /*1: Edit mode, 0: Navigate mode*/ + uint8_t click_focus :1; /*1: If an object in a group is clicked by an indev then it will be focused */ + uint8_t refocus_policy :1; /*1: Focus prev if focused on deletion. 0: Focus prev if focused on deletion.*/ + uint8_t wrap :1; /*1: Focus next/prev can wrap at end of list. 0: Focus next/prev stops at end of list.*/ +} lv_group_t; + +typedef enum _lv_group_refocus_policy_t { + LV_GROUP_REFOCUS_POLICY_NEXT = 0, + LV_GROUP_REFOCUS_POLICY_PREV = 1 +} lv_group_refocus_policy_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a new object group + * @return pointer to the new object group + */ +lv_group_t * lv_group_create(void); + +/** + * Delete a group object + * @param group pointer to a group + */ +void lv_group_del(lv_group_t * group); + +/** + * Add an object to a group + * @param group pointer to a group + * @param obj pointer to an object to add + */ +void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj); + +/** + * Remove an object from its group + * @param obj pointer to an object to remove + */ +void lv_group_remove_obj(lv_obj_t * obj); + +/** + * Focus on an object (defocus the current) + * @param obj pointer to an object to focus on + */ +void lv_group_focus_obj(lv_obj_t * obj); + +/** + * Focus the next object in a group (defocus the current) + * @param group pointer to a group + */ +void lv_group_focus_next(lv_group_t * group); + +/** + * Focus the previous object in a group (defocus the current) + * @param group pointer to a group + */ +void lv_group_focus_prev(lv_group_t * group); + +/** + * Do not let to change the focus from the current object + * @param group pointer to a group + * @param en true: freeze, false: release freezing (normal mode) + */ +void lv_group_focus_freeze(lv_group_t * group, bool en); + +/** + * Send a control character to the focuses object of a group + * @param group pointer to a group + * @param c a character (use LV_GROUP_KEY_.. to navigate) + * @return result of focused object in group. + */ +lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c); + +/** + * Set a function for a group which will modify the object's style if it is in focus + * @param group pointer to a group + * @param style_mod_func the style modifier function pointer + */ +void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func); + +/** + * Set a function for a group which will modify the object's style if it is in focus in edit mode + * @param group pointer to a group + * @param style_mod_func the style modifier function pointer + */ +void lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func); + +/** + * Set a function for a group which will be called when a new object is focused + * @param group pointer to a group + * @param focus_cb the call back function or NULL if unused + */ +void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb); + +/** + * Set whether the next or previous item in a group is focused if the currently focussed obj is deleted. + * @param group pointer to a group + * @param new refocus policy enum + */ +void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy); + +/** + * Manually set the current mode (edit or navigate). + * @param group pointer to group + * @param edit: true: edit mode; false: navigate mode + */ +void lv_group_set_editing(lv_group_t * group, bool edit); + +/** + * Set the `click_focus` attribute. If enabled then the object will be focused then it is clicked. + * @param group pointer to group + * @param en: true: enable `click_focus` + */ +void lv_group_set_click_focus(lv_group_t * group, bool en); + +/** + * Set whether focus next/prev will allow wrapping from first->last or last->first object. + * @param group pointer to group + * @param en: true: wrapping enabled; false: wrapping disabled + */ +void lv_group_set_wrap(lv_group_t * group, bool en); + +/** + * Modify a style with the set 'style_mod' function. The input style remains unchanged. + * @param group pointer to group + * @param style pointer to a style to modify + * @return a copy of the input style but modified with the 'style_mod' function + */ +lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style); + +/** + * Get the focused object or NULL if there isn't one + * @param group pointer to a group + * @return pointer to the focused object + */ +lv_obj_t * lv_group_get_focused(const lv_group_t * group); + +/** + * Get a the style modifier function of a group + * @param group pointer to a group + * @return pointer to the style modifier function + */ +lv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group); + +/** + * Get a the style modifier function of a group in edit mode + * @param group pointer to a group + * @return pointer to the style modifier function + */ +lv_group_style_mod_func_t lv_group_get_style_mod_edit_cb(const lv_group_t * group); + +/** + * Get the focus callback function of a group + * @param group pointer to a group + * @return the call back function or NULL if not set + */ +lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group); + +/** + * Get the current mode (edit or navigate). + * @param group pointer to group + * @return true: edit mode; false: navigate mode + */ +bool lv_group_get_editing(const lv_group_t * group); + +/** + * Get the `click_focus` attribute. + * @param group pointer to group + * @return true: `click_focus` is enabled; false: disabled + */ +bool lv_group_get_click_focus(const lv_group_t * group); + +/** + * Get whether focus next/prev will allow wrapping from first->last or last->first object. + * @param group pointer to group + * @param en: true: wrapping enabled; false: wrapping disabled + */ +bool lv_group_get_wrap(lv_group_t * group); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_GROUP != 0*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GROUP_H*/ diff --git a/pros/display/lv_core/lv_indev.h b/pros/display/lv_core/lv_indev.h new file mode 100644 index 00000000..b066246b --- /dev/null +++ b/pros/display/lv_core/lv_indev.h @@ -0,0 +1,157 @@ +/** + * @file lv_indev_proc.h + * + */ + +#ifndef LV_INDEV_H +#define LV_INDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" +#include "display/lv_hal/lv_hal_indev.h" +#include "display/lv_core/lv_group.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the display input device subsystem + */ +void lv_indev_init(void); + +/** + * Get the currently processed input device. Can be used in action functions too. + * @return pointer to the currently processed input device or NULL if no input device processing right now + */ +lv_indev_t * lv_indev_get_act(void); + + +/** + * Get the type of an input device + * @param indev pointer to an input device + * @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`) + */ +lv_hal_indev_type_t lv_indev_get_type(const lv_indev_t * indev); + +/** + * Reset one or all input devices + * @param indev pointer to an input device to reset or NULL to reset all of them + */ +void lv_indev_reset(lv_indev_t * indev); + +/** + * Reset the long press state of an input device + * @param indev_proc pointer to an input device + */ +void lv_indev_reset_lpr(lv_indev_t * indev); + +/** + * Enable input devices device by type + * @param type Input device type + * @param enable true: enable this type; false: disable this type + */ +void lv_indev_enable(lv_hal_indev_type_t type, bool enable); + +/** + * Set a cursor for a pointer input device (for LV_INPUT_TYPE_POINTER and LV_INPUT_TYPE_BUTTON) + * @param indev pointer to an input device + * @param cur_obj pointer to an object to be used as cursor + */ +void lv_indev_set_cursor(lv_indev_t *indev, lv_obj_t *cur_obj); + +#if USE_LV_GROUP +/** + * Set a destination group for a keypad input device (for LV_INDEV_TYPE_KEYPAD) + * @param indev pointer to an input device + * @param group point to a group + */ +void lv_indev_set_group(lv_indev_t *indev, lv_group_t *group); +#endif + +/** + * Set the an array of points for LV_INDEV_TYPE_BUTTON. + * These points will be assigned to the buttons to press a specific point on the screen + * @param indev pointer to an input device + * @param group point to a group + */ +void lv_indev_set_button_points(lv_indev_t *indev, const lv_point_t *points); + +/** + * Set feedback callback for indev. + * @param indev pointer to an input device + * @param feedback feedback callback + */ +void lv_indev_set_feedback(lv_indev_t *indev, lv_indev_feedback_t feedback); + +/** + * Get the last point of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @param point pointer to a point to store the result + */ +void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point); + +/** + * Get the last key of an input device (for LV_INDEV_TYPE_KEYPAD) + * @param indev pointer to an input device + * @return the last pressed key (0 on error) + */ +uint32_t lv_indev_get_key(const lv_indev_t * indev); + +/** + * Check if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @return true: drag is in progress + */ +bool lv_indev_is_dragging(const lv_indev_t * indev); + +/** + * Get the vector of dragging of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @param point pointer to a point to store the vector + */ +void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point); +/** + * Get elapsed time since last press + * @param indev pointer to an input device (NULL to get the overall smallest inactivity) + * @return Elapsed ticks (milliseconds) since last press + */ +uint32_t lv_indev_get_inactive_time(const lv_indev_t * indev); + +/** + * Get feedback callback for indev. + * @param indev pointer to an input device + * @return feedback callback + */ +lv_indev_feedback_t lv_indev_get_feedback(const lv_indev_t *indev); + +/** + * Do nothing until the next release + * @param indev pointer to an input device + */ +void lv_indev_wait_release(lv_indev_t * indev); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_INDEV_H*/ diff --git a/pros/display/lv_core/lv_lang.h b/pros/display/lv_core/lv_lang.h new file mode 100644 index 00000000..efbdd0a8 --- /dev/null +++ b/pros/display/lv_core/lv_lang.h @@ -0,0 +1,74 @@ +/** + * @file lv_lang.h + * + */ + +#ifndef LV_LANG_H +#define LV_LANG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_MULTI_LANG + +#include + +/********************* + * DEFINES + *********************/ +#define LV_LANG_TXT_ID_NONE 0xFFFF /*Used to not assign any text IDs for a multi-language object.*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Change the language + * @param lang_id the id of the + */ +void lv_lang_set(uint8_t lang_id); + +/** + * Set a function to get the texts of the set languages from a `txt_id` + * @param fp a function pointer to get the texts + */ +void lv_lang_set_text_func(const void * (*fp)(uint16_t)); + +/** + * Use the function set by `lv_lang_set_text_func` to get the `txt_id` text in the set language + * @param txt_id an ID of the text to get + * @return the `txt_id` txt on the set language + */ +const void * lv_lang_get_text(uint16_t txt_id); + +/** + * Return with ID of the currently selected language + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +uint8_t lv_lang_act(void); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_MULTI_LANG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LANG_H*/ diff --git a/pros/display/lv_core/lv_obj.h b/pros/display/lv_core/lv_obj.h new file mode 100644 index 00000000..02378a51 --- /dev/null +++ b/pros/display/lv_core/lv_obj.h @@ -0,0 +1,841 @@ +/** + * @file lv_obj.h + * + */ + +#ifndef LV_OBJ_H +#define LV_OBJ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include +#include "lv_style.h" +#include "display/lv_misc/lv_area.h" +#include "display/lv_misc/lv_mem.h" +#include "display/lv_misc/lv_ll.h" +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_log.h" + +/********************* + * DEFINES + *********************/ + +/*Error check of lv_conf.h*/ +#if LV_HOR_RES == 0 || LV_VER_RES == 0 +#error "LittlevGL: LV_HOR_RES and LV_VER_RES must be greater than 0" +#endif + +#if LV_ANTIALIAS > 1 +#error "LittlevGL: LV_ANTIALIAS can be only 0 or 1" +#endif + +#if LV_VDB_SIZE == 0 && LV_ANTIALIAS != 0 +#error "LittlevGL: If LV_VDB_SIZE == 0 the anti-aliasing must be disabled" +#endif + +#if LV_VDB_SIZE > 0 && LV_VDB_SIZE < LV_HOR_RES +#error "LittlevGL: Small Virtual Display Buffer (lv_conf.h: LV_VDB_SIZE >= LV_HOR_RES)" +#endif + +#if LV_VDB_SIZE == 0 && USE_LV_REAL_DRAW == 0 +#error "LittlevGL: If LV_VDB_SIZE = 0 Real drawing function are required (lv_conf.h: USE_LV_REAL_DRAW 1)" +#endif + + +#define LV_ANIM_IN 0x00 /*Animation to show an object. 'OR' it with lv_anim_builtin_t*/ +#define LV_ANIM_OUT 0x80 /*Animation to hide an object. 'OR' it with lv_anim_builtin_t*/ +#define LV_ANIM_DIR_MASK 0x80 /*ANIM_IN/ANIM_OUT mask*/ + +#define LV_MAX_ANCESTOR_NUM 8 + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_obj_t; + +enum +{ + LV_DESIGN_DRAW_MAIN, + LV_DESIGN_DRAW_POST, + LV_DESIGN_COVER_CHK, +}; +typedef uint8_t lv_design_mode_t; + +typedef bool (* lv_design_func_t) (struct _lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode); + +enum +{ + LV_RES_INV = 0, /*Typically indicates that the object is deleted (become invalid) in the action function or an operation was failed*/ + LV_RES_OK, /*The object is valid (no deleted) after the action*/ +}; +typedef uint8_t lv_res_t; + +enum +{ + /*General signals*/ + LV_SIGNAL_CLEANUP, + LV_SIGNAL_CHILD_CHG, + LV_SIGNAL_CORD_CHG, + LV_SIGNAL_STYLE_CHG, + LV_SIGNAL_REFR_EXT_SIZE, + LV_SIGNAL_LANG_CHG, + LV_SIGNAL_GET_TYPE, + + _LV_SIGNAL_FEEDBACK_SECTION_START, + /*Input device related*/ + LV_SIGNAL_PRESSED, + LV_SIGNAL_PRESSING, + LV_SIGNAL_PRESS_LOST, + LV_SIGNAL_RELEASED, + LV_SIGNAL_LONG_PRESS, + LV_SIGNAL_LONG_PRESS_REP, + LV_SIGNAL_DRAG_BEGIN, + LV_SIGNAL_DRAG_END, + + /*Group related*/ + LV_SIGNAL_FOCUS, + LV_SIGNAL_DEFOCUS, + LV_SIGNAL_CONTROLL, + _LV_SIGNAL_FEEDBACK_SECTION_END, + LV_SIGNAL_GET_EDITABLE, +}; +typedef uint8_t lv_signal_t; + +typedef lv_res_t (* lv_signal_func_t) (struct _lv_obj_t * obj, lv_signal_t sign, void * param); + +enum +{ + LV_ALIGN_CENTER = 0, + LV_ALIGN_IN_TOP_LEFT, + LV_ALIGN_IN_TOP_MID, + LV_ALIGN_IN_TOP_RIGHT, + LV_ALIGN_IN_BOTTOM_LEFT, + LV_ALIGN_IN_BOTTOM_MID, + LV_ALIGN_IN_BOTTOM_RIGHT, + LV_ALIGN_IN_LEFT_MID, + LV_ALIGN_IN_RIGHT_MID, + LV_ALIGN_OUT_TOP_LEFT, + LV_ALIGN_OUT_TOP_MID, + LV_ALIGN_OUT_TOP_RIGHT, + LV_ALIGN_OUT_BOTTOM_LEFT, + LV_ALIGN_OUT_BOTTOM_MID, + LV_ALIGN_OUT_BOTTOM_RIGHT, + LV_ALIGN_OUT_LEFT_TOP, + LV_ALIGN_OUT_LEFT_MID, + LV_ALIGN_OUT_LEFT_BOTTOM, + LV_ALIGN_OUT_RIGHT_TOP, + LV_ALIGN_OUT_RIGHT_MID, + LV_ALIGN_OUT_RIGHT_BOTTOM, +}; +typedef uint8_t lv_align_t; + +#if LV_OBJ_REALIGN +typedef struct { + const struct _lv_obj_t * base; + lv_coord_t xofs; + lv_coord_t yofs; + lv_align_t align; + uint8_t auto_realign :1; + uint8_t origo_align :1; /*1: the oigo (center of the object) was aligned with `lv_obj_align_origo`*/ +}lv_reailgn_t; +#endif + + +typedef struct _lv_obj_t +{ + struct _lv_obj_t * par; /*Pointer to the parent object*/ + lv_ll_t child_ll; /*Linked list to store the children objects*/ + + lv_area_t coords; /*Coordinates of the object (x1, y1, x2, y2)*/ + + lv_signal_func_t signal_func; /*Object type specific signal function*/ + lv_design_func_t design_func; /*Object type specific design function*/ + + void * ext_attr; /*Object type specific extended data*/ + lv_style_t * style_p; /*Pointer to the object's style*/ + +#if LV_OBJ_FREE_PTR != 0 + void * free_ptr; /*Application specific pointer (set it freely)*/ +#endif + +#if USE_LV_GROUP != 0 + void * group_p; /*Pointer to the group of the object*/ +#endif + /*Attributes and states*/ + uint8_t click :1; /*1: Can be pressed by an input device*/ + uint8_t drag :1; /*1: Enable the dragging*/ + uint8_t drag_throw :1; /*1: Enable throwing with drag*/ + uint8_t drag_parent :1; /*1: Parent will be dragged instead*/ + uint8_t hidden :1; /*1: Object is hidden*/ + uint8_t top :1; /*1: If the object or its children is clicked it goes to the foreground*/ + uint8_t opa_scale_en :1; /*1: opa_scale is set*/ + uint8_t protect; /*Automatically happening actions can be prevented. 'OR'ed values from `lv_protect_t`*/ + lv_opa_t opa_scale; /*Scale down the opacity by this factor. Effects all children as well*/ + + lv_coord_t ext_size; /*EXTtend the size of the object in every direction. E.g. for shadow drawing*/ +#if LV_OBJ_REALIGN + lv_reailgn_t realign; +#endif + +#ifdef LV_OBJ_FREE_NUM_TYPE + LV_OBJ_FREE_NUM_TYPE free_num; /*Application specific identifier (set it freely)*/ +#endif +} lv_obj_t; + +typedef lv_res_t (*lv_action_t) (struct _lv_obj_t * obj); + +/*Protect some attributes (max. 8 bit)*/ +enum +{ + LV_PROTECT_NONE = 0x00, + LV_PROTECT_CHILD_CHG = 0x01, /*Disable the child change signal. Used by the library*/ + LV_PROTECT_PARENT = 0x02, /*Prevent automatic parent change (e.g. in lv_page)*/ + LV_PROTECT_POS = 0x04, /*Prevent automatic positioning (e.g. in lv_cont layout)*/ + LV_PROTECT_FOLLOW = 0x08, /*Prevent the object be followed in automatic ordering (e.g. in lv_cont PRETTY layout)*/ + LV_PROTECT_PRESS_LOST= 0x10, /*If the `indev` was pressing this object but swiped out while pressing do not search other object.*/ + LV_PROTECT_CLICK_FOCUS= 0x20,/*Prevent focusing the object by clicking on it*/ +}; +typedef uint8_t lv_protect_t; + + +/*Used by `lv_obj_get_type()`. The object's and its ancestor types are stored here*/ +typedef struct { + const char * type[LV_MAX_ANCESTOR_NUM]; /*[0]: the actual type, [1]: ancestor, [2] #1's ancestor ... [x]: "lv_obj" */ +} lv_obj_type_t; + +enum +{ + LV_ANIM_NONE = 0, + LV_ANIM_FLOAT_TOP, /*Float from/to the top*/ + LV_ANIM_FLOAT_LEFT, /*Float from/to the left*/ + LV_ANIM_FLOAT_BOTTOM, /*Float from/to the bottom*/ + LV_ANIM_FLOAT_RIGHT, /*Float from/to the right*/ + LV_ANIM_GROW_H, /*Grow/shrink horizontally*/ + LV_ANIM_GROW_V, /*Grow/shrink vertically*/ +}; +typedef uint8_t lv_anim_builtin_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init. the 'lv' library. + */ +void lv_init(void); + +/*-------------------- + * Create and delete + *-------------------*/ + +/** + * Create a basic object + * @param parent pointer to a parent object. + * If NULL then a screen will be created + * @param copy pointer to a base object, if not NULL then the new object will be copied from it + * @return pointer to the new object + */ +lv_obj_t * lv_obj_create(lv_obj_t * parent,const lv_obj_t * copy); + +/** + * Delete 'obj' and all of its children + * @param obj pointer to an object to delete + * @return LV_RES_INV because the object is deleted + */ +lv_res_t lv_obj_del(lv_obj_t * obj); + +/** + * Delete all children of an object + * @param obj pointer to an object + */ +void lv_obj_clean(lv_obj_t *obj); + +/** + * Mark the object as invalid therefore its current position will be redrawn by 'lv_refr_task' + * @param obj pointer to an object + */ +void lv_obj_invalidate(const lv_obj_t * obj); + +/*===================== + * Setter functions + *====================*/ + +/*-------------- + * Screen set + *--------------*/ + +/** + * Load a new screen + * @param scr pointer to a screen + */ +void lv_scr_load(lv_obj_t * scr); + +/*-------------------- + * Parent/children set + *--------------------*/ + +/** + * Set a new parent for an object. Its relative position will be the same. + * @param obj pointer to an object. Can't be a screen. + * @param parent pointer to the new parent object. (Can't be NULL) + */ +void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent); + +/*-------------------- + * Coordinate set + * ------------------*/ + +/** + * Set relative the position of an object (relative to the parent) + * @param obj pointer to an object + * @param x new distance from the left side of the parent + * @param y new distance from the top of the parent + */ +void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y); + +/** + * Set the x coordinate of a object + * @param obj pointer to an object + * @param x new distance from the left side from the parent + */ +void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x); + +/** + * Set the y coordinate of a object + * @param obj pointer to an object + * @param y new distance from the top of the parent + */ +void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y); + +/** + * Set the size of an object + * @param obj pointer to an object + * @param w new width + * @param h new height + */ +void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h); + +/** + * Set the width of an object + * @param obj pointer to an object + * @param w new width + */ +void lv_obj_set_width(lv_obj_t * obj, lv_coord_t w); + +/** + * Set the height of an object + * @param obj pointer to an object + * @param h new height + */ +void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h); + +/** + * Align an object to an other object. + * @param obj pointer to an object to align + * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. + * @param align type of alignment (see 'lv_align_t' enum) + * @param x_mod x coordinate shift after alignment + * @param y_mod y coordinate shift after alignment + */ +void lv_obj_align(lv_obj_t * obj,const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod); + +/** + * Align an object to an other object. + * @param obj pointer to an object to align + * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. + * @param align type of alignment (see 'lv_align_t' enum) + * @param x_mod x coordinate shift after alignment + * @param y_mod y coordinate shift after alignment + */ +void lv_obj_align_origo(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod); + +/** + * Realign the object based on the last `lv_obj_align` parameters. + * @param obj pointer to an object + */ +void lv_obj_realign(lv_obj_t * obj); + +/** + * Enable the automatic realign of the object when its size has changed based on the last `lv_obj_align` parameters. + * @param obj pointer to an object + * @param en true: enable auto realign; false: disable auto realign + */ +void lv_obj_set_auto_realign(lv_obj_t * obj, bool en); + +/*--------------------- + * Appearance set + *--------------------*/ + +/** + * Set a new style for an object + * @param obj pointer to an object + * @param style_p pointer to the new style + */ +void lv_obj_set_style(lv_obj_t * obj, lv_style_t * style); + +/** + * Notify an object about its style is modified + * @param obj pointer to an object + */ +void lv_obj_refresh_style(lv_obj_t * obj); + +/** + * Notify all object if a style is modified + * @param style pointer to a style. Only the objects with this style will be notified + * (NULL to notify all objects) + */ +void lv_obj_report_style_mod(lv_style_t * style); + +/*----------------- + * Attribute set + *----------------*/ + +/** + * Hide an object. It won't be visible and clickable. + * @param obj pointer to an object + * @param en true: hide the object + */ +void lv_obj_set_hidden(lv_obj_t * obj, bool en); + +/** + * Enable or disable the clicking of an object + * @param obj pointer to an object + * @param en true: make the object clickable + */ +void lv_obj_set_click(lv_obj_t * obj, bool en); + +/** + * Enable to bring this object to the foreground if it + * or any of its children is clicked + * @param obj pointer to an object + * @param en true: enable the auto top feature + */ +void lv_obj_set_top(lv_obj_t * obj, bool en); + +/** + * Enable the dragging of an object + * @param obj pointer to an object + * @param en true: make the object dragable + */ +void lv_obj_set_drag(lv_obj_t * obj, bool en); + +/** + * Enable the throwing of an object after is is dragged + * @param obj pointer to an object + * @param en true: enable the drag throw + */ +void lv_obj_set_drag_throw(lv_obj_t * obj, bool en); + +/** + * Enable to use parent for drag related operations. + * If trying to drag the object the parent will be moved instead + * @param obj pointer to an object + * @param en true: enable the 'drag parent' for the object + */ +void lv_obj_set_drag_parent(lv_obj_t * obj, bool en); + +/** + * Set editable parameter Used by groups and keyboard/encoder control. + * Editable object has something inside to choose (the elements of a list) + * @param obj pointer to an object + * @param en true: enable editing + */ +//void lv_obj_set_editable(lv_obj_t * obj, bool en); + +/** + * Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`) + * @param obj pointer to an object + * @param en true: opa scaling is enabled for this object and all children; false: no opa scaling + */ +void lv_obj_set_opa_scale_enable(lv_obj_t * obj, bool en); + +/** + * Set the opa scale of an object + * @param obj pointer to an object + * @param opa_scale a factor to scale down opacity [0..255] + */ +void lv_obj_set_opa_scale(lv_obj_t * obj, lv_opa_t opa_scale); + +/** + * Set a bit or bits in the protect filed + * @param obj pointer to an object + * @param prot 'OR'-ed values from `lv_protect_t` + */ +void lv_obj_set_protect(lv_obj_t * obj, uint8_t prot); + +/** + * Clear a bit or bits in the protect filed + * @param obj pointer to an object + * @param prot 'OR'-ed values from `lv_protect_t` + */ +void lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot); + +/** + * Set the signal function of an object. + * Always call the previous signal function in the new. + * @param obj pointer to an object + * @param fp the new signal function + */ +void lv_obj_set_signal_func(lv_obj_t * obj, lv_signal_func_t fp); + +/** + * Set a new design function for an object + * @param obj pointer to an object + * @param fp the new design function + */ +void lv_obj_set_design_func(lv_obj_t * obj, lv_design_func_t fp); + +/*---------------- + * Other set + *--------------*/ + +/** + * Allocate a new ext. data for an object + * @param obj pointer to an object + * @param ext_size the size of the new ext. data + * @return pointer to the allocated ext + */ +void * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size); + +/** + * Send a 'LV_SIGNAL_REFR_EXT_SIZE' signal to the object + * @param obj pointer to an object + */ +void lv_obj_refresh_ext_size(lv_obj_t * obj); + +#ifdef LV_OBJ_FREE_NUM_TYPE +/** + * Set an application specific number for an object. + * It can help to identify objects in the application. + * @param obj pointer to an object + * @param free_num the new free number + */ +void lv_obj_set_free_num(lv_obj_t * obj, LV_OBJ_FREE_NUM_TYPE free_num); +#endif + +#if LV_OBJ_FREE_PTR != 0 +/** + * Set an application specific pointer for an object. + * It can help to identify objects in the application. + * @param obj pointer to an object + * @param free_p the new free pinter + */ +void lv_obj_set_free_ptr(lv_obj_t * obj, void * free_p); +#endif + +#if USE_LV_ANIMATION +/** + * Animate an object + * @param obj pointer to an object to animate + * @param type type of animation from 'lv_anim_builtin_t'. 'OR' it with ANIM_IN or ANIM_OUT + * @param time time of animation in milliseconds + * @param delay delay before the animation in milliseconds + * @param cb a function to call when the animation is ready + */ +void lv_obj_animate(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint16_t delay, void (*cb) (lv_obj_t *)); +#endif + +/*======================= + * Getter functions + *======================*/ + +/*------------------ + * Screen get + *-----------------*/ + +/** + * Return with a pointer to the active screen + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +lv_obj_t * lv_scr_act(void); + +/** + * Return with the top layer. (Same on every screen and it is above the normal screen layer) + * @return pointer to the top layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_layer_top(void); + +/** + * Return with the system layer. (Same on every screen and it is above the all other layers) + * It is used for example by the cursor + * @return pointer to the system layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_layer_sys(void); + +/** + * Return with the screen of an object + * @param obj pointer to an object + * @return pointer to a screen + */ +lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj); + +/*--------------------- + * Parent/children get + *--------------------*/ + +/** + * Returns with the parent of an object + * @param obj pointer to an object + * @return pointer to the parent of 'obj' + */ +lv_obj_t * lv_obj_get_parent(const lv_obj_t * obj); + +/** + * Iterate through the children of an object (start from the "youngest, lastly created") + * @param obj pointer to an object + * @param child NULL at first call to get the next children + * and the previous return value later + * @return the child after 'act_child' or NULL if no more child + */ +lv_obj_t * lv_obj_get_child(const lv_obj_t * obj, const lv_obj_t * child); + +/** + * Iterate through the children of an object (start from the "oldest", firstly created) + * @param obj pointer to an object + * @param child NULL at first call to get the next children + * and the previous return value later + * @return the child after 'act_child' or NULL if no more child + */ +lv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child); + +/** + * Count the children of an object (only children directly on 'obj') + * @param obj pointer to an object + * @return children number of 'obj' + */ +uint16_t lv_obj_count_children(const lv_obj_t * obj); + +/*--------------------- + * Coordinate get + *--------------------*/ + +/** + * Copy the coordinates of an object to an area + * @param obj pointer to an object + * @param cords_p pointer to an area to store the coordinates + */ +void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * cords_p); + +/** + * Get the x coordinate of object + * @param obj pointer to an object + * @return distance of 'obj' from the left side of its parent + */ +lv_coord_t lv_obj_get_x(const lv_obj_t * obj); + +/** + * Get the y coordinate of object + * @param obj pointer to an object + * @return distance of 'obj' from the top of its parent + */ +lv_coord_t lv_obj_get_y(const lv_obj_t * obj); + +/** + * Get the width of an object + * @param obj pointer to an object + * @return the width + */ +lv_coord_t lv_obj_get_width(const lv_obj_t * obj); + +/** + * Get the height of an object + * @param obj pointer to an object + * @return the height + */ +lv_coord_t lv_obj_get_height(const lv_obj_t * obj); + +/** + * Get the extended size attribute of an object + * @param obj pointer to an object + * @return the extended size attribute + */ +lv_coord_t lv_obj_get_ext_size(const lv_obj_t * obj); + +/** + * Get the automatic realign property of the object. + * @param obj pointer to an object + * @return true: auto realign is enabled; false: auto realign is disabled + */ +bool lv_obj_get_auto_realign(lv_obj_t * obj); + +/*----------------- + * Appearance get + *---------------*/ + +/** + * Get the style pointer of an object (if NULL get style of the parent) + * @param obj pointer to an object + * @return pointer to a style + */ +lv_style_t * lv_obj_get_style(const lv_obj_t * obj); + +/*----------------- + * Attribute get + *----------------*/ + +/** + * Get the hidden attribute of an object + * @param obj pointer to an object + * @return true: the object is hidden + */ +bool lv_obj_get_hidden(const lv_obj_t * obj); + +/** + * Get the click enable attribute of an object + * @param obj pointer to an object + * @return true: the object is clickable + */ +bool lv_obj_get_click(const lv_obj_t * obj); + +/** + * Get the top enable attribute of an object + * @param obj pointer to an object + * @return true: the auto top feature is enabled + */ +bool lv_obj_get_top(const lv_obj_t * obj); + +/** + * Get the drag enable attribute of an object + * @param obj pointer to an object + * @return true: the object is dragable + */ +bool lv_obj_get_drag(const lv_obj_t * obj); + +/** + * Get the drag throw enable attribute of an object + * @param obj pointer to an object + * @return true: drag throw is enabled + */ +bool lv_obj_get_drag_throw(const lv_obj_t * obj); + +/** + * Get the drag parent attribute of an object + * @param obj pointer to an object + * @return true: drag parent is enabled + */ +bool lv_obj_get_drag_parent(const lv_obj_t * obj); + + +/** + * Get the opa scale enable parameter + * @param obj pointer to an object + * @return true: opa scaling is enabled for this object and all children; false: no opa scaling + */ +lv_opa_t lv_obj_get_opa_scale_enable(const lv_obj_t * obj); + +/** + * Get the opa scale parameter of an object + * @param obj pointer to an object + * @return opa scale [0..255] + */ +lv_opa_t lv_obj_get_opa_scale(const lv_obj_t * obj); + +/** + * Get the protect field of an object + * @param obj pointer to an object + * @return protect field ('OR'ed values of `lv_protect_t`) + */ +uint8_t lv_obj_get_protect(const lv_obj_t * obj); + +/** + * Check at least one bit of a given protect bitfield is set + * @param obj pointer to an object + * @param prot protect bits to test ('OR'ed values of `lv_protect_t`) + * @return false: none of the given bits are set, true: at least one bit is set + */ +bool lv_obj_is_protected(const lv_obj_t * obj, uint8_t prot); + +/** + * Get the signal function of an object + * @param obj pointer to an object + * @return the signal function + */ +lv_signal_func_t lv_obj_get_signal_func(const lv_obj_t * obj); + +/** + * Get the design function of an object + * @param obj pointer to an object + * @return the design function + */ +lv_design_func_t lv_obj_get_design_func(const lv_obj_t * obj); + +/*------------------ + * Other get + *-----------------*/ + +/** + * Get the ext pointer + * @param obj pointer to an object + * @return the ext pointer but not the dynamic version + * Use it as ext->data1, and NOT da(ext)->data1 + */ +void * lv_obj_get_ext_attr(const lv_obj_t * obj); + +/** + * Get object's and its ancestors type. Put their name in `type_buf` starting with the current type. + * E.g. buf.type[0]="lv_btn", buf.type[1]="lv_cont", buf.type[2]="lv_obj" + * @param obj pointer to an object which type should be get + * @param buf pointer to an `lv_obj_type_t` buffer to store the types + */ +void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf); + +#ifdef LV_OBJ_FREE_NUM_TYPE +/** + * Get the free number + * @param obj pointer to an object + * @return the free number + */ +LV_OBJ_FREE_NUM_TYPE lv_obj_get_free_num(const lv_obj_t * obj); +#endif + +#if LV_OBJ_FREE_PTR != 0 +/** + * Get the free pointer + * @param obj pointer to an object + * @return the free pointer + */ +void * lv_obj_get_free_ptr(const lv_obj_t * obj); +#endif + +#if USE_LV_GROUP +/** + * Get the group of the object + * @param obj pointer to an object + * @return the pointer to group of the object + */ +void * lv_obj_get_group(const lv_obj_t * obj); + + +/** + * Tell whether the object is the focused object of a group or not. + * @param obj pointer to an object + * @return true: the object is focused, false: the object is not focused or not in a group + */ +bool lv_obj_is_focused(const lv_obj_t * obj); + +#endif + + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_OBJ_H*/ diff --git a/pros/display/lv_core/lv_refr.h b/pros/display/lv_core/lv_refr.h new file mode 100644 index 00000000..75b22d01 --- /dev/null +++ b/pros/display/lv_core/lv_refr.h @@ -0,0 +1,95 @@ +/** + * @file lv_refr.h + * + */ + +#ifndef LV_REFR_H +#define LV_REFR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the screen refresh subsystem + */ +void lv_refr_init(void); + +/** + * Redraw the invalidated areas now. + * Normally the redrawing is periodically executed in `lv_task_handler` but a long blocking process can + * prevent the call of `lv_task_handler`. In this case if the the GUI is updated in the process (e.g. progress bar) + * this function can be called when the screen should be updated. + */ +void lv_refr_now(void); + +/** + * Invalidate an area + * @param area_p pointer to area which should be invalidated + */ +void lv_inv_area(const lv_area_t * area_p); + +/** + * Set a function to call after every refresh to announce the refresh time and the number of refreshed pixels + * @param cb pointer to a callback function (void my_refr_cb(uint32_t time_ms, uint32_t px_num)) + */ +void lv_refr_set_monitor_cb(void (*cb)(uint32_t, uint32_t)); + +/** + * Called when an area is invalidated to modify the coordinates of the area. + * Special display controllers may require special coordinate rounding + * @param cb pointer to the a function which will modify the area + */ +void lv_refr_set_round_cb(void(*cb)(lv_area_t*)); + +/** + * Get the number of areas in the buffer + * @return number of invalid areas + */ +uint16_t lv_refr_get_buf_size(void); + +/** + * Pop (delete) the last 'num' invalidated areas from the buffer + * @param num number of areas to delete + */ +void lv_refr_pop_from_buf(uint16_t num); +/********************** + * STATIC FUNCTIONS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_REFR_H*/ diff --git a/pros/display/lv_core/lv_style.h b/pros/display/lv_core/lv_style.h new file mode 100644 index 00000000..4206ada3 --- /dev/null +++ b/pros/display/lv_core/lv_style.h @@ -0,0 +1,199 @@ +/** + * @file lv_style.h + * + */ + +#ifndef LV_STYLE_H +#define LV_STYLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_area.h" +#include "display/lv_misc/lv_font.h" +#include "display/lv_misc/lv_anim.h" + +/********************* + * DEFINES + *********************/ +#define LV_RADIUS_CIRCLE (LV_COORD_MAX) /*A very big radius to always draw as circle*/ + +/********************** + * TYPEDEFS + **********************/ + +/*Border types (Use 'OR'ed values)*/ +enum +{ + LV_BORDER_NONE = 0x00, + LV_BORDER_BOTTOM = 0x01, + LV_BORDER_TOP = 0x02, + LV_BORDER_LEFT = 0x04, + LV_BORDER_RIGHT = 0x08, + LV_BORDER_FULL = 0x0F, + LV_BORDER_INTERNAL = 0x10, /*FOR matrix-like objects (e.g. Button matrix)*/ +}; +typedef uint8_t lv_border_part_t; + +/*Shadow types*/ +enum +{ + LV_SHADOW_BOTTOM = 0, + LV_SHADOW_FULL, +}; +typedef uint8_t lv_shadow_type_t; + +typedef struct +{ + uint8_t glass :1; /*1: Do not inherit this style*/ + + struct { + lv_color_t main_color; + lv_color_t grad_color; /*`grad_color` will be removed in v6.0, use `aux_color` instead*/ + lv_coord_t radius; + lv_opa_t opa; + + struct { + lv_color_t color; + lv_coord_t width; + lv_border_part_t part; + lv_opa_t opa; + } border; + + struct { + lv_color_t color; + lv_coord_t width; + lv_shadow_type_t type; + } shadow; + + struct { + lv_coord_t ver; + lv_coord_t hor; + lv_coord_t inner; + } padding; + + uint8_t empty :1; /*Transparent background (border still drawn)*/ + } body; + + + struct { + lv_color_t color; + const lv_font_t * font; + lv_coord_t letter_space; + lv_coord_t line_space; + lv_opa_t opa; + } text; + + struct { + lv_color_t color; + lv_opa_t intense; + lv_opa_t opa; + } image; + + struct { + lv_color_t color; + lv_coord_t width; + lv_opa_t opa; + uint8_t rounded :1; /*1: rounded line endings*/ + } line; +} lv_style_t; + +#if USE_LV_ANIMATION +typedef struct { + const lv_style_t * style_start; /*Pointer to the starting style*/ + const lv_style_t * style_end; /*Pointer to the destination style*/ + lv_style_t * style_anim; /*Pointer to a style to animate*/ + lv_anim_cb_t end_cb; /*Call it when the animation is ready (NULL if unused)*/ + int16_t time; /*Animation time in ms*/ + int16_t act_time; /*Current time in animation. Set to negative to make delay.*/ + uint16_t playback_pause; /*Wait before play back*/ + uint16_t repeat_pause; /*Wait before repeat*/ + uint8_t playback :1; /*When the animation is ready play it back*/ + uint8_t repeat :1; /*Repeat the animation infinitely*/ +} lv_style_anim_t; + +/* Example initialization +lv_style_anim_t a; +a.style_anim = &style_to_anim; +a.style_start = &style_1; +a.style_end = &style_2; +a.act_time = 0; +a.time = 1000; +a.playback = 0; +a.playback_pause = 0; +a.repeat = 0; +a.repeat_pause = 0; +a.end_cb = NULL; +lv_style_anim_create(&a); + */ +#endif + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init the basic styles + */ +void lv_style_init (void); + +/** + * Copy a style to an other + * @param dest pointer to the destination style + * @param src pointer to the source style + */ +void lv_style_copy(lv_style_t * dest, const lv_style_t * src); + + +/** + * Mix two styles according to a given ratio + * @param start start style + * @param end end style + * @param res store the result style here + * @param ratio the ratio of mix [0..256]; 0: `start` style; 256: `end` style + */ +void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * res, uint16_t ratio); + +#if USE_LV_ANIMATION + +/** + * Create an animation from a pre-configured 'lv_style_anim_t' variable + * @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied) + * @return pointer to a descriptor. Really this variable will be animated. (Can be used in `lv_anim_del(dsc, NULL)`) + */ +void * lv_style_anim_create(lv_style_anim_t * anim); +#endif + +/************************* + * GLOBAL VARIABLES + *************************/ +extern lv_style_t lv_style_scr; +extern lv_style_t lv_style_transp; +extern lv_style_t lv_style_transp_fit; +extern lv_style_t lv_style_transp_tight; +extern lv_style_t lv_style_plain; +extern lv_style_t lv_style_plain_color; +extern lv_style_t lv_style_pretty; +extern lv_style_t lv_style_pretty_color; +extern lv_style_t lv_style_btn_rel; +extern lv_style_t lv_style_btn_pr; +extern lv_style_t lv_style_btn_tgl_rel; +extern lv_style_t lv_style_btn_tgl_pr; +extern lv_style_t lv_style_btn_ina; + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_STYLE_H*/ diff --git a/pros/display/lv_core/lv_vdb.h b/pros/display/lv_core/lv_vdb.h new file mode 100644 index 00000000..32aac5df --- /dev/null +++ b/pros/display/lv_core/lv_vdb.h @@ -0,0 +1,119 @@ +/** + * @file lv_vdb.h + * + */ + +#ifndef LV_VDB_H +#define LV_VDB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if LV_VDB_SIZE != 0 + +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_area.h" + +/********************* + * DEFINES + *********************/ +/*Can be used in `lv_conf.h` the set an invalid address for the VDB. It should be replaced later by a valid address using `lv_vdb_set_adr()`*/ +#define LV_VDB_ADR_INV 8 /*8 is still too small to be valid but it's aligned on 64 bit machines as well*/ + +#ifndef LV_VDB_PX_BPP +#define LV_VDB_PX_BPP LV_COLOR_SIZE /* Default is LV_COLOR_SIZE */ +#endif + + +#if LV_VDB_TRUE_DOUBLE_BUFFERED && (LV_VDB_SIZE != LV_HOR_RES * LV_VER_RES || LV_VDB_DOUBLE == 0) +#error "With LV_VDB_TRUE_DOUBLE_BUFFERED: (LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES and LV_VDB_DOUBLE = 1 is required" +#endif + + +/* The size of VDB in bytes. + * (LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3): just divide by 8 to convert bits to bytes + * (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0): add an extra byte to round up. + * E.g. if LV_VDB_SIZE = 10 and LV_VDB_PX_BPP = 1 -> 10 bits -> 2 bytes*/ +#define LV_VDB_SIZE_IN_BYTES ((LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3) + (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0) + +/********************** + * TYPEDEFS + **********************/ + +typedef struct +{ + lv_area_t area; + lv_color_t *buf; +} lv_vdb_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Get the 'vdb' variable or allocate one in LV_VDB_DOUBLE mode + * @return pointer to a 'vdb' variable + */ +lv_vdb_t * lv_vdb_get(void); + +/** + * Flush the content of the vdb + */ +void lv_vdb_flush(void); + +/** + * Set the address of VDB buffer(s) manually. To use this set `LV_VDB_ADR` (and `LV_VDB2_ADR`) to `LV_VDB_ADR_INV` in `lv_conf.h`. + * It should be called before `lv_init()`. The size of the buffer should be: `LV_VDB_SIZE_IN_BYTES` + * @param buf1 address of the VDB. + * @param buf2 address of the second buffer. `NULL` if `LV_VDB_DOUBLE 0` + */ +void lv_vdb_set_adr(void * buf1, void * buf2); + +/** + * Call in the display driver's 'disp_flush' function when the flushing is finished + */ +void lv_flush_ready(void); + +/** + * Get currently active VDB, where the drawing happens. Used with `LV_VDB_DOUBLE 1` + * @return pointer to the active VDB. If `LV_VDB_DOUBLE 0` give the single VDB + */ +lv_vdb_t * lv_vdb_get_active(void); + +/** + * Get currently inactive VDB, which is being displayed or being flushed. Used with `LV_VDB_DOUBLE 1` + * @return pointer to the inactive VDB. If `LV_VDB_DOUBLE 0` give the single VDB + */ +lv_vdb_t * lv_vdb_get_inactive(void); + +/** + * Whether the flushing is in progress or not + * @return true: flushing is in progress; false: flushing ready + */ +bool lv_vdb_is_flushing(void); + +/********************** + * MACROS + **********************/ + +#else /*LV_VDB_SIZE != 0*/ + +/*Just for compatibility*/ +void lv_flush_ready(void); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_VDB_H*/ diff --git a/pros/display/lv_draw/lv_draw.h b/pros/display/lv_draw/lv_draw.h new file mode 100644 index 00000000..55038836 --- /dev/null +++ b/pros/display/lv_draw/lv_draw.h @@ -0,0 +1,115 @@ +/** + * @file lv_draw.h + * + */ + +#ifndef LV_DRAW_H +#define LV_DRAW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include "display/lv_core/lv_style.h" +#include "display/lv_misc/lv_txt.h" + +/********************* + * DEFINES + *********************/ +/*If image pixels contains alpha we need to know how much byte is a pixel*/ +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 +# define LV_IMG_PX_SIZE_ALPHA_BYTE 2 +#elif LV_COLOR_DEPTH == 16 +# define LV_IMG_PX_SIZE_ALPHA_BYTE 3 +#elif LV_COLOR_DEPTH == 32 +# define LV_IMG_PX_SIZE_ALPHA_BYTE 4 +#endif + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_IMG_SRC_VARIABLE, + LV_IMG_SRC_FILE, + LV_IMG_SRC_SYMBOL, + LV_IMG_SRC_UNKNOWN, +}; +typedef uint8_t lv_img_src_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +#if LV_ANTIALIAS != 0 + +/** + * Get the opacity of a pixel based it's position in a line segment + * @param seg segment length + * @param px_id position of of a pixel which opacity should be get [0..seg-1] + * @param base_opa the base opacity + * @return the opacity of the given pixel + */ +lv_opa_t lv_draw_aa_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t base_opa); + +/** + * Add a vertical anti-aliasing segment (pixels with decreasing opacity) + * @param x start point x coordinate + * @param y start point y coordinate + * @param length length of segment (negative value to start from 0 opacity) + * @param mask draw only in this area + * @param color color of pixels + * @param opa maximum opacity + */ +void lv_draw_aa_ver_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); + +/** + * Add a horizontal anti-aliasing segment (pixels with decreasing opacity) + * @param x start point x coordinate + * @param y start point y coordinate + * @param length length of segment (negative value to start from 0 opacity) + * @param mask draw only in this area + * @param color color of pixels + * @param opa maximum opacity + */ +void lv_draw_aa_hor_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); +#endif + +/********************** + * GLOBAL VARIABLES + **********************/ +extern void (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); +extern void (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); +extern void (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa); +extern void (*const map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa); + +/********************** + * MACROS + **********************/ + +/********************** + * POST INCLUDES + *********************/ +#include "lv_draw_rect.h" +#include "lv_draw_label.h" +#include "lv_draw_img.h" +#include "lv_draw_line.h" +#include "lv_draw_triangle.h" + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_H*/ diff --git a/pros/display/lv_draw/lv_draw.mk b/pros/display/lv_draw/lv_draw.mk new file mode 100644 index 00000000..a384eefe --- /dev/null +++ b/pros/display/lv_draw/lv_draw.mk @@ -0,0 +1,14 @@ +CSRCS += lv_draw_vbasic.c +CSRCS += lv_draw_rbasic.c +CSRCS += lv_draw.c +CSRCS += lv_draw_rect.c +CSRCS += lv_draw_label.c +CSRCS += lv_draw_line.c +CSRCS += lv_draw_img.c +CSRCS += lv_draw_arc.c +CSRCS += lv_draw_triangle.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_draw +VPATH += :$(LVGL_DIR)/lvgl/lv_draw + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_draw" diff --git a/pros/display/lv_draw/lv_draw_arc.h b/pros/display/lv_draw/lv_draw_arc.h new file mode 100644 index 00000000..203eabe6 --- /dev/null +++ b/pros/display/lv_draw/lv_draw_arc.h @@ -0,0 +1,53 @@ +/** + * @file lv_draw_arc.h + * + */ + +#ifndef LV_DRAW_ARC_H +#define LV_DRAW_ARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw an arc. (Can draw pie too with great thickness.) + * @param center_x the x coordinate of the center of the arc + * @param center_y the y coordinate of the center of the arc + * @param radius the radius of the arc + * @param mask the arc will be drawn only in this mask + * @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right) + * @param end_angle the end angle of the arc + * @param style style of the arc (`body.thickness`, `body.main_color`, `body.opa` is used) + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, const lv_area_t * mask, + uint16_t start_angle, uint16_t end_angle, const lv_style_t * style, lv_opa_t opa_scale); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_ARC*/ diff --git a/pros/display/lv_draw/lv_draw_img.h b/pros/display/lv_draw/lv_draw_img.h new file mode 100644 index 00000000..ff779580 --- /dev/null +++ b/pros/display/lv_draw/lv_draw_img.h @@ -0,0 +1,167 @@ +/** + * @file lv_draw_img.h + * + */ + +#ifndef LV_DRAW_IMG_H +#define LV_DRAW_IMG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ +#define LV_IMG_DECODER_OPEN_FAIL ((void*)(-1)) + +/********************** + * TYPEDEFS + **********************/ +struct _lv_img_t; + +typedef struct { + + /* The first 8 bit is very important to distinguish the different source types. + * For more info see `lv_img_get_src_type()` in lv_img.c */ + uint32_t cf :5; /* Color format: See `lv_img_color_format_t`*/ + uint32_t always_zero :3; /*It the upper bits of the first byte. Always zero to look like a non-printable character*/ + + uint32_t reserved :2; /*Reserved to be used later*/ + + uint32_t w:11; /*Width of the image map*/ + uint32_t h:11; /*Height of the image map*/ +} lv_img_header_t; + +/*Image color format*/ +enum { + LV_IMG_CF_UNKOWN = 0, + + LV_IMG_CF_RAW, /*Contains the file as it is. Needs custom decoder function*/ + LV_IMG_CF_RAW_ALPHA, /*Contains the file as it is. The image has alpha. Needs custom decoder function*/ + LV_IMG_CF_RAW_CHROMA_KEYED, /*Contains the file as it is. The image is chroma keyed. Needs custom decoder function*/ + + LV_IMG_CF_TRUE_COLOR, /*Color format and depth should match with LV_COLOR settings*/ + LV_IMG_CF_TRUE_COLOR_ALPHA, /*Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/ + LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /*Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels will be transparent*/ + + LV_IMG_CF_INDEXED_1BIT, /*Can have 2 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_2BIT, /*Can have 4 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_4BIT, /*Can have 16 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_8BIT, /*Can have 256 different colors in a palette (always chroma keyed)*/ + + LV_IMG_CF_ALPHA_1BIT, /*Can have one color and it can be drawn or not*/ + LV_IMG_CF_ALPHA_2BIT, /*Can have one color but 4 different alpha value*/ + LV_IMG_CF_ALPHA_4BIT, /*Can have one color but 16 different alpha value*/ + LV_IMG_CF_ALPHA_8BIT, /*Can have one color but 256 different alpha value*/ +}; +typedef uint8_t lv_img_cf_t; + +/* Image header it is compatible with + * the result image converter utility*/ +typedef struct +{ + lv_img_header_t header; + uint32_t data_size; + const uint8_t * data; +} lv_img_dsc_t; + +/* Decoder function definitions */ + + +/** + * Get info from an image and store in the `header` + * @param src the image source. Can be a pointer to a C array or a file name (Use `lv_img_src_get_type` to determine the type) + * @param header store the info here + * @return LV_RES_OK: info written correctly; LV_RES_INV: failed + */ +typedef lv_res_t (*lv_img_decoder_info_f_t)(const void * src, lv_img_header_t * header); + +/** + * Open an image for decoding. Prepare it as it is required to read it later + * @param src the image source. Can be a pointer to a C array or a file name (Use `lv_img_src_get_type` to determine the type) + * @param style the style of image (maybe it will be required to determine a color or something) + * @return there are 3 possible return values: + * 1) buffer with the decoded image + * 2) if can decode the whole image NULL. decoder_read_line will be called to read the image line-by-line + * 3) LV_IMG_DECODER_OPEN_FAIL if the image format is unknown to the decoder or an error occurred + */ +typedef const uint8_t * (*lv_img_decoder_open_f_t)(const void * src, const lv_style_t * style); + +/** + * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`. + * Required only if the "open" function can't return with the whole decoded pixel array. + * @param x start x coordinate + * @param y startt y coordinate + * @param len number of pixels to decode + * @param buf a buffer to store the decoded pixels + * @return LV_RES_OK: ok; LV_RES_INV: failed + */ +typedef lv_res_t (*lv_img_decoder_read_line_f_t)(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); + +/** + * Close the pending decoding. Free resources etc. + */ +typedef void (*lv_img_decoder_close_f_t)(void); + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw an image + * @param coords the coordinates of the image + * @param mask the image will be drawn only in this area + * @param src pointer to a lv_color_t array which contains the pixels of the image + * @param style style of the image + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, + const void * src, const lv_style_t * style, lv_opa_t opa_scale); + + +/** + * Get the type of an image source + * @param src pointer to an image source: + * - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code) + * - a path to a file (e.g. "S:/folder/image.bin") + * - or a symbol (e.g. SYMBOL_CLOSE) + * @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKOWN + */ +lv_img_src_t lv_img_src_get_type(const void * src); + +/** + * Set custom decoder functions. See the typdefs of the function typed above for more info about them + * @param info_fp info get function + * @param open_fp open function + * @param read_fp read line function + * @param close_fp clode function + */ +void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp, + lv_img_decoder_read_line_f_t read_fp, lv_img_decoder_close_f_t close_fp); + +lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header); + +uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf); + +bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf); + +bool lv_img_color_format_has_alpha(lv_img_cf_t cf); + + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/pros/display/lv_draw/lv_draw_label.h b/pros/display/lv_draw/lv_draw_label.h new file mode 100644 index 00000000..8798573d --- /dev/null +++ b/pros/display/lv_draw/lv_draw_label.h @@ -0,0 +1,53 @@ +/** + * @file lv_draw_label.h + * + */ + +#ifndef LV_DRAW_LABEL_H +#define LV_DRAW_LABEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Write a text + * @param coords coordinates of the label + * @param mask the label will be drawn only in this area + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + * @param txt 0 terminated text to write + * @param flag settings for the text from 'txt_flag_t' enum + * @param offset text offset in x and y direction (NULL if unused) + * + */ +void lv_draw_label(const lv_area_t * coords,const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale, + const char * txt, lv_txt_flag_t flag, lv_point_t * offset); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_LABEL_H*/ diff --git a/pros/display/lv_draw/lv_draw_line.h b/pros/display/lv_draw/lv_draw_line.h new file mode 100644 index 00000000..4269475e --- /dev/null +++ b/pros/display/lv_draw/lv_draw_line.h @@ -0,0 +1,49 @@ +/** + * @file lv_draw_line.h + * + */ + +#ifndef LV_DRAW_LINE_H +#define LV_DRAW_LINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw a line + * @param point1 first point of the line + * @param point2 second point of the line + * @param mask the line will be drawn only on this area + * @param style pointer to a line's style + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask, + const lv_style_t * style, lv_opa_t opa_scale); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_LINE_H*/ diff --git a/pros/display/lv_draw/lv_draw_rbasic.h b/pros/display/lv_draw/lv_draw_rbasic.h new file mode 100644 index 00000000..403cb806 --- /dev/null +++ b/pros/display/lv_draw/lv_draw_rbasic.h @@ -0,0 +1,96 @@ +/** + * @file lv_draw_rbasic..h + * + */ + +#ifndef LV_DRAW_RBASIC_H +#define LV_DRAW_RBASIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_REAL_DRAW != 0 + +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_area.h" +#include "display/lv_misc/lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_rpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa); + +/** + * Fill an area on the display + * @param cords_p coordinates of the area to fill + * @param mask_p fill only o this mask + * @param color fill color + * @param opa opacity (ignored, only for compatibility with lv_vfill) + */ +void lv_rfill(const lv_area_t * cords_p, const lv_area_t * mask_p, + lv_color_t color, lv_opa_t opa); + +/** + * Draw a letter to the display + * @param pos_p left-top coordinate of the latter + * @param mask_p the letter will be drawn only on this area + * @param font_p pointer to font + * @param letter a letter to draw + * @param color color of letter + * @param opa opacity of letter (ignored, only for compatibility with lv_vletter) + */ +void lv_rletter(const lv_point_t * pos_p, const lv_area_t * mask_p, + const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa); + +/** + * When the letter is ant-aliased it needs to know the background color + * @param bg_color the background color of the currently drawn letter + */ +void lv_rletter_set_background(lv_color_t color); + + +/** + * Draw a color map to the display (image) + * @param cords_p coordinates the color map + * @param mask_p the map will drawn only on this area + * @param map_p pointer to a lv_color_t array + * @param opa opacity of the map (ignored, only for compatibility with 'lv_vmap') + * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels + * @param alpha_byte true: extra alpha byte is inserted for every pixel (not supported, only l'v_vmap' can draw it) + * @param recolor mix the pixels with this color + * @param recolor_opa the intense of recoloring + */ +void lv_rmap(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa); +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_REAL_DRAW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_RBASIC_H*/ diff --git a/pros/display/lv_draw/lv_draw_rect.h b/pros/display/lv_draw/lv_draw_rect.h new file mode 100644 index 00000000..933590ca --- /dev/null +++ b/pros/display/lv_draw/lv_draw_rect.h @@ -0,0 +1,48 @@ +/** + * @file lv_draw_rect.h + * + */ + +#ifndef LV_DRAW_RECT_H +#define LV_DRAW_RECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw a rectangle + * @param coords the coordinates of the rectangle + * @param mask the rectangle will be drawn only in this mask + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_RECT_H*/ diff --git a/pros/display/lv_draw/lv_draw_triangle.h b/pros/display/lv_draw/lv_draw_triangle.h new file mode 100644 index 00000000..c3c6208d --- /dev/null +++ b/pros/display/lv_draw/lv_draw_triangle.h @@ -0,0 +1,51 @@ +/** + * @file lv_draw_triangle.h + * + */ + +#ifndef LV_DRAW_TRIANGLE_H +#define LV_DRAW_TRIANGLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/*Experimental use for 3D modeling*/ +#define USE_LV_TRIANGLE 1 + +#if USE_LV_TRIANGLE != 0 +/** + * + * @param points pointer to an array with 3 points + * @param mask the triangle will be drawn only in this mask + * @param color color of the triangle + */ +void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color); +#endif + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_TRIANGLE_H*/ diff --git a/pros/display/lv_draw/lv_draw_vbasic.h b/pros/display/lv_draw/lv_draw_vbasic.h new file mode 100644 index 00000000..82d4b7a1 --- /dev/null +++ b/pros/display/lv_draw/lv_draw_vbasic.h @@ -0,0 +1,89 @@ +/** + * @file lv_draw_vbasic.h + * + */ + +#ifndef LV_DRAW_VBASIC_H +#define LV_DRAW_VBASIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if LV_VDB_SIZE != 0 + +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_area.h" +#include "display/lv_misc/lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_vpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa); +/** + * Fill an area in the Virtual Display Buffer + * @param cords_p coordinates of the area to fill + * @param mask_p fill only o this mask + * @param color fill color + * @param opa opacity of the area (0..255) + */ +void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p, + lv_color_t color, lv_opa_t opa); + +/** + * Draw a letter in the Virtual Display Buffer + * @param pos_p left-top coordinate of the latter + * @param mask_p the letter will be drawn only on this area + * @param font_p pointer to font + * @param letter a letter to draw + * @param color color of letter + * @param opa opacity of letter (0..255) + */ +void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p, + const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa); + +/** + * Draw a color map to the display (image) + * @param cords_p coordinates the color map + * @param mask_p the map will drawn only on this area (truncated to VDB area) + * @param map_p pointer to a lv_color_t array + * @param opa opacity of the map + * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels + * @param alpha_byte true: extra alpha byte is inserted for every pixel + * @param recolor mix the pixels with this color + * @param recolor_opa the intense of recoloring + */ +void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa); + +/********************** + * MACROS + **********************/ + +#endif /*LV_VDB_SIZE != 0*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_RBASIC_H*/ diff --git a/pros/display/lv_fonts/lv_font_builtin.h b/pros/display/lv_fonts/lv_font_builtin.h new file mode 100644 index 00000000..5687fa1f --- /dev/null +++ b/pros/display/lv_fonts/lv_font_builtin.h @@ -0,0 +1,150 @@ +/** + * @file lv_font_builtin.h + * + */ + +#ifndef LV_FONT_BUILTIN_H +#define LV_FONT_BUILTIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include "display/lv_misc/lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the built-in fonts + */ +void lv_font_builtin_init(void); + +/********************** + * MACROS + **********************/ + +/********************** + * FONT DECLARATIONS + **********************/ + +/*10 px */ +#if USE_LV_FONT_DEJAVU_10 +LV_FONT_DECLARE(lv_font_dejavu_10); +#endif + +#if USE_LV_FONT_DEJAVU_10_LATIN_SUP +LV_FONT_DECLARE(lv_font_dejavu_10_latin_sup); +#endif + +#if USE_LV_FONT_DEJAVU_10_CYRILLIC +LV_FONT_DECLARE(lv_font_dejavu_10_cyrillic); +#endif + +#if USE_LV_FONT_SYMBOL_10 +LV_FONT_DECLARE(lv_font_symbol_10); +#endif + +/*20 px */ +#if USE_LV_FONT_DEJAVU_20 +LV_FONT_DECLARE(lv_font_dejavu_20); +#endif + +#if USE_LV_FONT_DEJAVU_20_LATIN_SUP +LV_FONT_DECLARE(lv_font_dejavu_20_latin_sup); +#endif + +#if USE_LV_FONT_DEJAVU_20_CYRILLIC +LV_FONT_DECLARE(lv_font_dejavu_20_cyrillic); +#endif + +#if USE_LV_FONT_SYMBOL_20 +LV_FONT_DECLARE(lv_font_symbol_20); +#endif + +/*30 px */ +#if USE_LV_FONT_DEJAVU_30 +LV_FONT_DECLARE(lv_font_dejavu_30); +#endif + +#if USE_LV_FONT_DEJAVU_30_LATIN_SUP +LV_FONT_DECLARE(lv_font_dejavu_30_latin_sup); +#endif + +#if USE_LV_FONT_DEJAVU_30_CYRILLIC +LV_FONT_DECLARE(lv_font_dejavu_30_cyrillic); +#endif + +#if USE_LV_FONT_SYMBOL_30 +LV_FONT_DECLARE(lv_font_symbol_30); +#endif + +/*40 px */ +#if USE_LV_FONT_DEJAVU_40 +LV_FONT_DECLARE(lv_font_dejavu_40); +#endif + +#if USE_LV_FONT_DEJAVU_40_LATIN_SUP +LV_FONT_DECLARE(lv_font_dejavu_40_latin_sup); +#endif + +#if USE_LV_FONT_DEJAVU_40_CYRILLIC +LV_FONT_DECLARE(lv_font_dejavu_40_cyrillic); +#endif + +#if USE_LV_FONT_SYMBOL_40 +LV_FONT_DECLARE(lv_font_symbol_40); +#endif + +#if USE_LV_FONT_MONOSPACE_8 +LV_FONT_DECLARE(lv_font_monospace_8); +#endif + +#if USE_PROS_FONT_DEJAVU_MONO_10 +LV_FONT_DECLARE(pros_font_dejavu_mono_10); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_10_LATIN_SUP +LV_FONT_DECLARE(pros_font_dejavu_mono_10_latin_sup); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_20 +LV_FONT_DECLARE(pros_font_dejavu_mono_20); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_20_LATIN_SUP +LV_FONT_DECLARE(pros_font_dejavu_mono_20_latin_sup); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_30 +LV_FONT_DECLARE(pros_font_dejavu_mono_30); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_30_LATIN_SUP +LV_FONT_DECLARE(pros_font_dejavu_mono_30_latin_sup); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_40 +LV_FONT_DECLARE(pros_font_dejavu_mono_40); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_40_LATIN_SUP +LV_FONT_DECLARE(pros_font_dejavu_mono_40_latin_sup); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_FONT_BUILTIN_H*/ diff --git a/pros/display/lv_fonts/lv_fonts.mk b/pros/display/lv_fonts/lv_fonts.mk new file mode 100644 index 00000000..f124b559 --- /dev/null +++ b/pros/display/lv_fonts/lv_fonts.mk @@ -0,0 +1,23 @@ +CSRCS += lv_font_builtin.c +CSRCS += lv_font_dejavu_10.c +CSRCS += lv_font_dejavu_20.c +CSRCS += lv_font_dejavu_30.c +CSRCS += lv_font_dejavu_40.c +CSRCS += lv_font_dejavu_10_cyrillic.c +CSRCS += lv_font_dejavu_20_cyrillic.c +CSRCS += lv_font_dejavu_30_cyrillic.c +CSRCS += lv_font_dejavu_40_cyrillic.c +CSRCS += lv_font_dejavu_10_latin_sup.c +CSRCS += lv_font_dejavu_20_latin_sup.c +CSRCS += lv_font_dejavu_30_latin_sup.c +CSRCS += lv_font_dejavu_40_latin_sup.c +CSRCS += lv_font_symbol_10.c +CSRCS += lv_font_symbol_20.c +CSRCS += lv_font_symbol_30.c +CSRCS += lv_font_symbol_40.c +CSRCS += lv_font_monospace_8.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_fonts +VPATH += :$(LVGL_DIR)/lvgl/lv_fonts + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_fonts" diff --git a/pros/display/lv_hal/lv_hal.h b/pros/display/lv_hal/lv_hal.h new file mode 100644 index 00000000..5ab28f2a --- /dev/null +++ b/pros/display/lv_hal/lv_hal.h @@ -0,0 +1,40 @@ +/** + * @file hal.h + * + */ + +#ifndef HAL_H +#define HAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_hal_disp.h" +#include "lv_hal_indev.h" +#include "lv_hal_tick.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/pros/display/lv_hal/lv_hal.mk b/pros/display/lv_hal/lv_hal.mk new file mode 100644 index 00000000..83f4bf17 --- /dev/null +++ b/pros/display/lv_hal/lv_hal.mk @@ -0,0 +1,8 @@ +CSRCS += lv_hal_disp.c +CSRCS += lv_hal_indev.c +CSRCS += lv_hal_tick.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_hal +VPATH += :$(LVGL_DIR)/lvgl/lv_hal + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_hal" diff --git a/pros/display/lv_hal/lv_hal_disp.h b/pros/display/lv_hal/lv_hal_disp.h new file mode 100644 index 00000000..273f3314 --- /dev/null +++ b/pros/display/lv_hal/lv_hal_disp.h @@ -0,0 +1,174 @@ +/** + * @file hal_disp.h + * + * @description Display Driver HAL interface header file + * + */ + +#ifndef HAL_DISP_H +#define HAL_DISP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include +#include "lv_hal.h" +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_area.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** + * Display Driver structure to be registered by HAL + */ +typedef struct _disp_drv_t { + /*Write the internal buffer (VDB) to the display. 'lv_flush_ready()' has to be called when finished*/ + void (*disp_flush)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); + + /*Fill an area with a color on the display*/ + void (*disp_fill)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); + + /*Write pixel map (e.g. image) to the display*/ + void (*disp_map)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); + + /*Optional interface functions to use GPU*/ +#if USE_LV_GPU + /*Blend two memories using opacity (GPU only)*/ + void (*mem_blend)(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa); + + /*Fill a memory with a color (GPU only)*/ + void (*mem_fill)(lv_color_t * dest, uint32_t length, lv_color_t color); +#endif + +#if LV_VDB_SIZE + /*Optional: Set a pixel in a buffer according to the requirements of the display*/ + void (*vdb_wr)(uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa); +#endif +} lv_disp_drv_t; + +typedef struct _disp_t { + lv_disp_drv_t driver; + struct _disp_t *next; +} lv_disp_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize a display driver with default values. + * It is used to surly have known values in the fields ant not memory junk. + * After it you can set the fields. + * @param driver pointer to driver variable to initialize + */ +void lv_disp_drv_init(lv_disp_drv_t *driver); + +/** + * Register an initialized display driver. + * Automatically set the first display as active. + * @param driver pointer to an initialized 'lv_disp_drv_t' variable (can be local variable) + * @return pointer to the new display or NULL on error + */ +lv_disp_t * lv_disp_drv_register(lv_disp_drv_t *driver); + +/** + * Set the active display + * @param disp pointer to a display (return value of 'lv_disp_register') + */ +void lv_disp_set_active(lv_disp_t * disp); + +/** + * Get a pointer to the active display + * @return pointer to the active display + */ +lv_disp_t * lv_disp_get_active(void); + +/** + * Get the next display. + * @param disp pointer to the current display. NULL to initialize. + * @return the next display or NULL if no more. Give the first display when the parameter is NULL + */ +lv_disp_t * lv_disp_next(lv_disp_t * disp); + +/** + * Fill a rectangular area with a color on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_p pointer to an array of colors + */ +void lv_disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t *color_p); + +/** + * Fill a rectangular area with a color on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color fill color + */ +void lv_disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); + +/** + * Put a color map to a rectangular area on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_map pointer to an array of colors + */ +void lv_disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_map); + +#if USE_LV_GPU +/** + * Blend pixels to a destination memory from a source memory + * In 'lv_disp_drv_t' 'mem_blend' is optional. (NULL if not available) + * @param dest a memory address. Blend 'src' here. + * @param src pointer to pixel map. Blend it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +void lv_disp_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa); + +/** + * Fill a memory with a color (GPUs may support it) + * In 'lv_disp_drv_t' 'mem_fill' is optional. (NULL if not available) + * @param dest a memory address. Copy 'src' here. + * @param src pointer to pixel map. Copy it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +void lv_disp_mem_fill(lv_color_t * dest, uint32_t length, lv_color_t color); +/** + * Shows if memory blending (by GPU) is supported or not + * @return false: 'mem_blend' is not supported in the driver; true: 'mem_blend' is supported in the driver + */ +bool lv_disp_is_mem_blend_supported(void); + +/** + * Shows if memory fill (by GPU) is supported or not + * @return false: 'mem_fill' is not supported in the drover; true: 'mem_fill' is supported in the driver + */ +bool lv_disp_is_mem_fill_supported(void); +#endif +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/pros/display/lv_hal/lv_hal_indev.h b/pros/display/lv_hal/lv_hal_indev.h new file mode 100644 index 00000000..0252dc47 --- /dev/null +++ b/pros/display/lv_hal/lv_hal_indev.h @@ -0,0 +1,166 @@ +/** + * @file hal_indev.h + * + * @description Input Device HAL interface layer header file + * + */ + +#ifndef HAL_INDEV_H +#define HAL_INDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include +#include "lv_hal.h" +#include "display/lv_misc/lv_area.h" +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Possible input device types*/ +enum { + LV_INDEV_TYPE_NONE, /*Show uninitialized state*/ + LV_INDEV_TYPE_POINTER, /*Touch pad, mouse, external button*/ + LV_INDEV_TYPE_KEYPAD, /*Keypad or keyboard*/ + LV_INDEV_TYPE_BUTTON, /*External (hardware button) which is assinged to a specific point of the screen*/ + LV_INDEV_TYPE_ENCODER, /*Encoder with only Left, Right turn and a Button*/ +}; +typedef uint8_t lv_hal_indev_type_t; + +/*States for input devices*/ +enum { + LV_INDEV_STATE_REL = 0, + LV_INDEV_STATE_PR +}; +typedef uint8_t lv_indev_state_t; + +/*Data type when an input device is read */ +typedef struct { + union { + lv_point_t point; /*For LV_INDEV_TYPE_POINTER the currently pressed point*/ + uint32_t key; /*For LV_INDEV_TYPE_KEYPAD the currently pressed key*/ + uint32_t btn; /*For LV_INDEV_TYPE_BUTTON the currently pressed button*/ + int16_t enc_diff; /*For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/ + }; + void *user_data; /*'lv_indev_drv_t.priv' for this driver*/ + lv_indev_state_t state; /*LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/ +} lv_indev_data_t; + +/*Initialized by the user and registered by 'lv_indev_add()'*/ +typedef struct { + lv_hal_indev_type_t type; /*Input device type*/ + bool (*read)(lv_indev_data_t *data); /*Function pointer to read data. Return 'true' if there is still data to be read (buffered)*/ + void *user_data; /*Pointer to user defined data, passed in 'lv_indev_data_t' on read*/ +} lv_indev_drv_t; + +struct _lv_obj_t; + +/*Run time data of input devices*/ +typedef struct _lv_indev_proc_t { + lv_indev_state_t state; + union { + struct { /*Pointer and button data*/ + lv_point_t act_point; + lv_point_t last_point; + lv_point_t vect; + lv_point_t drag_sum; /*Count the dragged pixels to check LV_INDEV_DRAG_LIMIT*/ + struct _lv_obj_t * act_obj; + struct _lv_obj_t * last_obj; + + /*Flags*/ + uint8_t drag_range_out :1; + uint8_t drag_in_prog :1; + uint8_t wait_unil_release :1; + }; + struct { /*Keypad data*/ + lv_indev_state_t last_state; + uint32_t last_key; + }; + }; + + uint32_t pr_timestamp; /*Pressed time stamp*/ + uint32_t longpr_rep_timestamp; /*Long press repeat time stamp*/ + + /*Flags*/ + uint8_t long_pr_sent :1; + uint8_t reset_query :1; + uint8_t disabled :1; +} lv_indev_proc_t; + +struct _lv_indev_t; + +typedef void (*lv_indev_feedback_t)(struct _lv_indev_t *, lv_signal_t); + +struct _lv_obj_t; +struct _lv_group_t; + +/*The main input device descriptor with driver, runtime data ('proc') and some additional information*/ +typedef struct _lv_indev_t { + lv_indev_drv_t driver; + lv_indev_proc_t proc; + lv_indev_feedback_t feedback; + uint32_t last_activity_time; + union { + struct _lv_obj_t *cursor; /*Cursor for LV_INPUT_TYPE_POINTER*/ + struct _lv_group_t *group; /*Keypad destination group*/ + const lv_point_t * btn_points; /*Array points assigned to the button ()screen will be pressed here by the buttons*/ + + }; + struct _lv_indev_t *next; +} lv_indev_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize an input device driver with default values. + * It is used to surly have known values in the fields ant not memory junk. + * After it you can set the fields. + * @param driver pointer to driver variable to initialize + */ +void lv_indev_drv_init(lv_indev_drv_t *driver); + +/** + * Register an initialized input device driver. + * @param driver pointer to an initialized 'lv_indev_drv_t' variable (can be local variable) + * @return pointer to the new input device or NULL on error + */ +lv_indev_t * lv_indev_drv_register(lv_indev_drv_t *driver); + +/** + * Get the next input device. + * @param indev pointer to the current input device. NULL to initialize. + * @return the next input devise or NULL if no more. Gives the first input device when the parameter is NULL + */ +lv_indev_t * lv_indev_next(lv_indev_t * indev); + +/** + * Read data from an input device. + * @param indev pointer to an input device + * @param data input device will write its data here + * @return false: no more data; true: there more data to read (buffered) + */ +bool lv_indev_read(lv_indev_t * indev, lv_indev_data_t *data); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/pros/display/lv_hal/lv_hal_tick.h b/pros/display/lv_hal/lv_hal_tick.h new file mode 100644 index 00000000..c59ed0b2 --- /dev/null +++ b/pros/display/lv_hal/lv_hal_tick.h @@ -0,0 +1,66 @@ +/** + * @file lv_hal_tick.h + * Provide access to the system tick with 1 millisecond resolution + */ + +#ifndef LV_HAL_TICK_H +#define LV_HAL_TICK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif +#include +#include + +/********************* + * DEFINES + *********************/ +#ifndef LV_ATTRIBUTE_TICK_INC +#define LV_ATTRIBUTE_TICK_INC +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * You have to call this function periodically + * @param tick_period the call period of this function in milliseconds + */ +LV_ATTRIBUTE_TICK_INC void lv_tick_inc(uint32_t tick_period); + +/** + * Get the elapsed milliseconds since start up + * @return the elapsed milliseconds + */ +uint32_t lv_tick_get(void); + +/** + * Get the elapsed milliseconds since a previous time stamp + * @param prev_tick a previous time stamp (return value of systick_get() ) + * @return the elapsed milliseconds since 'prev_tick' + */ +uint32_t lv_tick_elaps(uint32_t prev_tick); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_HAL_TICK_H*/ diff --git a/pros/display/lv_misc/lv_anim.h b/pros/display/lv_misc/lv_anim.h new file mode 100644 index 00000000..b3b8553b --- /dev/null +++ b/pros/display/lv_misc/lv_anim.h @@ -0,0 +1,177 @@ +/** + * @file anim.h + * + */ + +#ifndef ANIM_H +#define ANIM_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_ANIMATION + +#include +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_anim_t; + +typedef int32_t(*lv_anim_path_t)(const struct _lv_anim_t*); + +typedef void (*lv_anim_fp_t)(void *, int32_t); +typedef void (*lv_anim_cb_t)(void *); + +typedef struct _lv_anim_t +{ + void * var; /*Variable to animate*/ + lv_anim_fp_t fp; /*Animator function*/ + lv_anim_cb_t end_cb; /*Call it when the animation is ready*/ + lv_anim_path_t path; /*An array with the steps of animations*/ + int32_t start; /*Start value*/ + int32_t end; /*End value*/ + uint16_t time; /*Animation time in ms*/ + int16_t act_time; /*Current time in animation. Set to negative to make delay.*/ + uint16_t playback_pause; /*Wait before play back*/ + uint16_t repeat_pause; /*Wait before repeat*/ + uint8_t playback :1; /*When the animation is ready play it back*/ + uint8_t repeat :1; /*Repeat the animation infinitely*/ + /*Animation system use these - user shouldn't set*/ + uint8_t playback_now :1; /*Play back is in progress*/ + uint32_t has_run :1; /*Indicates the animation has run it this round*/ +} lv_anim_t; + +/*Example initialization +lv_anim_t a; +a.var = obj; +a.start = lv_obj_get_height(obj); +a.end = new_height; +a.fp = (lv_anim_fp_t)lv_obj_set_height; +a.path = lv_anim_path_linear; +a.end_cb = NULL; +a.act_time = 0; +a.time = 200; +a.playback = 0; +a.playback_pause = 0; +a.repeat = 0; +a.repeat_pause = 0; +lv_anim_create(&a); + */ +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init. the animation module + */ +void lv_anim_init(void); + +/** + * Create an animation + * @param anim_p an initialized 'anim_t' variable. Not required after call. + */ +void lv_anim_create(lv_anim_t * anim_p); + +/** + * Delete an animation for a variable with a given animatior function + * @param var pointer to variable + * @param fp a function pointer which is animating 'var', + * or NULL to ignore it and delete all animation with 'var + * @return true: at least 1 animation is deleted, false: no animation is deleted + */ +bool lv_anim_del(void * var, lv_anim_fp_t fp); + +/** + * Get the number of currently running animations + * @return the number of running animations + */ +uint16_t lv_anim_count_running(void); + +/** + * Calculate the time of an animation with a given speed and the start and end values + * @param speed speed of animation in unit/sec + * @param start start value of the animation + * @param end end value of the animation + * @return the required time [ms] for the animation with the given parameters + */ +uint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end); + +/** + * Calculate the current value of an animation applying linear characteristic + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_linear(const lv_anim_t *a); + +/** + * Calculate the current value of an animation slowing down the start phase + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_in(const lv_anim_t * a); + +/** + * Calculate the current value of an animation slowing down the end phase + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_out(const lv_anim_t * a); + +/** + * Calculate the current value of an animation applying an "S" characteristic (cosine) + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_in_out(const lv_anim_t *a); + +/** + * Calculate the current value of an animation with overshoot at the end + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_overshoot(const lv_anim_t * a); + +/** + * Calculate the current value of an animation with 3 bounces + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_bounce(const lv_anim_t * a); + +/** + * Calculate the current value of an animation applying step characteristic. + * (Set end value on the end of the animation) + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_step(const lv_anim_t *a); +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_ANIMATION == 0*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ANIM_H*/ + diff --git a/pros/display/lv_misc/lv_area.h b/pros/display/lv_misc/lv_area.h new file mode 100644 index 00000000..fc8b7dec --- /dev/null +++ b/pros/display/lv_misc/lv_area.h @@ -0,0 +1,169 @@ +/** + * @file lv_area.h + * + */ + +#ifndef LV_AREA_H +#define LV_AREA_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include +#include +#include + +/********************* + * DEFINES + *********************/ +#define LV_COORD_MAX (16383) /*To avoid overflow don't let the max [-32,32k] range */ +#define LV_COORD_MIN (-16384) + +/********************** + * TYPEDEFS + **********************/ +typedef int16_t lv_coord_t; + +typedef struct +{ + lv_coord_t x; + lv_coord_t y; +} lv_point_t; + +typedef struct +{ + lv_coord_t x1; + lv_coord_t y1; + lv_coord_t x2; + lv_coord_t y2; +} lv_area_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize an area + * @param area_p pointer to an area + * @param x1 left coordinate of the area + * @param y1 top coordinate of the area + * @param x2 right coordinate of the area + * @param y2 bottom coordinate of the area + */ +void lv_area_set(lv_area_t * area_p, lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2); + +/** + * Copy an area + * @param dest pointer to the destination area + * @param src pointer to the source area + */ +inline static void lv_area_copy(lv_area_t * dest, const lv_area_t * src) +{ + memcpy(dest, src, sizeof(lv_area_t)); +} + +/** + * Get the width of an area + * @param area_p pointer to an area + * @return the width of the area (if x1 == x2 -> width = 1) + */ +static inline lv_coord_t lv_area_get_width(const lv_area_t * area_p) +{ + return area_p->x2 - area_p->x1 + 1; +} + +/** + * Get the height of an area + * @param area_p pointer to an area + * @return the height of the area (if y1 == y2 -> height = 1) + */ +static inline lv_coord_t lv_area_get_height(const lv_area_t * area_p) +{ + return area_p->y2 - area_p->y1 + 1; +} + +/** + * Set the width of an area + * @param area_p pointer to an area + * @param w the new width of the area (w == 1 makes x1 == x2) + */ +void lv_area_set_width(lv_area_t * area_p, lv_coord_t w); + +/** + * Set the height of an area + * @param area_p pointer to an area + * @param h the new height of the area (h == 1 makes y1 == y2) + */ +void lv_area_set_height(lv_area_t * area_p, lv_coord_t h); + +/** + * Set the position of an area (width and height will be kept) + * @param area_p pointer to an area + * @param x the new x coordinate of the area + * @param y the new y coordinate of the area + */ +void lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y); + +/** + * Return with area of an area (x * y) + * @param area_p pointer to an area + * @return size of area + */ +uint32_t lv_area_get_size(const lv_area_t * area_p); + +/** + * Get the common parts of two areas + * @param res_p pointer to an area, the result will be stored her + * @param a1_p pointer to the first area + * @param a2_p pointer to the second area + * @return false: the two area has NO common parts, res_p is invalid + */ +bool lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p); + +/** + * Join two areas into a third which involves the other two + * @param res_p pointer to an area, the result will be stored here + * @param a1_p pointer to the first area + * @param a2_p pointer to the second area + */ +void lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p); + +/** + * Check if a point is on an area + * @param a_p pointer to an area + * @param p_p pointer to a point + * @return false:the point is out of the area + */ +bool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p); + +/** + * Check if two area has common parts + * @param a1_p pointer to an area. + * @param a2_p pointer to an other area + * @return false: a1_p and a2_p has no common parts + */ +bool lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p); + +/** + * Check if an area is fully on an other + * @param ain_p pointer to an area which could be on aholder_p + * @param aholder pointer to an area which could involve ain_p + * @return + */ +bool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif diff --git a/pros/display/lv_misc/lv_circ.h b/pros/display/lv_misc/lv_circ.h new file mode 100644 index 00000000..f2065f71 --- /dev/null +++ b/pros/display/lv_misc/lv_circ.h @@ -0,0 +1,79 @@ +/** + * @file lv_circ.h + * + */ + +#ifndef LV_CIRC_H +#define LV_CIRC_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_area.h" + +/********************* + * DEFINES + *********************/ +#define LV_CIRC_OCT1_X(p) (p.x) +#define LV_CIRC_OCT1_Y(p) (p.y) +#define LV_CIRC_OCT2_X(p) (p.y) +#define LV_CIRC_OCT2_Y(p) (p.x) +#define LV_CIRC_OCT3_X(p) (-p.y) +#define LV_CIRC_OCT3_Y(p) (p.x) +#define LV_CIRC_OCT4_X(p) (-p.x) +#define LV_CIRC_OCT4_Y(p) (p.y) +#define LV_CIRC_OCT5_X(p) (-p.x) +#define LV_CIRC_OCT5_Y(p) (-p.y) +#define LV_CIRC_OCT6_X(p) (-p.y) +#define LV_CIRC_OCT6_Y(p) (-p.x) +#define LV_CIRC_OCT7_X(p) (p.y) +#define LV_CIRC_OCT7_Y(p) (-p.x) +#define LV_CIRC_OCT8_X(p) (p.x) +#define LV_CIRC_OCT8_Y(p) (-p.y) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the circle drawing + * @param c pointer to a point. The coordinates will be calculated here + * @param tmp point to a variable. It will store temporary data + * @param radius radius of the circle + */ +void lv_circ_init(lv_point_t * c, lv_coord_t * tmp, lv_coord_t radius); + +/** + * Test the circle drawing is ready or not + * @param c same as in circ_init + * @return true if the circle is not ready yet + */ +bool lv_circ_cont(lv_point_t * c); + +/** + * Get the next point from the circle + * @param c same as in circ_init. The next point stored here. + * @param tmp same as in circ_init. + */ +void lv_circ_next(lv_point_t * c, lv_coord_t * tmp); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif diff --git a/pros/display/lv_misc/lv_color.h b/pros/display/lv_misc/lv_color.h new file mode 100644 index 00000000..e2da8133 --- /dev/null +++ b/pros/display/lv_misc/lv_color.h @@ -0,0 +1,445 @@ +/** + * @file lv_color.h + * + */ + +#ifndef LV_COLOR_H +#define LV_COLOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +/*Error checking*/ +#if LV_COLOR_DEPTH == 24 +#error "LV_COLOR_DEPTH 24 is deprecated. Use LV_COLOR_DEPTH 32 instead (lv_conf.h)" +#endif + +#if LV_COLOR_DEPTH != 32 && LV_COLOR_SCREEN_TRANSP != 0 +#error "LV_COLOR_SCREEN_TRANSP requires LV_COLOR_DEPTH == 32. Set it in lv_conf.h" +#endif + +#if LV_COLOR_DEPTH != 16 && LV_COLOR_16_SWAP != 0 +#error "LV_COLOR_16_SWAP requires LV_COLOR_DEPTH == 16. Set it in lv_conf.h" +#endif + + +#include + +/********************* + * DEFINES + *********************/ +#define LV_COLOR_WHITE LV_COLOR_MAKE(0xFF,0xFF,0xFF) +#define LV_COLOR_SILVER LV_COLOR_MAKE(0xC0,0xC0,0xC0) +#define LV_COLOR_GRAY LV_COLOR_MAKE(0x80,0x80,0x80) +#define LV_COLOR_BLACK LV_COLOR_MAKE(0x00,0x00,0x00) +#define LV_COLOR_RED LV_COLOR_MAKE(0xFF,0x00,0x00) +#define LV_COLOR_MAROON LV_COLOR_MAKE(0x80,0x00,0x00) +#define LV_COLOR_YELLOW LV_COLOR_MAKE(0xFF,0xFF,0x00) +#define LV_COLOR_OLIVE LV_COLOR_MAKE(0x80,0x80,0x00) +#define LV_COLOR_LIME LV_COLOR_MAKE(0x00,0xFF,0x00) +#define LV_COLOR_GREEN LV_COLOR_MAKE(0x00,0x80,0x00) +#define LV_COLOR_CYAN LV_COLOR_MAKE(0x00,0xFF,0xFF) +#define LV_COLOR_AQUA LV_COLOR_CYAN +#define LV_COLOR_TEAL LV_COLOR_MAKE(0x00,0x80,0x80) +#define LV_COLOR_BLUE LV_COLOR_MAKE(0x00,0x00,0xFF) +#define LV_COLOR_NAVY LV_COLOR_MAKE(0x00,0x00,0x80) +#define LV_COLOR_MAGENTA LV_COLOR_MAKE(0xFF,0x00,0xFF) +#define LV_COLOR_PURPLE LV_COLOR_MAKE(0x80,0x00,0x80) +#define LV_COLOR_ORANGE LV_COLOR_MAKE(0xFF,0xA5,0x00) + +enum { + LV_OPA_TRANSP = 0, + LV_OPA_0 = 0, + LV_OPA_10 = 25, + LV_OPA_20 = 51, + LV_OPA_30 = 76, + LV_OPA_40 = 102, + LV_OPA_50 = 127, + LV_OPA_60 = 153, + LV_OPA_70 = 178, + LV_OPA_80 = 204, + LV_OPA_90 = 229, + LV_OPA_100 = 255, + LV_OPA_COVER = 255, +}; + +#define LV_OPA_MIN 16 /*Opacities below this will be transparent*/ +#define LV_OPA_MAX 251 /*Opacities above this will fully cover*/ + +#if LV_COLOR_DEPTH == 1 +#define LV_COLOR_SIZE 8 +#elif LV_COLOR_DEPTH == 8 +#define LV_COLOR_SIZE 8 +#elif LV_COLOR_DEPTH == 16 +#define LV_COLOR_SIZE 16 +#elif LV_COLOR_DEPTH == 32 +#define LV_COLOR_SIZE 32 +#else +#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!" +#endif + +/********************** + * TYPEDEFS + **********************/ + +typedef union +{ + uint8_t blue :1; + uint8_t green :1; + uint8_t red :1; + uint8_t full :1; +} lv_color1_t; + +typedef union +{ + struct + { + uint8_t blue :2; + uint8_t green :3; + uint8_t red :3; + }; + uint8_t full; +} lv_color8_t; + +typedef union +{ + struct + { +#if LV_COLOR_16_SWAP == 0 + uint16_t blue :5; + uint16_t green :6; + uint16_t red :5; +#else + uint16_t green_h :3; + uint16_t red :5; + uint16_t blue :5; + uint16_t green_l :3; +#endif + }; + uint16_t full; +} lv_color16_t; + +typedef union +{ + struct + { + uint8_t blue; + uint8_t green; + uint8_t red; + uint8_t alpha; + }; + uint32_t full; +} lv_color32_t; + +#if LV_COLOR_DEPTH == 1 +typedef uint8_t lv_color_int_t; +typedef lv_color1_t lv_color_t; +#elif LV_COLOR_DEPTH == 8 +typedef uint8_t lv_color_int_t; +typedef lv_color8_t lv_color_t; +#elif LV_COLOR_DEPTH == 16 +typedef uint16_t lv_color_int_t; +typedef lv_color16_t lv_color_t; +#elif LV_COLOR_DEPTH == 32 +typedef uint32_t lv_color_int_t; +typedef lv_color32_t lv_color_t; +#else +#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!" +#endif + +typedef uint8_t lv_opa_t; + +typedef struct +{ + uint16_t h; + uint8_t s; + uint8_t v; +} lv_color_hsv_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/*In color conversations: + * - When converting to bigger color type the LSB weight of 1 LSB is calculated + * E.g. 16 bit Red has 5 bits + * 8 bit Red has 2 bits + * ---------------------- + * 8 bit red LSB = (2^5 - 1) / (2^2 - 1) = 31 / 3 = 10 + * + * - When calculating to smaller color type simply shift out the LSBs + * E.g. 8 bit Red has 2 bits + * 16 bit Red has 5 bits + * ---------------------- + * Shift right with 5 - 3 = 2 + */ + +static inline uint8_t lv_color_to1(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + return color.full; +#elif LV_COLOR_DEPTH == 8 + if((color.red & 0x4) || + (color.green & 0x4) || + (color.blue & 0x2)) { + return 1; + } else { + return 0; + } +#elif LV_COLOR_DEPTH == 16 +# if LV_COLOR_16_SWAP == 0 + if((color.red & 0x10) || + (color.green & 0x20) || + (color.blue & 0x10)) { + return 1; +# else + if((color.red & 0x10) || + (color.green_h & 0x20) || + (color.blue & 0x10)) { + return 1; +# endif + } else { + return 0; + } +#elif LV_COLOR_DEPTH == 32 + if((color.red & 0x80) || + (color.green & 0x80) || + (color.blue & 0x80)) { + return 1; + } else { + return 0; + } +#endif +} + +static inline uint8_t lv_color_to8(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + if(color.full == 0) return 0; + else return 0xFF; +#elif LV_COLOR_DEPTH == 8 + return color.full; +#elif LV_COLOR_DEPTH == 16 + +# if LV_COLOR_16_SWAP == 0 + lv_color8_t ret; + ret.red = color.red >> 2; /* 5 - 3 = 2*/ + ret.green = color.green >> 3; /* 6 - 3 = 3*/ + ret.blue = color.blue >> 3; /* 5 - 2 = 3*/ + return ret.full; +# else + lv_color8_t ret; + ret.red = color.red >> 2; /* 5 - 3 = 2*/ + ret.green = color.green_h; /* 6 - 3 = 3*/ + ret.blue = color.blue >> 3; /* 5 - 2 = 3*/ + return ret.full; +# endif +#elif LV_COLOR_DEPTH == 32 + lv_color8_t ret; + ret.red = color.red >> 5; /* 8 - 3 = 5*/ + ret.green = color.green >> 5; /* 8 - 3 = 5*/ + ret.blue = color.blue >> 6; /* 8 - 2 = 6*/ + return ret.full; +#endif +} + +static inline uint16_t lv_color_to16(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + if(color.full == 0) return 0; + else return 0xFFFF; +#elif LV_COLOR_DEPTH == 8 + lv_color16_t ret; +# if LV_COLOR_16_SWAP == 0 + ret.red = color.red * 4; /*(2^5 - 1)/(2^3 - 1) = 31/7 = 4*/ + ret.green = color.green * 9; /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/ + ret.blue = color.blue * 10; /*(2^5 - 1)/(2^2 - 1) = 31/3 = 10*/ +# else + ret.red = color.red * 4; + uint8_t g_tmp = color.green * 9; + ret.green_h = (g_tmp & 0x1F) >> 3; + ret.green_l = g_tmp & 0x07; + ret.blue = color.blue * 10; +# endif + return ret.full; +#elif LV_COLOR_DEPTH == 16 + return color.full; +#elif LV_COLOR_DEPTH == 32 + lv_color16_t ret; +# if LV_COLOR_16_SWAP == 0 + ret.red = color.red >> 3; /* 8 - 5 = 3*/ + ret.green = color.green >> 2; /* 8 - 6 = 2*/ + ret.blue = color.blue >> 3; /* 8 - 5 = 3*/ +# else + ret.red = color.red >> 3; + ret.green_h = (color.green & 0xE0) >> 5; + ret.green_l = (color.green & 0x1C) >> 2; + ret.blue = color.blue >> 3; +# endif + return ret.full; +#endif +} + +static inline uint32_t lv_color_to32(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + if(color.full == 0) return 0; + else return 0xFFFFFFFF; +#elif LV_COLOR_DEPTH == 8 + lv_color32_t ret; + ret.red = color.red * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/ + ret.green = color.green * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/ + ret.blue = color.blue * 85; /*(2^8 - 1)/(2^2 - 1) = 255/3 = 85*/ + ret.alpha = 0xFF; + return ret.full; +#elif LV_COLOR_DEPTH == 16 +# if LV_COLOR_16_SWAP == 0 + lv_color32_t ret; + ret.red = color.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.green = color.green * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/ + ret.blue = color.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.alpha = 0xFF; + return ret.full; +# else + lv_color32_t ret; + ret.red = color.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.green = ((color.green_h << 3) + color.green_l) * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/ + ret.blue = color.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.alpha = 0xFF; + return ret.full; +# endif +#elif LV_COLOR_DEPTH == 32 + return color.full; +#endif +} + +static inline lv_color_t lv_color_mix(lv_color_t c1, lv_color_t c2, uint8_t mix) +{ + lv_color_t ret; +#if LV_COLOR_DEPTH != 1 + /*LV_COLOR_DEPTH == 8, 16 or 32*/ + ret.red = (uint16_t)((uint16_t) c1.red * mix + (c2.red * (255 - mix))) >> 8; +# if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP + /*If swapped Green is in 2 parts*/ + uint16_t g_1 = (c1.green_h << 3) + c1.green_l; + uint16_t g_2 = (c2.green_h << 3) + c2.green_l; + uint16_t g_out = (uint16_t)((uint16_t) g_1 * mix + (g_2 * (255 - mix))) >> 8; + ret.green_h = g_out >> 3; + ret.green_l = g_out & 0x7; +# else + ret.green = (uint16_t)((uint16_t) c1.green * mix + (c2.green * (255 - mix))) >> 8; +# endif + ret.blue = (uint16_t)((uint16_t) c1.blue * mix + (c2.blue * (255 - mix))) >> 8; +# if LV_COLOR_DEPTH == 32 + ret.alpha = 0xFF; +# endif +#else + /*LV_COLOR_DEPTH == 1*/ + ret.full = mix > LV_OPA_50 ? c1.full : c2.full; +#endif + + return ret; +} + +/** + * Get the brightness of a color + * @param color a color + * @return the brightness [0..255] + */ +static inline uint8_t lv_color_brightness(lv_color_t color) +{ + lv_color32_t c32; + c32.full = lv_color_to32(color); + uint16_t bright = 3 * c32.red + c32.blue + 4 * c32.green; + return (uint16_t) bright >> 3; +} + +/* The most simple macro to create a color from R,G and B values + * The order of bit field is different on Big-endian and Little-endian machines*/ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#if LV_COLOR_DEPTH == 1 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){(b8 >> 7 | g8 >> 7 | r8 >> 7)}) +#elif LV_COLOR_DEPTH == 8 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 6, g8 >> 5, r8 >> 5}}) +#elif LV_COLOR_DEPTH == 16 +# if LV_COLOR_16_SWAP == 0 +# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 3, g8 >> 2, r8 >> 3}}) +# else +# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{g8 >> 5, r8 >> 3, b8 >> 3, (g8 >> 2) & 0x7}}) +# endif +#elif LV_COLOR_DEPTH == 32 +#ifdef __cplusplus +# define LV_COLOR_MAKE(r8, g8, b8) lv_color_t{b8, g8, r8, 0xff} +#else +# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8, g8, r8, 0xff}}) /*Fix 0xff alpha*/ +#endif +#endif +#else +#if LV_COLOR_DEPTH == 1 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){(r8 >> 7 | g8 >> 7 | b8 >> 7)}) +#elif LV_COLOR_DEPTH == 8 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{r8 >> 6, g8 >> 5, b8 >> 5}}) +#elif LV_COLOR_DEPTH == 16 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{r8 >> 3, g8 >> 2, b8 >> 3}}) +#elif LV_COLOR_DEPTH == 32 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{0xff, r8, g8, b8}}) /*Fix 0xff alpha*/ +#endif +#endif + + +#define LV_COLOR_HEX(c) LV_COLOR_MAKE((uint8_t) ((uint32_t)((uint32_t)c >> 16) & 0xFF), \ + (uint8_t) ((uint32_t)((uint32_t)c >> 8) & 0xFF), \ + (uint8_t) ((uint32_t) c & 0xFF)) + +/*Usage LV_COLOR_HEX3(0x16C) which means LV_COLOR_HEX(0x1166CC)*/ +#define LV_COLOR_HEX3(c) LV_COLOR_MAKE((uint8_t) (((c >> 4) & 0xF0) | ((c >> 8) & 0xF)), \ + (uint8_t) ((uint32_t)(c & 0xF0) | ((c & 0xF0) >> 4)), \ + (uint8_t) ((uint32_t)(c & 0xF) | ((c & 0xF) << 4))) + +static inline lv_color_t lv_color_hex(uint32_t c){ + return LV_COLOR_HEX(c); +} + +static inline lv_color_t lv_color_hex3(uint32_t c){ + return LV_COLOR_HEX3(c); +} + + +/** + * Convert a HSV color to RGB + * @param h hue [0..359] + * @param s saturation [0..100] + * @param v value [0..100] + * @return the given RGB color in RGB (with LV_COLOR_DEPTH depth) + */ +lv_color_t lv_color_hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v); + +/** + * Convert an RGB color to HSV + * @param r red + * @param g green + * @param b blue + * @return the given RGB color n HSV + */ +lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r, uint8_t g, uint8_t b); + + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*USE_COLOR*/ diff --git a/pros/display/lv_misc/lv_font.h b/pros/display/lv_misc/lv_font.h new file mode 100644 index 00000000..0b1675c5 --- /dev/null +++ b/pros/display/lv_misc/lv_font.h @@ -0,0 +1,192 @@ +/** + * @file lv_font.h + * + */ + +#ifndef LV_FONT_H +#define LV_FONT_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include +#include + +#include "lv_symbol_def.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct +{ + uint32_t w_px :8; + uint32_t glyph_index :24; +} lv_font_glyph_dsc_t; + +typedef struct +{ + uint32_t unicode :21; + uint32_t glyph_dsc_index :11; +} lv_font_unicode_map_t; + +typedef struct _lv_font_struct +{ + uint32_t unicode_first; + uint32_t unicode_last; + const uint8_t * glyph_bitmap; + const lv_font_glyph_dsc_t * glyph_dsc; + const uint32_t * unicode_list; + const uint8_t * (*get_bitmap)(const struct _lv_font_struct *,uint32_t); /*Get a glyph's bitmap from a font*/ + int16_t (*get_width)(const struct _lv_font_struct *,uint32_t); /*Get a glyph's with with a given font*/ + struct _lv_font_struct * next_page; /*Pointer to a font extension*/ + uint32_t h_px :8; + uint32_t bpp :4; /*Bit per pixel: 1, 2 or 4*/ + uint32_t monospace :8; /*Fix width (0: normal width)*/ + uint16_t glyph_cnt; /*Number of glyphs (letters) in the font*/ +} lv_font_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the fonts + */ +void lv_font_init(void); + +/** + * Add a font to an other to extend the character set. + * @param child the font to add + * @param parent this font will be extended. Using it later will contain the characters from `child` + */ +void lv_font_add(lv_font_t *child, lv_font_t *parent); + +/** + * Remove a font from a character set. + * @param child the font to remove + * @param parent remove `child` from here + */ +void lv_font_remove(lv_font_t * child, lv_font_t * parent); + +/** + * Tells if font which contains `letter` is monospace or not + * @param font_p point to font + * @param letter an UNICODE character code + * @return true: the letter is monospace; false not monospace + */ +bool lv_font_is_monospace(const lv_font_t * font_p, uint32_t letter); + +/** + * Return with the bitmap of a font. + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return pointer to the bitmap of the letter + */ +const uint8_t * lv_font_get_bitmap(const lv_font_t * font_p, uint32_t letter); + +/** + * Get the width of a letter in a font. If `monospace` is set then return with it. + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return the width of a letter + */ +uint8_t lv_font_get_width(const lv_font_t * font_p, uint32_t letter); + + +/** + * Get the width of the letter without overwriting it with the `monospace` attribute + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return the width of a letter + */ +uint8_t lv_font_get_real_width(const lv_font_t * font_p, uint32_t letter); + +/** + * Get the height of a font + * @param font_p pointer to a font + * @return the height of a font + */ +static inline uint8_t lv_font_get_height(const lv_font_t * font_p) +{ + return font_p->h_px; +} + +/** + * Get the bit-per-pixel of font + * @param font pointer to font + * @param letter a letter from font (font extensions can have different bpp) + * @return bpp of the font (or font extension) + */ +uint8_t lv_font_get_bpp(const lv_font_t * font, uint32_t letter); + +/** + * Generic bitmap get function used in 'font->get_bitmap' when the font contains all characters in the range + * @param font pointer to font + * @param unicode_letter an unicode letter which bitmap should be get + * @return pointer to the bitmap or NULL if not found + */ +const uint8_t * lv_font_get_bitmap_continuous(const lv_font_t * font, uint32_t unicode_letter); + +/** + * Generic bitmap get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse) + * @param font pointer to font + * @param unicode_letter an unicode letter which bitmap should be get + * @return pointer to the bitmap or NULL if not found + */ +const uint8_t * lv_font_get_bitmap_sparse(const lv_font_t * font, uint32_t unicode_letter); +/** + * Generic glyph width get function used in 'font->get_width' when the font contains all characters in the range + * @param font pointer to font + * @param unicode_letter an unicode letter which width should be get + * @return width of the gylph or -1 if not found + */ +int16_t lv_font_get_width_continuous(const lv_font_t * font, uint32_t unicode_letter); + +/** + * Generic glyph width get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse) + * @param font pointer to font + * @param unicode_letter an unicode letter which width should be get + * @return width of the glyph or -1 if not found + */ +int16_t lv_font_get_width_sparse(const lv_font_t * font, uint32_t unicode_letter); + +/********************** + * MACROS + **********************/ + +#define LV_FONT_DECLARE(font_name) extern lv_font_t font_name + + +/********************** + * ADD BUILT IN FONTS + **********************/ +#include "display/lv_fonts/lv_font_builtin.h" + +/*Declare the custom (user defined) fonts*/ +#ifdef LV_FONT_CUSTOM_DECLARE +LV_FONT_CUSTOM_DECLARE +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*USE_FONT*/ + diff --git a/pros/display/lv_misc/lv_fs.h b/pros/display/lv_misc/lv_fs.h new file mode 100644 index 00000000..845b4794 --- /dev/null +++ b/pros/display/lv_misc/lv_fs.h @@ -0,0 +1,277 @@ +/** + * @file lv_fs.h + * + */ + +#ifndef LV_FS_H +#define LV_FS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_FILESYSTEM + +#include +#include +#include "lv_mem.h" + +/********************* + * DEFINES + *********************/ +#define LV_FS_MAX_FN_LENGTH 64 + +/********************** + * TYPEDEFS + **********************/ +enum +{ + LV_FS_RES_OK = 0, + LV_FS_RES_HW_ERR, /*Low level hardware error*/ + LV_FS_RES_FS_ERR, /*Error in the file system structure */ + LV_FS_RES_NOT_EX, /*Driver, file or directory is not exists*/ + LV_FS_RES_FULL, /*Disk full*/ + LV_FS_RES_LOCKED, /*The file is already opened*/ + LV_FS_RES_DENIED, /*Access denied. Check 'fs_open' modes and write protect*/ + LV_FS_RES_BUSY, /*The file system now can't handle it, try later*/ + LV_FS_RES_TOUT, /*Process time outed*/ + LV_FS_RES_NOT_IMP, /*Requested function is not implemented*/ + LV_FS_RES_OUT_OF_MEM, /*Not enough memory for an internal operation*/ + LV_FS_RES_INV_PARAM, /*Invalid parameter among arguments*/ + LV_FS_RES_UNKNOWN, /*Other unknown error*/ +}; +typedef uint8_t lv_fs_res_t; + +struct __lv_fs_drv_t; + +typedef struct +{ + void * file_d; + struct __lv_fs_drv_t* drv; +} lv_fs_file_t; + + +typedef struct +{ + void * dir_d; + struct __lv_fs_drv_t * drv; +} lv_fs_dir_t; + +enum +{ + LV_FS_MODE_WR = 0x01, + LV_FS_MODE_RD = 0x02, +}; +typedef uint8_t lv_fs_mode_t; + +typedef struct __lv_fs_drv_t +{ + char letter; + uint16_t file_size; + uint16_t rddir_size; + bool (*ready) (void); + + lv_fs_res_t (*open) (void * file_p, const char * path, lv_fs_mode_t mode); + lv_fs_res_t (*close) (void * file_p); + lv_fs_res_t (*remove) (const char * fn); + lv_fs_res_t (*read) (void * file_p, void * buf, uint32_t btr, uint32_t * br); + lv_fs_res_t (*write) (void * file_p, const void * buf, uint32_t btw, uint32_t * bw); + lv_fs_res_t (*seek) (void * file_p, uint32_t pos); + lv_fs_res_t (*tell) (void * file_p, uint32_t * pos_p); + lv_fs_res_t (*trunc) (void * file_p); + lv_fs_res_t (*size) (void * file_p, uint32_t * size_p); + lv_fs_res_t (*rename) (const char * oldname, const char * newname); + lv_fs_res_t (*free) (uint32_t * total_p, uint32_t * free_p); + + lv_fs_res_t (*dir_open) (void * rddir_p, const char * path); + lv_fs_res_t (*dir_read) (void * rddir_p, char * fn); + lv_fs_res_t (*dir_close) (void * rddir_p); +} lv_fs_drv_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the File system interface + */ +void lv_fs_init(void); + +/** + * Add a new drive + * @param drv_p pointer to an lv_fs_drv_t structure which is inited with the + * corresponding function pointers. The data will be copied so the variable can be local. + */ +void lv_fs_add_drv(lv_fs_drv_t * drv_p); + +/** + * Test if a drive is rady or not. If the `ready` function was not initialized `true` will be returned. + * @param letter letter of the drive + * @return true: drive is ready; false: drive is not ready + */ +bool lv_fs_is_ready(char letter); + +/** + * Open a file + * @param file_p pointer to a lv_fs_file_t variable + * @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt) + * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_open (lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode); + +/** + * Close an already opened file + * @param file_p pointer to a lv_fs_file_t variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_close (lv_fs_file_t * file_p); + +/** + * Delete a file + * @param path path of the file to delete + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_remove (const char * path); + +/** + * Read from a file + * @param file_p pointer to a lv_fs_file_t variable + * @param buf pointer to a buffer where the read bytes are stored + * @param btr Bytes To Read + * @param br the number of real read bytes (Bytes Read). NULL if unused. + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_read (lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br); + +/** + * Write into a file + * @param file_p pointer to a lv_fs_file_t variable + * @param buf pointer to a buffer with the bytes to write + * @param btr Bytes To Write + * @param br the number of real written bytes (Bytes Written). NULL if unused. + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_write (lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw); + +/** + * Set the position of the 'cursor' (read write pointer) in a file + * @param file_p pointer to a lv_fs_file_t variable + * @param pos the new position expressed in bytes index (0: start of file) + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_seek (lv_fs_file_t * file_p, uint32_t pos); + +/** + * Give the position of the read write pointer + * @param file_p pointer to a lv_fs_file_t variable + * @param pos_p pointer to store the position of the read write pointer + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_fs_tell (lv_fs_file_t * file_p, uint32_t * pos); + +/** + * Truncate the file size to the current position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_fs_open ) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_trunc (lv_fs_file_t * file_p); + +/** + * Give the size of a file bytes + * @param file_p pointer to a lv_fs_file_t variable + * @param size pointer to a variable to store the size + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_size (lv_fs_file_t * file_p, uint32_t * size); + +/** + * Rename a file + * @param oldname path to the file + * @param newname path with the new name + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_fs_rename (const char * oldname, const char * newname); + +/** + * Initialize a 'fs_dir_t' variable for directory reading + * @param rddir_p pointer to a 'fs_read_dir_t' variable + * @param path path to a directory + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path); + +/** + * Read the next filename form a directory. + * The name of the directories will begin with '/' + * @param rddir_p pointer to an initialized 'fs_rdir_t' variable + * @param fn pointer to a buffer to store the filename + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_read (lv_fs_dir_t * rddir_p, char * fn); + +/** + * Close the directory reading + * @param rddir_p pointer to an initialized 'fs_dir_t' variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_close (lv_fs_dir_t * rddir_p); + +/** + * Get the free and total size of a driver in kB + * @param letter the driver letter + * @param total_p pointer to store the total size [kB] + * @param free_p pointer to store the free size [kB] + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_free (char letter, uint32_t * total_p, uint32_t * free_p); + +/** + * Fill a buffer with the letters of existing drivers + * @param buf buffer to store the letters ('\0' added after the last letter) + * @return the buffer + */ +char * lv_fs_get_letters(char * buf); + +/** + * Return with the extension of the filename + * @param fn string with a filename + * @return pointer to the beginning extension or empty string if no extension + */ +const char * lv_fs_get_ext(const char * fn); + +/** + * Step up one level + * @param path pointer to a file name + * @return the truncated file name + */ +char * lv_fs_up(char * path); + +/** + * Get the last element of a path (e.g. U:/folder/file -> file) + * @param buf buffer to store the letters ('\0' added after the last letter) + * @return pointer to the beginning of the last element in the path + */ +const char * lv_fs_get_last(const char * path); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_FILESYSTEM*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_FS_H*/ diff --git a/pros/display/lv_misc/lv_gc.h b/pros/display/lv_misc/lv_gc.h new file mode 100644 index 00000000..e3d0d8ac --- /dev/null +++ b/pros/display/lv_misc/lv_gc.h @@ -0,0 +1,77 @@ +/** + * @file lv_gc.h + * + */ + +#ifndef LV_GC_H +#define LV_GC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include +#include "lv_mem.h" +#include "lv_ll.h" + +/********************* + * DEFINES + *********************/ + +#define LV_GC_ROOTS(prefix) \ + prefix lv_ll_t _lv_task_ll; /*Linked list to store the lv_tasks*/ \ + prefix lv_ll_t _lv_scr_ll; /*Linked list of screens*/ \ + prefix lv_ll_t _lv_drv_ll;\ + prefix lv_ll_t _lv_file_ll;\ + prefix lv_ll_t _lv_anim_ll;\ + prefix void * _lv_def_scr;\ + prefix void * _lv_act_scr;\ + prefix void * _lv_top_layer;\ + prefix void * _lv_sys_layer;\ + prefix void * _lv_task_act;\ + prefix void * _lv_indev_list;\ + prefix void * _lv_disp_list;\ + + +#define LV_NO_PREFIX +#define LV_ROOTS LV_GC_ROOTS(LV_NO_PREFIX) + +#if LV_ENABLE_GC == 1 +# if LV_MEM_CUSTOM != 1 +# error "GC requires CUSTOM_MEM" +# endif /* LV_MEM_CUSTOM */ +#else /* LV_ENABLE_GC */ +# define LV_GC_ROOT(x) x + LV_GC_ROOTS(extern) +#endif /* LV_ENABLE_GC */ + + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GC_H*/ diff --git a/pros/display/lv_misc/lv_ll.h b/pros/display/lv_misc/lv_ll.h new file mode 100644 index 00000000..086ba405 --- /dev/null +++ b/pros/display/lv_misc/lv_ll.h @@ -0,0 +1,145 @@ +/** + * @file lv_ll.c + * Handle linked lists. The nodes are dynamically allocated by the 'lv_mem' module. + */ + +#ifndef LV_LL_H +#define LV_LL_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include "lv_mem.h" +#include +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Dummy type to make handling easier*/ +typedef uint8_t lv_ll_node_t; + +/*Description of a linked list*/ +typedef struct +{ + uint32_t n_size; + lv_ll_node_t* head; + lv_ll_node_t* tail; +} lv_ll_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize linked list + * @param ll_dsc pointer to ll_dsc variable + * @param node_size the size of 1 node in bytes + */ +void lv_ll_init(lv_ll_t * ll_p, uint32_t node_size); + +/** + * Add a new head to a linked list + * @param ll_p pointer to linked list + * @return pointer to the new head + */ +void * lv_ll_ins_head(lv_ll_t * ll_p); + +/** + * Insert a new node in front of the n_act node + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the new head + */ +void * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act); + +/** + * Add a new tail to a linked list + * @param ll_p pointer to linked list + * @return pointer to the new tail + */ +void * lv_ll_ins_tail(lv_ll_t * ll_p); + +/** + * Remove the node 'node_p' from 'll_p' linked list. + * It does not free the the memory of node. + * @param ll_p pointer to the linked list of 'node_p' + * @param node_p pointer to node in 'll_p' linked list + */ +void lv_ll_rem(lv_ll_t * ll_p, void * node_p); + +/** + * Remove and free all elements from a linked list. The list remain valid but become empty. + * @param ll_p pointer to linked list + */ +void lv_ll_clear(lv_ll_t * ll_p); + +/** + * Move a node to a new linked list + * @param ll_ori_p pointer to the original (old) linked list + * @param ll_new_p pointer to the new linked list + * @param node pointer to a node + */ +void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node); + +/** + * Return with head node of the linked list + * @param ll_p pointer to linked list + * @return pointer to the head of 'll_p' + */ +void * lv_ll_get_head(const lv_ll_t * ll_p); + +/** + * Return with tail node of the linked list + * @param ll_p pointer to linked list + * @return pointer to the head of 'll_p' + */ +void * lv_ll_get_tail(const lv_ll_t * ll_p); + +/** + * Return with the pointer of the next node after 'n_act' + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the next node + */ +void * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act); + +/** + * Return with the pointer of the previous node after 'n_act' + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the previous node + */ +void * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act); + +/** + * Move a nodw before an other node in the same linked list + * @param ll_p pointer to a linked list + * @param n_act pointer to node to move + * @param n_after pointer to a node which should be after `n_act` + */ +void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after); + +/********************** + * MACROS + **********************/ + +#define LL_READ(list, i) for(i = lv_ll_get_head(&list); i != NULL; i = lv_ll_get_next(&list, i)) + +#define LL_READ_BACK(list, i) for(i = lv_ll_get_tail(&list); i != NULL; i = lv_ll_get_prev(&list, i)) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/pros/display/lv_misc/lv_log.h b/pros/display/lv_misc/lv_log.h new file mode 100644 index 00000000..adcb846d --- /dev/null +++ b/pros/display/lv_misc/lv_log.h @@ -0,0 +1,86 @@ +/** + * @file lv_log.h + * + */ + +#ifndef LV_LOG_H +#define LV_LOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif +#include + +/********************* + * DEFINES + *********************/ + +/*Possible log level. For compatibility declare it independently from `USE_LV_LOG`*/ + +#define LV_LOG_LEVEL_TRACE 0 /*A lot of logs to give detailed information*/ +#define LV_LOG_LEVEL_INFO 1 /*Log important events*/ +#define LV_LOG_LEVEL_WARN 2 /*Log if something unwanted happened but didn't caused problem*/ +#define LV_LOG_LEVEL_ERROR 3 /*Only critical issue, when the system may fail*/ +#define _LV_LOG_LEVEL_NUM 4 + +typedef int8_t lv_log_level_t; + +#if USE_LV_LOG +/********************** + * TYPEDEFS + **********************/ + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Register custom print (or anything else) function to call when log is added + * @param f a function pointer: + * `void my_print (lv_log_level_t level, const char * file, uint32_t line, const char * dsc)` + */ +void lv_log_register_print(void f(lv_log_level_t, const char *, uint32_t, const char *)); + +/** + * Add a log + * @param level the level of log. (From `lv_log_level_t` enum) + * @param file name of the file when the log added + * @param line line number in the source code where the log added + * @param dsc description of the log + */ +void lv_log_add(lv_log_level_t level, const char * file, int line, const char * dsc); + +/********************** + * MACROS + **********************/ + +#define LV_LOG_TRACE(dsc) lv_log_add(LV_LOG_LEVEL_TRACE, __FILE__, __LINE__, dsc); +#define LV_LOG_INFO(dsc) lv_log_add(LV_LOG_LEVEL_INFO, __FILE__, __LINE__, dsc); +#define LV_LOG_WARN(dsc) lv_log_add(LV_LOG_LEVEL_WARN, __FILE__, __LINE__, dsc); +#define LV_LOG_ERROR(dsc) lv_log_add(LV_LOG_LEVEL_ERROR, __FILE__, __LINE__, dsc); + +#else /*USE_LV_LOG*/ + +/*Do nothing if `USE_LV_LOG 0`*/ +#define lv_log_add(level, file, line, dsc) {;} +#define LV_LOG_TRACE(dsc) {;} +#define LV_LOG_INFO(dsc) {;} +#define LV_LOG_WARN(dsc) {;} +#define LV_LOG_ERROR(dsc) {;} +#endif /*USE_LV_LOG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LOG_H*/ diff --git a/pros/display/lv_misc/lv_math.h b/pros/display/lv_misc/lv_math.h new file mode 100644 index 00000000..a0229eb1 --- /dev/null +++ b/pros/display/lv_misc/lv_math.h @@ -0,0 +1,73 @@ +/** + * @file math_base.h + * + */ + +#ifndef LV_MATH_H +#define LV_MATH_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include + +/********************* + * DEFINES + *********************/ +#define LV_MATH_MIN(a,b) ((a) < (b) ? (a) : (b)) +#define LV_MATH_MAX(a,b) ((a) > (b) ? (a) : (b)) +#define LV_MATH_ABS(x) ((x) > 0 ? (x) : (-(x))) + +#define LV_TRIGO_SIN_MAX 32767 +#define LV_TRIGO_SHIFT 15 /* >> LV_TRIGO_SHIFT to normalize*/ + +#define LV_BEZIER_VAL_MAX 1024 /*Max time in Bezier functions (not [0..1] to use integers) */ +#define LV_BEZIER_VAL_SHIFT 10 /*log2(LV_BEZIER_VAL_MAX): used to normalize up scaled values*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/** + * Convert a number to string + * @param num a number + * @param buf pointer to a `char` buffer. The result will be stored here (max 10 elements) + * @return same as `buf` (just for convenience) + */ +char * lv_math_num_to_str(int32_t num, char * buf); + +/** + * Return with sinus of an angle + * @param angle + * @return sinus of 'angle'. sin(-90) = -32767, sin(90) = 32767 + */ +int16_t lv_trigo_sin(int16_t angle); + +/** + * Calculate a value of a Cubic Bezier function. + * @param t time in range of [0..LV_BEZIER_VAL_MAX] + * @param u0 start values in range of [0..LV_BEZIER_VAL_MAX] + * @param u1 control value 1 values in range of [0..LV_BEZIER_VAL_MAX] + * @param u2 control value 2 in range of [0..LV_BEZIER_VAL_MAX] + * @param u3 end values in range of [0..LV_BEZIER_VAL_MAX] + * @return the value calculated from the given parameters in range of [0..LV_BEZIER_VAL_MAX] + */ +int32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/pros/display/lv_misc/lv_mem.h b/pros/display/lv_misc/lv_mem.h new file mode 100644 index 00000000..77429018 --- /dev/null +++ b/pros/display/lv_misc/lv_mem.h @@ -0,0 +1,127 @@ +/** + * @file lv_mem.h + * + */ + +#ifndef LV_MEM_H +#define LV_MEM_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include +#include "lv_log.h" + +/********************* + * DEFINES + *********************/ +// Check windows +#ifdef __WIN64 +# define LV_MEM_ENV64 +#endif + +// Check GCC +#ifdef __GNUC__ +# if defined(__x86_64__) || defined(__ppc64__) +# define LV_MEM_ENV64 +# endif +#endif + +/********************** + * TYPEDEFS + **********************/ + +typedef struct +{ + uint32_t total_size; + uint32_t free_cnt; + uint32_t free_size; + uint32_t free_biggest_size; + uint32_t used_cnt; + uint8_t used_pct; + uint8_t frag_pct; +} lv_mem_monitor_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Initiaize the dyn_mem module (work memory and other variables) + */ +void lv_mem_init(void); + +/** + * Allocate a memory dynamically + * @param size size of the memory to allocate in bytes + * @return pointer to the allocated memory + */ +void * lv_mem_alloc(uint32_t size); + +/** + * Free an allocated data + * @param data pointer to an allocated memory + */ +void lv_mem_free(const void * data); + +/** + * Reallocate a memory with a new size. The old content will be kept. + * @param data pointer to an allocated memory. + * Its content will be copied to the new memory block and freed + * @param new_size the desired new size in byte + * @return pointer to the new memory + */ +void * lv_mem_realloc(void * data_p, uint32_t new_size); + +/** + * Join the adjacent free memory blocks + */ +void lv_mem_defrag(void); + +/** + * Give information about the work memory of dynamic allocation + * @param mon_p pointer to a dm_mon_p variable, + * the result of the analysis will be stored here + */ +void lv_mem_monitor(lv_mem_monitor_t * mon_p); + +/** + * Give the size of an allocated memory + * @param data pointer to an allocated memory + * @return the size of data memory in bytes + */ +uint32_t lv_mem_get_size(const void * data); + + +/********************** + * MACROS + **********************/ + +/** + * Halt on NULL pointer + * p pointer to a memory + */ +#if USE_LV_LOG == 0 +# define lv_mem_assert(p) {if(p == NULL) while(1); } +#else +# define lv_mem_assert(p) {if(p == NULL) {LV_LOG_ERROR("Out of memory!"); while(1); }} +#endif +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_MEM_H*/ + diff --git a/pros/display/lv_misc/lv_misc.mk b/pros/display/lv_misc/lv_misc.mk new file mode 100644 index 00000000..470f1230 --- /dev/null +++ b/pros/display/lv_misc/lv_misc.mk @@ -0,0 +1,19 @@ +CSRCS += lv_font.c +CSRCS += lv_circ.c +CSRCS += lv_area.c +CSRCS += lv_task.c +CSRCS += lv_fs.c +CSRCS += lv_anim.c +CSRCS += lv_mem.c +CSRCS += lv_ll.c +CSRCS += lv_color.c +CSRCS += lv_txt.c +CSRCS += lv_ufs.c +CSRCS += lv_math.c +CSRCS += lv_log.c +CSRCS += lv_gc.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_misc +VPATH += :$(LVGL_DIR)/lvgl/lv_misc + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_misc" diff --git a/pros/display/lv_misc/lv_symbol_def.h b/pros/display/lv_misc/lv_symbol_def.h new file mode 100644 index 00000000..6ba6241c --- /dev/null +++ b/pros/display/lv_misc/lv_symbol_def.h @@ -0,0 +1,207 @@ +#ifndef LV_SYMBOL_DEF_H +#define LV_SYMBOL_DEF_H + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +/* + * With no UTF-8 support (192- 255) (192..241 is used) + * + * With UTF-8 support (in Supplemental Private Use Area-A): 0xF800 .. 0xF831 + * - Basic symbols: 0xE000..0xE01F + * - File symbols: 0xE020..0xE03F + * - Feedback symbols: 0xE040..0xE05F + * - Reserved: 0xE060..0xE07F + */ + +#if LV_TXT_UTF8 == 0 +#define LV_SYMBOL_GLYPH_FIRST 0xC0 +#define SYMBOL_AUDIO _SYMBOL_VALUE1(C0) +#define SYMBOL_VIDEO _SYMBOL_VALUE1(C1) +#define SYMBOL_LIST _SYMBOL_VALUE1(C2) +#define SYMBOL_OK _SYMBOL_VALUE1(C3) +#define SYMBOL_CLOSE _SYMBOL_VALUE1(C4) +#define SYMBOL_POWER _SYMBOL_VALUE1(C5) +#define SYMBOL_SETTINGS _SYMBOL_VALUE1(C6) +#define SYMBOL_TRASH _SYMBOL_VALUE1(C7) +#define SYMBOL_HOME _SYMBOL_VALUE1(C8) +#define SYMBOL_DOWNLOAD _SYMBOL_VALUE1(C9) +#define SYMBOL_DRIVE _SYMBOL_VALUE1(CA) +#define SYMBOL_REFRESH _SYMBOL_VALUE1(CB) +#define SYMBOL_MUTE _SYMBOL_VALUE1(CC) +#define SYMBOL_VOLUME_MID _SYMBOL_VALUE1(CD) +#define SYMBOL_VOLUME_MAX _SYMBOL_VALUE1(CE) +#define SYMBOL_IMAGE _SYMBOL_VALUE1(CF) +#define SYMBOL_EDIT _SYMBOL_VALUE1(D0) +#define SYMBOL_PREV _SYMBOL_VALUE1(D1) +#define SYMBOL_PLAY _SYMBOL_VALUE1(D2) +#define SYMBOL_PAUSE _SYMBOL_VALUE1(D3) +#define SYMBOL_STOP _SYMBOL_VALUE1(D4) +#define SYMBOL_NEXT _SYMBOL_VALUE1(D5) +#define SYMBOL_EJECT _SYMBOL_VALUE1(D6) +#define SYMBOL_LEFT _SYMBOL_VALUE1(D7) +#define SYMBOL_RIGHT _SYMBOL_VALUE1(D8) +#define SYMBOL_PLUS _SYMBOL_VALUE1(D9) +#define SYMBOL_MINUS _SYMBOL_VALUE1(DA) +#define SYMBOL_WARNING _SYMBOL_VALUE1(DB) +#define SYMBOL_SHUFFLE _SYMBOL_VALUE1(DC) +#define SYMBOL_UP _SYMBOL_VALUE1(DD) +#define SYMBOL_DOWN _SYMBOL_VALUE1(DE) +#define SYMBOL_LOOP _SYMBOL_VALUE1(DF) +#define SYMBOL_DIRECTORY _SYMBOL_VALUE1(E0) +#define SYMBOL_UPLOAD _SYMBOL_VALUE1(E1) +#define SYMBOL_CALL _SYMBOL_VALUE1(E2) +#define SYMBOL_CUT _SYMBOL_VALUE1(E3) +#define SYMBOL_COPY _SYMBOL_VALUE1(E4) +#define SYMBOL_SAVE _SYMBOL_VALUE1(E5) +#define SYMBOL_CHARGE _SYMBOL_VALUE1(E6) +#define SYMBOL_BELL _SYMBOL_VALUE1(E7) +#define SYMBOL_KEYBOARD _SYMBOL_VALUE1(E8) +#define SYMBOL_GPS _SYMBOL_VALUE1(E9) +#define SYMBOL_FILE _SYMBOL_VALUE1(EA) +#define SYMBOL_WIFI _SYMBOL_VALUE1(EB) +#define SYMBOL_BATTERY_FULL _SYMBOL_VALUE1(EC) +#define SYMBOL_BATTERY_3 _SYMBOL_VALUE1(ED) +#define SYMBOL_BATTERY_2 _SYMBOL_VALUE1(EE) +#define SYMBOL_BATTERY_1 _SYMBOL_VALUE1(EF) +#define SYMBOL_BATTERY_EMPTY _SYMBOL_VALUE1(F0) +#define SYMBOL_BLUETOOTH _SYMBOL_VALUE1(F1) +#define LV_SYMBOL_GLYPH_LAST 0xF1 +#define SYMBOL_DUMMY _SYMBOL_VALUE1(FF) /*Invalid symbol. If written before a string then `lv_img` will show it as a label*/ + +#else +#define LV_SYMBOL_GLYPH_FIRST 0xF800 +#define SYMBOL_AUDIO _SYMBOL_VALUE3(EF,A0,80) +#define SYMBOL_VIDEO _SYMBOL_VALUE3(EF,A0,81) +#define SYMBOL_LIST _SYMBOL_VALUE3(EF,A0,82) +#define SYMBOL_OK _SYMBOL_VALUE3(EF,A0,83) +#define SYMBOL_CLOSE _SYMBOL_VALUE3(EF,A0,84) +#define SYMBOL_POWER _SYMBOL_VALUE3(EF,A0,85) +#define SYMBOL_SETTINGS _SYMBOL_VALUE3(EF,A0,86) +#define SYMBOL_TRASH _SYMBOL_VALUE3(EF,A0,87) +#define SYMBOL_HOME _SYMBOL_VALUE3(EF,A0,88) +#define SYMBOL_DOWNLOAD _SYMBOL_VALUE3(EF,A0,89) +#define SYMBOL_DRIVE _SYMBOL_VALUE3(EF,A0,8A) +#define SYMBOL_REFRESH _SYMBOL_VALUE3(EF,A0,8B) +#define SYMBOL_MUTE _SYMBOL_VALUE3(EF,A0,8C) +#define SYMBOL_VOLUME_MID _SYMBOL_VALUE3(EF,A0,8D) +#define SYMBOL_VOLUME_MAX _SYMBOL_VALUE3(EF,A0,8E) +#define SYMBOL_IMAGE _SYMBOL_VALUE3(EF,A0,8F) +#define SYMBOL_EDIT _SYMBOL_VALUE3(EF,A0,90) +#define SYMBOL_PREV _SYMBOL_VALUE3(EF,A0,91) +#define SYMBOL_PLAY _SYMBOL_VALUE3(EF,A0,92) +#define SYMBOL_PAUSE _SYMBOL_VALUE3(EF,A0,93) +#define SYMBOL_STOP _SYMBOL_VALUE3(EF,A0,94) +#define SYMBOL_NEXT _SYMBOL_VALUE3(EF,A0,95) +#define SYMBOL_EJECT _SYMBOL_VALUE3(EF,A0,96) +#define SYMBOL_LEFT _SYMBOL_VALUE3(EF,A0,97) +#define SYMBOL_RIGHT _SYMBOL_VALUE3(EF,A0,98) +#define SYMBOL_PLUS _SYMBOL_VALUE3(EF,A0,99) +#define SYMBOL_MINUS _SYMBOL_VALUE3(EF,A0,9A) +#define SYMBOL_WARNING _SYMBOL_VALUE3(EF,A0,9B) +#define SYMBOL_SHUFFLE _SYMBOL_VALUE3(EF,A0,9C) +#define SYMBOL_UP _SYMBOL_VALUE3(EF,A0,9D) +#define SYMBOL_DOWN _SYMBOL_VALUE3(EF,A0,9E) +#define SYMBOL_LOOP _SYMBOL_VALUE3(EF,A0,9F) +#define SYMBOL_DIRECTORY _SYMBOL_VALUE3(EF,A0,A0) +#define SYMBOL_UPLOAD _SYMBOL_VALUE3(EF,A0,A1) +#define SYMBOL_CALL _SYMBOL_VALUE3(EF,A0,A2) +#define SYMBOL_CUT _SYMBOL_VALUE3(EF,A0,A3) +#define SYMBOL_COPY _SYMBOL_VALUE3(EF,A0,A4) +#define SYMBOL_SAVE _SYMBOL_VALUE3(EF,A0,A5) +#define SYMBOL_CHARGE _SYMBOL_VALUE3(EF,A0,A6) +#define SYMBOL_BELL _SYMBOL_VALUE3(EF,A0,A7) +#define SYMBOL_KEYBOARD _SYMBOL_VALUE3(EF,A0,A8) +#define SYMBOL_GPS _SYMBOL_VALUE3(EF,A0,A9) +#define SYMBOL_FILE _SYMBOL_VALUE3(EF,A0,AA) +#define SYMBOL_WIFI _SYMBOL_VALUE3(EF,A0,AB) +#define SYMBOL_BATTERY_FULL _SYMBOL_VALUE3(EF,A0,AC) +#define SYMBOL_BATTERY_3 _SYMBOL_VALUE3(EF,A0,AD) +#define SYMBOL_BATTERY_2 _SYMBOL_VALUE3(EF,A0,AE) +#define SYMBOL_BATTERY_1 _SYMBOL_VALUE3(EF,A0,AF) +#define SYMBOL_BATTERY_EMPTY _SYMBOL_VALUE3(EF,A0,B0) +#define SYMBOL_BLUETOOTH _SYMBOL_VALUE3(EF,A0,B1) +#define LV_SYMBOL_GLYPH_LAST 0xF831 +#define SYMBOL_DUMMY _SYMBOL_VALUE3(EF,A3,BF) /*Invalid symbol at (U+F831). If written before a string then `lv_img` will show it as a label*/ +#endif + +#define _SYMBOL_VALUE1(x) (0x ## x) +#define _SYMBOL_VALUE3(x, y, z) (0x ## z ## y ## x) +#define _SYMBOL_NUMSTR(sym) LV_ ## sym ## _NUMSTR = sym + +enum +{ + _SYMBOL_NUMSTR(SYMBOL_AUDIO), + _SYMBOL_NUMSTR(SYMBOL_VIDEO), + _SYMBOL_NUMSTR(SYMBOL_LIST), + _SYMBOL_NUMSTR(SYMBOL_OK), + _SYMBOL_NUMSTR(SYMBOL_CLOSE), + _SYMBOL_NUMSTR(SYMBOL_POWER), + _SYMBOL_NUMSTR(SYMBOL_SETTINGS), + _SYMBOL_NUMSTR(SYMBOL_TRASH), + _SYMBOL_NUMSTR(SYMBOL_HOME), + _SYMBOL_NUMSTR(SYMBOL_DOWNLOAD), + _SYMBOL_NUMSTR(SYMBOL_DRIVE), + _SYMBOL_NUMSTR(SYMBOL_REFRESH), + _SYMBOL_NUMSTR(SYMBOL_MUTE), + _SYMBOL_NUMSTR(SYMBOL_VOLUME_MID), + _SYMBOL_NUMSTR(SYMBOL_VOLUME_MAX), + _SYMBOL_NUMSTR(SYMBOL_IMAGE), + _SYMBOL_NUMSTR(SYMBOL_EDIT), + _SYMBOL_NUMSTR(SYMBOL_PREV), + _SYMBOL_NUMSTR(SYMBOL_PLAY), + _SYMBOL_NUMSTR(SYMBOL_PAUSE), + _SYMBOL_NUMSTR(SYMBOL_STOP), + _SYMBOL_NUMSTR(SYMBOL_NEXT), + _SYMBOL_NUMSTR(SYMBOL_EJECT), + _SYMBOL_NUMSTR(SYMBOL_LEFT), + _SYMBOL_NUMSTR(SYMBOL_RIGHT), + _SYMBOL_NUMSTR(SYMBOL_PLUS), + _SYMBOL_NUMSTR(SYMBOL_MINUS), + _SYMBOL_NUMSTR(SYMBOL_WARNING), + _SYMBOL_NUMSTR(SYMBOL_SHUFFLE), + _SYMBOL_NUMSTR(SYMBOL_UP), + _SYMBOL_NUMSTR(SYMBOL_DOWN), + _SYMBOL_NUMSTR(SYMBOL_LOOP), + _SYMBOL_NUMSTR(SYMBOL_DIRECTORY), + _SYMBOL_NUMSTR(SYMBOL_UPLOAD), + _SYMBOL_NUMSTR(SYMBOL_CALL), + _SYMBOL_NUMSTR(SYMBOL_CUT), + _SYMBOL_NUMSTR(SYMBOL_COPY), + _SYMBOL_NUMSTR(SYMBOL_SAVE), + _SYMBOL_NUMSTR(SYMBOL_CHARGE), + _SYMBOL_NUMSTR(SYMBOL_BELL), + _SYMBOL_NUMSTR(SYMBOL_KEYBOARD), + _SYMBOL_NUMSTR(SYMBOL_GPS), + _SYMBOL_NUMSTR(SYMBOL_FILE), + _SYMBOL_NUMSTR(SYMBOL_WIFI), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_FULL), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_3), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_2), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_1), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_EMPTY), + _SYMBOL_NUMSTR(SYMBOL_BLUETOOTH), + _SYMBOL_NUMSTR(SYMBOL_DUMMY), +}; + +#undef _SYMBOL_VALUE1 +#undef _SYMBOL_VALUE3 + +#define _SYMBOL_STR_(x) #x +#define _SYMBOL_STR(x) _SYMBOL_STR_(x) +#define _SYMBOL_CHAR(c) \x ## c +#define _SYMBOL_VALUE1(x) _SYMBOL_STR(_SYMBOL_CHAR(x)) +#define _SYMBOL_VALUE3(x, y, z) _SYMBOL_STR(_SYMBOL_CHAR(x)_SYMBOL_CHAR(y)_SYMBOL_CHAR(z)) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /*LV_SYMBOL_DEF_H*/ diff --git a/pros/display/lv_misc/lv_task.h b/pros/display/lv_misc/lv_task.h new file mode 100644 index 00000000..6cac3efd --- /dev/null +++ b/pros/display/lv_misc/lv_task.h @@ -0,0 +1,149 @@ +/** + * @file lv_task.c + * An 'lv_task' is a void (*fp) (void* param) type function which will be called periodically. + * A priority (5 levels + disable) can be assigned to lv_tasks. + */ + +#ifndef LV_TASK_H +#define LV_TASK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include +#include "lv_mem.h" +#include "lv_ll.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_ATTRIBUTE_TASK_HANDLER +#define LV_ATTRIBUTE_TASK_HANDLER +#endif +/********************** + * TYPEDEFS + **********************/ +/** + * Possible priorities for lv_tasks + */ +enum +{ + LV_TASK_PRIO_OFF = 0, + LV_TASK_PRIO_LOWEST, + LV_TASK_PRIO_LOW, + LV_TASK_PRIO_MID, + LV_TASK_PRIO_HIGH, + LV_TASK_PRIO_HIGHEST, + LV_TASK_PRIO_NUM, +}; +typedef uint8_t lv_task_prio_t; + +/** + * Descriptor of a lv_task + */ +typedef struct +{ + uint32_t period; + uint32_t last_run; + void (*task) (void*); + void * param; + uint8_t prio:3; + uint8_t once:1; +} lv_task_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init the lv_task module + */ +void lv_task_init(void); + +/** + * Call it periodically to handle lv_tasks. + */ +LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void); + +/** + * Create a new lv_task + * @param task a function which is the task itself + * @param period call period in ms unit + * @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped) + * @param param free parameter + * @return pointer to the new task + */ +lv_task_t* lv_task_create(void (*task) (void *), uint32_t period, lv_task_prio_t prio, void * param); + +/** + * Delete a lv_task + * @param lv_task_p pointer to task created by lv_task_p + */ +void lv_task_del(lv_task_t* lv_task_p); + +/** + * Set new priority for a lv_task + * @param lv_task_p pointer to a lv_task + * @param prio the new priority + */ +void lv_task_set_prio(lv_task_t* lv_task_p, lv_task_prio_t prio); + +/** + * Set new period for a lv_task + * @param lv_task_p pointer to a lv_task + * @param period the new period + */ +void lv_task_set_period(lv_task_t* lv_task_p, uint32_t period); + +/** + * Make a lv_task ready. It will not wait its period. + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_ready(lv_task_t* lv_task_p); + + +/** + * Delete the lv_task after one call + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_once(lv_task_t * lv_task_p); + +/** + * Reset a lv_task. + * It will be called the previously set period milliseconds later. + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_reset(lv_task_t* lv_task_p); + +/** + * Enable or disable the whole lv_task handling + * @param en: true: lv_task handling is running, false: lv_task handling is suspended + */ +void lv_task_enable(bool en); + +/** + * Get idle percentage + * @return the lv_task idle in percentage + */ +uint8_t lv_task_get_idle(void); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/pros/display/lv_misc/lv_templ.h b/pros/display/lv_misc/lv_templ.h new file mode 100644 index 00000000..a5459e8d --- /dev/null +++ b/pros/display/lv_misc/lv_templ.h @@ -0,0 +1,38 @@ +/** + * @file lv_templ.h + * + */ + +#ifndef LV_TEMPL_H +#define LV_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/pros/display/lv_misc/lv_txt.h b/pros/display/lv_misc/lv_txt.h new file mode 100644 index 00000000..2e98b60e --- /dev/null +++ b/pros/display/lv_misc/lv_txt.h @@ -0,0 +1,198 @@ +/** + * @file lv_text.h + * + */ + +#ifndef LV_TXT_H +#define LV_TXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include "lv_area.h" +#include "lv_font.h" +#include "lv_area.h" + +/********************* + * DEFINES + *********************/ +#define LV_TXT_COLOR_CMD "#" + +/********************** + * TYPEDEFS + **********************/ +enum +{ + LV_TXT_FLAG_NONE = 0x00, + LV_TXT_FLAG_RECOLOR = 0x01, /*Enable parsing of recolor command*/ + LV_TXT_FLAG_EXPAND = 0x02, /*Ignore width to avoid automatic word wrapping*/ + LV_TXT_FLAG_CENTER = 0x04, /*Align the text to the middle*/ + LV_TXT_FLAG_RIGHT = 0x08, /*Align the text to the right*/ +}; +typedef uint8_t lv_txt_flag_t; + +enum +{ + LV_TXT_CMD_STATE_WAIT, /*Waiting for command*/ + LV_TXT_CMD_STATE_PAR, /*Processing the parameter*/ + LV_TXT_CMD_STATE_IN, /*Processing the command*/ +}; +typedef uint8_t lv_txt_cmd_state_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Get size of a text + * @param size_res pointer to a 'point_t' variable to store the result + * @param text pointer to a text + * @param font pinter to font of the text + * @param letter_space letter space of the text + * @param line_space line space of the text + * @param flags settings for the text from 'txt_flag_t' enum + * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks + */ +void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t line_space, lv_coord_t max_width, lv_txt_flag_t flag); + +/** + * Get the next line of text. Check line length and break chars too. + * @param txt a '\0' terminated string + * @param font pointer to a font + * @param letter_space letter space + * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks + * @param flags settings for the text from 'txt_flag_type' enum + * @return the index of the first char of the new line (in byte index not letter index. With UTF-8 they are different) + */ +uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t max_width, lv_txt_flag_t flag); + +/** + * Give the length of a text with a given font + * @param txt a '\0' terminate string + * @param length length of 'txt' in byte count and not characters (Á is 1 character but 2 bytes in UTF-8) + * @param font pointer to a font + * @param letter_space letter space + * @param flags settings for the text from 'txt_flag_t' enum + * @return length of a char_num long text + */ +lv_coord_t lv_txt_get_width(const char * txt, uint16_t length, + const lv_font_t * font, lv_coord_t letter_space, lv_txt_flag_t flag); + + +/** + * Check next character in a string and decide if te character is part of the command or not + * @param state pointer to a txt_cmd_state_t variable which stores the current state of command processing + * @param c the current character + * @return true: the character is part of a command and should not be written, + * false: the character should be written + */ +bool lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c); + +/** + * Insert a string into an other + * @param txt_buf the original text (must be big enough for the result text) + * @param pos position to insert (0: before the original text, 1: after the first char etc.) + * @param ins_txt text to insert + */ +void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt); + +/** + * Delete a part of a string + * @param txt string to modify + * @param pos position where to start the deleting (0: before the first char, 1: after the first char etc.) + * @param len number of characters to delete + */ +void lv_txt_cut(char * txt, uint32_t pos, uint32_t len); + +/*************************************************************** + * GLOBAL FUNCTION POINTERS FOR CAHRACTER ENCODING INTERFACE + ***************************************************************/ + +/** + * Give the size of an encoded character + * @param str pointer to a character in a string + * @return length of the encoded character (1,2,3 ...). O in invalid + */ +extern uint8_t (*lv_txt_encoded_size)(const char *); + + +/** + * Convert an Unicode letter to encoded + * @param letter_uni an Unicode letter + * @return Encoded character in Little Endian to be compatible with C chars (e.g. 'Á', 'Ü') + */ +extern uint32_t (*lv_txt_unicode_to_encoded)(uint32_t ); + +/** + * Convert a wide character, e.g. 'Á' little endian to be compatible with the encoded format. + * @param c a wide character + * @return `c` in the encoded format + */ +extern uint32_t (*lv_txt_encoded_conv_wc) (uint32_t c); + +/** + * Decode the next encoded character from a string. + * @param txt pointer to '\0' terminated string + * @param i start index in 'txt' where to start. + * After the call it will point to the next encoded char in 'txt'. + * NULL to use txt[0] as index + * @return the decoded Unicode character or 0 on invalid data code + */ +extern uint32_t (*lv_txt_encoded_next)(const char *, uint32_t * ); + +/** + * Get the previous encoded character form a string. + * @param txt pointer to '\0' terminated string + * @param i_start index in 'txt' where to start. After the call it will point to the previous encoded char in 'txt'. + * @return the decoded Unicode character or 0 on invalid data + */ +extern uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *); + +/** + * Convert a letter index (in an the encoded text) to byte index. + * E.g. in UTF-8 "AÁRT" index of 'R' is 2 but start at byte 3 because 'Á' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param enc_id letter index + * @return byte index of the 'enc_id'th letter + */ +extern uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t); + +/** + * Convert a byte index (in an encoded text) to character index. + * E.g. in UTF-8 "AÁRT" index of 'R' is 2 but start at byte 3 because 'Á' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param byte_id byte index + * @return character index of the letter at 'byte_id'th position + */ +extern uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t); + +/** + * Get the number of characters (and NOT bytes) in a string. + * E.g. in UTF-8 "ÁBC" is 3 characters (but 4 bytes) + * @param txt a '\0' terminated char string + * @return number of characters + */ +extern uint32_t (*lv_txt_get_encoded_length)(const char *); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*USE_TXT*/ diff --git a/pros/display/lv_misc/lv_ufs.h b/pros/display/lv_misc/lv_ufs.h new file mode 100644 index 00000000..d30cbe0f --- /dev/null +++ b/pros/display/lv_misc/lv_ufs.h @@ -0,0 +1,214 @@ +/** + * @file lv_ufs.h + * Implementation of RAM file system which do NOT support directories. + * The API is compatible with the lv_fs_int module. + */ + +#ifndef LV_UFS_H +#define LV_UFS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_FILESYSTEM + +#include +#include "lv_fs.h" +#include "lv_mem.h" + +/********************* + * DEFINES + *********************/ +#define UFS_LETTER 'U' + +/********************** + * TYPEDEFS + **********************/ +/*Description of a file entry */ +typedef struct +{ + char * fn_d; + void * data_d; + uint32_t size; /*Data length in bytes*/ + uint16_t oc; /*Open Count*/ + uint8_t const_data :1; +} lv_ufs_ent_t; + +/*File descriptor, used to handle opening an entry more times simultaneously + Contains unique informations about the specific opening*/ +typedef struct +{ + lv_ufs_ent_t* ent; /*Pointer to the entry*/ + uint32_t rwp; /*Read Write Pointer*/ + uint8_t ar :1; /*1: Access for read is enabled */ + uint8_t aw :1; /*1: Access for write is enabled */ +} lv_ufs_file_t; + +/* Read directory descriptor. + * It is used to to iterate through the entries in a directory*/ +typedef struct +{ + lv_ufs_ent_t * last_ent; +} lv_ufs_dir_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a driver for ufs and initialize it. + */ +void lv_ufs_init(void); + +/** + * Give the state of the ufs + * @return true if ufs is initialized and can be used else false + */ +bool lv_ufs_ready(void); + +/** + * Open a file in ufs + * @param file_p pointer to a lv_ufs_file_t variable + * @param fn name of the file. There are no directories so e.g. "myfile.txt" + * @param mode element of 'fs_mode_t' enum or its 'OR' connection (e.g. FS_MODE_WR | FS_MODE_RD) + * @return LV_FS_RES_OK: no error, the file is opened + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_open (void * file_p, const char * fn, lv_fs_mode_t mode); + +/** + * Create a file with a constant data + * @param fn name of the file (directories are not supported) + * @param const_p pointer to a constant data + * @param len length of the data pointed by 'const_p' in bytes + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_create_const(const char * fn, const void * const_p, uint32_t len); + +/** + * Close an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_close (void * file_p); + +/** + * Remove a file. The file can not be opened. + * @param fn '\0' terminated string + * @return LV_FS_RES_OK: no error, the file is removed + * LV_FS_RES_DENIED: the file was opened, remove failed + */ +lv_fs_res_t lv_ufs_remove(const char * fn); + +/** + * Read data from an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param buf pointer to a memory block where to store the read data + * @param btr number of Bytes To Read + * @param br the real number of read bytes (Byte Read) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_read (void * file_p, void * buf, uint32_t btr, uint32_t * br); + +/** + * Write data to an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open) + * @param buf pointer to a memory block which content will be written + * @param btw the number Bytes To Write + * @param bw The real number of written bytes (Byte Written) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_write (void * file_p, const void * buf, uint32_t btw, uint32_t * bw); + +/** + * Set the read write pointer. Also expand the file size if necessary. + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param pos the new position of read write pointer + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_seek (void * file_p, uint32_t pos); + +/** + * Give the position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param pos_p pointer to to store the result + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_tell (void * file_p, uint32_t * pos_p); + +/** + * Truncate the file size to the current position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_trunc (void * file_p); + +/** + * Give the size of the file in bytes + * @param file_p file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param size_p pointer to store the size + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_size (void * file_p, uint32_t * size_p); + +/** + * Initialize a lv_ufs_read_dir_t variable to directory reading + * @param rddir_p pointer to a 'ufs_read_dir_t' variable + * @param path uFS doesn't support folders so it has to be "" + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_open(void * rddir_p, const char * path); + +/** + * Read the next file name + * @param dir_p pointer to an initialized 'ufs_read_dir_t' variable + * @param fn pointer to buffer to sore the file name + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_read(void * dir_p, char * fn); + +/** + * Close the directory reading + * @param rddir_p pointer to an initialized 'ufs_read_dir_t' variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_close(void * rddir_p); + +/** + * Give the size of a drive + * @param total_p pointer to store the total size [kB] + * @param free_p pointer to store the free site [kB] + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_ufs_free (uint32_t * total_p, uint32_t * free_p); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_FILESYSTEM*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/pros/display/lv_objx/lv_arc.h b/pros/display/lv_objx/lv_arc.h new file mode 100644 index 00000000..4f82e0d8 --- /dev/null +++ b/pros/display/lv_objx/lv_arc.h @@ -0,0 +1,127 @@ +/** + * @file lv_arc.h + * + */ + + +#ifndef LV_ARC_H +#define LV_ARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_ARC != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of arc*/ +typedef struct { + /*New data for this type */ + lv_coord_t angle_start; + lv_coord_t angle_end; +} lv_arc_ext_t; + + +/*Styles*/ +enum { + LV_ARC_STYLE_MAIN, +}; +typedef uint8_t lv_arc_style_t; + + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a arc objects + * @param par pointer to an object, it will be the parent of the new arc + * @param copy pointer to a arc object, if not NULL then the new object will be copied from it + * @return pointer to the created arc + */ +lv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the start and end angles of an arc. 0 deg: bottom, 90 deg: right etc. + * @param arc pointer to an arc object + * @param start the start angle [0..360] + * @param end the end angle [0..360] + */ +void lv_arc_set_angles(lv_obj_t * arc, uint16_t start, uint16_t end); + +/** + * Set a style of a arc. + * @param arc pointer to arc object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_arc_set_style(lv_obj_t * arc, lv_arc_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the start angle of an arc. + * @param arc pointer to an arc object + * @return the start angle [0..360] + */ +uint16_t lv_arc_get_angle_start(lv_obj_t * arc); + +/** + * Get the end angle of an arc. + * @param arc pointer to an arc object + * @return the end angle [0..360] + */ +uint16_t lv_arc_get_angle_end(lv_obj_t * arc); + +/** + * Get style of a arc. + * @param arc pointer to arc object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_arc_get_style(const lv_obj_t * arc, lv_arc_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_ARC*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ARC_H*/ diff --git a/pros/display/lv_objx/lv_bar.h b/pros/display/lv_objx/lv_bar.h new file mode 100644 index 00000000..3938aa28 --- /dev/null +++ b/pros/display/lv_objx/lv_bar.h @@ -0,0 +1,160 @@ +/** + * @file lv_bar.h + * + */ + +#ifndef LV_BAR_H +#define LV_BAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_BAR != 0 + +#include "display/lv_core/lv_obj.h" +#include "lv_cont.h" +#include "lv_btn.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of bar*/ +typedef struct +{ + /*No inherited ext*/ /*Ext. of ancestor*/ + /*New data for this type */ + int16_t cur_value; /*Current value of the bar*/ + int16_t min_value; /*Minimum value of the bar*/ + int16_t max_value; /*Maximum value of the bar*/ + uint8_t sym :1; /*Symmetric: means the center is around zero value*/ + lv_style_t *style_indic; /*Style of the indicator*/ +} lv_bar_ext_t; + +enum { + LV_BAR_STYLE_BG, + LV_BAR_STYLE_INDIC, +}; +typedef uint8_t lv_bar_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a bar objects + * @param par pointer to an object, it will be the parent of the new bar + * @param copy pointer to a bar object, if not NULL then the new object will be copied from it + * @return pointer to the created bar + */ +lv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the bar + * @param bar pointer to a bar object + * @param value new value + */ +void lv_bar_set_value(lv_obj_t * bar, int16_t value); + +/** + * Set a new value with animation on the bar + * @param bar pointer to a bar object + * @param value new value + * @param anim_time animation time in milliseconds + */ +void lv_bar_set_value_anim(lv_obj_t * bar, int16_t value, uint16_t anim_time); + + +/** + * Set minimum and the maximum values of a bar + * @param bar pointer to the bar object + * @param min minimum value + * @param max maximum value + */ +void lv_bar_set_range(lv_obj_t * bar, int16_t min, int16_t max); + +/** + * Make the bar symmetric to zero. The indicator will grow from zero instead of the minimum position. + * @param bar pointer to a bar object + * @param en true: enable disable symmetric behavior; false: disable + */ +void lv_bar_set_sym(lv_obj_t * bar, bool en); + +/** + * Set a style of a bar + * @param bar pointer to a bar object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_bar_set_style(lv_obj_t *bar, lv_bar_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a bar + * @param bar pointer to a bar object + * @return the value of the bar + */ +int16_t lv_bar_get_value(const lv_obj_t * bar); + +/** + * Get the minimum value of a bar + * @param bar pointer to a bar object + * @return the minimum value of the bar + */ +int16_t lv_bar_get_min_value(const lv_obj_t * bar); + +/** + * Get the maximum value of a bar + * @param bar pointer to a bar object + * @return the maximum value of the bar + */ +int16_t lv_bar_get_max_value(const lv_obj_t * bar); + +/** + * Get whether the bar is symmetric or not. + * @param bar pointer to a bar object + * @return true: symmetric is enabled; false: disable + */ +bool lv_bar_get_sym(lv_obj_t * bar); + +/** + * Get a style of a bar + * @param bar pointer to a bar object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_bar_get_style(const lv_obj_t *bar, lv_bar_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_BAR*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BAR_H*/ diff --git a/pros/display/lv_objx/lv_btn.h b/pros/display/lv_objx/lv_btn.h new file mode 100644 index 00000000..805b5d78 --- /dev/null +++ b/pros/display/lv_objx/lv_btn.h @@ -0,0 +1,279 @@ +/** + * @file lv_btn.h + * + */ + +#ifndef LV_BTN_H +#define LV_BTN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_BTN != 0 + +/*Testing of dependencies*/ +#if USE_LV_CONT == 0 +#error "lv_btn: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT 1) " +#endif + +#include "lv_cont.h" +#include "display/lv_core/lv_indev.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/* Button states + * It can be used not only by buttons but other button-like objects too*/ +enum +{ + LV_BTN_STATE_REL, + LV_BTN_STATE_PR, + LV_BTN_STATE_TGL_REL, + LV_BTN_STATE_TGL_PR, + LV_BTN_STATE_INA, + LV_BTN_STATE_NUM, +}; +typedef uint8_t lv_btn_state_t; + +enum +{ + LV_BTN_ACTION_CLICK, + LV_BTN_ACTION_PR, + LV_BTN_ACTION_LONG_PR, + LV_BTN_ACTION_LONG_PR_REPEAT, + LV_BTN_ACTION_NUM, +}; +typedef uint8_t lv_btn_action_t; + + +/*Data of button*/ +typedef struct +{ + lv_cont_ext_t cont; /*Ext. of ancestor*/ + /*New data for this type */ + lv_action_t actions[LV_BTN_ACTION_NUM]; + lv_style_t * styles[LV_BTN_STATE_NUM]; /*Styles in each state*/ + lv_btn_state_t state; /*Current state of the button from 'lv_btn_state_t' enum*/ +#if LV_BTN_INK_EFFECT + uint16_t ink_in_time; /*[ms] Time of ink fill effect (0: disable ink effect)*/ + uint16_t ink_wait_time; /*[ms] Wait before the ink disappears */ + uint16_t ink_out_time; /*[ms] Time of ink disappearing*/ +#endif + uint8_t toggle :1; /*1: Toggle enabled*/ + uint8_t long_pr_action_executed :1; /*1: Long press action executed (Handled by the library)*/ +} lv_btn_ext_t; + +/*Styles*/ +enum { + LV_BTN_STYLE_REL, + LV_BTN_STYLE_PR, + LV_BTN_STYLE_TGL_REL, + LV_BTN_STYLE_TGL_PR, + LV_BTN_STYLE_INA, +}; +typedef uint8_t lv_btn_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a button objects + * @param par pointer to an object, it will be the parent of the new button + * @param copy pointer to a button object, if not NULL then the new object will be copied from it + * @return pointer to the created button + */ +lv_obj_t * lv_btn_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Enable the toggled states. On release the button will change from/to toggled state. + * @param btn pointer to a button object + * @param tgl true: enable toggled states, false: disable + */ +void lv_btn_set_toggle(lv_obj_t * btn, bool tgl); + +/** + * Set the state of the button + * @param btn pointer to a button object + * @param state the new state of the button (from lv_btn_state_t enum) + */ +void lv_btn_set_state(lv_obj_t * btn, lv_btn_state_t state); + +/** + * Toggle the state of the button (ON->OFF, OFF->ON) + * @param btn pointer to a button object + */ +void lv_btn_toggle(lv_obj_t * btn); + +/** + * Set a function to call when a button event happens + * @param btn pointer to a button object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +void lv_btn_set_action(lv_obj_t * btn, lv_btn_action_t type, lv_action_t action); + +/** + * Set the layout on a button + * @param btn pointer to a button object + * @param layout a layout from 'lv_cont_layout_t' + */ +static inline void lv_btn_set_layout(lv_obj_t * btn, lv_layout_t layout) +{ + lv_cont_set_layout(btn, layout); +} + +/** + * Enable the horizontal or vertical fit. + * The button size will be set to involve the children horizontally or vertically. + * @param btn pointer to a button object + * @param hor_en true: enable the horizontal fit + * @param ver_en true: enable the vertical fit + */ +static inline void lv_btn_set_fit(lv_obj_t * btn, bool hor_en, bool ver_en) +{ + lv_cont_set_fit(btn, hor_en, ver_en); +} + +/** + * Set time of the ink effect (draw a circle on click to animate in the new state) + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_in_time(lv_obj_t * btn, uint16_t time); + +/** + * Set the wait time before the ink disappears + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_wait_time(lv_obj_t * btn, uint16_t time); + +/** + * Set time of the ink out effect (animate to the released state) + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_out_time(lv_obj_t * btn, uint16_t time); + +/** + * Set a style of a button. + * @param btn pointer to button object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_btn_set_style(lv_obj_t * btn, lv_btn_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current state of the button + * @param btn pointer to a button object + * @return the state of the button (from lv_btn_state_t enum) + */ +lv_btn_state_t lv_btn_get_state(const lv_obj_t * btn); + +/** + * Get the toggle enable attribute of the button + * @param btn pointer to a button object + * @return ture: toggle enabled, false: disabled + */ +bool lv_btn_get_toggle(const lv_obj_t * btn); + +/** + * Get the release action of a button + * @param btn pointer to a button object + * @return pointer to the release action function + */ +lv_action_t lv_btn_get_action(const lv_obj_t * btn, lv_btn_action_t type); + +/** + * Get the layout of a button + * @param btn pointer to button object + * @return the layout from 'lv_cont_layout_t' + */ +static inline lv_layout_t lv_btn_get_layout(const lv_obj_t * btn) +{ + return lv_cont_get_layout(btn); +} + +/** + * Get horizontal fit enable attribute of a button + * @param btn pointer to a button object + * @return true: horizontal fit is enabled; false: disabled + */ +static inline bool lv_btn_get_hor_fit(const lv_obj_t * btn) +{ + return lv_cont_get_hor_fit(btn); +} + +/** + * Get vertical fit enable attribute of a container + * @param btn pointer to a button object + * @return true: vertical fit is enabled; false: disabled + */ +static inline bool lv_btn_get_ver_fit(const lv_obj_t * btn) +{ + return lv_cont_get_ver_fit(btn); +} + +/** + * Get time of the ink in effect (draw a circle on click to animate in the new state) + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_in_time(const lv_obj_t * btn); + +/** + * Get the wait time before the ink disappears + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_wait_time(const lv_obj_t * btn); + +/** + * Get time of the ink out effect (animate to the releases state) + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_out_time(const lv_obj_t * btn); + +/** + * Get style of a button. + * @param btn pointer to button object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_btn_get_style(const lv_obj_t * btn, lv_btn_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_BUTTON*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BTN_H*/ diff --git a/pros/display/lv_objx/lv_btnm.h b/pros/display/lv_objx/lv_btnm.h new file mode 100644 index 00000000..89c066a4 --- /dev/null +++ b/pros/display/lv_objx/lv_btnm.h @@ -0,0 +1,197 @@ +/** + * @file lv_btnm.h + * + */ + + +#ifndef LV_BTNM_H +#define LV_BTNM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_BTNM != 0 + +#include "display/lv_core/lv_obj.h" +#include "lv_label.h" +#include "lv_btn.h" + +/********************* + * DEFINES + *********************/ + +/*Control byte*/ +#define LV_BTNM_CTRL_CODE 0x80 /*The control byte has to begin (if present) with 0b10xxxxxx*/ +#define LV_BTNM_CTRL_MASK 0xC0 +#define LV_BTNM_WIDTH_MASK 0x07 +#define LV_BTNM_HIDE_MASK 0x08 +#define LV_BTNM_REPEAT_DISABLE_MASK 0x10 +#define LV_BTNM_INACTIVE_MASK 0x20 + + +#define LV_BTNM_PR_NONE 0xFFFF +/********************** + * TYPEDEFS + **********************/ + +/* Type of callback function which is called when a button is released or long pressed on the button matrix + * Parameters: button matrix, text of the released button + * return LV_ACTION_RES_INV if the button matrix is deleted else LV_ACTION_RES_OK*/ +typedef lv_res_t (*lv_btnm_action_t) (lv_obj_t *, const char *txt); + +/*Data of button matrix*/ +typedef struct +{ + /*No inherited ext.*/ /*Ext. of ancestor*/ + /*New data for this type */ + const char ** map_p; /*Pointer to the current map*/ + lv_area_t *button_areas; /*Array of areas of buttons*/ + lv_btnm_action_t action; /*A function to call when a button is releases*/ + lv_style_t *styles_btn[LV_BTN_STATE_NUM]; /*Styles of buttons in each state*/ + uint16_t btn_cnt; /*Number of button in 'map_p'(Handled by the library)*/ + uint16_t btn_id_pr; /*Index of the currently pressed button (in `button_areas`) or LV_BTNM_PR_NONE*/ + uint16_t btn_id_tgl; /*Index of the currently toggled button (in `button_areas`) or LV_BTNM_PR_NONE */ + uint8_t toggle :1; /*Enable toggling*/ + uint8_t recolor :1; /*Enable button recoloring*/ +} lv_btnm_ext_t; + +enum { + LV_BTNM_STYLE_BG, + LV_BTNM_STYLE_BTN_REL, + LV_BTNM_STYLE_BTN_PR, + LV_BTNM_STYLE_BTN_TGL_REL, + LV_BTNM_STYLE_BTN_TGL_PR, + LV_BTNM_STYLE_BTN_INA, +}; +typedef uint8_t lv_btnm_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a button matrix objects + * @param par pointer to an object, it will be the parent of the new button matrix + * @param copy pointer to a button matrix object, if not NULL then the new object will be copied from it + * @return pointer to the created button matrix + */ +lv_obj_t * lv_btnm_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new map. Buttons will be created/deleted according to the map. + * @param btnm pointer to a button matrix object + * @param map pointer a string array. The last string has to be: "". + * Use "\n" to begin a new line. + * The first byte can be a control data: + * - bit 7: always 1 + * - bit 6: always 0 + * - bit 5: inactive (disabled) + * - bit 4: no repeat (on long press) + * - bit 3: hidden + * - bit 2..0: button relative width + * Example (practically use octal numbers): "\224abc": "abc" text with 4 width and no long press + */ +void lv_btnm_set_map(lv_obj_t * btnm, const char ** map); + +/** + * Set a new callback function for the buttons (It will be called when a button is released) + * @param btnm: pointer to button matrix object + * @param action pointer to a callback function + */ +void lv_btnm_set_action(lv_obj_t * btnm, lv_btnm_action_t action); + +/** + * Enable or disable button toggling + * @param btnm pointer to button matrix object + * @param en true: enable toggling; false: disable toggling + * @param id index of the currently toggled button (ignored if 'en' == false) + */ +void lv_btnm_set_toggle(lv_obj_t * btnm, bool en, uint16_t id); + +/** + * Set a style of a button matrix + * @param btnm pointer to a button matrix object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_btnm_set_style(lv_obj_t *btnm, lv_btnm_style_t type, lv_style_t *style); + +/** + * Set whether recoloring is enabled + * @param btnm pointer to button matrix object + * @param en whether recoloring is enabled + */ +void lv_btnm_set_recolor(const lv_obj_t * btnm, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current map of a button matrix + * @param btnm pointer to a button matrix object + * @return the current map + */ +const char ** lv_btnm_get_map(const lv_obj_t * btnm); + +/** + * Get a the callback function of the buttons on a button matrix + * @param btnm: pointer to button matrix object + * @return pointer to the callback function + */ +lv_btnm_action_t lv_btnm_get_action(const lv_obj_t * btnm); + +/** + * Get the pressed button + * @param btnm pointer to button matrix object + * @return index of the currently pressed button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_pressed(const lv_obj_t * btnm); + +/** + * Get the toggled button + * @param btnm pointer to button matrix object + * @return index of the currently toggled button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_toggled(const lv_obj_t * btnm); + +/** + * Get a style of a button matrix + * @param btnm pointer to a button matrix object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_btnm_get_style(const lv_obj_t *btnm, lv_btnm_style_t type); + +/** + * Find whether recoloring is enabled + * @param btnm pointer to button matrix object + * @return whether recoloring is enabled + */ +bool lv_btnm_get_recolor(const lv_obj_t * btnm); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_BTNM*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BTNM_H*/ diff --git a/pros/display/lv_objx/lv_calendar.h b/pros/display/lv_objx/lv_calendar.h new file mode 100644 index 00000000..3ef4b025 --- /dev/null +++ b/pros/display/lv_objx/lv_calendar.h @@ -0,0 +1,246 @@ +/** + * @file lv_calendar.h + * + */ + +#ifndef LV_CALENDAR_H +#define LV_CALENDAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_CALENDAR != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + uint16_t year; + int8_t month; + int8_t day; +} lv_calendar_date_t; + +enum +{ + LV_CALENDAR_ACTION_CLICK, + LV_CALENDAR_ACTION_PR, + LV_CALENDAR_ACTION_LONG_PR, + LV_CALENDAR_ACTION_LONG_PR_REPEAT, + LV_CALENDAR_ACTION_NUM, +}; +typedef uint8_t lv_calendar_action_t; + +/*Data of calendar*/ +typedef struct { + /*None*/ /*Ext. of ancestor*/ + /*New data for this type */ + lv_calendar_date_t today; /*Date of today*/ + lv_calendar_date_t showed_date; /*Currently visible month (day is ignored)*/ + lv_calendar_date_t * highlighted_dates; /*Apply different style on these days (pointer to an array defined by the user)*/ + uint8_t highlighted_dates_num; /*Number of elements in `highlighted_days`*/ + int8_t btn_pressing; /*-1: prev month pressing, +1 next month pressing on the header*/ + lv_calendar_date_t pressed_date; + const char ** day_names; /*Pointer to an array with the name of the days (NULL: use default names)*/ + const char ** month_names; /*Pointer to an array with the name of the month (NULL. use default names)*/ + lv_action_t actions[LV_CALENDAR_ACTION_NUM]; + + /*Styles*/ + lv_style_t * style_header; + lv_style_t * style_header_pr; + lv_style_t * style_day_names; + lv_style_t * style_highlighted_days; + lv_style_t * style_inactive_days; + lv_style_t * style_week_box; + lv_style_t * style_today_box; +} lv_calendar_ext_t; + +/*Styles*/ +enum { + LV_CALENDAR_STYLE_BG, /*Also the style of the "normal" date numbers*/ + LV_CALENDAR_STYLE_HEADER, + LV_CALENDAR_STYLE_HEADER_PR, + LV_CALENDAR_STYLE_DAY_NAMES, + LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS, + LV_CALENDAR_STYLE_INACTIVE_DAYS, + LV_CALENDAR_STYLE_WEEK_BOX, + LV_CALENDAR_STYLE_TODAY_BOX, +}; +typedef uint8_t lv_calendar_style_t; + + + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a calendar objects + * @param par pointer to an object, it will be the parent of the new calendar + * @param copy pointer to a calendar object, if not NULL then the new object will be copied from it + * @return pointer to the created calendar + */ +lv_obj_t * lv_calendar_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ +/** + * Set a function to call when a calendar event happens + * @param calendar pointer to a calendar object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +void lv_calendar_set_action(lv_obj_t * calendar, lv_calendar_action_t type, lv_action_t action); + +/** + * Set the today's date + * @param calendar pointer to a calendar object + * @param today pointer to an `lv_calendar_date_t` variable containing the date of today. The value will be saved it can be local variable too. + */ +void lv_calendar_set_today_date(lv_obj_t * calendar, lv_calendar_date_t * today); + +/** + * Set the currently showed + * @param calendar pointer to a calendar object + * @param showed pointer to an `lv_calendar_date_t` variable containing the date to show. The value will be saved it can be local variable too. + */ +void lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showed); + +/** + * Set the the highlighted dates + * @param calendar pointer to a calendar object + * @param highlighted pointer to an `lv_calendar_date_t` array containing the dates. ONLY A POINTER WILL BE SAVED! CAN'T BE LOCAL ARRAY. + * @param date_num number of dates in the array + */ +void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t * highlighted, uint16_t date_num); + + +/** + * Set the name of the days + * @param calendar pointer to a calendar object + * @param day_names pointer to an array with the names. E.g. `const char * days[7] = {"Sun", "Mon", ...}` + * Only the pointer will be saved so this variable can't be local which will be destroyed later. + */ +void lv_calendar_set_day_names(lv_obj_t * calendar, const char ** day_names); + +/** + * Set the name of the month + * @param calendar pointer to a calendar object + * @param day_names pointer to an array with the names. E.g. `const char * days[12] = {"Jan", "Feb", ...}` + * Only the pointer will be saved so this variable can't be local which will be destroyed later. + */ +void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** day_names); + +/** + * Set a style of a calendar. + * @param calendar pointer to calendar object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_calendar_set_style(lv_obj_t * calendar, lv_calendar_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ +/** + * Get the action of a calendar + * @param calendar pointer to a calendar object + * @return pointer to the action function + */ +lv_action_t lv_calendar_get_action(const lv_obj_t * calendar, lv_calendar_action_t type); + +/** + * Get the today's date + * @param calendar pointer to a calendar object + * @return return pointer to an `lv_calendar_date_t` variable containing the date of today. + */ +lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar); + +/** + * Get the currently showed + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the date is being shown. + */ +lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar); + +/** + * Get the the pressed date. + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the pressed date. + */ +lv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar); + +/** + * Get the the highlighted dates + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` array containing the dates. + */ +lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar); + +/** + * Get the number of the highlighted dates + * @param calendar pointer to a calendar object + * @return number of highlighted days + */ +uint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar); + + +/** + * Get the name of the days + * @param calendar pointer to a calendar object + * @return pointer to the array of day names + */ +const char ** lv_calendar_get_day_names(const lv_obj_t * calendar); + +/** + * Get the name of the month + * @param calendar pointer to a calendar object + * @return pointer to the array of month names + */ +const char ** lv_calendar_get_month_names(const lv_obj_t * calendar); + +/** + * Get style of a calendar. + * @param calendar pointer to calendar object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_calendar_get_style(const lv_obj_t * calendar, lv_calendar_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CALENDAR*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CALENDAR_H*/ diff --git a/pros/display/lv_objx/lv_canvas.h b/pros/display/lv_objx/lv_canvas.h new file mode 100644 index 00000000..14d6e87b --- /dev/null +++ b/pros/display/lv_objx/lv_canvas.h @@ -0,0 +1,229 @@ +/** + * @file lv_canvas.h + * + */ + +#ifndef LV_CANVAS_H +#define LV_CANVAS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_CANVAS != 0 + +#include "display/lv_core/lv_obj.h" +#include "display/lv_objx/lv_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of canvas*/ +typedef struct { + lv_img_ext_t img; /*Ext. of ancestor*/ + /*New data for this type */ + lv_img_dsc_t dsc; +} lv_canvas_ext_t; + + +/*Styles*/ +enum { + LV_CANVAS_STYLE_MAIN, +}; +typedef uint8_t lv_canvas_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a canvas object + * @param par pointer to an object, it will be the parent of the new canvas + * @param copy pointer to a canvas object, if not NULL then the new object will be copied from it + * @return pointer to the created canvas + */ +lv_obj_t * lv_canvas_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a buffer for the canvas. + * @param buf a buffer where the content of the canvas will be. + * The required size is (lv_img_color_format_get_px_size(cf) * w * h) / 8) + * It can be allocated with `lv_mem_alloc()` or + * it can be statically allocated array (e.g. static lv_color_t buf[100*50]) or + * it can be an address in RAM or external SRAM + * @param canvas pointer to a canvas object + * @param w width of the canvas + * @param h height of the canvas + * @param cf color format. The following formats are supported: + * LV_IMG_CF_TRUE_COLOR, LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, LV_IMG_CF_INDEXES_1/2/4/8BIT + */ +void lv_canvas_set_buffer(lv_obj_t * canvas, void * buf, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf); + +/** + * Set the color of a pixel on the canvas + * @param canvas + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @param c color of the point + */ +void lv_canvas_set_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t c); + +/** + * Set a style of a canvas. + * @param canvas pointer to canvas object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_canvas_set_style(lv_obj_t * canvas, lv_canvas_style_t type, lv_style_t * style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the color of a pixel on the canvas + * @param canvas + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @return color of the point + */ +lv_color_t lv_canvas_get_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y); + +/** + * Get style of a canvas. + * @param canvas pointer to canvas object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_canvas_get_style(const lv_obj_t * canvas, lv_canvas_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Copy a buffer to the canvas + * @param canvas pointer to a canvas object + * @param to_copy buffer to copy. The color format has to match with the canvas's buffer color format + * @param w width of the buffer to copy + * @param h height of the buffer to copy + * @param x left side of the destination position + * @param y top side of the destination position + */ +void lv_canvas_copy_buf(lv_obj_t * canvas, const void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y); + +/** + * Multiply a buffer with the canvas + * @param canvas pointer to a canvas object + * @param to_copy buffer to copy (multiply). LV_IMG_CF_TRUE_COLOR_ALPHA is not supported + * @param w width of the buffer to copy + * @param h height of the buffer to copy + * @param x left side of the destination position + * @param y top side of the destination position + */ +void lv_canvas_mult_buf(lv_obj_t * canvas, void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y); + +/** + * Draw circle function of the canvas + * @param canvas pointer to a canvas object + * @param x0 x coordinate of the circle + * @param y0 y coordinate of the circle + * @param radius radius of the circle + * @param color border color of the circle + */ +void lv_canvas_draw_circle(lv_obj_t * canvas, lv_coord_t x0, lv_coord_t y0, lv_coord_t radius, lv_color_t color); + +/** + * Draw line function of the canvas + * @param canvas pointer to a canvas object + * @param point1 start point of the line + * @param point2 end point of the line + * @param color color of the line + * + * NOTE: The lv_canvas_draw_line function originates from https://github.com/jb55/bresenham-line.c. + */ +void lv_canvas_draw_line(lv_obj_t * canvas, lv_point_t point1, lv_point_t point2, lv_color_t color); + +/** + * Draw triangle function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the triangle + * @param color line color of the triangle + */ +void lv_canvas_draw_triangle(lv_obj_t * canvas, lv_point_t * points, lv_color_t color); + +/** + * Draw rectangle function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the rectangle + * @param color line color of the rectangle + */ +void lv_canvas_draw_rect(lv_obj_t * canvas, lv_point_t * points, lv_color_t color); + +/** + * Draw polygon function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the polygon + * @param size edge count of the polygon + * @param color line color of the polygon + */ +void lv_canvas_draw_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t color); + +/** + * Fill polygon function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the polygon + * @param size edge count of the polygon + * @param boundary_color line color of the polygon + * @param fill_color fill color of the polygon + */ +void lv_canvas_fill_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t boundary_color, lv_color_t fill_color); +/** + * Boundary fill function of the canvas + * @param canvas pointer to a canvas object + * @param x x coordinate of the start position (seed) + * @param y y coordinate of the start position (seed) + * @param boundary_color edge/boundary color of the area + * @param fill_color fill color of the area + */ +void lv_canvas_boundary_fill4(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t boundary_color, lv_color_t fill_color); + +/** + * Flood fill function of the canvas + * @param canvas pointer to a canvas object + * @param x x coordinate of the start position (seed) + * @param y y coordinate of the start position (seed) + * @param fill_color fill color of the area + * @param bg_color background color of the area + */ +void lv_canvas_flood_fill(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t fill_color, lv_color_t bg_color); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CANVAS*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CANVAS_H*/ diff --git a/pros/display/lv_objx/lv_cb.h b/pros/display/lv_objx/lv_cb.h new file mode 100644 index 00000000..5c550b6f --- /dev/null +++ b/pros/display/lv_objx/lv_cb.h @@ -0,0 +1,174 @@ +/** + * @file lv_cb.h + * + */ + +#ifndef LV_CB_H +#define LV_CB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_CB != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTN == 0 +#error "lv_cb: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_cb: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_btn.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of check box*/ +typedef struct +{ + lv_btn_ext_t bg_btn; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * bullet; /*Pointer to button*/ + lv_obj_t * label; /*Pointer to label*/ +} lv_cb_ext_t; + +enum { + LV_CB_STYLE_BG, + LV_CB_STYLE_BOX_REL, + LV_CB_STYLE_BOX_PR, + LV_CB_STYLE_BOX_TGL_REL, + LV_CB_STYLE_BOX_TGL_PR, + LV_CB_STYLE_BOX_INA, +}; +typedef uint8_t lv_cb_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a check box objects + * @param par pointer to an object, it will be the parent of the new check box + * @param copy pointer to a check box object, if not NULL then the new object will be copied from it + * @return pointer to the created check box + */ +lv_obj_t * lv_cb_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a check box + * @param cb pointer to a check box + * @param txt the text of the check box + */ +void lv_cb_set_text(lv_obj_t * cb, const char * txt); + +/** + * Set the state of the check box + * @param cb pointer to a check box object + * @param checked true: make the check box checked; false: make it unchecked + */ +static inline void lv_cb_set_checked(lv_obj_t * cb, bool checked) +{ + lv_btn_set_state(cb, checked ? LV_BTN_STATE_TGL_REL : LV_BTN_STATE_REL); +} + +/** + * Make the check box inactive (disabled) + * @param cb pointer to a check box object + */ +static inline void lv_cb_set_inactive(lv_obj_t * cb) +{ + lv_btn_set_state(cb, LV_BTN_STATE_INA); +} + +/** + * Set a function to call when the check box is clicked + * @param cb pointer to a check box object + */ +static inline void lv_cb_set_action(lv_obj_t * cb, lv_action_t action) +{ + lv_btn_set_action(cb, LV_BTN_ACTION_CLICK, action); +} + + +/** + * Set a style of a check box + * @param cb pointer to check box object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_cb_set_style(lv_obj_t * cb, lv_cb_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a check box + * @param cb pointer to check box object + * @return pointer to the text of the check box + */ +const char * lv_cb_get_text(const lv_obj_t * cb); + +/** + * Get the current state of the check box + * @param cb pointer to a check box object + * @return true: checked; false: not checked + */ +static inline bool lv_cb_is_checked(const lv_obj_t * cb) +{ + return lv_btn_get_state(cb) == LV_BTN_STATE_REL ? false : true; +} + +/** + * Get the action of a check box + * @param cb pointer to a button object + * @return pointer to the action function + */ +static inline lv_action_t lv_cb_get_action(const lv_obj_t * cb) +{ + return lv_btn_get_action(cb, LV_BTN_ACTION_CLICK); +} + + +/** + * Get a style of a button + * @param cb pointer to check box object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_cb_get_style(const lv_obj_t * cb, lv_cb_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CB*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CB_H*/ diff --git a/pros/display/lv_objx/lv_chart.h b/pros/display/lv_objx/lv_chart.h new file mode 100644 index 00000000..92637e89 --- /dev/null +++ b/pros/display/lv_objx/lv_chart.h @@ -0,0 +1,262 @@ +/** + * @file lv_chart.h + * + */ + +#ifndef LV_CHART_H +#define LV_CHART_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_CHART != 0 + +#include "display/lv_core/lv_obj.h" +#include "lv_line.h" + +/********************* + * DEFINES + *********************/ +#define LV_CHART_POINT_DEF (LV_COORD_MIN) + +/********************** + * TYPEDEFS + **********************/ +typedef struct +{ + lv_coord_t * points; + lv_color_t color; + uint16_t start_point; +} lv_chart_series_t; + +/*Data of chart */ +typedef struct +{ + /*No inherited ext*/ /*Ext. of ancestor*/ + /*New data for this type */ + lv_ll_t series_ll; /*Linked list for the data line pointers (stores lv_chart_dl_t)*/ + lv_coord_t ymin; /*y min value (used to scale the data)*/ + lv_coord_t ymax; /*y max value (used to scale the data)*/ + uint8_t hdiv_cnt; /*Number of horizontal division lines*/ + uint8_t vdiv_cnt; /*Number of vertical division lines*/ + uint16_t point_cnt; /*Point number in a data line*/ + uint8_t type :4; /*Line, column or point chart (from 'lv_chart_type_t')*/ + struct { + lv_coord_t width; /*Line width or point radius*/ + uint8_t num; /*Number of data lines in dl_ll*/ + lv_opa_t opa; /*Opacity of data lines*/ + lv_opa_t dark; /*Dark level of the point/column bottoms*/ + } series; +} lv_chart_ext_t; + +/*Chart types*/ +enum +{ + LV_CHART_TYPE_LINE = 0x01, /*Connect the points with lines*/ + LV_CHART_TYPE_COLUMN = 0x02, /*Draw columns*/ + LV_CHART_TYPE_POINT = 0x04, /*Draw circles on the points*/ + LV_CHART_TYPE_VERTICAL_LINE = 0x08, /*Draw vertical lines on points (useful when chart width == point count)*/ +}; +typedef uint8_t lv_chart_type_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a chart background objects + * @param par pointer to an object, it will be the parent of the new chart background + * @param copy pointer to a chart background object, if not NULL then the new object will be copied from it + * @return pointer to the created chart background + */ +lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Allocate and add a data series to the chart + * @param chart pointer to a chart object + * @param color color of the data series + * @return pointer to the allocated data series + */ +lv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, lv_color_t color); + +/** + * Clear the point of a serie + * @param chart pointer to a chart object + * @param serie pointer to the chart's serie to clear + */ +void lv_chart_clear_serie(lv_obj_t * chart, lv_chart_series_t * serie); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the number of horizontal and vertical division lines + * @param chart pointer to a graph background object + * @param hdiv number of horizontal division lines + * @param vdiv number of vertical division lines + */ +void lv_chart_set_div_line_count(lv_obj_t * chart, uint8_t hdiv, uint8_t vdiv); + +/** + * Set the minimal and maximal y values + * @param chart pointer to a graph background object + * @param ymin y minimum value + * @param ymax y maximum value + */ +void lv_chart_set_range(lv_obj_t * chart, lv_coord_t ymin, lv_coord_t ymax); + +/** + * Set a new type for a chart + * @param chart pointer to a chart object + * @param type new type of the chart (from 'lv_chart_type_t' enum) + */ +void lv_chart_set_type(lv_obj_t * chart, lv_chart_type_t type); + +/** + * Set the number of points on a data line on a chart + * @param chart pointer r to chart object + * @param point_cnt new number of points on the data lines + */ +void lv_chart_set_point_count(lv_obj_t * chart, uint16_t point_cnt); + +/** + * Set the opacity of the data series + * @param chart pointer to a chart object + * @param opa opacity of the data series + */ +void lv_chart_set_series_opa(lv_obj_t * chart, lv_opa_t opa); + +/** + * Set the line width or point radius of the data series + * @param chart pointer to a chart object + * @param width the new width + */ +void lv_chart_set_series_width(lv_obj_t * chart, lv_coord_t width); + +/** + * Set the dark effect on the bottom of the points or columns + * @param chart pointer to a chart object + * @param dark_eff dark effect level (LV_OPA_TRANSP to turn off) + */ +void lv_chart_set_series_darking(lv_obj_t * chart, lv_opa_t dark_eff); + +/** + * Initialize all data points with a value + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y the new value for all points + */ +void lv_chart_init_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y); + +/** + * Set the value s of points from an array + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y_array array of 'lv_coord_t' points (with 'points count' elements ) + */ +void lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t * y_array); + +/** + * Shift all data right and set the most right data on a data line + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y the new value of the most right data + */ +void lv_chart_set_next(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y); + +/** + * Set the style of a chart + * @param chart pointer to a chart object + * @param style pointer to a style + */ +static inline void lv_chart_set_style(lv_obj_t *chart, lv_style_t *style) +{ + lv_obj_set_style(chart, style); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the type of a chart + * @param chart pointer to chart object + * @return type of the chart (from 'lv_chart_t' enum) + */ +lv_chart_type_t lv_chart_get_type(const lv_obj_t * chart); + +/** + * Get the data point number per data line on chart + * @param chart pointer to chart object + * @return point number on each data line + */ +uint16_t lv_chart_get_point_cnt(const lv_obj_t * chart); + +/** + * Get the opacity of the data series + * @param chart pointer to chart object + * @return the opacity of the data series + */ +lv_opa_t lv_chart_get_series_opa(const lv_obj_t * chart); + +/** + * Get the data series width + * @param chart pointer to chart object + * @return the width the data series (lines or points) + */ +lv_coord_t lv_chart_get_series_width(const lv_obj_t * chart); + +/** + * Get the dark effect level on the bottom of the points or columns + * @param chart pointer to chart object + * @return dark effect level (LV_OPA_TRANSP to turn off) + */ +lv_opa_t lv_chart_get_series_darking(const lv_obj_t * chart); + +/** + * Get the style of an chart object + * @param chart pointer to an chart object + * @return pointer to the chart's style + */ +static inline lv_style_t* lv_chart_get_style(const lv_obj_t *chart) +{ + return lv_obj_get_style(chart); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Refresh a chart if its data line has changed + * @param chart pointer to chart object + */ +void lv_chart_refresh(lv_obj_t * chart); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CHART*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CHART_H*/ diff --git a/pros/display/lv_objx/lv_cont.h b/pros/display/lv_objx/lv_cont.h new file mode 100644 index 00000000..3f4923dc --- /dev/null +++ b/pros/display/lv_objx/lv_cont.h @@ -0,0 +1,163 @@ +/** + * @file lv_cont.h + * + */ + +#ifndef LV_CONT_H +#define LV_CONT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_CONT != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Layout options*/ +enum +{ + LV_LAYOUT_OFF = 0, + LV_LAYOUT_CENTER, + LV_LAYOUT_COL_L, /*Column left align*/ + LV_LAYOUT_COL_M, /*Column middle align*/ + LV_LAYOUT_COL_R, /*Column right align*/ + LV_LAYOUT_ROW_T, /*Row top align*/ + LV_LAYOUT_ROW_M, /*Row middle align*/ + LV_LAYOUT_ROW_B, /*Row bottom align*/ + LV_LAYOUT_PRETTY, /*Put as many object as possible in row and begin a new row*/ + LV_LAYOUT_GRID, /*Align same-sized object into a grid*/ +}; +typedef uint8_t lv_layout_t; + +typedef struct +{ + /*Inherited from 'base_obj' so no inherited ext. */ /*Ext. of ancestor*/ + /*New data for this type */ + uint8_t layout :4; /*A layout from 'lv_cont_layout_t' enum*/ + uint8_t hor_fit :1; /*1: Enable horizontal fit to involve all children*/ + uint8_t ver_fit :1; /*1: Enable horizontal fit to involve all children*/ +} lv_cont_ext_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a container objects + * @param par pointer to an object, it will be the parent of the new container + * @param copy pointer to a container object, if not NULL then the new object will be copied from it + * @return pointer to the created container + */ +lv_obj_t * lv_cont_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a layout on a container + * @param cont pointer to a container object + * @param layout a layout from 'lv_cont_layout_t' + */ +void lv_cont_set_layout(lv_obj_t * cont, lv_layout_t layout); + + +/** + * Enable the horizontal or vertical fit. + * The container size will be set to involve the children horizontally or vertically. + * @param cont pointer to a container object + * @param hor_en true: enable the horizontal fit + * @param ver_en true: enable the vertical fit + */ +void lv_cont_set_fit(lv_obj_t * cont, bool hor_en, bool ver_en); + +/** + * Set the style of a container + * @param cont pointer to a container object + * @param style pointer to the new style + */ +static inline void lv_cont_set_style(lv_obj_t *cont, lv_style_t * style) +{ + lv_obj_set_style(cont, style); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the layout of a container + * @param cont pointer to container object + * @return the layout from 'lv_cont_layout_t' + */ +lv_layout_t lv_cont_get_layout(const lv_obj_t * cont); + +/** + * Get horizontal fit enable attribute of a container + * @param cont pointer to a container object + * @return true: horizontal fit is enabled; false: disabled + */ +bool lv_cont_get_hor_fit(const lv_obj_t * cont); + +/** + * Get vertical fit enable attribute of a container + * @param cont pointer to a container object + * @return true: vertical fit is enabled; false: disabled + */ +bool lv_cont_get_ver_fit(const lv_obj_t * cont); + + +/** + * Get that width reduced by the horizontal padding. Useful if a layout is used. + * @param cont pointer to a container object + * @return the width which still fits into the container + */ +lv_coord_t lv_cont_get_fit_width(lv_obj_t * cont); + +/** + * Get that height reduced by the vertical padding. Useful if a layout is used. + * @param cont pointer to a container object + * @return the height which still fits into the container + */ +lv_coord_t lv_cont_get_fit_height(lv_obj_t * cont); + +/** + * Get the style of a container + * @param cont pointer to a container object + * @return pointer to the container's style + */ +static inline lv_style_t * lv_cont_get_style(const lv_obj_t *cont) +{ + return lv_obj_get_style(cont); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CONT*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CONT_H*/ diff --git a/pros/display/lv_objx/lv_ddlist.h b/pros/display/lv_objx/lv_ddlist.h new file mode 100644 index 00000000..cd9de975 --- /dev/null +++ b/pros/display/lv_objx/lv_ddlist.h @@ -0,0 +1,265 @@ +/** + * @file lv_ddlist.h + * + */ + +#ifndef LV_DDLIST_H +#define LV_DDLIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_DDLIST != 0 + +/*Testing of dependencies*/ +#if USE_LV_PAGE == 0 +#error "lv_ddlist: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_ddlist: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "display/lv_objx/lv_page.h" +#include "display/lv_objx/lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of drop down list*/ +typedef struct +{ + lv_page_ext_t page; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t *label; /*Label for the options*/ + lv_style_t * sel_style; /*Style of the selected option*/ + lv_action_t action; /*Pointer to function to call when an option is selected*/ + uint16_t option_cnt; /*Number of options*/ + uint16_t sel_opt_id; /*Index of the current option*/ + uint16_t sel_opt_id_ori; /*Store the original index on focus*/ + uint16_t anim_time; /*Open/Close animation time [ms]*/ + uint8_t opened :1; /*1: The list is opened (handled by the library)*/ + uint8_t draw_arrow :1; /*1: Draw arrow*/ + + lv_coord_t fix_height; /*Height of the ddlist when opened. (0: auto-size)*/ +} lv_ddlist_ext_t; + +enum { + LV_DDLIST_STYLE_BG, + LV_DDLIST_STYLE_SEL, + LV_DDLIST_STYLE_SB, +}; +typedef uint8_t lv_ddlist_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/** + * Create a drop down list objects + * @param par pointer to an object, it will be the parent of the new drop down list + * @param copy pointer to a drop down list object, if not NULL then the new object will be copied from it + * @return pointer to the created drop down list + */ +lv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set arrow draw in a drop down list + * @param ddlist pointer to drop down list object + * @param en enable/disable a arrow draw. E.g. "true" for draw. + */ +void lv_ddlist_set_draw_arrow(lv_obj_t * ddlist, bool en); + +/** + * Set the options in a drop down list from a string + * @param ddlist pointer to drop down list object + * @param options a string with '\n' separated options. E.g. "One\nTwo\nThree" + */ +void lv_ddlist_set_options(lv_obj_t * ddlist, const char * options); + +/** + * Set the selected option + * @param ddlist pointer to drop down list object + * @param sel_opt id of the selected option (0 ... number of option - 1); + */ +void lv_ddlist_set_selected(lv_obj_t * ddlist, uint16_t sel_opt); + +/** + * Set a function to call when a new option is chosen + * @param ddlist pointer to a drop down list + * @param action pointer to a call back function + */ +void lv_ddlist_set_action(lv_obj_t * ddlist, lv_action_t action); + +/** + * Set the fix height for the drop down list + * If 0 then the opened ddlist will be auto. sized else the set height will be applied. + * @param ddlist pointer to a drop down list + * @param h the height when the list is opened (0: auto size) + */ +void lv_ddlist_set_fix_height(lv_obj_t * ddlist, lv_coord_t h); + +/** + * Enable or disable the horizontal fit to the content + * @param ddlist pointer to a drop down list + * @param en true: enable auto fit; false: disable auto fit + */ +void lv_ddlist_set_hor_fit(lv_obj_t * ddlist, bool en); + +/** + * Set the scroll bar mode of a drop down list + * @param ddlist pointer to a drop down list object + * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum + */ +static inline void lv_ddlist_set_sb_mode(lv_obj_t * ddlist, lv_sb_mode_t mode) +{ + lv_page_set_sb_mode(ddlist, mode); +} + +/** + * Set the open/close animation time. + * @param ddlist pointer to a drop down list + * @param anim_time: open/close animation time [ms] + */ +void lv_ddlist_set_anim_time(lv_obj_t * ddlist, uint16_t anim_time); + + +/** + * Set a style of a drop down list + * @param ddlist pointer to a drop down list object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_ddlist_set_style(lv_obj_t *ddlist, lv_ddlist_style_t type, lv_style_t *style); + +/** + * Set the alignment of the labels in a drop down list + * @param ddlist pointer to a drop down list object + * @param align alignment of labels + */ +void lv_ddlist_set_align(lv_obj_t *ddlist, lv_label_align_t align); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get arrow draw in a drop down list + * @param ddlist pointer to drop down list object + */ +bool lv_ddlist_get_draw_arrow(lv_obj_t * ddlist); + +/** + * Get the options of a drop down list + * @param ddlist pointer to drop down list object + * @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3") + */ +const char * lv_ddlist_get_options(const lv_obj_t * ddlist); + +/** + * Get the selected option + * @param ddlist pointer to drop down list object + * @return id of the selected option (0 ... number of option - 1); + */ +uint16_t lv_ddlist_get_selected(const lv_obj_t * ddlist); + +/** + * Get the current selected option as a string + * @param ddlist pointer to ddlist object + * @param buf pointer to an array to store the string + */ +void lv_ddlist_get_selected_str(const lv_obj_t * ddlist, char * buf); + +/** + * Get the "option selected" callback function + * @param ddlist pointer to a drop down list + * @return pointer to the call back function + */ +lv_action_t lv_ddlist_get_action(const lv_obj_t * ddlist); + +/** + * Get the fix height value. + * @param ddlist pointer to a drop down list object + * @return the height if the ddlist is opened (0: auto size) + */ +lv_coord_t lv_ddlist_get_fix_height(const lv_obj_t * ddlist); + +/** + * Get the scroll bar mode of a drop down list + * @param ddlist pointer to a drop down list object + * @return scrollbar mode from 'lv_page_sb_mode_t' enum + */ +static inline lv_sb_mode_t lv_ddlist_get_sb_mode(const lv_obj_t * ddlist) +{ + return lv_page_get_sb_mode(ddlist); +} + +/** + * Get the open/close animation time. + * @param ddlist pointer to a drop down list + * @return open/close animation time [ms] + */ +uint16_t lv_ddlist_get_anim_time(const lv_obj_t * ddlist); + +/** + * Get a style of a drop down list + * @param ddlist pointer to a drop down list object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_ddlist_get_style(const lv_obj_t *ddlist, lv_ddlist_style_t type); + +/** + * Get the alignment of the labels in a drop down list + * @param ddlist pointer to a drop down list object + * @return alignment of labels + */ +lv_label_align_t lv_ddlist_get_align(const lv_obj_t *ddlist); + +/*===================== + * Other functions + *====================*/ + +/** + * Open the drop down list with or without animation + * @param ddlist pointer to drop down list object + * @param anim_en true: use animation; false: not use animations + */ +void lv_ddlist_open(lv_obj_t * ddlist, bool anim_en); + +/** + * Close (Collapse) the drop down list + * @param ddlist pointer to drop down list object + * @param anim_en true: use animation; false: not use animations + */ +void lv_ddlist_close(lv_obj_t * ddlist, bool anim_en); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_DDLIST*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DDLIST_H*/ diff --git a/pros/display/lv_objx/lv_gauge.h b/pros/display/lv_objx/lv_gauge.h new file mode 100644 index 00000000..3f269cd0 --- /dev/null +++ b/pros/display/lv_objx/lv_gauge.h @@ -0,0 +1,222 @@ +/** + * @file lv_gauge.h + * + */ + +#ifndef LV_GAUGE_H +#define LV_GAUGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_GAUGE != 0 + +/*Testing of dependencies*/ +#if USE_LV_LMETER == 0 +#error "lv_gauge: lv_lmeter is required. Enable it in lv_conf.h (USE_LV_LMETER 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_lmeter.h" +#include "lv_label.h" +#include "lv_line.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of gauge*/ +typedef struct +{ + lv_lmeter_ext_t lmeter; /*Ext. of ancestor*/ + /*New data for this type */ + int16_t * values; /*Array of the set values (for needles) */ + const lv_color_t * needle_colors; /*Color of the needles (lv_color_t my_colors[needle_num])*/ + uint8_t needle_count; /*Number of needles*/ + uint8_t label_count; /*Number of labels on the scale*/ +} lv_gauge_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a gauge objects + * @param par pointer to an object, it will be the parent of the new gauge + * @param copy pointer to a gauge object, if not NULL then the new object will be copied from it + * @return pointer to the created gauge + */ +lv_obj_t * lv_gauge_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the number of needles + * @param gauge pointer to gauge object + * @param needle_cnt new count of needles + * @param colors an array of colors for needles (with 'num' elements) + */ +void lv_gauge_set_needle_count(lv_obj_t * gauge, uint8_t needle_cnt, const lv_color_t * colors); + +/** + * Set the value of a needle + * @param gauge pointer to a gauge + * @param needle_id the id of the needle + * @param value the new value + */ +void lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int16_t value); + +/** + * Set minimum and the maximum values of a gauge + * @param gauge pointer to he gauge object + * @param min minimum value + * @param max maximum value + */ +static inline void lv_gauge_set_range(lv_obj_t *gauge, int16_t min, int16_t max) +{ + lv_lmeter_set_range(gauge, min, max); +} + +/** + * Set a critical value on the scale. After this value 'line.color' scale lines will be drawn + * @param gauge pointer to a gauge object + * @param value the critical value + */ +static inline void lv_gauge_set_critical_value(lv_obj_t * gauge, int16_t value) +{ + lv_lmeter_set_value(gauge, value); +} + +/** + * Set the scale settings of a gauge + * @param gauge pointer to a gauge object + * @param angle angle of the scale (0..360) + * @param line_cnt count of scale lines. + * The get a given "subdivision" lines between label, `line_cnt` = (sub_div + 1) * (label_cnt - 1) + 1 + * @param label_cnt count of scale labels. + */ +void lv_gauge_set_scale(lv_obj_t * gauge, uint16_t angle, uint8_t line_cnt, uint8_t label_cnt); + +/** + * Set the styles of a gauge + * @param gauge pointer to a gauge object + * @param bg set the style of the gauge + * */ +static inline void lv_gauge_set_style(lv_obj_t *gauge, lv_style_t *bg) +{ + lv_obj_set_style(gauge, bg); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a needle + * @param gauge pointer to gauge object + * @param needle the id of the needle + * @return the value of the needle [min,max] + */ +int16_t lv_gauge_get_value(const lv_obj_t * gauge, uint8_t needle); + +/** + * Get the count of needles on a gauge + * @param gauge pointer to gauge + * @return count of needles + */ +uint8_t lv_gauge_get_needle_count(const lv_obj_t * gauge); + +/** + * Get the minimum value of a gauge + * @param gauge pointer to a gauge object + * @return the minimum value of the gauge + */ +static inline int16_t lv_gauge_get_min_value(const lv_obj_t * lmeter) +{ + return lv_lmeter_get_min_value(lmeter); +} + +/** + * Get the maximum value of a gauge + * @param gauge pointer to a gauge object + * @return the maximum value of the gauge + */ +static inline int16_t lv_gauge_get_max_value(const lv_obj_t * lmeter) +{ + return lv_lmeter_get_max_value(lmeter); +} + +/** + * Get a critical value on the scale. + * @param gauge pointer to a gauge object + * @return the critical value + */ +static inline int16_t lv_gauge_get_critical_value(const lv_obj_t * gauge) +{ + return lv_lmeter_get_value(gauge); +} + +/** + * Set the number of labels (and the thicker lines too) + * @param gauge pointer to a gauge object + * @return count of labels + */ +uint8_t lv_gauge_get_label_count(const lv_obj_t * gauge); + +/** + * Get the scale number of a gauge + * @param gauge pointer to a gauge object + * @return number of the scale units + */ +static inline uint8_t lv_gauge_get_line_count(const lv_obj_t * gauge) +{ + return lv_lmeter_get_line_count(gauge); +} + +/** + * Get the scale angle of a gauge + * @param gauge pointer to a gauge object + * @return angle of the scale + */ +static inline uint16_t lv_gauge_get_scale_angle(const lv_obj_t * gauge) +{ + return lv_lmeter_get_scale_angle(gauge); +} + +/** + * Get the style of a gauge + * @param gauge pointer to a gauge object + * @return pointer to the gauge's style + */ +static inline lv_style_t * lv_gauge_get_style(const lv_obj_t *gauge) +{ + return lv_obj_get_style(gauge); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_GAUGE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GAUGE_H*/ diff --git a/pros/display/lv_objx/lv_img.h b/pros/display/lv_objx/lv_img.h new file mode 100644 index 00000000..03eca247 --- /dev/null +++ b/pros/display/lv_objx/lv_img.h @@ -0,0 +1,195 @@ +/** + * @file lv_img.h + * + */ + +#ifndef LV_IMG_H +#define LV_IMG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_IMG != 0 + +#include "display/lv_core/lv_obj.h" +#include "display/lv_misc/lv_fs.h" +#include "display/lv_misc/lv_symbol_def.h" +#include "lv_label.h" +#include "display/lv_draw/lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of image*/ +typedef struct +{ + /*No inherited ext. because inherited from the base object*/ /*Ext. of ancestor*/ + /*New data for this type */ + const void * src; /*Image source: Pointer to an array or a file or a symbol*/ + + lv_coord_t w; /*Width of the image (Handled by the library)*/ + lv_coord_t h; /*Height of the image (Handled by the library)*/ +#if USE_LV_MULTI_LANG + uint16_t lang_txt_id; /*The ID of the image to display. */ +#endif + uint8_t src_type :2; /*See: lv_img_src_t*/ + uint8_t auto_size :1; /*1: automatically set the object size to the image size*/ + uint8_t cf :5; /*Color format from `lv_img_color_format_t`*/ +} lv_img_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create an image objects + * @param par pointer to an object, it will be the parent of the new button + * @param copy pointer to a image object, if not NULL then the new object will be copied from it + * @return pointer to the created image + */ +lv_obj_t * lv_img_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the pixel map to display by the image + * @param img pointer to an image object + * @param data the image data + */ +void lv_img_set_src(lv_obj_t * img, const void * src_img); + +#if USE_LV_MULTI_LANG +/** + * Set an ID which means a the same source but on different languages + * @param img pointer to an image object + * @param src_id ID of the source + */ +void lv_img_set_src_id(lv_obj_t * img, uint32_t txt_id); +#endif + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0. + * Use 'lv_img_set_src()' instead. + * @param img - + * @param fn - + */ +static inline void lv_img_set_file(lv_obj_t * img, const char * fn) +{ + (void) img; + (void) fn; +} + +/** + * Enable the auto size feature. + * If enabled the object size will be same as the picture size. + * @param img pointer to an image + * @param en true: auto size enable, false: auto size disable + */ +void lv_img_set_auto_size(lv_obj_t * img, bool autosize_en); + +/** + * Set the style of an image + * @param img pointer to an image object + * @param style pointer to a style + */ +static inline void lv_img_set_style(lv_obj_t *img, lv_style_t *style) +{ + lv_obj_set_style(img, style); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param img - + * @param upscale - + */ +static inline void lv_img_set_upscale(lv_obj_t * img, bool upcale) +{ + (void) img; + (void) upcale; +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the source of the image + * @param img pointer to an image object + * @return the image source (symbol, file name or C array) + */ +const void * lv_img_get_src(lv_obj_t * img); + +/** + * Get the name of the file set for an image + * @param img pointer to an image + * @return file name + */ +const char * lv_img_get_file_name(const lv_obj_t * img); + +#if USE_LV_MULTI_LANG +/** + * Get the source ID of the image. (Used by the multi-language feature) + * @param img pointer to an image + * @return ID of the source + */ +uint16_t lv_img_get_src_id(lv_obj_t * img); +#endif + +/** + * Get the auto size enable attribute + * @param img pointer to an image + * @return true: auto size is enabled, false: auto size is disabled + */ +bool lv_img_get_auto_size(const lv_obj_t * img); + +/** + * Get the style of an image object + * @param img pointer to an image object + * @return pointer to the image's style + */ +static inline lv_style_t* lv_img_get_style(const lv_obj_t *img) +{ + return lv_obj_get_style(img); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param img - + * @return false + */ +static inline bool lv_img_get_upscale(const lv_obj_t * img) +{ + (void)img; + return false; +} + +/********************** + * MACROS + **********************/ + +/*Use this macro to declare an image in a c file*/ +#define LV_IMG_DECLARE(var_name) extern const lv_img_dsc_t var_name; + +#endif /*USE_LV_IMG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_IMG_H*/ diff --git a/pros/display/lv_objx/lv_imgbtn.h b/pros/display/lv_objx/lv_imgbtn.h new file mode 100644 index 00000000..295be8f2 --- /dev/null +++ b/pros/display/lv_objx/lv_imgbtn.h @@ -0,0 +1,248 @@ +/** + * @file lv_imgbtn.h + * + */ + +#ifndef LV_IMGBTN_H +#define LV_IMGBTN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_IMGBTN != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTN == 0 +#error "lv_imgbtn: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_btn.h" +#include "display/lv_draw/lv_draw_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of image button*/ +typedef struct { + lv_btn_ext_t btn; /*Ext. of ancestor*/ + /*New data for this type */ +#if LV_IMGBTN_TILED == 0 + const void * img_src[LV_BTN_STATE_NUM]; /*Store images to each state*/ +#else + const void * img_src_left[LV_BTN_STATE_NUM]; /*Store left side images to each state*/ + const void * img_src_mid[LV_BTN_STATE_NUM]; /*Store center images to each state*/ + const void * img_src_right[LV_BTN_STATE_NUM]; /*Store right side images to each state*/ +#endif + lv_img_cf_t act_cf; /*Color format of the currently active image*/ +} lv_imgbtn_ext_t; + + +/*Styles*/ +enum { + LV_IMGBTN_STYLE_REL, + LV_IMGBTN_STYLE_PR, + LV_IMGBTN_STYLE_TGL_REL, + LV_IMGBTN_STYLE_TGL_PR, + LV_IMGBTN_STYLE_INA, +}; +typedef uint8_t lv_imgbtn_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a image button objects + * @param par pointer to an object, it will be the parent of the new image button + * @param copy pointer to a image button object, if not NULL then the new object will be copied from it + * @return pointer to the created image button + */ +lv_obj_t * lv_imgbtn_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ + +#if LV_IMGBTN_TILED == 0 +/** + * Set images for a state of the image button + * @param imgbtn pointer to an image button object + * @param state for which state set the new image (from `lv_btn_state_t`) ` + * @param src pointer to an image source (a C array or path to a file) + */ +void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src); +#else +/** + * Set images for a state of the image button + * @param imgbtn pointer to an image button object + * @param state for which state set the new image (from `lv_btn_state_t`) ` + * @param src_left pointer to an image source for the left side of the button (a C array or path to a file) + * @param src_mid pointer to an image source for the middle of the button (ideally 1px wide) (a C array or path to a file) + * @param src_right pointer to an image source for the right side of the button (a C array or path to a file) + */ +void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src_left, const void * src_mid, const void * src_right); + +#endif + +/** + * Enable the toggled states. On release the button will change from/to toggled state. + * @param imgbtn pointer to an image button object + * @param tgl true: enable toggled states, false: disable + */ +static inline void lv_imgbtn_set_toggle(lv_obj_t * imgbtn, bool tgl) +{ + lv_btn_set_toggle(imgbtn, tgl); +} + +/** + * Set the state of the image button + * @param imgbtn pointer to an image button object + * @param state the new state of the button (from lv_btn_state_t enum) + */ +static inline void lv_imgbtn_set_state(lv_obj_t * imgbtn, lv_btn_state_t state) +{ + lv_btn_set_state(imgbtn, state); +} + +/** + * Toggle the state of the image button (ON->OFF, OFF->ON) + * @param imgbtn pointer to a image button object + */ +static inline void lv_imgbtn_toggle(lv_obj_t * imgbtn) +{ + lv_btn_toggle(imgbtn); +} + +/** + * Set a function to call when a button event happens + * @param imgbtn pointer to an image button object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +static inline void lv_imgbtn_set_action(lv_obj_t * imgbtn, lv_btn_action_t type, lv_action_t action) +{ + lv_btn_set_action(imgbtn, type, action); +} + +/** + * Set a style of a image button. + * @param imgbtn pointer to image button object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_imgbtn_set_style(lv_obj_t * imgbtn, lv_imgbtn_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + + +#if LV_IMGBTN_TILED == 0 +/** + * Get the images in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to an image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src(lv_obj_t * imgbtn, lv_btn_state_t state); + +#else + +/** + * Get the left image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the left image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_left(lv_obj_t * imgbtn, lv_btn_state_t state); + +/** + * Get the middle image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the middle image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_middle(lv_obj_t * imgbtn, lv_btn_state_t state); + +/** + * Get the right image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the left image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_right(lv_obj_t * imgbtn, lv_btn_state_t state); + +#endif +/** + * Get the current state of the image button + * @param imgbtn pointer to a image button object + * @return the state of the button (from lv_btn_state_t enum) + */ +static inline lv_btn_state_t lv_imgbtn_get_state(const lv_obj_t * imgbtn) +{ + return lv_btn_get_state(imgbtn); +} + +/** + * Get the toggle enable attribute of the image button + * @param imgbtn pointer to a image button object + * @return ture: toggle enabled, false: disabled + */ +static inline bool lv_imgbtn_get_toggle(const lv_obj_t * imgbtn) +{ + return lv_btn_get_toggle(imgbtn); +} + +/** + * Get the release action of a image button + * @param imgbtn pointer to a image button object + * @return pointer to the release action function + */ +static inline lv_action_t lv_imgbtn_get_action(const lv_obj_t * imgbtn, lv_btn_action_t type) +{ + return lv_btn_get_action(imgbtn, type); +} + +/** + * Get style of a image button. + * @param imgbtn pointer to image button object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_imgbtn_get_style(const lv_obj_t * imgbtn, lv_imgbtn_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_IMGBTN*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_IMGBTN_H*/ diff --git a/pros/display/lv_objx/lv_kb.h b/pros/display/lv_objx/lv_kb.h new file mode 100644 index 00000000..d6ab9795 --- /dev/null +++ b/pros/display/lv_objx/lv_kb.h @@ -0,0 +1,199 @@ +/** + * @file lv_kb.h + * + */ + +#ifndef LV_KB_H +#define LV_KB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_KB != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTNM == 0 +#error "lv_kb: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM 1) " +#endif + +#if USE_LV_TA == 0 +#error "lv_kb: lv_ta is required. Enable it in lv_conf.h (USE_LV_TA 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_btnm.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_KB_MODE_TEXT, + LV_KB_MODE_NUM, +}; +typedef uint8_t lv_kb_mode_t; + +/*Data of keyboard*/ +typedef struct { + lv_btnm_ext_t btnm; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t *ta; /*Pointer to the assigned text area*/ + lv_kb_mode_t mode; /*Key map type*/ + uint8_t cursor_mng :1; /*1: automatically show/hide cursor when a text area is assigned or left*/ + lv_action_t ok_action; /*Called when the "Ok" button is clicked*/ + lv_action_t hide_action; /*Called when the "Hide" button is clicked*/ +} lv_kb_ext_t; + +enum { + LV_KB_STYLE_BG, + LV_KB_STYLE_BTN_REL, + LV_KB_STYLE_BTN_PR, + LV_KB_STYLE_BTN_TGL_REL, + LV_KB_STYLE_BTN_TGL_PR, + LV_KB_STYLE_BTN_INA, +}; +typedef uint8_t lv_kb_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a keyboard objects + * @param par pointer to an object, it will be the parent of the new keyboard + * @param copy pointer to a keyboard object, if not NULL then the new object will be copied from it + * @return pointer to the created keyboard + */ +lv_obj_t * lv_kb_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Assign a Text Area to the Keyboard. The pressed characters will be put there. + * @param kb pointer to a Keyboard object + * @param ta pointer to a Text Area object to write there + */ +void lv_kb_set_ta(lv_obj_t * kb, lv_obj_t * ta); + +/** + * Set a new a mode (text or number map) + * @param kb pointer to a Keyboard object + * @param mode the mode from 'lv_kb_mode_t' + */ +void lv_kb_set_mode(lv_obj_t * kb, lv_kb_mode_t mode); + +/** + * Automatically hide or show the cursor of the current Text Area + * @param kb pointer to a Keyboard object + * @param en true: show cursor on the current text area, false: hide cursor + */ +void lv_kb_set_cursor_manage(lv_obj_t * kb, bool en); + +/** + * Set call back to call when the "Ok" button is pressed + * @param kb pointer to Keyboard object + * @param action a callback with 'lv_action_t' type + */ +void lv_kb_set_ok_action(lv_obj_t * kb, lv_action_t action); + +/** + * Set call back to call when the "Hide" button is pressed + * @param kb pointer to Keyboard object + * @param action a callback with 'lv_action_t' type + */ +void lv_kb_set_hide_action(lv_obj_t * kb, lv_action_t action); + +/** + * Set a new map for the keyboard + * @param kb pointer to a Keyboard object + * @param map pointer to a string array to describe the map. + * See 'lv_btnm_set_map()' for more info. + */ +static inline void lv_kb_set_map(lv_obj_t *kb, const char ** map) +{ + lv_btnm_set_map(kb, map); +} + +/** + * Set a style of a keyboard + * @param kb pointer to a keyboard object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_kb_set_style(lv_obj_t *kb, lv_kb_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Assign a Text Area to the Keyboard. The pressed characters will be put there. + * @param kb pointer to a Keyboard object + * @return pointer to the assigned Text Area object + */ +lv_obj_t * lv_kb_get_ta(const lv_obj_t * kb); + +/** + * Set a new a mode (text or number map) + * @param kb pointer to a Keyboard object + * @return the current mode from 'lv_kb_mode_t' + */ +lv_kb_mode_t lv_kb_get_mode(const lv_obj_t * kb); + +/** + * Get the current cursor manage mode. + * @param kb pointer to a Keyboard object + * @return true: show cursor on the current text area, false: hide cursor + */ +bool lv_kb_get_cursor_manage(const lv_obj_t * kb); + +/** + * Get the callback to call when the "Ok" button is pressed + * @param kb pointer to Keyboard object + * @return the ok callback + */ +lv_action_t lv_kb_get_ok_action(const lv_obj_t * kb); + +/** + * Get the callback to call when the "Hide" button is pressed + * @param kb pointer to Keyboard object + * @return the close callback + */ +lv_action_t lv_kb_get_hide_action(const lv_obj_t * kb); + +/** + * Get a style of a keyboard + * @param kb pointer to a keyboard object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_kb_get_style(const lv_obj_t *kb, lv_kb_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_KB*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_KB_H*/ diff --git a/pros/display/lv_objx/lv_label.h b/pros/display/lv_objx/lv_label.h new file mode 100644 index 00000000..abd176a0 --- /dev/null +++ b/pros/display/lv_objx/lv_label.h @@ -0,0 +1,295 @@ +/** + * @file lv_rect.h + * + */ + +#ifndef LV_LABEL_H +#define LV_LABEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_LABEL != 0 + +#include "display/lv_core/lv_obj.h" +#include "display/lv_misc/lv_font.h" +#include "display/lv_misc/lv_txt.h" +#include "display/lv_misc/lv_symbol_def.h" + +/********************* + * DEFINES + *********************/ +#define LV_LABEL_DOT_NUM 3 +#define LV_LABEL_POS_LAST 0xFFFF + +/********************** + * TYPEDEFS + **********************/ + +/*Long mode behaviors. Used in 'lv_label_ext_t' */ +enum +{ + LV_LABEL_LONG_EXPAND, /*Expand the object size to the text size*/ + LV_LABEL_LONG_BREAK, /*Keep the object width, break the too long lines and expand the object height*/ + LV_LABEL_LONG_SCROLL, /*Expand the object size and scroll the text on the parent (move the label object)*/ + LV_LABEL_LONG_DOT, /*Keep the size and write dots at the end if the text is too long*/ + LV_LABEL_LONG_ROLL, /*Keep the size and roll the text infinitely*/ + LV_LABEL_LONG_CROP, /*Keep the size and crop the text out of it*/ +}; +typedef uint8_t lv_label_long_mode_t; + +/*Label align policy*/ +enum { + LV_LABEL_ALIGN_LEFT, + LV_LABEL_ALIGN_CENTER, + LV_LABEL_ALIGN_RIGHT, +}; +typedef uint8_t lv_label_align_t; + +/*Data of label*/ +typedef struct +{ + /*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/ + /*New data for this type */ + char * text; /*Text of the label*/ + lv_label_long_mode_t long_mode; /*Determinate what to do with the long texts*/ +#if LV_TXT_UTF8 == 0 + char dot_tmp[LV_LABEL_DOT_NUM + 1]; /*Store the character which are replaced by dots (Handled by the library)*/ +#else + char dot_tmp[LV_LABEL_DOT_NUM * 4 + 1]; /*Store the character which are replaced by dots (Handled by the library)*/ +#endif + +#if USE_LV_MULTI_LANG + uint16_t lang_txt_id; /*The ID of the text to display*/ +#endif + uint16_t dot_end; /*The text end position in dot mode (Handled by the library)*/ + uint16_t anim_speed; /*Speed of scroll and roll animation in px/sec unit*/ + lv_point_t offset; /*Text draw position offset*/ + uint8_t static_txt :1; /*Flag to indicate the text is static*/ + uint8_t align :2; /*Align type from 'lv_label_align_t'*/ + uint8_t recolor :1; /*Enable in-line letter re-coloring*/ + uint8_t expand :1; /*Ignore real width (used by the library with LV_LABEL_LONG_ROLL)*/ + uint8_t body_draw :1; /*Draw background body*/ +} lv_label_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a label objects + * @param par pointer to an object, it will be the parent of the new label + * @param copy pointer to a button object, if not NULL then the new object will be copied from it + * @return pointer to the created button + */ +lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new text for a label. Memory will be allocated to store the text by the label. + * @param label pointer to a label object + * @param text '\0' terminated character string. NULL to refresh with the current text. + */ +void lv_label_set_text(lv_obj_t * label, const char * text); + +/** + * Set a new text for a label from a character array. The array don't has to be '\0' terminated. + * Memory will be allocated to store the array by the label. + * @param label pointer to a label object + * @param array array of characters or NULL to refresh the label + * @param size the size of 'array' in bytes + */ +void lv_label_set_array_text(lv_obj_t * label, const char * array, uint16_t size); + +/** + * Set a static text. It will not be saved by the label so the 'text' variable + * has to be 'alive' while the label exist. + * @param label pointer to a label object + * @param text pointer to a text. NULL to refresh with the current text. + */ +void lv_label_set_static_text(lv_obj_t * label, const char * text); + +/** + *Set a text ID which means a the same text but on different languages + * @param label pointer to a label object + * @param txt_id ID of the text + */ +#if USE_LV_MULTI_LANG +void lv_label_set_text_id(lv_obj_t * label, uint32_t txt_id); +#endif + +/** + * Set the behavior of the label with longer text then the object size + * @param label pointer to a label object + * @param long_mode the new mode from 'lv_label_long_mode' enum. + * In LV_LONG_BREAK/LONG/ROLL the size of the label should be set AFTER this function + */ +void lv_label_set_long_mode(lv_obj_t * label, lv_label_long_mode_t long_mode); + +/** + * Set the align of the label (left or center) + * @param label pointer to a label object + * @param align 'LV_LABEL_ALIGN_LEFT' or 'LV_LABEL_ALIGN_LEFT' + */ +void lv_label_set_align(lv_obj_t *label, lv_label_align_t align); + +/** + * Enable the recoloring by in-line commands + * @param label pointer to a label object + * @param en true: enable recoloring, false: disable + */ +void lv_label_set_recolor(lv_obj_t * label, bool en); + +/** + * Set the label to draw (or not draw) background specified in its style's body + * @param label pointer to a label object + * @param en true: draw body; false: don't draw body + */ +void lv_label_set_body_draw(lv_obj_t *label, bool en); + +/** + * Set the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes + * @param label pointer to a label object + * @param anim_speed speed of animation in px/sec unit + */ +void lv_label_set_anim_speed(lv_obj_t *label, uint16_t anim_speed); + +/** + * Set the style of an label + * @param label pointer to an label object + * @param style pointer to a style + */ +static inline void lv_label_set_style(lv_obj_t *label, lv_style_t *style) +{ + lv_obj_set_style(label, style); +} +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a label + * @param label pointer to a label object + * @return the text of the label + */ +char * lv_label_get_text(const lv_obj_t * label); + +#if USE_LV_MULTI_LANG +/** + * Get the text ID of the label. (Used by the multi-language feature) + * @param label pointer to a label object + * @return ID of the text + */ +uint16_t lv_label_get_text_id(lv_obj_t * label); +#endif + +/** + * Get the long mode of a label + * @param label pointer to a label object + * @return the long mode + */ +lv_label_long_mode_t lv_label_get_long_mode(const lv_obj_t * label); + +/** + * Get the align attribute + * @param label pointer to a label object + * @return LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_label_get_align(const lv_obj_t * label); + +/** + * Get the recoloring attribute + * @param label pointer to a label object + * @return true: recoloring is enabled, false: disable + */ +bool lv_label_get_recolor(const lv_obj_t * label); + +/** + * Get the body draw attribute + * @param label pointer to a label object + * @return true: draw body; false: don't draw body + */ +bool lv_label_get_body_draw(const lv_obj_t *label); + +/** + * Get the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes + * @param label pointer to a label object + * @return speed of animation in px/sec unit + */ +uint16_t lv_label_get_anim_speed(const lv_obj_t *label); + +/** + * Get the relative x and y coordinates of a letter + * @param label pointer to a label object + * @param index index of the letter [0 ... text length]. Expressed in character index, not byte index (different in UTF-8) + * @param pos store the result here (E.g. index = 0 gives 0;0 coordinates) + */ +void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t * pos); + +/** + * Get the index of letter on a relative point of a label + * @param label pointer to label object + * @param pos pointer to point with coordinates on a the label + * @return the index of the letter on the 'pos_p' point (E.g. on 0;0 is the 0. letter) + * Expressed in character index and not byte index (different in UTF-8) + */ +uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos); + +/** + * Get the style of an label object + * @param label pointer to an label object + * @return pointer to the label's style + */ +static inline lv_style_t* lv_label_get_style(const lv_obj_t *label) +{ + return lv_obj_get_style(label); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Insert a text to the label. The label text can not be static. + * @param label pointer to a label object + * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8) + * 0: before first char. + * LV_LABEL_POS_LAST: after last char. + * @param txt pointer to the text to insert + */ +void lv_label_ins_text(lv_obj_t * label, uint32_t pos, const char * txt); + +/** + * Delete characters from a label. The label text can not be static. + * @param label pointer to a label object + * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8) + * 0: before first char. + * @param cnt number of characters to cut + */ +void lv_label_cut_text(lv_obj_t * label, uint32_t pos, uint32_t cnt); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LABEL*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LABEL_H*/ diff --git a/pros/display/lv_objx/lv_led.h b/pros/display/lv_objx/lv_led.h new file mode 100644 index 00000000..f6a18acb --- /dev/null +++ b/pros/display/lv_objx/lv_led.h @@ -0,0 +1,116 @@ +/** + * @file lv_led.h + * + */ + +#ifndef LV_LED_H +#define LV_LED_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_LED != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of led*/ +typedef struct +{ + /*No inherited ext.*/ + /*New data for this type */ + uint8_t bright; /*Current brightness of the LED (0..255)*/ +} lv_led_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a led objects + * @param par pointer to an object, it will be the parent of the new led + * @param copy pointer to a led object, if not NULL then the new object will be copied from it + * @return pointer to the created led + */ +lv_obj_t * lv_led_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Set the brightness of a LED object + * @param led pointer to a LED object + * @param bright 0 (max. dark) ... 255 (max. light) + */ +void lv_led_set_bright(lv_obj_t * led, uint8_t bright); + +/** + * Light on a LED + * @param led pointer to a LED object + */ +void lv_led_on(lv_obj_t * led); + +/** + * Light off a LED + * @param led pointer to a LED object + */ +void lv_led_off(lv_obj_t * led); + +/** + * Toggle the state of a LED + * @param led pointer to a LED object + */ +void lv_led_toggle(lv_obj_t * led); + +/** + * Set the style of a led + * @param led pointer to a led object + * @param style pointer to a style + */ +static inline void lv_led_set_style(lv_obj_t *led, lv_style_t *style) +{ + lv_obj_set_style(led, style); +} + +/** + * Get the brightness of a LEd object + * @param led pointer to LED object + * @return bright 0 (max. dark) ... 255 (max. light) + */ +uint8_t lv_led_get_bright(const lv_obj_t * led); + +/** + * Get the style of an led object + * @param led pointer to an led object + * @return pointer to the led's style + */ +static inline lv_style_t* lv_led_get_style(const lv_obj_t *led) +{ + return lv_obj_get_style(led); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LED*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LED_H*/ diff --git a/pros/display/lv_objx/lv_line.h b/pros/display/lv_objx/lv_line.h new file mode 100644 index 00000000..e7be8a32 --- /dev/null +++ b/pros/display/lv_objx/lv_line.h @@ -0,0 +1,158 @@ +/** + * @file lv_line.h + * + */ + +#ifndef LV_LINE_H +#define LV_LINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_LINE != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of line*/ +typedef struct +{ + /*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/ + const lv_point_t * point_array; /*Pointer to an array with the points of the line*/ + uint16_t point_num; /*Number of points in 'point_array' */ + uint8_t auto_size :1; /*1: set obj. width to x max and obj. height to y max */ + uint8_t y_inv :1; /*1: y == 0 will be on the bottom*/ +} lv_line_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a line objects + * @param par pointer to an object, it will be the parent of the new line + * @return pointer to the created line + */ +lv_obj_t * lv_line_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set an array of points. The line object will connect these points. + * @param line pointer to a line object + * @param point_a an array of points. Only the address is saved, + * so the array can NOT be a local variable which will be destroyed + * @param point_num number of points in 'point_a' + */ +void lv_line_set_points(lv_obj_t * line, const lv_point_t * point_a, uint16_t point_num); + +/** + * Enable (or disable) the auto-size option. The size of the object will fit to its points. + * (set width to x max and height to y max) + * @param line pointer to a line object + * @param en true: auto size is enabled, false: auto size is disabled + */ +void lv_line_set_auto_size(lv_obj_t * line, bool en); + +/** + * Enable (or disable) the y coordinate inversion. + * If enabled then y will be subtracted from the height of the object, + * therefore the y=0 coordinate will be on the bottom. + * @param line pointer to a line object + * @param en true: enable the y inversion, false:disable the y inversion + */ +void lv_line_set_y_invert(lv_obj_t * line, bool en); + +#define lv_line_set_y_inv lv_line_set_y_invert /*The name was inconsistent. In v.6.0 only `lv_line_set_y_invert`will work */ + +/** + * Set the style of a line + * @param line pointer to a line object + * @param style pointer to a style + */ +static inline void lv_line_set_style(lv_obj_t *line, lv_style_t *style) +{ + lv_obj_set_style(line, style); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param line - + * @param upscale - + */ +static inline void lv_line_set_upscale(lv_obj_t * line, bool upcale) +{ + (void) line; + (void) upcale; +} +/*===================== + * Getter functions + *====================*/ + +/** + * Get the auto size attribute + * @param line pointer to a line object + * @return true: auto size is enabled, false: disabled + */ +bool lv_line_get_auto_size(const lv_obj_t * line); + +/** + * Get the y inversion attribute + * @param line pointer to a line object + * @return true: y inversion is enabled, false: disabled + */ +bool lv_line_get_y_invert(const lv_obj_t * line); + +/** + * Get the style of an line object + * @param line pointer to an line object + * @return pointer to the line's style + */ +static inline lv_style_t* lv_line_get_style(const lv_obj_t *line) +{ + return lv_obj_get_style(line); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param line - + * @return false + */ +static inline bool lv_line_get_upscale(const lv_obj_t * line) +{ + (void) line; + return false; +} + + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LINE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LINE_H*/ diff --git a/pros/display/lv_objx/lv_list.h b/pros/display/lv_objx/lv_list.h new file mode 100644 index 00000000..397059a5 --- /dev/null +++ b/pros/display/lv_objx/lv_list.h @@ -0,0 +1,336 @@ +/** + * @file lv_list.h + * + */ + +#ifndef LV_LIST_H +#define LV_LIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_LIST != 0 + +/*Testing of dependencies*/ +#if USE_LV_PAGE == 0 +#error "lv_list: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#if USE_LV_BTN == 0 +#error "lv_list: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_list: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + + +#include "display/lv_core/lv_obj.h" +#include "lv_page.h" +#include "lv_btn.h" +#include "lv_label.h" +#include "lv_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of list*/ +typedef struct +{ + lv_page_ext_t page; /*Ext. of ancestor*/ + /*New data for this type */ + uint16_t anim_time; /*Scroll animation time*/ + lv_style_t *styles_btn[LV_BTN_STATE_NUM]; /*Styles of the list element buttons*/ + lv_style_t *style_img; /*Style of the list element images on buttons*/ + uint32_t size; /*the number of items(buttons) in the list*/ + bool single_mode; /* whether single selected mode is enabled */ +#if USE_LV_GROUP + lv_obj_t * last_sel; /* The last selected button. It will be reverted when the list is focused again */ + lv_obj_t * selected_btn; /* The button is currently being selected*/ +#endif +} lv_list_ext_t; + +enum { + LV_LIST_STYLE_BG, + LV_LIST_STYLE_SCRL, + LV_LIST_STYLE_SB, + LV_LIST_STYLE_EDGE_FLASH, + LV_LIST_STYLE_BTN_REL, + LV_LIST_STYLE_BTN_PR, + LV_LIST_STYLE_BTN_TGL_REL, + LV_LIST_STYLE_BTN_TGL_PR, + LV_LIST_STYLE_BTN_INA, +}; +typedef uint8_t lv_list_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a list objects + * @param par pointer to an object, it will be the parent of the new list + * @param copy pointer to a list object, if not NULL then the new object will be copied from it + * @return pointer to the created list + */ +lv_obj_t * lv_list_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_list_clean(lv_obj_t *obj); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add a list element to the list + * @param list pointer to list object + * @param img_fn file name of an image before the text (NULL if unused) + * @param txt text of the list element (NULL if unused) + * @param rel_action pointer to release action function (like with lv_btn) + * @return pointer to the new list element which can be customized (a button) + */ +lv_obj_t * lv_list_add(lv_obj_t * list, const void * img_src, const char * txt, lv_action_t rel_action); + +/** + * Remove the index of the button in the list + * @param list pointer to a list object + * @param index pointer to a the button's index in the list, index must be 0 <= index < lv_list_ext_t.size + * @return true: successfully deleted + */ +bool lv_list_remove(const lv_obj_t * list, uint32_t index); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set single button selected mode, only one button will be selected if enabled. + * @param list pointer to the currently pressed list object + * @param mode, enable(true)/disable(false) single selected mode. + */ +void lv_list_set_single_mode(lv_obj_t *list, bool mode); + +#if USE_LV_GROUP + +/** + * Make a button selected. Can be used while navigating in the list with a keypad. + * @param list pointer to a list object + * @param btn pointer to a button to select + */ +void lv_list_set_btn_selected(lv_obj_t * list, lv_obj_t * btn); +#endif + +/** + * Set scroll animation duration on 'list_up()' 'list_down()' 'list_focus()' + * @param list pointer to a list object + * @param anim_time duration of animation [ms] + */ +void lv_list_set_anim_time(lv_obj_t *list, uint16_t anim_time); + +/** + * Set the scroll bar mode of a list + * @param list pointer to a list object + * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum + */ +static inline void lv_list_set_sb_mode(lv_obj_t * list, lv_sb_mode_t mode) +{ + lv_page_set_sb_mode(list, mode); +} + +/** + * Enable the scroll propagation feature. If enabled then the List will move its parent if there is no more space to scroll. + * @param list pointer to a List + * @param en true or false to enable/disable scroll propagation + */ +static inline void lv_list_set_scroll_propagation(lv_obj_t * list, bool en) +{ + lv_page_set_scroll_propagation(list, en); +} + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param list pointer to a List + * @param en true or false to enable/disable end flash + */ +static inline void lv_list_set_edge_flash(lv_obj_t * list, bool en) +{ + lv_page_set_edge_flash(list, en); +} + +/** + * Set a style of a list + * @param list pointer to a list object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_list_set_style(lv_obj_t *list, lv_list_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get single button selected mode. + * @param list pointer to the currently pressed list object. + */ +bool lv_list_get_single_mode(lv_obj_t *list); + +/** + * Get the text of a list element + * @param btn pointer to list element + * @return pointer to the text + */ +const char * lv_list_get_btn_text(const lv_obj_t * btn); +/** + * Get the label object from a list element + * @param btn pointer to a list element (button) + * @return pointer to the label from the list element or NULL if not found + */ +lv_obj_t * lv_list_get_btn_label(const lv_obj_t * btn); + +/** + * Get the image object from a list element + * @param btn pointer to a list element (button) + * @return pointer to the image from the list element or NULL if not found + */ +lv_obj_t * lv_list_get_btn_img(const lv_obj_t * btn); + +/** + * Get the next button from list. (Starts from the bottom button) + * @param list pointer to a list object + * @param prev_btn pointer to button. Search the next after it. + * @return pointer to the next button or NULL when no more buttons + */ +lv_obj_t * lv_list_get_prev_btn(const lv_obj_t * list, lv_obj_t * prev_btn); + +/** + * Get the previous button from list. (Starts from the top button) + * @param list pointer to a list object + * @param prev_btn pointer to button. Search the previous before it. + * @return pointer to the previous button or NULL when no more buttons + */ +lv_obj_t * lv_list_get_next_btn(const lv_obj_t * list, lv_obj_t * prev_btn); + +/** + * Get the index of the button in the list + * @param list pointer to a list object. If NULL, assumes btn is part of a list. + * @param btn pointer to a list element (button) + * @return the index of the button in the list, or -1 of the button not in this list + */ +int32_t lv_list_get_btn_index(const lv_obj_t * list, const lv_obj_t * btn); + +/** + * Get the number of buttons in the list + * @param list pointer to a list object + * @return the number of buttons in the list + */ +uint32_t lv_list_get_size(const lv_obj_t * list); + +#if USE_LV_GROUP +/** + * Get the currently selected button. Can be used while navigating in the list with a keypad. + * @param list pointer to a list object + * @return pointer to the selected button + */ +lv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list); +#endif + + +/** + * Get scroll animation duration + * @param list pointer to a list object + * @return duration of animation [ms] + */ +uint16_t lv_list_get_anim_time(const lv_obj_t *list); + + +/** + * Get the scroll bar mode of a list + * @param list pointer to a list object + * @return scrollbar mode from 'lv_page_sb_mode_t' enum + */ +static inline lv_sb_mode_t lv_list_get_sb_mode(const lv_obj_t * list) +{ + return lv_page_get_sb_mode(list); +} + +/** + * Get the scroll propagation property + * @param list pointer to a List + * @return true or false + */ +static inline bool lv_list_get_scroll_propagation(lv_obj_t * list) +{ + return lv_page_get_scroll_propagation(list); +} + +/** + * Get the scroll propagation property + * @param list pointer to a List + * @return true or false + */ +static inline bool lv_list_get_edge_flash(lv_obj_t * list) +{ + return lv_page_get_edge_flash(list); +} + +/** + * Get a style of a list + * @param list pointer to a list object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_list_get_style(const lv_obj_t *list, lv_list_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Move the list elements up by one + * @param list pointer a to list object + */ +void lv_list_up(const lv_obj_t * list); +/** + * Move the list elements down by one + * @param list pointer to a list object + */ +void lv_list_down(const lv_obj_t * list); + +/** + * Focus on a list button. It ensures that the button will be visible on the list. + * @param btn pointer to a list button to focus + * @param anim_en true: scroll with animation, false: without animation + */ +void lv_list_focus(const lv_obj_t *btn, bool anim_en); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LIST*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LIST_H*/ diff --git a/pros/display/lv_objx/lv_lmeter.h b/pros/display/lv_objx/lv_lmeter.h new file mode 100644 index 00000000..dcb42bf4 --- /dev/null +++ b/pros/display/lv_objx/lv_lmeter.h @@ -0,0 +1,153 @@ +/** + * @file lv_lmeter.h + * + */ + +#ifndef LV_LMETER_H +#define LV_LMETER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_LMETER != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of line meter*/ +typedef struct +{ + /*No inherited ext.*/ /*Ext. of ancestor*/ + /*New data for this type */ + uint16_t scale_angle; /*Angle of the scale in deg. (0..360)*/ + uint8_t line_cnt; /*Count of lines */ + int16_t cur_value; + int16_t min_value; + int16_t max_value; +} lv_lmeter_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a line meter objects + * @param par pointer to an object, it will be the parent of the new line meter + * @param copy pointer to a line meter object, if not NULL then the new object will be copied from it + * @return pointer to the created line meter + */ +lv_obj_t * lv_lmeter_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the line meter + * @param lmeter pointer to a line meter object + * @param value new value + */ +void lv_lmeter_set_value(lv_obj_t *lmeter, int16_t value); + +/** + * Set minimum and the maximum values of a line meter + * @param lmeter pointer to he line meter object + * @param min minimum value + * @param max maximum value + */ +void lv_lmeter_set_range(lv_obj_t *lmeter, int16_t min, int16_t max); + +/** + * Set the scale settings of a line meter + * @param lmeter pointer to a line meter object + * @param angle angle of the scale (0..360) + * @param line_cnt number of lines + */ +void lv_lmeter_set_scale(lv_obj_t * lmeter, uint16_t angle, uint8_t line_cnt); + +/** + * Set the styles of a line meter + * @param lmeter pointer to a line meter object + * @param bg set the style of the line meter + */ +static inline void lv_lmeter_set_style(lv_obj_t *lmeter, lv_style_t *bg) +{ + lv_obj_set_style(lmeter, bg); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a line meter + * @param lmeter pointer to a line meter object + * @return the value of the line meter + */ +int16_t lv_lmeter_get_value(const lv_obj_t *lmeter); + +/** + * Get the minimum value of a line meter + * @param lmeter pointer to a line meter object + * @return the minimum value of the line meter + */ +int16_t lv_lmeter_get_min_value(const lv_obj_t * lmeter); + +/** + * Get the maximum value of a line meter + * @param lmeter pointer to a line meter object + * @return the maximum value of the line meter + */ +int16_t lv_lmeter_get_max_value(const lv_obj_t * lmeter); + +/** + * Get the scale number of a line meter + * @param lmeter pointer to a line meter object + * @return number of the scale units + */ +uint8_t lv_lmeter_get_line_count(const lv_obj_t * lmeter); + +/** + * Get the scale angle of a line meter + * @param lmeter pointer to a line meter object + * @return angle of the scale + */ +uint16_t lv_lmeter_get_scale_angle(const lv_obj_t * lmeter); + +/** + * Get the style of a line meter + * @param lmeter pointer to a line meter object + * @return pointer to the line meter's style + */ +static inline lv_style_t * lv_lmeter_get_style(const lv_obj_t * lmeter) +{ + return lv_obj_get_style(lmeter); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LMETER*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LMETER_H*/ diff --git a/pros/display/lv_objx/lv_mbox.h b/pros/display/lv_objx/lv_mbox.h new file mode 100644 index 00000000..2dc0c6dc --- /dev/null +++ b/pros/display/lv_objx/lv_mbox.h @@ -0,0 +1,203 @@ +/** + * @file lv_mbox.h + * + */ + +#ifndef LV_MBOX_H +#define LV_MBOX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_MBOX != 0 + +/*Testing of dependencies*/ +#if USE_LV_CONT == 0 +#error "lv_mbox: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT 1) " +#endif + +#if USE_LV_BTNM == 0 +#error "lv_mbox: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_mbox: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + + +#include "display/lv_core/lv_obj.h" +#include "lv_cont.h" +#include "lv_btnm.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of message box*/ +typedef struct +{ + lv_cont_ext_t bg; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t *text; /*Text of the message box*/ + lv_obj_t *btnm; /*Button matrix for the buttons*/ + uint16_t anim_time; /*Duration of close animation [ms] (0: no animation)*/ +} lv_mbox_ext_t; + +enum { + LV_MBOX_STYLE_BG, + LV_MBOX_STYLE_BTN_BG, + LV_MBOX_STYLE_BTN_REL, + LV_MBOX_STYLE_BTN_PR, + LV_MBOX_STYLE_BTN_TGL_REL, + LV_MBOX_STYLE_BTN_TGL_PR, + LV_MBOX_STYLE_BTN_INA, +}; +typedef uint8_t lv_mbox_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a message box objects + * @param par pointer to an object, it will be the parent of the new message box + * @param copy pointer to a message box object, if not NULL then the new object will be copied from it + * @return pointer to the created message box + */ +lv_obj_t * lv_mbox_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add button to the message box + * @param mbox pointer to message box object + * @param btn_map button descriptor (button matrix map). + * E.g. a const char *txt[] = {"ok", "close", ""} (Can not be local variable) + * @param action a function which will be called when a button is released + */ +void lv_mbox_add_btns(lv_obj_t * mbox, const char **btn_map, lv_btnm_action_t action); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of the message box + * @param mbox pointer to a message box + * @param txt a '\0' terminated character string which will be the message box text + */ +void lv_mbox_set_text(lv_obj_t * mbox, const char * txt); + +/** + * Stop the action to call when button is released + * @param mbox pointer to a message box object + * @param pointer to an 'lv_btnm_action_t' action. In the action you need to use `lv_mbox_get_from_btn()` to get the `mbox`. + */ +void lv_mbox_set_action(lv_obj_t * mbox, lv_btnm_action_t action); + +/** + * Set animation duration + * @param mbox pointer to a message box object + * @param anim_time animation length in milliseconds (0: no animation) + */ +void lv_mbox_set_anim_time(lv_obj_t * mbox, uint16_t anim_time); + +/** + * Automatically delete the message box after a given time + * @param mbox pointer to a message box object + * @param delay a time (in milliseconds) to wait before delete the message box + */ +void lv_mbox_start_auto_close(lv_obj_t * mbox, uint16_t delay); + +/** + * Stop the auto. closing of message box + * @param mbox pointer to a message box object + */ +void lv_mbox_stop_auto_close(lv_obj_t * mbox); + +/** + * Set a style of a message box + * @param mbox pointer to a message box object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_mbox_set_style(lv_obj_t *mbox, lv_mbox_style_t type, lv_style_t *style); + +/** + * Set whether recoloring is enabled. Must be called after `lv_mbox_add_btns`. + * @param btnm pointer to button matrix object + * @param en whether recoloring is enabled + */ +void lv_mbox_set_recolor(lv_obj_t * mbox, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of the message box + * @param mbox pointer to a message box object + * @return pointer to the text of the message box + */ +const char * lv_mbox_get_text(const lv_obj_t * mbox); + +/** + * Get the message box object from one of its button. + * It is useful in the button release actions where only the button is known + * @param btn pointer to a button of a message box + * @return pointer to the button's message box + */ +lv_obj_t * lv_mbox_get_from_btn(const lv_obj_t * btn); + +/** + * Get the animation duration (close animation time) + * @param mbox pointer to a message box object + * @return animation length in milliseconds (0: no animation) + */ +uint16_t lv_mbox_get_anim_time(const lv_obj_t * mbox); + + +/** + * Get a style of a message box + * @param mbox pointer to a message box object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_mbox_get_style(const lv_obj_t *mbox, lv_mbox_style_t type); + +/** + * Get whether recoloring is enabled + * @param btnm pointer to button matrix object + * @return whether recoloring is enabled + */ +bool lv_mbox_get_recolor(const lv_obj_t * mbox); + +/********************** + * MACROS + **********************/ + + +#endif /*USE_LV_MBOX*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_MBOX_H*/ diff --git a/pros/display/lv_objx/lv_objx.mk b/pros/display/lv_objx/lv_objx.mk new file mode 100644 index 00000000..d35252bc --- /dev/null +++ b/pros/display/lv_objx/lv_objx.mk @@ -0,0 +1,36 @@ +CSRCS += lv_arc.c +CSRCS += lv_bar.c +CSRCS += lv_cb.c +CSRCS += lv_ddlist.c +CSRCS += lv_kb.c +CSRCS += lv_line.c +CSRCS += lv_mbox.c +CSRCS += lv_preload.c +CSRCS += lv_roller.c +CSRCS += lv_table.c +CSRCS += lv_tabview.c +CSRCS += lv_tileview.c +CSRCS += lv_btn.c +CSRCS += lv_calendar.c +CSRCS += lv_chart.c +CSRCS += lv_canvas.c +CSRCS += lv_gauge.c +CSRCS += lv_label.c +CSRCS += lv_list.c +CSRCS += lv_slider.c +CSRCS += lv_ta.c +CSRCS += lv_spinbox.c +CSRCS += lv_btnm.c +CSRCS += lv_cont.c +CSRCS += lv_img.c +CSRCS += lv_imgbtn.c +CSRCS += lv_led.c +CSRCS += lv_lmeter.c +CSRCS += lv_page.c +CSRCS += lv_sw.c +CSRCS += lv_win.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_objx +VPATH += :$(LVGL_DIR)/lvgl/lv_objx + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_objx" diff --git a/pros/display/lv_objx/lv_objx_templ.h b/pros/display/lv_objx/lv_objx_templ.h new file mode 100644 index 00000000..b8473dfb --- /dev/null +++ b/pros/display/lv_objx/lv_objx_templ.h @@ -0,0 +1,111 @@ +/** + * @file lv_templ.h + * + */ + + +/* TODO Remove these instructions + * Search an replace: template -> object normal name with lower case (e.g. button, label etc.) + * templ -> object short name with lower case(e.g. btn, label etc) + * TEMPL -> object short name with upper case (e.g. BTN, LABEL etc.) + * + */ + +#ifndef LV_TEMPL_H +#define LV_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_TEMPL != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of template*/ +typedef struct { + lv_ANCESTOR_ext_t ANCESTOR; /*Ext. of ancestor*/ + /*New data for this type */ +} lv_templ_ext_t; + + +/*Styles*/ +enum { + LV_TEMPL_STYLE_X, + LV_TEMPL_STYLE_Y, +}; +typedef uint8_t lv_templ_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a template objects + * @param par pointer to an object, it will be the parent of the new template + * @param copy pointer to a template object, if not NULL then the new object will be copied from it + * @return pointer to the created template + */ +lv_obj_t * lv_templ_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a template. + * @param templ pointer to template object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_templ_set_style(lv_obj_t * templ, lv_templ_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get style of a template. + * @param templ pointer to template object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_templ_get_style(const lv_obj_t * templ, lv_templ_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TEMPL*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/pros/display/lv_objx/lv_page.h b/pros/display/lv_objx/lv_page.h new file mode 100644 index 00000000..d01de358 --- /dev/null +++ b/pros/display/lv_objx/lv_page.h @@ -0,0 +1,382 @@ +/** + * @file lv_page.h + * + */ + +#ifndef LV_PAGE_H +#define LV_PAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_PAGE != 0 + +/*Testing of dependencies*/ +#if USE_LV_CONT == 0 +#error "lv_page: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT 1) " +#endif + +#include "lv_cont.h" +#include "display/lv_core/lv_indev.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Scrollbar modes: shows when should the scrollbars be visible*/ +enum +{ + LV_SB_MODE_OFF = 0x0, /*Never show scrollbars*/ + LV_SB_MODE_ON = 0x1, /*Always show scrollbars*/ + LV_SB_MODE_DRAG = 0x2, /*Show scrollbars when page is being dragged*/ + LV_SB_MODE_AUTO = 0x3, /*Show scrollbars when the scrollable container is large enough to be scrolled*/ + LV_SB_MODE_HIDE = 0x4, /*Hide the scroll bar temporally*/ + LV_SB_MODE_UNHIDE = 0x5, /*Unhide the previously hidden scrollbar. Recover it's type too*/ +}; +typedef uint8_t lv_sb_mode_t; + +/*Data of page*/ +typedef struct +{ + lv_cont_ext_t bg; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * scrl; /*The scrollable object on the background*/ + lv_action_t rel_action; /*Function to call when the page is released*/ + lv_action_t pr_action; /*Function to call when the page is pressed*/ + struct { + lv_style_t *style; /*Style of scrollbars*/ + lv_area_t hor_area; /*Horizontal scrollbar area relative to the page. (Handled by the library) */ + lv_area_t ver_area; /*Vertical scrollbar area relative to the page (Handled by the library)*/ + uint8_t hor_draw :1; /*1: horizontal scrollbar is visible now (Handled by the library)*/ + uint8_t ver_draw :1; /*1: vertical scrollbar is visible now (Handled by the library)*/ + lv_sb_mode_t mode:3; /*Scrollbar visibility from 'lv_page_sb_mode_t'*/ + } sb; + struct { + uint16_t state; /*Store the current size of the edge flash effect*/ + lv_style_t *style; /*Style of edge flash effect (usually homogeneous circle)*/ + uint8_t enabled :1; /*1: Show a flash animation on the edge*/ + uint8_t top_ip :1; /*Used internally to show that top most position is reached (flash is In Progress)*/ + uint8_t bottom_ip :1; /*Used internally to show that bottom most position is reached (flash is In Progress)*/ + uint8_t right_ip :1; /*Used internally to show that right most position is reached (flash is In Progress)*/ + uint8_t left_ip :1; /*Used internally to show that left most position is reached (flash is In Progress)*/ + }edge_flash; + + uint8_t arrow_scroll :1; /*1: Enable scrolling with LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN*/ + uint8_t scroll_prop :1; /*1: Propagate the scrolling the the parent if the edge is reached*/ + uint8_t scroll_prop_ip :1; /*1: Scroll propagation is in progress (used by the library)*/ +} lv_page_ext_t; + +enum { + LV_PAGE_STYLE_BG, + LV_PAGE_STYLE_SCRL, + LV_PAGE_STYLE_SB, + LV_PAGE_STYLE_EDGE_FLASH, +}; +typedef uint8_t lv_page_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a page objects + * @param par pointer to an object, it will be the parent of the new page + * @param copy pointer to a page object, if not NULL then the new object will be copied from it + * @return pointer to the created page + */ +lv_obj_t * lv_page_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_page_clean(lv_obj_t *obj); + +/** + * Get the press action of the page + * @param page pointer to a page object + * @return a function to call when the page is pressed + */ +lv_action_t lv_page_get_pr_action(lv_obj_t * page); + +/** + * Get the release action of the page + * @param page pointer to a page object + * @return a function to call when the page is released + */ +lv_action_t lv_page_get_rel_action(lv_obj_t * page); + +/** + * Get the scrollable object of a page + * @param page pointer to a page object + * @return pointer to a container which is the scrollable part of the page + */ +lv_obj_t * lv_page_get_scrl(const lv_obj_t * page); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a release action for the page + * @param page pointer to a page object + * @param rel_action a function to call when the page is released + */ +void lv_page_set_rel_action(lv_obj_t * page, lv_action_t rel_action); + +/** + * Set a press action for the page + * @param page pointer to a page object + * @param pr_action a function to call when the page is pressed + */ +void lv_page_set_pr_action(lv_obj_t * page, lv_action_t pr_action); + +/** + * Set the scroll bar mode on a page + * @param page pointer to a page object + * @param sb_mode the new mode from 'lv_page_sb.mode_t' enum + */ +void lv_page_set_sb_mode(lv_obj_t * page, lv_sb_mode_t sb_mode); + +/** + * Enable/Disable scrolling with arrows if the page is in group (arrows: LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) + * @param page pointer to a page object + * @param en true: enable scrolling with arrows + */ +void lv_page_set_arrow_scroll(lv_obj_t * page, bool en); + +/** + * Enable the scroll propagation feature. If enabled then the page will move its parent if there is no more space to scroll. + * @param page pointer to a Page + * @param en true or false to enable/disable scroll propagation + */ +void lv_page_set_scroll_propagation(lv_obj_t * page, bool en); + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param page pointer to a Page + * @param en true or false to enable/disable end flash + */ +void lv_page_set_edge_flash(lv_obj_t * page, bool en); + +/** + * Set the fit attribute of the scrollable part of a page. + * It means it can set its size automatically to involve all children. + * (Can be set separately horizontally and vertically) + * @param page pointer to a page object + * @param hor_en true: enable horizontal fit + * @param ver_en true: enable vertical fit + */ +static inline void lv_page_set_scrl_fit(lv_obj_t *page, bool hor_en, bool ver_en) +{ + lv_cont_set_fit(lv_page_get_scrl(page), hor_en, ver_en); +} + +/** + * Set width of the scrollable part of a page + * @param page pointer to a page object + * @param w the new width of the scrollable (it ha no effect is horizontal fit is enabled) + */ +static inline void lv_page_set_scrl_width(lv_obj_t *page, lv_coord_t w) +{ + lv_obj_set_width(lv_page_get_scrl(page), w); +} + +/** + * Set height of the scrollable part of a page + * @param page pointer to a page object + * @param h the new height of the scrollable (it ha no effect is vertical fit is enabled) + */ +static inline void lv_page_set_scrl_height(lv_obj_t *page, lv_coord_t h) +{ + lv_obj_set_height(lv_page_get_scrl(page), h); + +} + +/** +* Set the layout of the scrollable part of the page +* @param page pointer to a page object +* @param layout a layout from 'lv_cont_layout_t' +*/ +static inline void lv_page_set_scrl_layout(lv_obj_t * page, lv_layout_t layout) +{ + lv_cont_set_layout(lv_page_get_scrl(page), layout); +} + +/** + * Set a style of a page + * @param page pointer to a page object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_page_set_style(lv_obj_t *page, lv_page_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Set the scroll bar mode on a page + * @param page pointer to a page object + * @return the mode from 'lv_page_sb.mode_t' enum + */ +lv_sb_mode_t lv_page_get_sb_mode(const lv_obj_t * page); + + +/** + * Get the the scrolling with arrows (LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) is enabled or not + * @param page pointer to a page object + * @return true: scrolling with arrows is enabled + */ +bool lv_page_get_arrow_scroll(const lv_obj_t * page); + +/** + * Get the scroll propagation property + * @param page pointer to a Page + * @return true or false + */ +bool lv_page_get_scroll_propagation(lv_obj_t * page); + +/** + * Get the edge flash effect property. + * @param page pointer to a Page + * return true or false + */ +bool lv_page_get_edge_flash(lv_obj_t * page); + +/** + * Get that width which can be set to the children to still not cause overflow (show scrollbars) + * @param page pointer to a page object + * @return the width which still fits into the page + */ +lv_coord_t lv_page_get_fit_width(lv_obj_t * page); + +/** + * Get that height which can be set to the children to still not cause overflow (show scrollbars) + * @param page pointer to a page object + * @return the height which still fits into the page + */ +lv_coord_t lv_page_get_fit_height(lv_obj_t * page); + +/** + * Get width of the scrollable part of a page + * @param page pointer to a page object + * @return the width of the scrollable + */ +static inline lv_coord_t lv_page_get_scrl_width(const lv_obj_t *page) +{ + return lv_obj_get_width(lv_page_get_scrl(page)); +} + +/** + * Get height of the scrollable part of a page + * @param page pointer to a page object + * @return the height of the scrollable + */ +static inline lv_coord_t lv_page_get_scrl_height(const lv_obj_t *page) +{ + return lv_obj_get_height(lv_page_get_scrl(page)); +} + +/** +* Get the layout of the scrollable part of a page +* @param page pointer to page object +* @return the layout from 'lv_cont_layout_t' +*/ +static inline lv_layout_t lv_page_get_scrl_layout(const lv_obj_t * page) +{ + return lv_cont_get_layout(lv_page_get_scrl(page)); +} + +/** +* Get horizontal fit attribute of the scrollable part of a page +* @param page pointer to a page object +* @return true: horizontal fit is enabled; false: disabled +*/ +static inline bool lv_page_get_scrl_hor_fit(const lv_obj_t * page) +{ + return lv_cont_get_hor_fit(lv_page_get_scrl(page)); +} + +/** +* Get vertical fit attribute of the scrollable part of a page +* @param page pointer to a page object +* @return true: vertical fit is enabled; false: disabled +*/ +static inline bool lv_page_get_scrl_fit_ver(const lv_obj_t * page) +{ + return lv_cont_get_ver_fit(lv_page_get_scrl(page)); +} + +/** + * Get a style of a page + * @param page pointer to page object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_page_get_style(const lv_obj_t *page, lv_page_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Glue the object to the page. After it the page can be moved (dragged) with this object too. + * @param obj pointer to an object on a page + * @param glue true: enable glue, false: disable glue + */ +void lv_page_glue_obj(lv_obj_t * obj, bool glue); + +/** + * Focus on an object. It ensures that the object will be visible on the page. + * @param page pointer to a page object + * @param obj pointer to an object to focus (must be on the page) + * @param anim_time scroll animation time in milliseconds (0: no animation) + */ +void lv_page_focus(lv_obj_t * page, const lv_obj_t * obj, uint16_t anim_time); + +/** + * Scroll the page horizontally + * @param page pointer to a page object + * @param dist the distance to scroll (< 0: scroll left; > 0 scroll right) + */ +void lv_page_scroll_hor(lv_obj_t * page, lv_coord_t dist); + +/** + * Scroll the page vertically + * @param page pointer to a page object + * @param dist the distance to scroll (< 0: scroll down; > 0 scroll up) + */ +void lv_page_scroll_ver(lv_obj_t * page, lv_coord_t dist); + +/** + * Not intended to use directly by the user but by other object types internally. + * Start an edge flash animation. Exactly one `ext->edge_flash.xxx_ip` should be set + * @param page + */ +void lv_page_start_edge_flash(lv_obj_t * page); +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_PAGE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_PAGE_H*/ diff --git a/pros/display/lv_objx/lv_preload.h b/pros/display/lv_objx/lv_preload.h new file mode 100644 index 00000000..7e228906 --- /dev/null +++ b/pros/display/lv_objx/lv_preload.h @@ -0,0 +1,168 @@ +/** + * @file lv_preload.h + * + */ + +#ifndef LV_PRELOAD_H +#define LV_PRELOAD_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_PRELOAD != 0 + +/*Testing of dependencies*/ +#if USE_LV_ARC == 0 +#error "lv_preload: lv_arc is required. Enable it in lv_conf.h (USE_LV_ARC 1) " +#endif + +#if USE_LV_ANIMATION == 0 +#error "lv_preload: animations are required. Enable it in lv_conf.h (USE_LV_ANIMATION 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_arc.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_PRELOAD_TYPE_SPINNING_ARC, + LV_PRELOAD_TYPE_FILLSPIN_ARC, +}; +typedef uint8_t lv_preloader_type_t; + +/*Data of pre loader*/ +typedef struct { + lv_arc_ext_t arc; /*Ext. of ancestor*/ + /*New data for this type */ + uint16_t arc_length; /*Length of the spinning indicator in degree*/ + uint16_t time; /*Time of one round*/ + lv_preloader_type_t anim_type; /*Type of the arc animation*/ +} lv_preload_ext_t; + + +/*Styles*/ +enum { + LV_PRELOAD_STYLE_MAIN, +}; +typedef uint8_t lv_preload_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a pre loader objects + * @param par pointer to an object, it will be the parent of the new pre loader + * @param copy pointer to a pre loader object, if not NULL then the new object will be copied from it + * @return pointer to the created pre loader + */ +lv_obj_t * lv_preload_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Set the length of the spinning arc in degrees + * @param preload pointer to a preload object + * @param deg length of the arc + */ +void lv_preload_set_arc_length(lv_obj_t * preload, uint16_t deg); + +/** + * Set the spin time of the arc + * @param preload pointer to a preload object + * @param time time of one round in milliseconds + */ +void lv_preload_set_spin_time(lv_obj_t * preload, uint16_t time); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_preload_set_style(lv_obj_t * preload, lv_preload_style_t type, lv_style_t *style); + +/** + * Set the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @param type animation type of the preload + * */ +void lv_preload_set_animation_type(lv_obj_t * preload, lv_preloader_type_t type); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the arc length [degree] of the a pre loader + * @param preload pointer to a pre loader object + */ +uint16_t lv_preload_get_arc_length(const lv_obj_t * preload); + +/** + * Get the spin time of the arc + * @param preload pointer to a pre loader object [milliseconds] + */ +uint16_t lv_preload_get_spin_time(const lv_obj_t * preload); + +/** + * Get style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_preload_get_style(const lv_obj_t * preload, lv_preload_style_t type); + +/** + * Get the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @return animation type + * */ +lv_preloader_type_t lv_preload_get_animation_type(lv_obj_t * preload); + +/*===================== + * Other functions + *====================*/ + +/** + * Get style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be get + * @return style pointer to the style + * */ +void lv_preload_spinner_animation(void * ptr, int32_t val); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_PRELOAD*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_PRELOAD_H*/ diff --git a/pros/display/lv_objx/lv_roller.h b/pros/display/lv_objx/lv_roller.h new file mode 100644 index 00000000..232f5526 --- /dev/null +++ b/pros/display/lv_objx/lv_roller.h @@ -0,0 +1,224 @@ +/** + * @file lv_roller.h + * + */ + +#ifndef LV_ROLLER_H +#define LV_ROLLER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_ROLLER != 0 + +/*Testing of dependencies*/ +#if USE_LV_DDLIST == 0 +#error "lv_roller: lv_ddlist is required. Enable it in lv_conf.h (USE_LV_DDLIST 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_ddlist.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of roller*/ +typedef struct { + lv_ddlist_ext_t ddlist; /*Ext. of ancestor*/ + /*New data for this type */ +} lv_roller_ext_t; + +enum { + LV_ROLLER_STYLE_BG, + LV_ROLLER_STYLE_SEL, +}; +typedef uint8_t lv_roller_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a roller object + * @param par pointer to an object, it will be the parent of the new roller + * @param copy pointer to a roller object, if not NULL then the new object will be copied from it + * @return pointer to the created roller + */ +lv_obj_t * lv_roller_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the align of the roller's options (left, right or center[default]) + * @param roller - pointer to a roller object + * @param align - one of lv_label_align_t values (left, right, center) + */ +void lv_roller_set_align(lv_obj_t * roller, lv_label_align_t align); + +/** + * Set the options on a roller + * @param roller pointer to roller object + * @param options a string with '\n' separated options. E.g. "One\nTwo\nThree" + */ +static inline void lv_roller_set_options(lv_obj_t * roller, const char * options) +{ + lv_ddlist_set_options(roller, options); +} + +/** + * Set the selected option + * @param roller pointer to a roller object + * @param sel_opt id of the selected option (0 ... number of option - 1); + * @param anim_en true: set with animation; false set immediately + */ +void lv_roller_set_selected(lv_obj_t *roller, uint16_t sel_opt, bool anim_en); + +/** + * Set a function to call when a new option is chosen + * @param roller pointer to a roller + * @param action pointer to a callback function + */ +static inline void lv_roller_set_action(lv_obj_t * roller, lv_action_t action) +{ + lv_ddlist_set_action(roller, action); +} + +/** + * Set the height to show the given number of rows (options) + * @param roller pointer to a roller object + * @param row_cnt number of desired visible rows + */ +void lv_roller_set_visible_row_count(lv_obj_t *roller, uint8_t row_cnt); + +/** + * Enable or disable the horizontal fit to the content + * @param roller pointer to a roller + * @param en true: enable auto fit; false: disable auto fit + */ +static inline void lv_roller_set_hor_fit(lv_obj_t * roller, bool en) +{ + lv_ddlist_set_hor_fit(roller, en); +} + +/** + * Set the open/close animation time. + * @param roller pointer to a roller object + * @param anim_time: open/close animation time [ms] + */ +static inline void lv_roller_set_anim_time(lv_obj_t *roller, uint16_t anim_time) +{ + lv_ddlist_set_anim_time(roller, anim_time); +} + +/** + * Set a style of a roller + * @param roller pointer to a roller object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_roller_set_style(lv_obj_t *roller, lv_roller_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the align attribute. Default alignment after _create is LV_LABEL_ALIGN_CENTER + * @param roller pointer to a roller object + * @return LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_roller_get_align(const lv_obj_t * roller); + +/** + * Get the options of a roller + * @param roller pointer to roller object + * @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3") + */ +static inline const char * lv_roller_get_options(const lv_obj_t *roller) +{ + return lv_ddlist_get_options(roller); +} + +/** + * Get the id of the selected option + * @param roller pointer to a roller object + * @return id of the selected option (0 ... number of option - 1); + */ +static inline uint16_t lv_roller_get_selected(const lv_obj_t *roller) +{ + return lv_ddlist_get_selected(roller); +} + +/** + * Get the current selected option as a string + * @param roller pointer to roller object + * @param buf pointer to an array to store the string + */ +static inline void lv_roller_get_selected_str(const lv_obj_t * roller, char * buf) +{ + lv_ddlist_get_selected_str(roller, buf); +} + +/** + * Get the "option selected" callback function + * @param roller pointer to a roller + * @return pointer to the call back function + */ +static inline lv_action_t lv_roller_get_action(const lv_obj_t * roller) +{ + return lv_ddlist_get_action(roller); +} + +/** + * Get the open/close animation time. + * @param roller pointer to a roller + * @return open/close animation time [ms] + */ +static inline uint16_t lv_roller_get_anim_time(const lv_obj_t * roller) +{ + return lv_ddlist_get_anim_time(roller); +} + +/** + * Get the auto width set attribute + * @param roller pointer to a roller object + * @return true: auto size enabled; false: manual width settings enabled + */ +bool lv_roller_get_hor_fit(const lv_obj_t *roller); + +/** + * Get a style of a roller + * @param roller pointer to a roller object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_roller_get_style(const lv_obj_t *roller, lv_roller_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_ROLLER*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ROLLER_H*/ diff --git a/pros/display/lv_objx/lv_slider.h b/pros/display/lv_objx/lv_slider.h new file mode 100644 index 00000000..8d0d9d66 --- /dev/null +++ b/pros/display/lv_objx/lv_slider.h @@ -0,0 +1,202 @@ +/** + * @file lv_slider.h + * + */ + +#ifndef LV_SLIDER_H +#define LV_SLIDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_SLIDER != 0 + +/*Testing of dependencies*/ +#if USE_LV_BAR == 0 +#error "lv_slider: lv_bar is required. Enable it in lv_conf.h (USE_LV_BAR 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_bar.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of slider*/ +typedef struct +{ + lv_bar_ext_t bar; /*Ext. of ancestor*/ + /*New data for this type */ + lv_action_t action; /*Function to call when a new value is set*/ + lv_style_t *style_knob; /*Style of the knob*/ + int16_t drag_value; /*Store a temporal value during press until release (Handled by the library)*/ + uint8_t knob_in :1; /*1: Draw the knob inside the bar*/ +} lv_slider_ext_t; + +/*Built-in styles of slider*/ +enum +{ + LV_SLIDER_STYLE_BG, + LV_SLIDER_STYLE_INDIC, + LV_SLIDER_STYLE_KNOB, +}; +typedef uint8_t lv_slider_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a slider objects + * @param par pointer to an object, it will be the parent of the new slider + * @param copy pointer to a slider object, if not NULL then the new object will be copied from it + * @return pointer to the created slider + */ +lv_obj_t * lv_slider_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the slider + * @param slider pointer to a slider object + * @param value new value + */ +static inline void lv_slider_set_value(lv_obj_t * slider, int16_t value) +{ + lv_bar_set_value(slider, value); +} + +/** + * Set a new value with animation on a slider + * @param slider pointer to a slider object + * @param value new value + * @param anim_time animation time in milliseconds + */ +static inline void lv_slider_set_value_anim(lv_obj_t * slider, int16_t value, uint16_t anim_time) +{ + lv_bar_set_value_anim(slider, value, anim_time); +} + +/** + * Set minimum and the maximum values of a bar + * @param slider pointer to the slider object + * @param min minimum value + * @param max maximum value + */ +static inline void lv_slider_set_range(lv_obj_t *slider, int16_t min, int16_t max) +{ + lv_bar_set_range(slider, min, max); +} + +/** + * Set a function which will be called when a new value is set on the slider + * @param slider pointer to slider object + * @param action a callback function + */ +void lv_slider_set_action(lv_obj_t * slider, lv_action_t action); + +/** + * Set the 'knob in' attribute of a slider + * @param slider pointer to slider object + * @param in true: the knob is drawn always in the slider; + * false: the knob can be out on the edges + */ +void lv_slider_set_knob_in(lv_obj_t * slider, bool in); + +/** + * Set a style of a slider + * @param slider pointer to a slider object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_slider_set_style(lv_obj_t *slider, lv_slider_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a slider + * @param slider pointer to a slider object + * @return the value of the slider + */ +int16_t lv_slider_get_value(const lv_obj_t * slider); + +/** + * Get the minimum value of a slider + * @param slider pointer to a slider object + * @return the minimum value of the slider + */ +static inline int16_t lv_slider_get_min_value(const lv_obj_t * slider) +{ + return lv_bar_get_min_value(slider); +} + +/** + * Get the maximum value of a slider + * @param slider pointer to a slider object + * @return the maximum value of the slider + */ +static inline int16_t lv_slider_get_max_value(const lv_obj_t * slider) +{ + return lv_bar_get_max_value(slider); +} + +/** + * Get the slider action function + * @param slider pointer to slider object + * @return the callback function + */ +lv_action_t lv_slider_get_action(const lv_obj_t * slider); + +/** + * Give the slider is being dragged or not + * @param slider pointer to a slider object + * @return true: drag in progress false: not dragged + */ +bool lv_slider_is_dragged(const lv_obj_t * slider); + +/** + * Get the 'knob in' attribute of a slider + * @param slider pointer to slider object + * @return true: the knob is drawn always in the slider; + * false: the knob can be out on the edges + */ +bool lv_slider_get_knob_in(const lv_obj_t * slider); + + +/** + * Get a style of a slider + * @param slider pointer to a slider object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_slider_get_style(const lv_obj_t *slider, lv_slider_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_SLIDER*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SLIDER_H*/ diff --git a/pros/display/lv_objx/lv_spinbox.h b/pros/display/lv_objx/lv_spinbox.h new file mode 100644 index 00000000..6ec1e667 --- /dev/null +++ b/pros/display/lv_objx/lv_spinbox.h @@ -0,0 +1,201 @@ +/** + * @file lv_spinbox.h + * + */ + + +#ifndef LV_SPINBOX_H +#define LV_SPINBOX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_SPINBOX != 0 + +/*Testing of dependencies*/ +#if USE_LV_TA == 0 +#error "lv_spinbox: lv_ta is required. Enable it in lv_conf.h (USE_LV_TA 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "display/lv_objx/lv_ta.h" + +/********************* + * DEFINES + *********************/ +#define LV_SPINBOX_MAX_DIGIT_COUNT 16 + +/********************** + * TYPEDEFS + **********************/ + +/*callback on value change*/ +typedef void (*lv_spinbox_value_changed_cb_t)(lv_obj_t * spinbox, int32_t new_value); + +/*Data of spinbox*/ +typedef struct { + lv_ta_ext_t ta; /*Ext. of ancestor*/ + /*New data for this type */ + int32_t value; + int32_t range_max; + int32_t range_min; + int32_t step; + uint16_t digit_count:4; + uint16_t dec_point_pos:4; /*if 0, there is no separator and the number is an integer*/ + uint16_t digit_padding_left:4; + lv_spinbox_value_changed_cb_t value_changed_cb; +} lv_spinbox_ext_t; + + +/*Styles*/ +enum { + LV_SPINBOX_STYLE_BG, + LV_SPINBOX_STYLE_SB, + LV_SPINBOX_STYLE_CURSOR, +}; +typedef uint8_t lv_spinbox_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a spinbox objects + * @param par pointer to an object, it will be the parent of the new spinbox + * @param copy pointer to a spinbox object, if not NULL then the new object will be copied from it + * @return pointer to the created spinbox + */ +lv_obj_t * lv_spinbox_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a spinbox. + * @param templ pointer to template object + * @param type which style should be set + * @param style pointer to a style + */ +static inline void lv_spinbox_set_style(lv_obj_t * spinbox, lv_spinbox_style_t type, lv_style_t *style) +{ + lv_ta_set_style(spinbox, type, style); +} + +/** + * Set spinbox value + * @param spinbox pointer to spinbox + * @param i value to be set + */ +void lv_spinbox_set_value(lv_obj_t * spinbox, int32_t i); + +/** + * Set spinbox digit format (digit count and decimal format) + * @param spinbox pointer to spinbox + * @param digit_count number of digit excluding the decimal separator and the sign + * @param separator_position number of digit before the decimal point. If 0, decimal point is not shown + */ +void lv_spinbox_set_digit_format(lv_obj_t * spinbox, uint8_t digit_count, uint8_t separator_position); + +/** + * Set spinbox step + * @param spinbox pointer to spinbox + * @param step steps on increment/decrement + */ +void lv_spinbox_set_step(lv_obj_t * spinbox, uint32_t step); + +/** + * Set spinbox value range + * @param spinbox pointer to spinbox + * @param range_min maximum value, inclusive + * @param range_max minimum value, inclusive + */ +void lv_spinbox_set_range(lv_obj_t * spinbox, int32_t range_min, int32_t range_max); + +/** + * Set spinbox callback on calue change + * @param spinbox pointer to spinbox + * @param cb Callback function called on value change event + */ +void lv_spinbox_set_value_changed_cb(lv_obj_t * spinbox, lv_spinbox_value_changed_cb_t cb); + +/** + * Set spinbox left padding in digits count (added between sign and first digit) + * @param spinbox pointer to spinbox + * @param cb Callback function called on value change event + */ +void lv_spinbox_set_padding_left(lv_obj_t * spinbox, uint8_t padding); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get style of a spinbox. + * @param templ pointer to template object + * @param type which style should be get + * @return style pointer to the style + */ +static inline lv_style_t * lv_spinbox_get_style(lv_obj_t * spinbox, lv_spinbox_style_t type) +{ + return lv_ta_get_style(spinbox, type); +} + +/** + * Get the spinbox numeral value (user has to convert to float according to its digit format) + * @param spinbox pointer to spinbox + * @return value integer value of the spinbox + */ +int32_t lv_spinbox_get_value(lv_obj_t * spinbox); + +/*===================== + * Other functions + *====================*/ + +/** + * Select next lower digit for edition by dividing the step by 10 + * @param spinbox pointer to spinbox + */ +void lv_spinbox_step_next(lv_obj_t * spinbox); + +/** + * Select next higher digit for edition by multiplying the step by 10 + * @param spinbox pointer to spinbox + */ +void lv_spinbox_step_previous(lv_obj_t * spinbox); + +/** + * Increment spinbox value by one step + * @param spinbox pointer to spinbox + */ +void lv_spinbox_increment(lv_obj_t * spinbox); + +/** + * Decrement spinbox value by one step + * @param spinbox pointer to spinbox + */ +void lv_spinbox_decrement(lv_obj_t * spinbox); + + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_SPINBOX*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SPINBOX_H*/ diff --git a/pros/display/lv_objx/lv_sw.h b/pros/display/lv_objx/lv_sw.h new file mode 100644 index 00000000..7f4513c8 --- /dev/null +++ b/pros/display/lv_objx/lv_sw.h @@ -0,0 +1,194 @@ +/** + * @file lv_sw.h + * + */ + +#ifndef LV_SW_H +#define LV_SW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_SW != 0 + +/*Testing of dependencies*/ +#if USE_LV_SLIDER == 0 +#error "lv_sw: lv_slider is required. Enable it in lv_conf.h (USE_LV_SLIDER 1)" +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_slider.h" + +/********************* + * DEFINES + *********************/ +#define LV_SWITCH_SLIDER_ANIM_MAX 1000 + +/********************** + * TYPEDEFS + **********************/ +/*Data of switch*/ +typedef struct +{ + lv_slider_ext_t slider; /*Ext. of ancestor*/ + /*New data for this type */ + lv_style_t *style_knob_off; /*Style of the knob when the switch is OFF*/ + lv_style_t *style_knob_on; /*Style of the knob when the switch is ON (NULL to use the same as OFF)*/ + lv_coord_t start_x; + uint8_t changed :1; /*Indicates the switch state explicitly changed by drag*/ + uint8_t slided :1; +#if USE_LV_ANIMATION + uint16_t anim_time; /*switch animation time */ +#endif +} lv_sw_ext_t; + +enum { + LV_SW_STYLE_BG, + LV_SW_STYLE_INDIC, + LV_SW_STYLE_KNOB_OFF, + LV_SW_STYLE_KNOB_ON, +}; +typedef uint8_t lv_sw_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a switch objects + * @param par pointer to an object, it will be the parent of the new switch + * @param copy pointer to a switch object, if not NULL then the new object will be copied from it + * @return pointer to the created switch + */ +lv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Turn ON the switch + * @param sw pointer to a switch object + */ +void lv_sw_on(lv_obj_t *sw); + +/** + * Turn OFF the switch + * @param sw pointer to a switch object + */ +void lv_sw_off(lv_obj_t *sw); + +/** + * Toggle the position of the switch + * @param sw pointer to a switch object + * @return resulting state of the switch. + */ +bool lv_sw_toggle(lv_obj_t *sw); + +/** + * Turn ON the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_on_anim(lv_obj_t * sw); + +/** + * Turn OFF the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_off_anim(lv_obj_t * sw); + +/** + * Toggle the position of the switch with an animation + * @param sw pointer to a switch object + * @return resulting state of the switch. + */ +bool lv_sw_toggle_anim(lv_obj_t *sw); + +/** + * Set a function which will be called when the switch is toggled by the user + * @param sw pointer to switch object + * @param action a callback function + */ +static inline void lv_sw_set_action(lv_obj_t * sw, lv_action_t action) +{ + lv_slider_set_action(sw, action); +} + +/** + * Set a style of a switch + * @param sw pointer to a switch object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_sw_set_style(lv_obj_t *sw, lv_sw_style_t type, lv_style_t *style); + +#if USE_LV_ANIMATION +/** + * Set the animation time of the switch + * @param sw pointer to a switch object + * @param anim_time animation time + * @return style pointer to a style + */ +void lv_sw_set_anim_time(lv_obj_t *sw, uint16_t anim_time); +#endif + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the state of a switch + * @param sw pointer to a switch object + * @return false: OFF; true: ON + */ +static inline bool lv_sw_get_state(const lv_obj_t *sw) +{ + return lv_bar_get_value(sw) < LV_SWITCH_SLIDER_ANIM_MAX / 2 ? false : true; +} + +/** + * Get the switch action function + * @param slider pointer to a switch object + * @return the callback function + */ +static inline lv_action_t lv_sw_get_action(const lv_obj_t * slider) +{ + return lv_slider_get_action(slider); +} + +/** + * Get a style of a switch + * @param sw pointer to a switch object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_sw_get_style(const lv_obj_t *sw, lv_sw_style_t type); + +/** + * Get the animation time of the switch + * @param sw pointer to a switch object + * @return style pointer to a style + */ +uint16_t lv_sw_get_anim_time(const lv_obj_t *sw); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_SW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SW_H*/ diff --git a/pros/display/lv_objx/lv_ta.h b/pros/display/lv_objx/lv_ta.h new file mode 100644 index 00000000..8e12314a --- /dev/null +++ b/pros/display/lv_objx/lv_ta.h @@ -0,0 +1,390 @@ +/** + * @file lv_ta.h + * + */ + +#ifndef LV_TA_H +#define LV_TA_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_TA != 0 + +/*Testing of dependencies*/ +#if USE_LV_PAGE == 0 +#error "lv_ta: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_ta: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_page.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ +#define LV_TA_CURSOR_LAST (0x7FFF) /*Put the cursor after the last character*/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_CURSOR_NONE, + LV_CURSOR_LINE, + LV_CURSOR_BLOCK, + LV_CURSOR_OUTLINE, + LV_CURSOR_UNDERLINE, + LV_CURSOR_HIDDEN = 0x08, /*Or it to any value to hide the cursor temporally*/ +}; +typedef uint8_t lv_cursor_type_t; + +/*Data of text area*/ +typedef struct +{ + lv_page_ext_t page; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * label; /*Label of the text area*/ + char * pwd_tmp; /*Used to store the original text in password mode*/ + const char * accapted_chars;/*Only these characters will be accepted. NULL: accept all*/ + uint16_t max_length; /*The max. number of characters. 0: no limit*/ + uint8_t pwd_mode :1; /*Replace characters with '*' */ + uint8_t one_line :1; /*One line mode (ignore line breaks)*/ + struct { + lv_style_t *style; /*Style of the cursor (NULL to use label's style)*/ + lv_coord_t valid_x; /*Used when stepping up/down in text area when stepping to a shorter line. (Handled by the library)*/ + uint16_t pos; /*The current cursor position (0: before 1. letter; 1: before 2. letter etc.)*/ + lv_area_t area; /*Cursor area relative to the Text Area*/ + uint16_t txt_byte_pos; /*Byte index of the letter after (on) the cursor*/ + lv_cursor_type_t type:4; /*Shape of the cursor*/ + uint8_t state :1; /*Indicates that the cursor is visible now or not (Handled by the library)*/ + } cursor; +} lv_ta_ext_t; + +enum { + LV_TA_STYLE_BG, + LV_TA_STYLE_SB, + LV_TA_STYLE_EDGE_FLASH, + LV_TA_STYLE_CURSOR, +}; +typedef uint8_t lv_ta_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a text area objects + * @param par pointer to an object, it will be the parent of the new text area + * @param copy pointer to a text area object, if not NULL then the new object will be copied from it + * @return pointer to the created text area + */ +lv_obj_t * lv_ta_create(lv_obj_t * par, const lv_obj_t * copy); + + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Insert a character to the current cursor position. + * To add a wide char, e.g. 'Á' use `lv_txt_encoded_conv_wc('Á')` + * @param ta pointer to a text area object + * @param c a character (e.g. 'a') + */ +void lv_ta_add_char(lv_obj_t * ta, uint32_t c); + +/** + * Insert a text to the current cursor position + * @param ta pointer to a text area object + * @param txt a '\0' terminated string to insert + */ +void lv_ta_add_text(lv_obj_t * ta, const char * txt); + +/** + * Delete a the left character from the current cursor position + * @param ta pointer to a text area object + */ +void lv_ta_del_char(lv_obj_t * ta); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a text area + * @param ta pointer to a text area + * @param txt pointer to the text + */ +void lv_ta_set_text(lv_obj_t * ta, const char * txt); + +/** + * Set the cursor position + * @param obj pointer to a text area object + * @param pos the new cursor position in character index + * < 0 : index from the end of the text + * LV_TA_CURSOR_LAST: go after the last character + */ +void lv_ta_set_cursor_pos(lv_obj_t * ta, int16_t pos); + +/** + * Set the cursor type. + * @param ta pointer to a text area object + * @param cur_type: element of 'lv_cursor_type_t' + */ +void lv_ta_set_cursor_type(lv_obj_t * ta, lv_cursor_type_t cur_type); + +/** + * Enable/Disable password mode + * @param ta pointer to a text area object + * @param en true: enable, false: disable + */ +void lv_ta_set_pwd_mode(lv_obj_t * ta, bool en); + +/** + * Configure the text area to one line or back to normal + * @param ta pointer to a Text area object + * @param en true: one line, false: normal + */ +void lv_ta_set_one_line(lv_obj_t * ta, bool en); + +/** + * Set the alignment of the text area. + * In one line mode the text can be scrolled only with `LV_LABEL_ALIGN_LEFT`. + * This function should be called if the size of text area changes. + * @param ta pointer to a text are object + * @param align the desired alignment from `lv_label_align_t`. (LV_LABEL_ALIGN_LEFT/CENTER/RIGHT) + */ +void lv_ta_set_text_align(lv_obj_t * ta, lv_label_align_t align); + +/** + * Set a list of characters. Only these characters will be accepted by the text area + * @param ta pointer to Text Area + * @param list list of characters. Only the pointer is saved. E.g. "+-.,0123456789" + */ +void lv_ta_set_accepted_chars(lv_obj_t * ta, const char * list); + +/** + * Set max length of a Text Area. + * @param ta pointer to Text Area + * @param num the maximal number of characters can be added (`lv_ta_set_text` ignores it) + */ +void lv_ta_set_max_length(lv_obj_t * ta, uint16_t num); + +/** + * Set an action to call when the Text area is clicked + * @param ta pointer to a Text area + * @param action a function pointer + */ +static inline void lv_ta_set_action(lv_obj_t * ta, lv_action_t action) +{ + lv_page_set_rel_action(ta, action); +} + +/** + * Set the scroll bar mode of a text area + * @param ta pointer to a text area object + * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum + */ +static inline void lv_ta_set_sb_mode(lv_obj_t * ta, lv_sb_mode_t mode) +{ + lv_page_set_sb_mode(ta, mode); +} + +/** + * Enable the scroll propagation feature. If enabled then the Text area will move its parent if there is no more space to scroll. + * @param ta pointer to a Text area + * @param en true or false to enable/disable scroll propagation + */ +static inline void lv_ta_set_scroll_propagation(lv_obj_t * ta, bool en) +{ + lv_page_set_scroll_propagation(ta, en); +} + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param page pointer to a Text Area + * @param en true or false to enable/disable end flash + */ +static inline void lv_ta_set_edge_flash(lv_obj_t * ta, bool en) +{ + lv_page_set_edge_flash(ta, en); +} + +/** + * Set a style of a text area + * @param ta pointer to a text area object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_ta_set_style(lv_obj_t *ta, lv_ta_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a text area. In password mode it gives the real text (not '*'s). + * @param ta pointer to a text area object + * @return pointer to the text + */ +const char * lv_ta_get_text(const lv_obj_t * ta); + +/** + * Get the label of a text area + * @param ta pointer to a text area object + * @return pointer to the label object + */ +lv_obj_t * lv_ta_get_label(const lv_obj_t * ta); + +/** + * Get the current cursor position in character index + * @param ta pointer to a text area object + * @return the cursor position + */ +uint16_t lv_ta_get_cursor_pos(const lv_obj_t * ta); + +/** + * Get the current cursor visibility. + * @param ta pointer to a text area object + * @return true: the cursor is drawn, false: the cursor is hidden + */ +//bool lv_ta_get_cursor_show(const lv_obj_t * ta); + +/** + * Get the current cursor type. + * @param ta pointer to a text area object + * @return element of 'lv_cursor_type_t' + */ +lv_cursor_type_t lv_ta_get_cursor_type(const lv_obj_t * ta); + +/** + * Get the password mode attribute + * @param ta pointer to a text area object + * @return true: password mode is enabled, false: disabled + */ +bool lv_ta_get_pwd_mode(const lv_obj_t * ta); + +/** + * Get the one line configuration attribute + * @param ta pointer to a text area object + * @return true: one line configuration is enabled, false: disabled + */ +bool lv_ta_get_one_line(const lv_obj_t * ta); + +/** + * Get a list of accepted characters. + * @param ta pointer to Text Area + * @return list of accented characters. + */ +const char * lv_ta_get_accepted_chars(lv_obj_t * ta); + +/** + * Set max length of a Text Area. + * @param ta pointer to Text Area + * @return the maximal number of characters to be add + */ +uint16_t lv_ta_get_max_length(lv_obj_t * ta); + +/** + * Set an action to call when the Text area is clicked + * @param ta pointer to a Text area + * @param action a function pointer + */ +static inline lv_action_t lv_ta_get_action(lv_obj_t * ta) +{ + return lv_page_get_rel_action(ta); +} + +/** + * Get the scroll bar mode of a text area + * @param ta pointer to a text area object + * @return scrollbar mode from 'lv_page_sb_mode_t' enum + */ +static inline lv_sb_mode_t lv_ta_get_sb_mode(const lv_obj_t * ta) +{ + return lv_page_get_sb_mode(ta); +} + +/** + * Get the scroll propagation property + * @param ta pointer to a Text area + * @return true or false + */ +static inline bool lv_ta_get_scroll_propagation(lv_obj_t * ta) +{ + return lv_page_get_scroll_propagation(ta); +} + +/** + * Get the scroll propagation property + * @param ta pointer to a Text area + * @return true or false + */ +static inline bool lv_ta_get_edge_flash(lv_obj_t * ta) +{ + return lv_page_get_edge_flash(ta); +} + +/** + * Get a style of a text area + * @param ta pointer to a text area object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_ta_get_style(const lv_obj_t *ta, lv_ta_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Move the cursor one character right + * @param ta pointer to a text area object + */ +void lv_ta_cursor_right(lv_obj_t * ta); + +/** + * Move the cursor one character left + * @param ta pointer to a text area object + */ +void lv_ta_cursor_left(lv_obj_t * ta); + +/** + * Move the cursor one line down + * @param ta pointer to a text area object + */ +void lv_ta_cursor_down(lv_obj_t * ta); + +/** + * Move the cursor one line up + * @param ta pointer to a text area object + */ +void lv_ta_cursor_up(lv_obj_t * ta); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TA_H*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TA_H*/ diff --git a/pros/display/lv_objx/lv_table.h b/pros/display/lv_objx/lv_table.h new file mode 100644 index 00000000..79ba22dc --- /dev/null +++ b/pros/display/lv_objx/lv_table.h @@ -0,0 +1,261 @@ +/** + * @file lv_table.h + * + */ + +#ifndef LV_TABLE_H +#define LV_TABLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_TABLE != 0 + +/*Testing of dependencies*/ +#if USE_LV_LABEL == 0 +#error "lv_table: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_TABLE_COL_MAX +#define LV_TABLE_COL_MAX 12 +#endif + +#define LV_TABLE_CELL_STYLE_CNT 4 +/********************** + * TYPEDEFS + **********************/ + +typedef union { + struct { + uint8_t align:2; + uint8_t right_merge:1; + uint8_t type:2; + uint8_t crop:1; + }; + uint8_t format_byte; +}lv_table_cell_format_t; + +/*Data of table*/ +typedef struct { + /*New data for this type */ + uint16_t col_cnt; + uint16_t row_cnt; + char ** cell_data; + lv_style_t * cell_style[LV_TABLE_CELL_STYLE_CNT]; + lv_coord_t col_w[LV_TABLE_COL_MAX]; +} lv_table_ext_t; + + +/*Styles*/ +enum { + LV_TABLE_STYLE_BG, + LV_TABLE_STYLE_CELL1, + LV_TABLE_STYLE_CELL2, + LV_TABLE_STYLE_CELL3, + LV_TABLE_STYLE_CELL4, +}; +typedef uint8_t lv_table_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a table object + * @param par pointer to an object, it will be the parent of the new table + * @param copy pointer to a table object, if not NULL then the new object will be copied from it + * @return pointer to the created table + */ +lv_obj_t * lv_table_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the value of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param txt text to display in the cell. It will be copied and saved so this variable is not required after this function call. + */ +void lv_table_set_cell_value(lv_obj_t * table, uint16_t row, uint16_t col, const char * txt); + +/** + * Set the number of rows + * @param table table pointer to a Table object + * @param row_cnt number of rows + */ +void lv_table_set_row_cnt(lv_obj_t * table, uint16_t row_cnt); + +/** + * Set the number of columns + * @param table table pointer to a Table object + * @param col_cnt number of columns. Must be < LV_TABLE_COL_MAX + */ +void lv_table_set_col_cnt(lv_obj_t * table, uint16_t col_cnt); + +/** + * Set the width of a column + * @param table table pointer to a Table object + * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1] + * @param w width of the column + */ +void lv_table_set_col_width(lv_obj_t * table, uint16_t col_id, lv_coord_t w); + +/** + * Set the text align in a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param align LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT + */ +void lv_table_set_cell_align(lv_obj_t * table, uint16_t row, uint16_t col, lv_label_align_t align); + +/** + * Set the type of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param type 1,2,3 or 4. The cell style will be chosen accordingly. + */ +void lv_table_set_cell_type(lv_obj_t * table, uint16_t row, uint16_t col, uint8_t type); + +/** + * Set the cell crop. (Don't adjust the height of the cell according to its content) + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param crop true: crop the cell content; false: set the cell height to the content. + */ +void lv_table_set_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col, bool crop); + +/** + * Merge a cell with the right neighbor. The value of the cell to the right won't be displayed. + * @param table table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param en true: merge right; false: don't merge right + */ +void lv_table_set_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col, bool en); + +/** + * Set a style of a table. + * @param table pointer to table object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_table_set_style(lv_obj_t * table, lv_table_style_t type, lv_style_t * style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a cell. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return text in the cell + */ +const char * lv_table_get_cell_value(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get the number of rows. + * @param table table pointer to a Table object + * @return number of rows. + */ +uint16_t lv_table_get_row_cnt(lv_obj_t * table); + +/** + * Get the number of columns. + * @param table table pointer to a Table object + * @return number of columns. + */ +uint16_t lv_table_get_col_cnt(lv_obj_t * table); + +/** + * Get the width of a column + * @param table table pointer to a Table object + * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1] + * @return width of the column + */ +lv_coord_t lv_table_get_col_width(lv_obj_t * table, uint16_t col_id); + +/** + * Get the text align of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return LV_LABEL_ALIGN_LEFT (default in case of error) or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT + */ +lv_label_align_t lv_table_get_cell_align(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get the type of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return 1,2,3 or 4 + */ +lv_label_align_t lv_table_get_cell_type(lv_obj_t * table, uint16_t row, uint16_t col); + + +/** + * Get the crop property of a cell + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return true: text crop enabled; false: disabled + */ +lv_label_align_t lv_table_get_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get the cell merge attribute. + * @param table table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return true: merge right; false: don't merge right + */ +bool lv_table_get_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get style of a table. + * @param table pointer to table object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_table_get_style(const lv_obj_t * table, lv_table_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TABLE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TABLE_H*/ diff --git a/pros/display/lv_objx/lv_tabview.h b/pros/display/lv_objx/lv_tabview.h new file mode 100644 index 00000000..73d8b17c --- /dev/null +++ b/pros/display/lv_objx/lv_tabview.h @@ -0,0 +1,252 @@ +/** + * @file lv_tabview.h + * + */ + +#ifndef LV_TABVIEW_H +#define LV_TABVIEW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_TABVIEW != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTNM == 0 +#error "lv_tabview: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM 1) " +#endif + +#if USE_LV_PAGE == 0 +#error "lv_tabview: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "display/lv_objx/lv_win.h" +#include "display/lv_objx/lv_page.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/* parametes: pointer to a tabview object, tab_id + * return: LV_RES_INV: to prevent the loading of the tab; LV_RES_OK: if everything is fine*/ +typedef lv_res_t (*lv_tabview_action_t)(lv_obj_t *, uint16_t); + + +enum { + LV_TABVIEW_BTNS_POS_TOP, + LV_TABVIEW_BTNS_POS_BOTTOM, +}; +typedef uint8_t lv_tabview_btns_pos_t; + +/*Data of tab*/ +typedef struct +{ + /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * btns; + lv_obj_t * indic; + lv_obj_t * content; /*A rectangle to show the current tab*/ + const char ** tab_name_ptr; + lv_point_t point_last; + uint16_t tab_cur; + uint16_t tab_cnt; + uint16_t anim_time; + uint8_t slide_enable :1; /*1: enable horizontal sliding by touch pad*/ + uint8_t draging :1; + uint8_t drag_hor :1; + uint8_t btns_hide :1; + lv_tabview_btns_pos_t btns_pos :1; + lv_tabview_action_t tab_load_action; +} lv_tabview_ext_t; + +enum { + LV_TABVIEW_STYLE_BG, + LV_TABVIEW_STYLE_INDIC, + LV_TABVIEW_STYLE_BTN_BG, + LV_TABVIEW_STYLE_BTN_REL, + LV_TABVIEW_STYLE_BTN_PR, + LV_TABVIEW_STYLE_BTN_TGL_REL, + LV_TABVIEW_STYLE_BTN_TGL_PR, +}; +typedef uint8_t lv_tabview_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a Tab view object + * @param par pointer to an object, it will be the parent of the new tab + * @param copy pointer to a tab object, if not NULL then the new object will be copied from it + * @return pointer to the created tab + */ +lv_obj_t * lv_tabview_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_tabview_clean(lv_obj_t *obj); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add a new tab with the given name + * @param tabview pointer to Tab view object where to ass the new tab + * @param name the text on the tab button + * @return pointer to the created page object (lv_page). You can create your content here + */ +lv_obj_t * lv_tabview_add_tab(lv_obj_t * tabview, const char * name); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new tab + * @param tabview pointer to Tab view object + * @param id index of a tab to load + * @param anim_en true: set with sliding animation; false: set immediately + */ +void lv_tabview_set_tab_act(lv_obj_t * tabview, uint16_t id, bool anim_en); + +/** + * Set an action to call when a tab is loaded (Good to create content only if required) + * lv_tabview_get_act() still gives the current (old) tab (to remove content from here) + * @param tabview pointer to a tabview object + * @param action pointer to a function to call when a tab is loaded + */ +void lv_tabview_set_tab_load_action(lv_obj_t *tabview, lv_tabview_action_t action); + +/** + * Enable horizontal sliding with touch pad + * @param tabview pointer to Tab view object + * @param en true: enable sliding; false: disable sliding + */ +void lv_tabview_set_sliding(lv_obj_t * tabview, bool en); + +/** + * Set the animation time of tab view when a new tab is loaded + * @param tabview pointer to Tab view object + * @param anim_time time of animation in milliseconds + */ +void lv_tabview_set_anim_time(lv_obj_t * tabview, uint16_t anim_time); + +/** + * Set the style of a tab view + * @param tabview pointer to a tan view object + * @param type which style should be set + * @param style pointer to the new style + */ +void lv_tabview_set_style(lv_obj_t *tabview, lv_tabview_style_t type, lv_style_t *style); + +/** + * Set the position of tab select buttons + * @param tabview pointer to a tab view object + * @param btns_pos which button position + */ +void lv_tabview_set_btns_pos(lv_obj_t *tabview, lv_tabview_btns_pos_t btns_pos); + +/** + * Set whether tab buttons are hidden + * @param tabview pointer to a tab view object + * @param en whether tab buttons are hidden + */ +void lv_tabview_set_btns_hidden(lv_obj_t *tabview, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the index of the currently active tab + * @param tabview pointer to Tab view object + * @return the active tab index + */ +uint16_t lv_tabview_get_tab_act(const lv_obj_t * tabview); + +/** + * Get the number of tabs + * @param tabview pointer to Tab view object + * @return tab count + */ +uint16_t lv_tabview_get_tab_count(const lv_obj_t * tabview); +/** + * Get the page (content area) of a tab + * @param tabview pointer to Tab view object + * @param id index of the tab (>= 0) + * @return pointer to page (lv_page) object + */ +lv_obj_t * lv_tabview_get_tab(const lv_obj_t * tabview, uint16_t id); + +/** + * Get the tab load action + * @param tabview pointer to a tabview object + * @param return the current tab load action + */ +lv_tabview_action_t lv_tabview_get_tab_load_action(const lv_obj_t *tabview); + +/** + * Get horizontal sliding is enabled or not + * @param tabview pointer to Tab view object + * @return true: enable sliding; false: disable sliding + */ +bool lv_tabview_get_sliding(const lv_obj_t * tabview); + +/** + * Get the animation time of tab view when a new tab is loaded + * @param tabview pointer to Tab view object + * @return time of animation in milliseconds + */ +uint16_t lv_tabview_get_anim_time(const lv_obj_t * tabview); + +/** + * Get a style of a tab view + * @param tabview pointer to a ab view object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_tabview_get_style(const lv_obj_t *tabview, lv_tabview_style_t type); + +/** + * Get position of tab select buttons + * @param tabview pointer to a ab view object + */ +lv_tabview_btns_pos_t lv_tabview_get_btns_pos(const lv_obj_t *tabview); + +/** + * Get whether tab buttons are hidden + * @param tabview pointer to a tab view object + * @return whether tab buttons are hidden + */ +bool lv_tabview_get_btns_hidden(const lv_obj_t *tabview); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TABVIEW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TABVIEW_H*/ diff --git a/pros/display/lv_objx/lv_tileview.h b/pros/display/lv_objx/lv_tileview.h new file mode 100644 index 00000000..b869e7ce --- /dev/null +++ b/pros/display/lv_objx/lv_tileview.h @@ -0,0 +1,163 @@ +/** + * @file lv_tileview.h + * + */ + + +#ifndef LV_TILEVIEW_H +#define LV_TILEVIEW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_TILEVIEW != 0 + +#include "display/lv_objx/lv_page.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + + + +/* parametes: pointer to a tileview object, x, y (tile coordinates to load) + * return: LV_RES_INV: to prevent the loading of the tab; LV_RES_OK: if everything is fine*/ +typedef lv_res_t (*lv_tileview_action_t)(lv_obj_t *, lv_coord_t, lv_coord_t); + +/*Data of tileview*/ +typedef struct { + lv_page_ext_t page; + /*New data for this type */ + const lv_point_t * valid_pos; + uint16_t anim_time; + lv_tileview_action_t action; + lv_point_t act_id; + uint8_t drag_top_en :1; + uint8_t drag_bottom_en :1; + uint8_t drag_left_en :1; + uint8_t drag_right_en :1; + uint8_t drag_hor :1; + uint8_t drag_ver :1; +} lv_tileview_ext_t; + + +/*Styles*/ +enum { + LV_TILEVIEW_STYLE_BG, +}; +typedef uint8_t lv_tileview_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a tileview objects + * @param par pointer to an object, it will be the parent of the new tileview + * @param copy pointer to a tileview object, if not NULL then the new object will be copied from it + * @return pointer to the created tileview + */ +lv_obj_t * lv_tileview_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Register an object on the tileview. The register object will able to slide the tileview + * @param element pointer to an object + */ +void lv_tileview_add_element(lv_obj_t * element); + +/*===================== + * Setter functions + *====================*/ + + +/** + * Set the valid position's indices. The scrolling will be possible only to these positions. + * @param tileview pointer to a Tileview object + * @param valid_pos array width the indices. E.g. `lv_point_t p[] = {{0,0}, {1,0}, {1,1}, {LV_COORD_MIN, LV_COORD_MIN}};` + * Must be closed with `{LV_COORD_MIN, LV_COORD_MIN}`. Only the pointer is saved so can't be a local variable. + */ +void lv_tileview_set_valid_positions(lv_obj_t * tileview, const lv_point_t * valid_pos); + +/** + * Set the tile to be shown + * @param tileview pointer to a tileview object + * @param x column id (0, 1, 2...) + * @param y line id (0, 1, 2...) + * @param anim_en true: move with animation + */ +void lv_tileview_set_tile_act(lv_obj_t * tileview, lv_coord_t x, lv_coord_t y, bool anim_en); + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param tileview pointer to a Tileview + * @param en true or false to enable/disable end flash + */ +static inline void lv_tileview_set_edge_flash(lv_obj_t * tileview, bool en) +{ + lv_page_set_edge_flash(tileview, en); +} + +/** + * Set a style of a tileview. + * @param tileview pointer to tileview object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_tileview_set_style(lv_obj_t * tileview, lv_tileview_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the scroll propagation property + * @param tileview pointer to a Tileview + * @return true or false + */ +static inline bool lv_tileview_get_edge_flash(lv_obj_t * tileview) +{ + return lv_page_get_edge_flash(tileview); +} + +/** + * Get style of a tileview. + * @param tileview pointer to tileview object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_tileview_get_style(const lv_obj_t * tileview, lv_tileview_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TILEVIEW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TILEVIEW_H*/ diff --git a/pros/display/lv_objx/lv_win.h b/pros/display/lv_objx/lv_win.h new file mode 100644 index 00000000..4a64aa81 --- /dev/null +++ b/pros/display/lv_objx/lv_win.h @@ -0,0 +1,282 @@ +/** + * @file lv_win.h + * + */ + +#ifndef LV_WIN_H +#define LV_WIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_WIN != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTN == 0 +#error "lv_win: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_win: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#if USE_LV_IMG == 0 +#error "lv_win: lv_img is required. Enable it in lv_conf.h (USE_LV_IMG 1) " +#endif + + +#if USE_LV_PAGE == 0 +#error "lv_win: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_cont.h" +#include "lv_btn.h" +#include "lv_label.h" +#include "lv_img.h" +#include "lv_page.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of window*/ +typedef struct +{ + /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * page; /*Pointer to a page which holds the content*/ + lv_obj_t * header; /*Pointer to the header container of the window*/ + lv_obj_t * title; /*Pointer to the title label of the window*/ + lv_style_t * style_header; /*Style of the header container*/ + lv_style_t * style_btn_rel; /*Control button releases style*/ + lv_style_t * style_btn_pr; /*Control button pressed style*/ + lv_coord_t btn_size; /*Size of the control buttons (square)*/ +} lv_win_ext_t; + +enum { + LV_WIN_STYLE_BG, + LV_WIN_STYLE_CONTENT_BG, + LV_WIN_STYLE_CONTENT_SCRL, + LV_WIN_STYLE_SB, + LV_WIN_STYLE_HEADER, + LV_WIN_STYLE_BTN_REL, + LV_WIN_STYLE_BTN_PR, +}; +typedef uint8_t lv_win_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a window objects + * @param par pointer to an object, it will be the parent of the new window + * @param copy pointer to a window object, if not NULL then the new object will be copied from it + * @return pointer to the created window + */ +lv_obj_t * lv_win_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_win_clean(lv_obj_t *obj); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add control button to the header of the window + * @param win pointer to a window object + * @param img_src an image source ('lv_img_t' variable, path to file or a symbol) + * @param rel_action a function pointer to call when the button is released + * @return pointer to the created button object + */ +lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src, lv_action_t rel_action); + +/*===================== + * Setter functions + *====================*/ + +/** + * A release action which can be assigned to a window control button to close it + * @param btn pointer to the released button + * @return always LV_ACTION_RES_INV because the button is deleted with the window + */ +lv_res_t lv_win_close_action(lv_obj_t * btn); + +/** + * Set the title of a window + * @param win pointer to a window object + * @param title string of the new title + */ +void lv_win_set_title(lv_obj_t * win, const char * title); + +/** + * Set the control button size of a window + * @param win pointer to a window object + * @return control button size + */ +void lv_win_set_btn_size(lv_obj_t * win, lv_coord_t size); + +/** + * Set the layout of the window + * @param win pointer to a window object + * @param layout the layout from 'lv_layout_t' + */ +void lv_win_set_layout(lv_obj_t *win, lv_layout_t layout); + +/** + * Set the scroll bar mode of a window + * @param win pointer to a window object + * @param sb_mode the new scroll bar mode from 'lv_sb_mode_t' + */ +void lv_win_set_sb_mode(lv_obj_t *win, lv_sb_mode_t sb_mode); + +/** + * Set a style of a window + * @param win pointer to a window object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_win_set_style(lv_obj_t *win, lv_win_style_t type, lv_style_t *style); + +/** + * Set drag status of a window. If set to 'true' window can be dragged like on a PC. + * @param win pointer to a window object + * @param en whether dragging is enabled + */ +void lv_win_set_drag(lv_obj_t *win, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the title of a window + * @param win pointer to a window object + * @return title string of the window + */ +const char * lv_win_get_title(const lv_obj_t * win); + +/** +* Get the content holder object of window (`lv_page`) to allow additional customization +* @param win pointer to a window object +* @return the Page object where the window's content is +*/ +lv_obj_t * lv_win_get_content(const lv_obj_t * win); + +/** + * Get the control button size of a window + * @param win pointer to a window object + * @return control button size + */ +lv_coord_t lv_win_get_btn_size(const lv_obj_t * win); + +/** + * Get the pointer of a widow from one of its control button. + * It is useful in the action of the control buttons where only button is known. + * @param ctrl_btn pointer to a control button of a window + * @return pointer to the window of 'ctrl_btn' + */ +lv_obj_t * lv_win_get_from_btn(const lv_obj_t * ctrl_btn); + +/** + * Get the layout of a window + * @param win pointer to a window object + * @return the layout of the window (from 'lv_layout_t') + */ +lv_layout_t lv_win_get_layout(lv_obj_t *win); + +/** + * Get the scroll bar mode of a window + * @param win pointer to a window object + * @return the scroll bar mode of the window (from 'lv_sb_mode_t') + */ +lv_sb_mode_t lv_win_get_sb_mode(lv_obj_t *win); + +/** + * Get width of the content area (page scrollable) of the window + * @param win pointer to a window object + * @return the width of the content area + */ +lv_coord_t lv_win_get_width(lv_obj_t * win); + +/** + * Get a style of a window + * @param win pointer to a button object + * @param type which style window be get + * @return style pointer to a style + */ +lv_style_t * lv_win_get_style(const lv_obj_t *win, lv_win_style_t type); + +/** + * Get drag status of a window. If set to 'true' window can be dragged like on a PC. + * @param win pointer to a window object + * @return whether window is draggable + */ +static inline bool lv_win_get_drag(const lv_obj_t *win) +{ + return lv_obj_get_drag(win); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Focus on an object. It ensures that the object will be visible in the window. + * @param win pointer to a window object + * @param obj pointer to an object to focus (must be in the window) + * @param anim_time scroll animation time in milliseconds (0: no animation) + */ +void lv_win_focus(lv_obj_t * win, lv_obj_t * obj, uint16_t anim_time); + +/** + * Scroll the window horizontally + * @param win pointer to a window object + * @param dist the distance to scroll (< 0: scroll right; > 0 scroll left) + */ +static inline void lv_win_scroll_hor(lv_obj_t * win, lv_coord_t dist) +{ + lv_win_ext_t * ext = (lv_win_ext_t *)lv_obj_get_ext_attr(win); + lv_page_scroll_hor(ext->page, dist); +} +/** + * Scroll the window vertically + * @param win pointer to a window object + * @param dist the distance to scroll (< 0: scroll down; > 0 scroll up) + */ +static inline void lv_win_scroll_ver(lv_obj_t * win, lv_coord_t dist) +{ + lv_win_ext_t * ext = (lv_win_ext_t *)lv_obj_get_ext_attr(win); + lv_page_scroll_ver(ext->page, dist); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_WIN*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_WIN_H*/ diff --git a/pros/display/lv_themes/lv_theme.h b/pros/display/lv_themes/lv_theme.h new file mode 100644 index 00000000..69aae29f --- /dev/null +++ b/pros/display/lv_themes/lv_theme.h @@ -0,0 +1,332 @@ +/** + *@file lv_themes.h + * + */ + +#ifndef LV_THEMES_H +#define LV_THEMES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include "display/lv_core/lv_style.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_style_t *bg; + lv_style_t *panel; + +#if USE_LV_CONT != 0 + lv_style_t *cont; +#endif + +#if USE_LV_BTN != 0 + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; +#endif + + +#if USE_LV_IMGBTN != 0 + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } imgbtn; +#endif + +#if USE_LV_LABEL != 0 + struct { + lv_style_t *prim; + lv_style_t *sec; + lv_style_t *hint; + } label; +#endif + +#if USE_LV_IMG != 0 + struct { + lv_style_t *light; + lv_style_t *dark; + } img; +#endif + +#if USE_LV_LINE != 0 + struct { + lv_style_t *decor; + } line; +#endif + +#if USE_LV_LED != 0 + lv_style_t *led; +#endif + +#if USE_LV_BAR != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + } bar; +#endif + +#if USE_LV_SLIDER != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + lv_style_t *knob; + } slider; +#endif + +#if USE_LV_LMETER != 0 + lv_style_t *lmeter; +#endif + +#if USE_LV_GAUGE != 0 + lv_style_t *gauge; +#endif + +#if USE_LV_ARC != 0 + lv_style_t *arc; +#endif + +#if USE_LV_PRELOAD != 0 + lv_style_t *preload; +#endif + +#if USE_LV_SW != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + lv_style_t *knob_off; + lv_style_t *knob_on; + } sw; +#endif + +#if USE_LV_CHART != 0 + lv_style_t *chart; +#endif + +#if USE_LV_CALENDAR != 0 + struct { + lv_style_t *bg; + lv_style_t *header; + lv_style_t *header_pr; + lv_style_t *day_names; + lv_style_t *highlighted_days; + lv_style_t *inactive_days; + lv_style_t *week_box; + lv_style_t *today_box; + } calendar; +#endif + +#if USE_LV_CB != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } box; + } cb; +#endif + +#if USE_LV_BTNM != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; + } btnm; +#endif + +#if USE_LV_KB != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; + } kb; +#endif + +#if USE_LV_MBOX != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *bg; + lv_style_t *rel; + lv_style_t *pr; + } btn; + } mbox; +#endif + +#if USE_LV_PAGE != 0 + struct { + lv_style_t *bg; + lv_style_t *scrl; + lv_style_t *sb; + } page; +#endif + +#if USE_LV_TA != 0 + struct { + lv_style_t *area; + lv_style_t *oneline; + lv_style_t *cursor; + lv_style_t *sb; + } ta; +#endif + +#if USE_LV_SPINBOX != 0 + struct { + lv_style_t *bg; + lv_style_t *cursor; + lv_style_t *sb; + } spinbox; +#endif + +#if USE_LV_LIST + struct { + lv_style_t *bg; + lv_style_t *scrl; + lv_style_t *sb; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; + } list; +#endif + +#if USE_LV_DDLIST != 0 + struct { + lv_style_t *bg; + lv_style_t *sel; + lv_style_t *sb; + } ddlist; +#endif + +#if USE_LV_ROLLER != 0 + struct { + lv_style_t *bg; + lv_style_t *sel; + } roller; +#endif + +#if USE_LV_TABVIEW != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + struct { + lv_style_t *bg; + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + } btn; + } tabview; +#endif + +#if USE_LV_TILEVIEW != 0 + struct { + lv_style_t *bg; + lv_style_t *scrl; + lv_style_t *sb; + } tileview; +#endif + +#if USE_LV_TABLE != 0 + struct { + lv_style_t *bg; + lv_style_t *cell; + } table; +#endif + +#if USE_LV_WIN != 0 + struct { + lv_style_t *bg; + lv_style_t *sb; + lv_style_t *header; + struct { + lv_style_t *bg; + lv_style_t *scrl; + } content; + struct { + lv_style_t *rel; + lv_style_t *pr; + } btn; + } win; +#endif +} lv_theme_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Set a theme for the system. + * From now, all the created objects will use styles from this theme by default + * @param th pointer to theme (return value of: 'lv_theme_init_xxx()') + */ +void lv_theme_set_current(lv_theme_t *th); + +/** + * Get the current system theme. + * @return pointer to the current system theme. NULL if not set. + */ +lv_theme_t * lv_theme_get_current(void); + +/********************** + * MACROS + **********************/ + +/********************** + * POST INCLUDE + *********************/ +#include "lv_theme_templ.h" +#include "lv_theme_default.h" +#include "lv_theme_alien.h" +#include "lv_theme_night.h" +#include "lv_theme_zen.h" +#include "lv_theme_mono.h" +#include "lv_theme_nemo.h" +#include "lv_theme_material.h" + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEMES_H*/ diff --git a/pros/display/lv_themes/lv_theme_alien.h b/pros/display/lv_themes/lv_theme_alien.h new file mode 100644 index 00000000..1f62315d --- /dev/null +++ b/pros/display/lv_themes/lv_theme_alien.h @@ -0,0 +1,59 @@ +/** + * @file lv_theme_alien.h + * + */ + +#ifndef LV_THEME_ALIEN_H +#define LV_THEME_ALIEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_ALIEN + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the alien theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_alien_init(uint16_t hue, lv_font_t *font); +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_alien(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_ALIEN_H*/ diff --git a/pros/display/lv_themes/lv_theme_default.h b/pros/display/lv_themes/lv_theme_default.h new file mode 100644 index 00000000..1348f1fc --- /dev/null +++ b/pros/display/lv_themes/lv_theme_default.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_default.h + * + */ + +#ifndef LV_THEME_DEFAULT_H +#define LV_THEME_DEFAULT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_DEFAULT + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the default theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_default_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_default(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_TEMPL_H*/ diff --git a/pros/display/lv_themes/lv_theme_material.h b/pros/display/lv_themes/lv_theme_material.h new file mode 100644 index 00000000..d9da6646 --- /dev/null +++ b/pros/display/lv_themes/lv_theme_material.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_material.h + * + */ + +#ifndef LV_THEME_MATERIAL_H +#define LV_THEME_MATERIAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_MATERIAL + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the material theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_material_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_material(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_MATERIAL_H*/ diff --git a/pros/display/lv_themes/lv_theme_mono.h b/pros/display/lv_themes/lv_theme_mono.h new file mode 100644 index 00000000..63039fa9 --- /dev/null +++ b/pros/display/lv_themes/lv_theme_mono.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_mono.h + * + */ + +#ifndef LV_THEME_MONO_H +#define LV_THEME_MONO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_MONO + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the mono theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_mono_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_mono(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_MONO_H*/ diff --git a/pros/display/lv_themes/lv_theme_nemo.h b/pros/display/lv_themes/lv_theme_nemo.h new file mode 100644 index 00000000..46d43bdb --- /dev/null +++ b/pros/display/lv_themes/lv_theme_nemo.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_nemo.h + * + */ + +#ifndef LV_THEME_NEMO_H +#define LV_THEME_NEMO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_NEMO + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the material theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_nemo_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_nemo(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_NEMO_H*/ diff --git a/pros/display/lv_themes/lv_theme_night.h b/pros/display/lv_themes/lv_theme_night.h new file mode 100644 index 00000000..3e5efb8f --- /dev/null +++ b/pros/display/lv_themes/lv_theme_night.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_night.h + * + */ + +#ifndef LV_THEME_NIGHT_H +#define LV_THEME_NIGHT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_NIGHT + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the night theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_night_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_night(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_NIGHT_H*/ diff --git a/pros/display/lv_themes/lv_theme_templ.h b/pros/display/lv_themes/lv_theme_templ.h new file mode 100644 index 00000000..e7176636 --- /dev/null +++ b/pros/display/lv_themes/lv_theme_templ.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_templ.h + * + */ + +#ifndef LV_THEME_TEMPL_H +#define LV_THEME_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_TEMPL + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the templ theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_templ_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_templ(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_TEMPL_H*/ diff --git a/pros/display/lv_themes/lv_theme_zen.h b/pros/display/lv_themes/lv_theme_zen.h new file mode 100644 index 00000000..ddd7cb35 --- /dev/null +++ b/pros/display/lv_themes/lv_theme_zen.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_zen.h + * + */ + +#ifndef LV_THEME_ZEN_H +#define LV_THEME_ZEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_ZEN + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the zen theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_zen_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_zen(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_ZEN_H*/ diff --git a/pros/display/lv_themes/lv_themes.mk b/pros/display/lv_themes/lv_themes.mk new file mode 100644 index 00000000..0e4a81a5 --- /dev/null +++ b/pros/display/lv_themes/lv_themes.mk @@ -0,0 +1,14 @@ +CSRCS += lv_theme_alien.c +CSRCS += lv_theme.c +CSRCS += lv_theme_default.c +CSRCS += lv_theme_night.c +CSRCS += lv_theme_templ.c +CSRCS += lv_theme_zen.c +CSRCS += lv_theme_material.c +CSRCS += lv_theme_nemo.c +CSRCS += lv_theme_mono.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_themes +VPATH += :$(LVGL_DIR)/lvgl/lv_themes + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_themes" diff --git a/pros/display/lv_version.h b/pros/display/lv_version.h new file mode 100644 index 00000000..1e62e1e2 --- /dev/null +++ b/pros/display/lv_version.h @@ -0,0 +1,66 @@ +/** + * @file lv_version.h + * + */ + +#ifndef LV_VERSION_H +#define LV_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +/*Current version of LittlevGL*/ +#define LVGL_VERSION_MAJOR 5 +#define LVGL_VERSION_MINOR 3 +#define LVGL_VERSION_PATCH 0 +#define LVGL_VERSION_INFO "" + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ +/* Gives 1 if the x.y.z version is supported in the current version + * Usage: + * + * - Require v6 + * #if LV_VERSION_CHECK(6,0,0) + * new_func_in_v6(); + * #endif + * + * + * - Require at least v5.3 + * #if LV_VERSION_CHECK(5,3,0) + * new_feature_from_v5_3(); + * #endif + * + * + * - Require v5.3.2 bugfixes + * #if LV_VERSION_CHECK(5,3,2) + * bugfix_in_v5_3_2(); + * #endif + * + * */ +#define LV_VERSION_CHECK(x,y,z) (x == LVGL_VERSION_MAJOR && (y < LVGL_VERSION_MINOR || (y == LVGL_VERSION_MINOR && z <= LVGL_VERSION_PATCH))) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_VERSION_H*/ diff --git a/pros/display/lvgl.h b/pros/display/lvgl.h new file mode 100644 index 00000000..d2c93b4e --- /dev/null +++ b/pros/display/lvgl.h @@ -0,0 +1,88 @@ +/** + * @file lvgl.h + * Include all LittleV GL related headers + */ + +#ifndef LVGL_H +#define LVGL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#include "lv_version.h" + +#include "lv_misc/lv_log.h" +#include "lv_misc/lv_task.h" + +#include "lv_hal/lv_hal.h" + +#include "lv_core/lv_obj.h" +#include "lv_core/lv_group.h" +#include "lv_core/lv_lang.h" +#include "lv_core/lv_vdb.h" +#include "lv_core/lv_refr.h" + +#include "lv_themes/lv_theme.h" + +#include "lv_objx/lv_btn.h" +#include "lv_objx/lv_imgbtn.h" +#include "lv_objx/lv_img.h" +#include "lv_objx/lv_label.h" +#include "lv_objx/lv_line.h" +#include "lv_objx/lv_page.h" +#include "lv_objx/lv_cont.h" +#include "lv_objx/lv_list.h" +#include "lv_objx/lv_chart.h" +#include "lv_objx/lv_table.h" +#include "lv_objx/lv_cb.h" +#include "lv_objx/lv_bar.h" +#include "lv_objx/lv_slider.h" +#include "lv_objx/lv_led.h" +#include "lv_objx/lv_btnm.h" +#include "lv_objx/lv_kb.h" +#include "lv_objx/lv_ddlist.h" +#include "lv_objx/lv_roller.h" +#include "lv_objx/lv_ta.h" +#include "lv_objx/lv_canvas.h" +#include "lv_objx/lv_win.h" +#include "lv_objx/lv_tabview.h" +#include "lv_objx/lv_tileview.h" +#include "lv_objx/lv_mbox.h" +#include "lv_objx/lv_gauge.h" +#include "lv_objx/lv_lmeter.h" +#include "lv_objx/lv_sw.h" +#include "lv_objx/lv_kb.h" +#include "lv_objx/lv_arc.h" +#include "lv_objx/lv_preload.h" +#include "lv_objx/lv_calendar.h" +#include "lv_objx/lv_spinbox.h" +#pragma GCC diagnostic pop + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} +#endif + +#endif /*LVGL_H*/ diff --git a/pros/okapi/api.hpp b/pros/okapi/api.hpp new file mode 100644 index 00000000..2c403e06 --- /dev/null +++ b/pros/okapi/api.hpp @@ -0,0 +1,134 @@ +/* + * 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 + +/** @mainpage OkapiLib Index Page + * + * @section intro_sec Introduction + * + * **OkapiLib** is a PROS library for programming VEX V5 robots. This library is intended to raise + * the floor for teams with all levels of experience. New teams should have an easier time getting + * their robot up and running, and veteran teams should find that OkapiLib doesn't get in the way or + * place any limits on functionality. + * + * For tutorials on how to get the most out of OkapiLib, see the + * [Tutorials](docs/tutorials/index.md) section. For documentation on using the OkapiLib API, see + * the [API](docs/api/index.md) section. + * + * @section getting_started Getting Started + * Not sure where to start? Take a look at the + * [Getting Started](docs/tutorials/walkthrough/gettingStarted.md) tutorial. + * Once you have OkapiLib set up, check out the + * [Clawbot](docs/tutorials/walkthrough/clawbot.md) tutorial. + * + * @section using_docs Using The Documentation + * + * Start with reading the [Tutorials](docs/tutorials/index.md). Use the [API](docs/api/index.md) + * section to explore the class hierarchy. To see a list of all available classes, use the + * [Classes](annotated.html) section. + * + * This documentation has a powerful search feature, which can be brought up with the keyboard + * shortcuts `Tab` or `T`. All exports to the `okapi` namespace such as enums, constants, units, or + * functions can be found [here](@ref okapi). + */ + +#include "okapi/api/chassis/controller/chassisControllerIntegrated.hpp" +#include "okapi/api/chassis/controller/chassisControllerPid.hpp" +#include "okapi/api/chassis/controller/chassisScales.hpp" +#include "okapi/api/chassis/controller/defaultOdomChassisController.hpp" +#include "okapi/api/chassis/controller/odomChassisController.hpp" +#include "okapi/api/chassis/model/hDriveModel.hpp" +#include "okapi/api/chassis/model/readOnlyChassisModel.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp" +#include "okapi/api/chassis/model/threeEncoderXDriveModel.hpp" +#include "okapi/api/chassis/model/xDriveModel.hpp" +#include "okapi/impl/chassis/controller/chassisControllerBuilder.hpp" + +#include "okapi/api/control/async/asyncLinearMotionProfileController.hpp" +#include "okapi/api/control/async/asyncMotionProfileController.hpp" +#include "okapi/api/control/async/asyncPosIntegratedController.hpp" +#include "okapi/api/control/async/asyncPosPidController.hpp" +#include "okapi/api/control/async/asyncVelIntegratedController.hpp" +#include "okapi/api/control/async/asyncVelPidController.hpp" +#include "okapi/api/control/async/asyncWrapper.hpp" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/control/iterative/iterativeMotorVelocityController.hpp" +#include "okapi/api/control/iterative/iterativePosPidController.hpp" +#include "okapi/api/control/iterative/iterativeVelPidController.hpp" +#include "okapi/api/control/util/controllerRunner.hpp" +#include "okapi/api/control/util/flywheelSimulator.hpp" +#include "okapi/api/control/util/pidTuner.hpp" +#include "okapi/api/control/util/settledUtil.hpp" +#include "okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp" +#include "okapi/impl/control/async/asyncPosControllerBuilder.hpp" +#include "okapi/impl/control/async/asyncVelControllerBuilder.hpp" +#include "okapi/impl/control/iterative/iterativeControllerFactory.hpp" +#include "okapi/impl/control/util/controllerRunnerFactory.hpp" +#include "okapi/impl/control/util/pidTunerFactory.hpp" + +#include "okapi/api/odometry/odomMath.hpp" +#include "okapi/api/odometry/odometry.hpp" +#include "okapi/api/odometry/threeEncoderOdometry.hpp" + +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" +#include "okapi/api/device/rotarysensor/rotarySensor.hpp" +#include "okapi/impl/device/adiUltrasonic.hpp" +#include "okapi/impl/device/button/adiButton.hpp" +#include "okapi/impl/device/button/controllerButton.hpp" +#include "okapi/impl/device/controller.hpp" +#include "okapi/impl/device/distanceSensor.hpp" +#include "okapi/impl/device/motor/adiMotor.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/device/opticalSensor.hpp" +#include "okapi/impl/device/rotarysensor/IMU.hpp" +#include "okapi/impl/device/rotarysensor/adiEncoder.hpp" +#include "okapi/impl/device/rotarysensor/adiGyro.hpp" +#include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" +#include "okapi/impl/device/rotarysensor/potentiometer.hpp" +#include "okapi/impl/device/rotarysensor/rotationSensor.hpp" + +#include "okapi/api/filter/averageFilter.hpp" +#include "okapi/api/filter/composableFilter.hpp" +#include "okapi/api/filter/demaFilter.hpp" +#include "okapi/api/filter/ekfFilter.hpp" +#include "okapi/api/filter/emaFilter.hpp" +#include "okapi/api/filter/filter.hpp" +#include "okapi/api/filter/filteredControllerInput.hpp" +#include "okapi/api/filter/medianFilter.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include "okapi/api/filter/velMath.hpp" +#include "okapi/impl/filter/velMathFactory.hpp" + +#include "okapi/api/units/QAcceleration.hpp" +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QAngularAcceleration.hpp" +#include "okapi/api/units/QAngularJerk.hpp" +#include "okapi/api/units/QAngularSpeed.hpp" +#include "okapi/api/units/QArea.hpp" +#include "okapi/api/units/QForce.hpp" +#include "okapi/api/units/QFrequency.hpp" +#include "okapi/api/units/QJerk.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/QMass.hpp" +#include "okapi/api/units/QPressure.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/QTorque.hpp" +#include "okapi/api/units/QVolume.hpp" +#include "okapi/api/units/RQuantityName.hpp" + +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/abstractTimer.hpp" +#include "okapi/api/util/mathUtil.hpp" +#include "okapi/api/util/supplier.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include "okapi/impl/util/configurableTimeUtilFactory.hpp" +#include "okapi/impl/util/rate.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" +#include "okapi/impl/util/timer.hpp" diff --git a/pros/okapi/api/chassis/controller/chassisController.hpp b/pros/okapi/api/chassis/controller/chassisController.hpp new file mode 100644 index 00000000..9e3dcf9a --- /dev/null +++ b/pros/okapi/api/chassis/controller/chassisController.hpp @@ -0,0 +1,142 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisScales.hpp" +#include "okapi/api/chassis/model/chassisModel.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QLength.hpp" +#include +#include + +namespace okapi { +class ChassisController { + public: + /** + * A ChassisController adds a closed-loop layer on top of a ChassisModel. moveDistance and + * turnAngle both use closed-loop control to move the robot. There are passthrough functions for + * everything defined in ChassisModel. + * + * @param imodel underlying ChassisModel + */ + explicit ChassisController() = default; + + virtual ~ChassisController() = default; + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * @param itarget distance to travel + */ + virtual void moveDistance(QLength itarget) = 0; + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * @param itarget distance to travel in motor degrees + */ + virtual void moveRaw(double itarget) = 0; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel + */ + virtual void moveDistanceAsync(QLength itarget) = 0; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel in motor degrees + */ + virtual void moveRawAsync(double itarget) = 0; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for + */ + virtual void turnAngle(QAngle idegTarget) = 0; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for in motor degrees + */ + virtual void turnRaw(double idegTarget) = 0; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for + */ + virtual void turnAngleAsync(QAngle idegTarget) = 0; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for in motor degrees + */ + virtual void turnRawAsync(double idegTarget) = 0; + + /** + * Sets whether turns should be mirrored. + * + * @param ishouldMirror whether turns should be mirrored + */ + virtual void setTurnsMirrored(bool ishouldMirror) = 0; + + /** + * Checks whether the internal controllers are currently settled. + * + * @return Whether this ChassisController is settled. + */ + virtual bool isSettled() = 0; + + /** + * Delays until the currently executing movement completes. + */ + virtual void waitUntilSettled() = 0; + + /** + * Interrupts the current movement to stop the robot. + */ + virtual void stop() = 0; + + /** + * Sets a new maximum velocity in RPM [0-600]. + * + * @param imaxVelocity The new maximum velocity. + */ + virtual void setMaxVelocity(double imaxVelocity) = 0; + + /** + * @return The maximum velocity in RPM [0-600]. + */ + virtual double getMaxVelocity() const = 0; + + /** + * Get the ChassisScales. + */ + virtual ChassisScales getChassisScales() const = 0; + + /** + * Get the GearsetRatioPair. + */ + virtual AbstractMotor::GearsetRatioPair getGearsetRatioPair() const = 0; + + /** + * @return The internal ChassisModel. + */ + virtual std::shared_ptr getModel() = 0; + + /** + * @return The internal ChassisModel. + */ + virtual ChassisModel &model() = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/chassis/controller/chassisControllerIntegrated.hpp b/pros/okapi/api/chassis/controller/chassisControllerIntegrated.hpp new file mode 100644 index 00000000..6bee44ef --- /dev/null +++ b/pros/okapi/api/chassis/controller/chassisControllerIntegrated.hpp @@ -0,0 +1,184 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisController.hpp" +#include "okapi/api/control/async/asyncPosIntegratedController.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" + +namespace okapi { +class ChassisControllerIntegrated : public ChassisController { + public: + /** + * ChassisController using the V5 motor's integrated control. Puts the motors into encoder count + * units. Throws a `std::invalid_argument` exception if the gear ratio is zero. The initial + * model's max velocity will be propagated to the controllers. + * + * @param itimeUtil The TimeUtil. + * @param imodel The ChassisModel used to read from sensors/write to motors. + * @param ileftController The controller used for the left side motors. + * @param irightController The controller used for the right side motors. + * @param igearset The internal gearset and external ratio used on the drive motors. + * @param iscales The ChassisScales. + * @param ilogger The logger this instance will log to. + */ + ChassisControllerIntegrated( + const TimeUtil &itimeUtil, + std::shared_ptr imodel, + std::unique_ptr ileftController, + std::unique_ptr irightController, + const AbstractMotor::GearsetRatioPair &igearset = AbstractMotor::gearset::green, + const ChassisScales &iscales = ChassisScales({1, 1}, imev5GreenTPR), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * ```cpp + * // Drive forward 6 inches + * chassis->moveDistance(6_in); + * + * // Drive backward 0.2 meters + * chassis->moveDistance(-0.2_m); + * ``` + * + * @param itarget distance to travel + */ + void moveDistance(QLength itarget) override; + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * ```cpp + * // Drive forward by spinning the motors 400 degrees + * chassis->moveRaw(400); + * ``` + * + * @param itarget distance to travel in motor degrees + */ + void moveRaw(double itarget) override; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel + */ + void moveDistanceAsync(QLength itarget) override; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel in motor degrees + */ + void moveRawAsync(double itarget) override; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * ```cpp + * // Turn 90 degrees clockwise + * chassis->turnAngle(90_deg); + * ``` + * + * @param idegTarget angle to turn for + */ + void turnAngle(QAngle idegTarget) override; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * ```cpp + * // Turn clockwise by spinning the motors 200 degrees + * chassis->turnRaw(200); + * ``` + * + * @param idegTarget angle to turn for in motor degrees + */ + void turnRaw(double idegTarget) override; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for + */ + void turnAngleAsync(QAngle idegTarget) override; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for in motor degrees + */ + void turnRawAsync(double idegTarget) override; + + /** + * Sets whether turns should be mirrored. + * + * @param ishouldMirror whether turns should be mirrored + */ + void setTurnsMirrored(bool ishouldMirror) override; + + /** + * Checks whether the internal controllers are currently settled. + * + * @return Whether this ChassisController is settled. + */ + bool isSettled() override; + + /** + * Delays until the currently executing movement completes. + */ + void waitUntilSettled() override; + + /** + * Interrupts the current movement to stop the robot. + */ + void stop() override; + + /** + * Get the ChassisScales. + */ + ChassisScales getChassisScales() const override; + + /** + * Get the GearsetRatioPair. + */ + AbstractMotor::GearsetRatioPair getGearsetRatioPair() const override; + + /** + * @return The internal ChassisModel. + */ + std::shared_ptr getModel() override; + + /** + * @return The internal ChassisModel. + */ + ChassisModel &model() override; + + /** + * Sets a new maximum velocity in RPM [0-600]. + * + * @param imaxVelocity The new maximum velocity. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * @return The maximum velocity in RPM [0-600]. + */ + double getMaxVelocity() const override; + + protected: + std::shared_ptr logger; + bool normalTurns{true}; + std::shared_ptr chassisModel; + TimeUtil timeUtil; + std::unique_ptr leftController; + std::unique_ptr rightController; + int lastTarget; + ChassisScales scales; + AbstractMotor::GearsetRatioPair gearsetRatioPair; +}; +} // namespace okapi diff --git a/pros/okapi/api/chassis/controller/chassisControllerPid.hpp b/pros/okapi/api/chassis/controller/chassisControllerPid.hpp new file mode 100644 index 00000000..91441ecb --- /dev/null +++ b/pros/okapi/api/chassis/controller/chassisControllerPid.hpp @@ -0,0 +1,275 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisController.hpp" +#include "okapi/api/control/iterative/iterativePosPidController.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include +#include + +namespace okapi { +class ChassisControllerPID : public ChassisController { + public: + /** + * ChassisController using PID control. Puts the motors into encoder count units. Throws a + * `std::invalid_argument` exception if the gear ratio is zero. + * + * @param itimeUtil The TimeUtil. + * @param imodel The ChassisModel used to read from sensors/write to motors. + * @param idistanceController The PID controller that controls chassis distance for driving + * straight. + * @param iturnController The PID controller that controls chassis angle for turning. + * @param iangleController The PID controller that controls chassis angle for driving straight. + * @param igearset The internal gearset and external ratio used on the drive motors. + * @param iscales The ChassisScales. + * @param ilogger The logger this instance will log to. + */ + ChassisControllerPID( + TimeUtil itimeUtil, + std::shared_ptr imodel, + std::unique_ptr idistanceController, + std::unique_ptr iturnController, + std::unique_ptr iangleController, + const AbstractMotor::GearsetRatioPair &igearset = AbstractMotor::gearset::green, + const ChassisScales &iscales = ChassisScales({1, 1}, imev5GreenTPR), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + ChassisControllerPID(const ChassisControllerPID &) = delete; + ChassisControllerPID(ChassisControllerPID &&other) = delete; + ChassisControllerPID &operator=(const ChassisControllerPID &other) = delete; + ChassisControllerPID &operator=(ChassisControllerPID &&other) = delete; + + ~ChassisControllerPID() override; + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * ```cpp + * // Drive forward 6 inches + * chassis->moveDistance(6_in); + * + * // Drive backward 0.2 meters + * chassis->moveDistance(-0.2_m); + * ``` + * + * @param itarget distance to travel + */ + void moveDistance(QLength itarget) override; + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * ```cpp + * // Drive forward by spinning the motors 400 degrees + * chassis->moveRaw(400); + * ``` + * + * @param itarget distance to travel in motor degrees + */ + void moveRaw(double itarget) override; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel + */ + void moveDistanceAsync(QLength itarget) override; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel in motor degrees + */ + void moveRawAsync(double itarget) override; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * ```cpp + * // Turn 90 degrees clockwise + * chassis->turnAngle(90_deg); + * ``` + * + * @param idegTarget angle to turn for + */ + void turnAngle(QAngle idegTarget) override; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * ```cpp + * // Turn clockwise by spinning the motors 200 degrees + * chassis->turnRaw(200); + * ``` + * + * @param idegTarget angle to turn for in motor degrees + */ + void turnRaw(double idegTarget) override; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for + */ + void turnAngleAsync(QAngle idegTarget) override; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for in motor degrees + */ + void turnRawAsync(double idegTarget) override; + + /** + * Sets whether turns should be mirrored. + * + * @param ishouldMirror whether turns should be mirrored + */ + void setTurnsMirrored(bool ishouldMirror) override; + + /** + * Checks whether the internal controllers are currently settled. + * + * @return Whether this ChassisController is settled. + */ + bool isSettled() override; + + /** + * Delays until the currently executing movement completes. + */ + void waitUntilSettled() override; + + /** + * Gets the ChassisScales. + */ + ChassisScales getChassisScales() const override; + + /** + * Gets the GearsetRatioPair. + */ + AbstractMotor::GearsetRatioPair getGearsetRatioPair() const override; + + /** + * Sets the velocity mode flag. When the controller is in velocity mode, the control loop will + * set motor velocities. When the controller is in voltage mode (`ivelocityMode = false`), the + * control loop will set motor voltages. Additionally, when the controller is in voltage mode, + * it will not obey maximum velocity limits. + * + * @param ivelocityMode Whether the controller should be in velocity or voltage mode. + */ + void setVelocityMode(bool ivelocityMode); + + /** + * Sets the gains for all controllers. + * + * @param idistanceGains The distance controller gains. + * @param iturnGains The turn controller gains. + * @param iangleGains The angle controller gains. + */ + void setGains(const IterativePosPIDController::Gains &idistanceGains, + const IterativePosPIDController::Gains &iturnGains, + const IterativePosPIDController::Gains &iangleGains); + + /** + * Gets the current controller gains. + * + * @return The current controller gains in the order: distance, turn, angle. + */ + std::tuple + getGains() const; + + /** + * Starts the internal thread. This method is called by the ChassisControllerBuilder when making a + * new instance of this class. + */ + void startThread(); + + /** + * Returns the underlying thread handle. + * + * @return The underlying thread handle. + */ + CrossplatformThread *getThread() const; + + /** + * Interrupts the current movement to stop the robot. + */ + void stop() override; + + /** + * Sets a new maximum velocity in RPM [0-600]. In voltage mode, the max velocity is ignored and a + * max voltage should be set on the underlying ChassisModel instead. + * + * @param imaxVelocity The new maximum velocity. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * @return The maximum velocity in RPM [0-600]. + */ + double getMaxVelocity() const override; + + /** + * @return The internal ChassisModel. + */ + std::shared_ptr getModel() override; + + /** + * @return The internal ChassisModel. + */ + ChassisModel &model() override; + + protected: + std::shared_ptr logger; + bool normalTurns{true}; + std::shared_ptr chassisModel; + TimeUtil timeUtil; + std::unique_ptr distancePid; + std::unique_ptr turnPid; + std::unique_ptr anglePid; + ChassisScales scales; + AbstractMotor::GearsetRatioPair gearsetRatioPair; + bool velocityMode{true}; + std::atomic_bool doneLooping{true}; + std::atomic_bool doneLoopingSeen{true}; + std::atomic_bool newMovement{false}; + std::atomic_bool dtorCalled{false}; + QTime threadSleepTime{10_ms}; + + static void trampoline(void *context); + void loop(); + + /** + * Wait for the distance setup (distancePid and anglePid) to settle. + * + * @return true if done settling; false if settling should be tried again + */ + bool waitForDistanceSettled(); + + /** + * Wait for the angle setup (anglePid) to settle. + * + * @return true if done settling; false if settling should be tried again + */ + bool waitForAngleSettled(); + + /** + * Stops all the controllers and the ChassisModel. + */ + void stopAfterSettled(); + + typedef enum { distance, angle, none } modeType; + modeType mode{none}; + + CrossplatformThread *task{nullptr}; +}; +} // namespace okapi diff --git a/pros/okapi/api/chassis/controller/chassisScales.hpp b/pros/okapi/api/chassis/controller/chassisScales.hpp new file mode 100644 index 00000000..d4d29096 --- /dev/null +++ b/pros/okapi/api/chassis/controller/chassisScales.hpp @@ -0,0 +1,88 @@ +/* + * 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 + +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/RQuantity.hpp" +#include "okapi/api/util/logging.hpp" +#include +#include +#include + +namespace okapi { +class ChassisScales { + public: + /** + * The scales a ChassisController needs to do all of its closed-loop control. The first element is + * the wheel diameter, the second element is the wheel track. For three-encoder configurations, + * the length from the center of rotation to the middle wheel and the middle wheel diameter are + * passed as the third and fourth elements. + * + * The wheel track is the center-to-center distance between the wheels (center-to-center + * meaning the width between the centers of both wheels). For example, if you are using four inch + * omni wheels and there are 11.5 inches between the centers of each wheel, you would call the + * constructor like so: + * `ChassisScales scales({4_in, 11.5_in}, imev5GreenTPR); // imev5GreenTPR for a green gearset` + * + * Wheel diameter + * + * +-+ Center of rotation + * | | | + * v v +----------+ Length to middle wheel + * | | from center of rotation + * +---> === | === | + * | + v + | + * | ++---------------++ | + * | | | v + * Wheel track | | | + * | | x |+| <-- Middle wheel + * | | | + * | | | + * | ++---------------++ + * | + + + * +---> === === + * + * + * @param idimensions {wheel diameter, wheel track} or {wheel diameter, wheel track, length to + * middle wheel, middle wheel diameter}. + * @param itpr The ticks per revolution of the encoders. + * @param ilogger The logger this instance will log to. + */ + ChassisScales(const std::initializer_list &idimensions, + double itpr, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * The scales a ChassisController needs to do all of its closed-loop control. The first element is + * the straight scale, the second element is the turn scale. Optionally, the length from the + * center of rotation to the middle wheel and the middle scale can be passed as the third and + * fourth elements. The straight scale converts motor degrees to meters, the turn scale converts + * motor degrees to robot turn degrees, and the middle scale converts middle wheel degrees to + * meters. + * + * @param iscales {straight scale, turn scale} or {straight scale, turn scale, length to middle + * wheel in meters, middle scale}. + * @param itpr The ticks per revolution of the encoders. + * @param ilogger The logger this instance will log to. + */ + ChassisScales(const std::initializer_list &iscales, + double itpr, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + QLength wheelDiameter; + QLength wheelTrack; + QLength middleWheelDistance; + QLength middleWheelDiameter; + double straight; + double turn; + double middle; + double tpr; + + protected: + static void validateInputSize(std::size_t inputSize, const std::shared_ptr &logger); +}; +} // namespace okapi diff --git a/pros/okapi/api/chassis/controller/defaultOdomChassisController.hpp b/pros/okapi/api/chassis/controller/defaultOdomChassisController.hpp new file mode 100644 index 00000000..f8fe52e8 --- /dev/null +++ b/pros/okapi/api/chassis/controller/defaultOdomChassisController.hpp @@ -0,0 +1,183 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisControllerIntegrated.hpp" +#include "okapi/api/chassis/controller/odomChassisController.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/odometry/odometry.hpp" +#include + +namespace okapi { +class DefaultOdomChassisController : public OdomChassisController { + public: + /** + * Odometry based chassis controller that moves using a separately constructed chassis controller. + * Spins up a task at the default priority plus 1 for odometry when constructed. + * + * Moves the robot around in the odom frame. Instead of telling the robot to drive forward or + * turn some amount, you instead tell it to drive to a specific point on the field or turn to + * a specific angle, relative to its starting position. + * + * @param itimeUtil The TimeUtil. + * @param iodometry The odometry to read state estimates from. + * @param icontroller The chassis controller to delegate to. + * @param imode The new default StateMode used to interpret target points and query the Odometry + * state. + * @param imoveThreshold minimum length movement (smaller movements will be skipped) + * @param iturnThreshold minimum angle turn (smaller turns will be skipped) + * @param ilogger The logger this instance will log to. + */ + DefaultOdomChassisController(const TimeUtil &itimeUtil, + std::shared_ptr iodometry, + std::shared_ptr icontroller, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION, + QLength imoveThreshold = 0_mm, + QAngle iturnThreshold = 0_deg, + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + DefaultOdomChassisController(const DefaultOdomChassisController &) = delete; + DefaultOdomChassisController(DefaultOdomChassisController &&other) = delete; + DefaultOdomChassisController &operator=(const DefaultOdomChassisController &other) = delete; + DefaultOdomChassisController &operator=(DefaultOdomChassisController &&other) = delete; + + /** + * Drives the robot straight to a point in the odom frame. + * + * @param ipoint The target point to navigate to. + * @param ibackwards Whether to drive to the target point backwards. + * @param ioffset An offset from the target point in the direction pointing towards the robot. The + * robot will stop this far away from the target point. + */ + void driveToPoint(const Point &ipoint, + bool ibackwards = false, + const QLength &ioffset = 0_mm) override; + + /** + * Turns the robot to face a point in the odom frame. + * + * @param ipoint The target point to turn to face. + */ + void turnToPoint(const Point &ipoint) override; + + /** + * @return The internal ChassisController. + */ + std::shared_ptr getChassisController(); + + /** + * @return The internal ChassisController. + */ + ChassisController &chassisController(); + + /** + * This delegates to the input ChassisController. + */ + void turnToAngle(const QAngle &iangle) override; + + /** + * This delegates to the input ChassisController. + */ + void moveDistance(QLength itarget) override; + + /** + * This delegates to the input ChassisController. + */ + void moveRaw(double itarget) override; + + /** + * This delegates to the input ChassisController. + */ + void moveDistanceAsync(QLength itarget) override; + + /** + * This delegates to the input ChassisController. + */ + void moveRawAsync(double itarget) override; + + /** + * Turns chassis to desired angle (turns in the direction of smallest angle) + * (ex. If current angle is 0 and target is 270, the chassis will turn -90 degrees) + * + * @param idegTarget target angle + */ + void turnAngle(QAngle idegTarget) override; + + /** + * This delegates to the input ChassisController. + */ + void turnRaw(double idegTarget) override; + + /** + * Turns chassis to desired angle (turns in the direction of smallest angle) + * (ex. If current angle is 0 and target is 270, the chassis will turn -90 degrees) + * + * @param idegTarget target angle + */ + void turnAngleAsync(QAngle idegTarget) override; + + /** + * This delegates to the input ChassisController. + */ + void turnRawAsync(double idegTarget) override; + + /** + * This delegates to the input ChassisController. + */ + void setTurnsMirrored(bool ishouldMirror) override; + + /** + * This delegates to the input ChassisController. + */ + bool isSettled() override; + + /** + * This delegates to the input ChassisController. + */ + void waitUntilSettled() override; + + /** + * This delegates to the input ChassisController. + */ + void stop() override; + + /** + * This delegates to the input ChassisController. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * This delegates to the input ChassisController. + */ + double getMaxVelocity() const override; + + /** + * This delegates to the input ChassisController. + */ + ChassisScales getChassisScales() const override; + + /** + * This delegates to the input ChassisController. + */ + AbstractMotor::GearsetRatioPair getGearsetRatioPair() const override; + + /** + * This delegates to the input ChassisController. + */ + std::shared_ptr getModel() override; + + /** + * This delegates to the input ChassisController. + */ + ChassisModel &model() override; + + protected: + std::shared_ptr logger; + std::shared_ptr controller; + + void waitForOdomTask(); +}; +} // namespace okapi diff --git a/pros/okapi/api/chassis/controller/odomChassisController.hpp b/pros/okapi/api/chassis/controller/odomChassisController.hpp new file mode 100644 index 00000000..e2de53a7 --- /dev/null +++ b/pros/okapi/api/chassis/controller/odomChassisController.hpp @@ -0,0 +1,154 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisController.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/coreProsAPI.hpp" +#include "okapi/api/odometry/odometry.hpp" +#include "okapi/api/odometry/point.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include +#include + +namespace okapi { +class OdomChassisController : public ChassisController { + public: + /** + * Odometry based chassis controller. Starts task at the default for odometry when constructed, + * which calls `Odometry::step` every `10ms`. The default StateMode is + * `StateMode::FRAME_TRANSFORMATION`. + * + * Moves the robot around in the odom frame. Instead of telling the robot to drive forward or + * turn some amount, you instead tell it to drive to a specific point on the field or turn to + * a specific angle relative to its starting position. + * + * @param itimeUtil The TimeUtil. + * @param iodometry The Odometry instance to run in a new task. + * @param imode The new default StateMode used to interpret target points and query the Odometry + * state. + * @param imoveThreshold minimum length movement (smaller movements will be skipped) + * @param iturnThreshold minimum angle turn (smaller turns will be skipped) + */ + OdomChassisController(TimeUtil itimeUtil, + std::shared_ptr iodometry, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION, + const QLength &imoveThreshold = 0_mm, + const QAngle &iturnThreshold = 0_deg, + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + ~OdomChassisController() override; + + OdomChassisController(const OdomChassisController &) = delete; + OdomChassisController(OdomChassisController &&other) = delete; + OdomChassisController &operator=(const OdomChassisController &other) = delete; + OdomChassisController &operator=(OdomChassisController &&other) = delete; + + /** + * Drives the robot straight to a point in the odom frame. + * + * @param ipoint The target point to navigate to. + * @param ibackwards Whether to drive to the target point backwards. + * @param ioffset An offset from the target point in the direction pointing towards the robot. The + * robot will stop this far away from the target point. + */ + virtual void + driveToPoint(const Point &ipoint, bool ibackwards = false, const QLength &ioffset = 0_mm) = 0; + + /** + * Turns the robot to face a point in the odom frame. + * + * @param ipoint The target point to turn to face. + */ + virtual void turnToPoint(const Point &ipoint) = 0; + + /** + * Turns the robot to face an angle in the odom frame. + * + * @param iangle The angle to turn to. + */ + virtual void turnToAngle(const QAngle &iangle) = 0; + + /** + * @return The current state. + */ + virtual OdomState getState() const; + + /** + * Set a new state to be the current state. The default StateMode is + * `StateMode::FRAME_TRANSFORMATION`. + * + * @param istate The new state in the given format. + * @param imode The mode to treat the input state as. + */ + virtual void setState(const OdomState &istate); + + /** + * Sets a default StateMode that will be used to interpret target points and query the Odometry + * state. + * + * @param imode The new default StateMode. + */ + void setDefaultStateMode(const StateMode &imode); + + /** + * Set a new move threshold. Any requested movements smaller than this threshold will be skipped. + * + * @param imoveThreshold new move threshold + */ + virtual void setMoveThreshold(const QLength &imoveThreshold); + + /** + * Set a new turn threshold. Any requested turns smaller than this threshold will be skipped. + * + * @param iturnTreshold new turn threshold + */ + virtual void setTurnThreshold(const QAngle &iturnTreshold); + + /** + * @return The current move threshold. + */ + virtual QLength getMoveThreshold() const; + + /** + * @return The current turn threshold. + */ + virtual QAngle getTurnThreshold() const; + + /** + * Starts the internal odometry thread. This should not be called by normal users. + */ + void startOdomThread(); + + /** + * @return The underlying thread handle. + */ + CrossplatformThread *getOdomThread() const; + + /** + * @return The internal odometry. + */ + std::shared_ptr getOdometry(); + + protected: + std::shared_ptr logger; + TimeUtil timeUtil; + QLength moveThreshold; + QAngle turnThreshold; + std::shared_ptr odom; + CrossplatformThread *odomTask{nullptr}; + std::atomic_bool dtorCalled{false}; + StateMode defaultStateMode{StateMode::FRAME_TRANSFORMATION}; + std::atomic_bool odomTaskRunning{false}; + + static void trampoline(void *context); + void loop(); +}; +} // namespace okapi diff --git a/pros/okapi/api/chassis/model/chassisModel.hpp b/pros/okapi/api/chassis/model/chassisModel.hpp new file mode 100644 index 00000000..19687598 --- /dev/null +++ b/pros/okapi/api/chassis/model/chassisModel.hpp @@ -0,0 +1,165 @@ +/* + * 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 + +#include "okapi/api/chassis/model/readOnlyChassisModel.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include +#include +#include +#include + +namespace okapi { +/** + * A version of the ReadOnlyChassisModel that also supports write methods, such as setting motor + * speed. Because this class can write to motors, there can only be one owner and as such copying + * is disabled. + */ +class ChassisModel : public ReadOnlyChassisModel { + public: + explicit ChassisModel() = default; + ChassisModel(const ChassisModel &) = delete; + ChassisModel &operator=(const ChassisModel &) = delete; + + /** + * Drive the robot forwards (using open-loop control). Uses velocity mode. + * + * @param ipower motor power + */ + virtual void forward(double ispeed) = 0; + + /** + * Drive the robot in an arc (using open-loop control). Uses velocity mode. + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwadSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + virtual void driveVector(double iforwardSpeed, double iyaw) = 0; + + /** + * Drive the robot in an arc. Uses voltage mode. + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwadSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + virtual void driveVectorVoltage(double iforwardSpeed, double iyaw) = 0; + + /** + * Turn the robot clockwise (using open-loop control). Uses velocity mode. + * + * @param ispeed motor power + */ + virtual void rotate(double ispeed) = 0; + + /** + * Stop the robot (set all the motors to 0). Uses velocity mode. + */ + virtual void stop() = 0; + + /** + * Drive the robot with a tank drive layout. Uses voltage mode. + * + * @param ileftSpeed left side speed + * @param irightSpeed right side speed + * @param ithreshold deadband on joystick values + */ + virtual void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) = 0; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. + * + * @param iforwardSpeed speed forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + virtual void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) = 0; + + /** + * Drive the robot with a curvature drive layout. The robot drives in constant radius turns + * where you control the curvature (inverse of radius) you drive in. This is advantageous + * because the forward speed will not affect the rate of turning. The algorithm switches to + * arcade if the forward speed is 0. Uses voltage mode. + * + * @param iforwardSpeed speed in the forward direction + * @param icurvature curvature (inverse of radius) to drive in + * @param ithreshold deadband on joystick values + */ + virtual void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) = 0; + + /** + * Power the left side motors. Uses velocity mode. + * + * @param ipower motor power + */ + virtual void left(double ispeed) = 0; + + /** + * Power the right side motors. Uses velocity mode. + * + * @param ipower motor power + */ + virtual void right(double ispeed) = 0; + + /** + * Reset the sensors to their zero point. + */ + virtual void resetSensors() = 0; + + /** + * Set the brake mode for each motor. + * + * @param mode new brake mode + */ + virtual void setBrakeMode(AbstractMotor::brakeMode mode) = 0; + + /** + * Set the encoder units for each motor. + * + * @param units new motor encoder units + */ + virtual void setEncoderUnits(AbstractMotor::encoderUnits units) = 0; + + /** + * Set the gearset for each motor. + * + * @param gearset new motor gearset + */ + virtual void setGearing(AbstractMotor::gearset gearset) = 0; + + /** + * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the + * currently installed gearset. If the configured maximum velocity is greater than the attainable + * maximum velocity from the currently installed gearset, the ChassisModel will still scale to + * that velocity. + * + * @param imaxVelocity The new maximum velocity. + */ + virtual void setMaxVelocity(double imaxVelocity) = 0; + + /** + * @return The current maximum velocity. + */ + virtual double getMaxVelocity() const = 0; + + /** + * Sets a new maximum voltage in mV in the range `[0-12000]`. + * + * @param imaxVoltage The new maximum voltage. + */ + virtual void setMaxVoltage(double imaxVoltage) = 0; + + /** + * @return The maximum voltage in mV `[0-12000]`. + */ + virtual double getMaxVoltage() const = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/chassis/model/hDriveModel.hpp b/pros/okapi/api/chassis/model/hDriveModel.hpp new file mode 100644 index 00000000..5afb95fc --- /dev/null +++ b/pros/okapi/api/chassis/model/hDriveModel.hpp @@ -0,0 +1,247 @@ +/* + * 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 + +#include "okapi/api/chassis/model/chassisModel.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +class HDriveModel : public ChassisModel { + public: + /** + * Model for an h-drive (wheels parallel with robot's direction of motion, with an additional + * wheel perpendicular to those). When the left and right side motors are powered +100%, the robot + * should move forward in a straight line. When the middle motor is powered +100%, the robot + * should strafe right in a straight line. + * + * @param ileftSideMotor The left side motor. + * @param irightSideMotor The right side motor. + * @param imiddleMotor The middle (perpendicular) motor. + * @param ileftEnc The left side encoder. + * @param irightEnc The right side encoder. + * @param imiddleEnc The middle encoder. + */ + HDriveModel(std::shared_ptr ileftSideMotor, + std::shared_ptr irightSideMotor, + std::shared_ptr imiddleMotor, + std::shared_ptr ileftEnc, + std::shared_ptr irightEnc, + std::shared_ptr imiddleEnc, + double imaxVelocity, + double imaxVoltage); + + /** + * Drive the robot forwards (using open-loop control). Uses velocity mode. Sets the middle motor + * to zero velocity. + * + * @param ispeed motor power + */ + void forward(double ispeed) override; + + /** + * Drive the robot in an arc (using open-loop control). Uses velocity mode. Sets the middle motor + * to zero velocity. + * + * The algorithm is (approximately): + * leftPower = ySpeed + zRotation + * rightPower = ySpeed - zRotation + * + * @param iySpeed speed on y axis (forward) + * @param izRotation speed around z axis (up) + */ + void driveVector(double iySpeed, double izRotation) override; + + /** + * Drive the robot in an arc. Uses voltage mode. Sets the middle motor to zero velocity. + * + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwadSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + void driveVectorVoltage(double iforwardSpeed, double iyaw) override; + + /** + * Turn the robot clockwise (using open-loop control). Uses velocity mode. Sets the middle motor + * to zero velocity. + * + * @param ispeed motor power + */ + void rotate(double ispeed) override; + + /** + * Stop the robot (set all the motors to 0). Uses velocity mode. + */ + void stop() override; + + /** + * Drive the robot with a tank drive layout. Uses voltage mode. Sets the middle motor to zero + * velocity. + * + * @param ileftSpeed left side speed + * @param irightSpeed right side speed + * @param ithreshold deadband on joystick values + */ + void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) override; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. Sets the middle motor to zero + * velocity. + * + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) override; + + /** + * Drive the robot with a curvature drive layout. The robot drives in constant radius turns + * where you control the curvature (inverse of radius) you drive in. This is advantageous + * because the forward speed will not affect the rate of turning. The algorithm switches to + * arcade if the forward speed is 0. Uses voltage mode. Sets the middle motor to zero velocity. + * + * @param iforwardSpeed speed in the forward direction + * @param icurvature curvature (inverse of radius) to drive in + * @param ithreshold deadband on joystick values + */ + void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) override; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. + * + * @param irightSpeed speed to the right + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + virtual void + hArcade(double irightSpeed, double iforwardSpeed, double iyaw, double ithreshold = 0); + + /** + * Drive the robot with an curvature drive layout. Uses voltage mode. + * + * @param irightSpeed speed to the right + * @param iforwardSpeed speed in the forward direction + * @param icurvature curvature (inverse of radius) to drive in + * @param ithreshold deadband on joystick values + */ + virtual void + hCurvature(double irightSpeed, double iforwardSpeed, double icurvature, double ithreshold = 0); + + /** + * Power the left side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void left(double ispeed) override; + + /** + * Power the right side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void right(double ispeed) override; + + /** + * Power the middle motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + virtual void middle(double ispeed); + + /** + * Read the sensors. + * + * @return sensor readings in the format {left, right, middle} + */ + std::valarray getSensorVals() const override; + + /** + * Reset the sensors to their zero point. + */ + void resetSensors() override; + + /** + * Set the brake mode for each motor. + * + * @param mode new brake mode + */ + void setBrakeMode(AbstractMotor::brakeMode mode) override; + + /** + * Set the encoder units for each motor. + * + * @param units new motor encoder units + */ + void setEncoderUnits(AbstractMotor::encoderUnits units) override; + + /** + * Set the gearset for each motor. + * + * @param gearset new motor gearset + */ + void setGearing(AbstractMotor::gearset gearset) override; + + /** + * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the + * currently installed gearset. If the configured maximum velocity is greater than the attainable + * maximum velocity from the currently installed gearset, the ChassisModel will still scale to + * that velocity. + * + * @param imaxVelocity The new maximum velocity. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * @return The current maximum velocity. + */ + double getMaxVelocity() const override; + + /** + * Sets a new maximum voltage in mV in the range `[0-12000]`. + * + * @param imaxVoltage The new maximum voltage. + */ + void setMaxVoltage(double imaxVoltage) override; + + /** + * @return The maximum voltage in mV in the range `[0-12000]`. + */ + double getMaxVoltage() const override; + + /** + * Returns the left side motor. + * + * @return the left side motor + */ + std::shared_ptr getLeftSideMotor() const; + + /** + * Returns the left side motor. + * + * @return the left side motor + */ + std::shared_ptr getRightSideMotor() const; + + /** + * @return The middle motor. + */ + std::shared_ptr getMiddleMotor() const; + + protected: + double maxVelocity; + double maxVoltage; + std::shared_ptr leftSideMotor; + std::shared_ptr rightSideMotor; + std::shared_ptr middleMotor; + std::shared_ptr leftSensor; + std::shared_ptr rightSensor; + std::shared_ptr middleSensor; +}; +} // namespace okapi diff --git a/pros/okapi/api/chassis/model/readOnlyChassisModel.hpp b/pros/okapi/api/chassis/model/readOnlyChassisModel.hpp new file mode 100644 index 00000000..01526f16 --- /dev/null +++ b/pros/okapi/api/chassis/model/readOnlyChassisModel.hpp @@ -0,0 +1,28 @@ +/* + * 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 + +#include "okapi/api/coreProsAPI.hpp" +#include + +namespace okapi { +/** + * A version of the ChassisModel that only supports read methods, such as querying sensor values. + * This class does not let you write to motors, so it supports having multiple owners and as a + * result copying is enabled. + */ +class ReadOnlyChassisModel { + public: + virtual ~ReadOnlyChassisModel() = default; + + /** + * Read the sensors. + * + * @return sensor readings (format is implementation dependent) + */ + virtual std::valarray getSensorVals() const = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/chassis/model/skidSteerModel.hpp b/pros/okapi/api/chassis/model/skidSteerModel.hpp new file mode 100644 index 00000000..7994c14e --- /dev/null +++ b/pros/okapi/api/chassis/model/skidSteerModel.hpp @@ -0,0 +1,198 @@ +/* + * 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 + +#include "okapi/api/chassis/model/chassisModel.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +class SkidSteerModel : public ChassisModel { + public: + /** + * Model for a skid steer drive (wheels parallel with robot's direction of motion). When all + * motors are powered +100%, the robot should move forward in a straight line. + * + * @param ileftSideMotor The left side motor. + * @param irightSideMotor The right side motor. + * @param ileftEnc The left side encoder. + * @param irightEnc The right side encoder. + */ + SkidSteerModel(std::shared_ptr ileftSideMotor, + std::shared_ptr irightSideMotor, + std::shared_ptr ileftEnc, + std::shared_ptr irightEnc, + double imaxVelocity, + double imaxVoltage); + + /** + * Drive the robot forwards (using open-loop control). Uses velocity mode. + * + * @param ispeed motor power + */ + void forward(double ispeed) override; + + /** + * Drive the robot in an arc (using open-loop control). Uses velocity mode. + * The algorithm is (approximately): + * leftPower = ySpeed + zRotation + * rightPower = ySpeed - zRotation + * + * @param iySpeed speed on y axis (forward) + * @param izRotation speed around z axis (up) + */ + void driveVector(double iySpeed, double izRotation) override; + + /** + * Drive the robot in an arc. Uses voltage mode. + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwadSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + void driveVectorVoltage(double iforwardSpeed, double iyaw) override; + + /** + * Turn the robot clockwise (using open-loop control). Uses velocity mode. + * + * @param ispeed motor power + */ + void rotate(double ispeed) override; + + /** + * Stop the robot (set all the motors to 0). Uses velocity mode. + */ + void stop() override; + + /** + * Drive the robot with a tank drive layout. Uses voltage mode. + * + * @param ileftSpeed left side speed + * @param irightSpeed right side speed + * @param ithreshold deadband on joystick values + */ + void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) override; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. + * + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) override; + + /** + * Drive the robot with a curvature drive layout. The robot drives in constant radius turns + * where you control the curvature (inverse of radius) you drive in. This is advantageous + * because the forward speed will not affect the rate of turning. The algorithm switches to + * arcade if the forward speed is 0. Uses voltage mode. + * + * @param iforwardSpeed speed in the forward direction + * @param icurvature curvature (inverse of radius) to drive in + * @param ithreshold deadband on joystick values + */ + void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) override; + + /** + * Power the left side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void left(double ispeed) override; + + /** + * Power the right side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void right(double ispeed) override; + + /** + * Read the sensors. + * + * @return sensor readings in the format {left, right} + */ + std::valarray getSensorVals() const override; + + /** + * Reset the sensors to their zero point. + */ + void resetSensors() override; + + /** + * Set the brake mode for each motor. + * + * @param mode new brake mode + */ + void setBrakeMode(AbstractMotor::brakeMode mode) override; + + /** + * Set the encoder units for each motor. + * + * @param units new motor encoder units + */ + void setEncoderUnits(AbstractMotor::encoderUnits units) override; + + /** + * Set the gearset for each motor. + * + * @param gearset new motor gearset + */ + void setGearing(AbstractMotor::gearset gearset) override; + + /** + * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the + * currently installed gearset. If the configured maximum velocity is greater than the attainable + * maximum velocity from the currently installed gearset, the ChassisModel will still scale to + * that velocity. + * + * @param imaxVelocity The new maximum velocity. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * @return The current maximum velocity. + */ + double getMaxVelocity() const override; + + /** + * Sets a new maximum voltage in mV in the range `[0-12000]`. + * + * @param imaxVoltage The new maximum voltage. + */ + void setMaxVoltage(double imaxVoltage) override; + + /** + * @return The maximum voltage in mV in the range `[0-12000]`. + */ + double getMaxVoltage() const override; + + /** + * Returns the left side motor. + * + * @return the left side motor + */ + std::shared_ptr getLeftSideMotor() const; + + /** + * Returns the left side motor. + * + * @return the left side motor + */ + std::shared_ptr getRightSideMotor() const; + + protected: + double maxVelocity; + double maxVoltage; + std::shared_ptr leftSideMotor; + std::shared_ptr rightSideMotor; + std::shared_ptr leftSensor; + std::shared_ptr rightSensor; +}; +} // namespace okapi diff --git a/pros/okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp b/pros/okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp new file mode 100644 index 00000000..2acbe3c9 --- /dev/null +++ b/pros/okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp @@ -0,0 +1,46 @@ +/* + * 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 + +#include "okapi/api/chassis/model/skidSteerModel.hpp" + +namespace okapi { +class ThreeEncoderSkidSteerModel : public SkidSteerModel { + public: + /** + * Model for a skid steer drive (wheels parallel with robot's direction of motion). When all + * motors are powered +127, the robot should move forward in a straight line. + * + * @param ileftSideMotor left side motor + * @param irightSideMotor right side motor + * @param ileftEnc left side encoder + * @param imiddleEnc middle encoder (mounted perpendicular to the left and right side encoders) + * @param irightEnc right side encoder + */ + ThreeEncoderSkidSteerModel(std::shared_ptr ileftSideMotor, + std::shared_ptr irightSideMotor, + std::shared_ptr ileftEnc, + std::shared_ptr irightEnc, + std::shared_ptr imiddleEnc, + double imaxVelocity, + double imaxVoltage); + + /** + * Read the sensors. + * + * @return sensor readings in the format {left, right, middle} + */ + std::valarray getSensorVals() const override; + + /** + * Reset the sensors to their zero point. + */ + void resetSensors() override; + + protected: + std::shared_ptr middleSensor; +}; +} // namespace okapi diff --git a/pros/okapi/api/chassis/model/threeEncoderXDriveModel.hpp b/pros/okapi/api/chassis/model/threeEncoderXDriveModel.hpp new file mode 100644 index 00000000..14e4ee04 --- /dev/null +++ b/pros/okapi/api/chassis/model/threeEncoderXDriveModel.hpp @@ -0,0 +1,50 @@ +/* + * 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 + +#include "okapi/api/chassis/model/xDriveModel.hpp" + +namespace okapi { +class ThreeEncoderXDriveModel : public XDriveModel { + public: + /** + * Model for an x drive (wheels at 45 deg from a skid steer drive). When all motors are powered + * +100%, the robot should move forward in a straight line. + * + * @param itopLeftMotor The top left motor. + * @param itopRightMotor The top right motor. + * @param ibottomRightMotor The bottom right motor. + * @param ibottomLeftMotor The bottom left motor. + * @param ileftEnc The left side encoder. + * @param irightEnc The right side encoder. + * @param imiddleEnc The middle encoder. + */ + ThreeEncoderXDriveModel(std::shared_ptr itopLeftMotor, + std::shared_ptr itopRightMotor, + std::shared_ptr ibottomRightMotor, + std::shared_ptr ibottomLeftMotor, + std::shared_ptr ileftEnc, + std::shared_ptr irightEnc, + std::shared_ptr imiddleEnc, + double imaxVelocity, + double imaxVoltage); + + /** + * Read the sensors. + * + * @return sensor readings in the format {left, right, middle} + */ + std::valarray getSensorVals() const override; + + /** + * Reset the sensors to their zero point. + */ + void resetSensors() override; + + protected: + std::shared_ptr middleSensor; +}; +} // namespace okapi diff --git a/pros/okapi/api/chassis/model/xDriveModel.hpp b/pros/okapi/api/chassis/model/xDriveModel.hpp new file mode 100644 index 00000000..07781be8 --- /dev/null +++ b/pros/okapi/api/chassis/model/xDriveModel.hpp @@ -0,0 +1,273 @@ +/* + * 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 + +#include "okapi/api/chassis/model/chassisModel.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" +#include "okapi/api/units/QAngle.hpp" + +namespace okapi { +class XDriveModel : public ChassisModel { + public: + /** + * Model for an x drive (wheels at 45 deg from a skid steer drive). When all motors are powered + * +100%, the robot should move forward in a straight line. + * + * @param itopLeftMotor The top left motor. + * @param itopRightMotor The top right motor. + * @param ibottomRightMotor The bottom right motor. + * @param ibottomLeftMotor The bottom left motor. + * @param ileftEnc The left side encoder. + * @param irightEnc The right side encoder. + */ + XDriveModel(std::shared_ptr itopLeftMotor, + std::shared_ptr itopRightMotor, + std::shared_ptr ibottomRightMotor, + std::shared_ptr ibottomLeftMotor, + std::shared_ptr ileftEnc, + std::shared_ptr irightEnc, + double imaxVelocity, + double imaxVoltage); + + /** + * Drive the robot forwards (using open-loop control). Uses velocity mode. + * + * @param ispeed motor power + */ + void forward(double ipower) override; + + /** + * Drive the robot in an arc (using open-loop control). Uses velocity mode. + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + void driveVector(double iforwardSpeed, double iyaw) override; + + /** + * Drive the robot in an arc. Uses voltage mode. + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwadSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + void driveVectorVoltage(double iforwardSpeed, double iyaw) override; + + /** + * Turn the robot clockwise (using open-loop control). Uses velocity mode. + * + * @param ipower motor power + */ + void rotate(double ipower) override; + + /** + * Drive the robot side-ways (using open-loop control) where positive ipower is + * to the right and negative ipower is to the left. Uses velocity mode. + * + * @param ispeed motor power + */ + void strafe(double ipower); + + /** + * Strafe the robot in an arc (using open-loop control) where positive istrafeSpeed is + * to the right and negative istrafeSpeed is to the left. Uses velocity mode. + * The algorithm is (approximately): + * topLeftPower = -1 * istrafeSpeed + yaw + * topRightPower = istrafeSpeed - yaw + * bottomRightPower = -1 * istrafeSpeed - yaw + * bottomLeftPower = istrafeSpeed + yaw + * + * @param istrafeSpeed speed to the right + * @param iyaw speed around the vertical axis + */ + void strafeVector(double istrafeSpeed, double iyaw); + + /** + * Stop the robot (set all the motors to 0). Uses velocity mode. + */ + void stop() override; + + /** + * Drive the robot with a tank drive layout. Uses voltage mode. + * + * @param ileftSpeed left side speed + * @param irightSpeed right side speed + * @param ithreshold deadband on joystick values + */ + void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) override; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. + * + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) override; + + /** + * Drive the robot with a curvature drive layout. The robot drives in constant radius turns + * where you control the curvature (inverse of radius) you drive in. This is advantageous + * because the forward speed will not affect the rate of turning. The algorithm switches to + * arcade if the forward speed is 0. Uses voltage mode. + * + * @param iforwardSpeed speed forward direction + * @param icurvature curvature (inverse of radius) to drive in + * @param ithreshold deadband on joystick values + */ + void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) override; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. + * + * @param irightSpeed speed to the right + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + virtual void + xArcade(double irightSpeed, double iforwardSpeed, double iyaw, double ithreshold = 0); + + /** + * Drive the robot with a field-oriented arcade drive layout. Uses voltage mode. + * For example: + * Both `fieldOrientedXArcade(1, 0, 0, 0_deg)` and `fieldOrientedXArcade(1, 0, 0, 90_deg)` + * will drive the chassis in the forward/north direction. In other words, no matter + * the robot's heading, the robot will move forward/north when you tell it + * to move forward/north and will move right/east when you tell it to move right/east. + * + * + * @param ixSpeed forward speed -- (`+1`) forward, (`-1`) backward + * @param iySpeed sideways speed -- (`+1`) right, (`-1`) left + * @param iyaw turn speed -- (`+1`) clockwise, (`-1`) counter-clockwise + * @param iangle current chassis angle (`0_deg` = no correction, winds clockwise) + * @param ithreshold deadband on joystick values + */ + virtual void fieldOrientedXArcade(double ixSpeed, + double iySpeed, + double iyaw, + QAngle iangle, + double ithreshold = 0); + + /** + * Power the left side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void left(double ispeed) override; + + /** + * Power the right side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void right(double ispeed) override; + + /** + * Read the sensors. + * + * @return sensor readings in the format {left, right} + */ + std::valarray getSensorVals() const override; + + /** + * Reset the sensors to their zero point. + */ + void resetSensors() override; + + /** + * Set the brake mode for each motor. + * + * @param mode new brake mode + */ + void setBrakeMode(AbstractMotor::brakeMode mode) override; + + /** + * Set the encoder units for each motor. + * + * @param units new motor encoder units + */ + void setEncoderUnits(AbstractMotor::encoderUnits units) override; + + /** + * Set the gearset for each motor. + * + * @param gearset new motor gearset + */ + void setGearing(AbstractMotor::gearset gearset) override; + + /** + * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the + * currently installed gearset. If the configured maximum velocity is greater than the attainable + * maximum velocity from the currently installed gearset, the ChassisModel will still scale to + * that velocity. + * + * @param imaxVelocity The new maximum velocity. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * @return The current maximum velocity. + */ + double getMaxVelocity() const override; + + /** + * Sets a new maximum voltage in mV in the range `[0-12000]`. + * + * @param imaxVoltage The new maximum voltage. + */ + void setMaxVoltage(double imaxVoltage) override; + + /** + * @return The maximum voltage in mV in the range `[0-12000]`. + */ + double getMaxVoltage() const override; + + /** + * Returns the top left motor. + * + * @return the top left motor + */ + std::shared_ptr getTopLeftMotor() const; + + /** + * Returns the top right motor. + * + * @return the top right motor + */ + std::shared_ptr getTopRightMotor() const; + + /** + * Returns the bottom right motor. + * + * @return the bottom right motor + */ + std::shared_ptr getBottomRightMotor() const; + + /** + * Returns the bottom left motor. + * + * @return the bottom left motor + */ + std::shared_ptr getBottomLeftMotor() const; + + protected: + double maxVelocity; + double maxVoltage; + std::shared_ptr topLeftMotor; + std::shared_ptr topRightMotor; + std::shared_ptr bottomRightMotor; + std::shared_ptr bottomLeftMotor; + std::shared_ptr leftSensor; + std::shared_ptr rightSensor; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/async/asyncController.hpp b/pros/okapi/api/control/async/asyncController.hpp new file mode 100644 index 00000000..e0da0da0 --- /dev/null +++ b/pros/okapi/api/control/async/asyncController.hpp @@ -0,0 +1,24 @@ +/* + * 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 + +#include "okapi/api/control/closedLoopController.hpp" + +namespace okapi { +/** + * Closed-loop controller that steps on its own in another thread and automatically writes to the + * output. + */ +template +class AsyncController : public ClosedLoopController { + public: + /** + * Blocks the current task until the controller has settled. Determining what settling means is + * implementation-dependent. + */ + virtual void waitUntilSettled() = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/async/asyncLinearMotionProfileController.hpp b/pros/okapi/api/control/async/asyncLinearMotionProfileController.hpp new file mode 100644 index 00000000..8efcc74f --- /dev/null +++ b/pros/okapi/api/control/async/asyncLinearMotionProfileController.hpp @@ -0,0 +1,291 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncPositionController.hpp" +#include "okapi/api/control/util/pathfinderUtil.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/units/QAngularSpeed.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include + +#include "squiggles.hpp" + +namespace okapi { +class AsyncLinearMotionProfileController : public AsyncPositionController { + public: + /** + * An Async Controller which generates and follows 1D motion profiles. + * + * @param itimeUtil The TimeUtil. + * @param ilimits The default limits. + * @param ioutput The output to write velocity targets to. + * @param idiameter The effective diameter for whatever the motor spins. + * @param ipair The gearset. + * @param ilogger The logger this instance will log to. + */ + AsyncLinearMotionProfileController( + const TimeUtil &itimeUtil, + const PathfinderLimits &ilimits, + const std::shared_ptr> &ioutput, + const QLength &idiameter, + const AbstractMotor::GearsetRatioPair &ipair, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + AsyncLinearMotionProfileController(AsyncLinearMotionProfileController &&other) = delete; + + AsyncLinearMotionProfileController & + operator=(AsyncLinearMotionProfileController &&other) = delete; + + ~AsyncLinearMotionProfileController() override; + + /** + * Generates a path which intersects the given waypoints and saves it internally with a key of + * pathId. Call `executePath()` with the same `pathId` to run it. + * + * If the waypoints form a path which is impossible to achieve, an instance of + * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there + * are no waypoints, no path is generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ipathId A unique identifier to save the path with. + */ + void generatePath(std::initializer_list iwaypoints, const std::string &ipathId); + + /** + * Generates a path which intersects the given waypoints and saves it internally with a key of + * pathId. Call `executePath()` with the same pathId to run it. + * + * If the waypoints form a path which is impossible to achieve, an instance of + * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there + * are no waypoints, no path is generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ipathId A unique identifier to save the path with. + * @param ilimits The limits to use for this path only. + */ + void generatePath(std::initializer_list iwaypoints, + const std::string &ipathId, + const PathfinderLimits &ilimits); + + /** + * Removes a path and frees the memory it used. This function returns `true` if the path was + * either deleted or didn't exist in the first place. It returns `false` if the path could not be + * removed because it is running. + * + * @param ipathId A unique identifier for the path, previously passed to generatePath() + * @return `true` if the path no longer exists + */ + bool removePath(const std::string &ipathId); + + /** + * Gets the identifiers of all paths saved in this `AsyncMotionProfileController`. + * + * @return The identifiers of all paths + */ + std::vector getPaths(); + + /** + * Executes a path with the given ID. If there is no path matching the ID, the method will + * return. Any targets set while a path is being followed will be ignored. + * + * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. + */ + void setTarget(std::string ipathId) override; + + /** + * Executes a path with the given ID. If there is no path matching the ID, the method will + * return. Any targets set while a path is being followed will be ignored. + * + * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. + * @param ibackwards Whether to follow the profile backwards. + */ + void setTarget(std::string ipathId, bool ibackwards); + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. + * + * This just calls `setTarget()`. + */ + void controllerSet(std::string ivalue) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + std::string getTarget() override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + virtual std::string getTarget() const; + + /** + * This is overridden to return the current path. + * + * @return The most recent value of the process variable. + */ + std::string getProcessValue() const override; + + /** + * Blocks the current task until the controller has settled. This controller is settled when + * it has finished following a path. If no path is being followed, it is settled. + */ + void waitUntilSettled() override; + + /** + * Generates a new path from the position (typically the current position) to the target and + * blocks until the controller has settled. Does not save the path which was generated. + * + * @param iposition The starting position. + * @param itarget The target position. + * @param ibackwards Whether to follow the profile backwards. + */ + void moveTo(const QLength &iposition, const QLength &itarget, bool ibackwards = false); + + /** + * Generates a new path from the position (typically the current position) to the target and + * blocks until the controller has settled. Does not save the path which was generated. + * + * @param iposition The starting position. + * @param itarget The target position. + * @param ilimits The limits to use for this path only. + * @param ibackwards Whether to follow the profile backwards. + */ + void moveTo(const QLength &iposition, + const QLength &itarget, + const PathfinderLimits &ilimits, + bool ibackwards = false); + + /** + * Returns the last error of the controller. Does not update when disabled. Returns zero if there + * is no path currently being followed. + * + * @return the last error + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return `true`. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. This implementation also stops movement. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * NOT cause the controller to move to its last set target. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * NOT cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * This implementation does nothing because the API always requires the starting position to be + * specified. + */ + void tarePosition() override; + + /** + * This implementation does nothing because the maximum velocity is configured using + * PathfinderLimits elsewhere. + * + * @param imaxVelocity Ignored. + */ + void setMaxVelocity(std::int32_t imaxVelocity) override; + + /** + * Starts the internal thread. This should not be called by normal users. This method is called + * by the AsyncControllerFactory when making a new instance of this class. + */ + void startThread(); + + /** + * Returns the underlying thread handle. + * + * @return The underlying thread handle. + */ + CrossplatformThread *getThread() const; + + /** + * Attempts to remove a path without stopping execution, then if that fails, disables the + * controller and removes the path. + * + * @param ipathId The path ID that will be removed + */ + void forceRemovePath(const std::string &ipathId); + + protected: + std::shared_ptr logger; + std::map> paths{}; + PathfinderLimits limits; + std::shared_ptr> output; + QLength diameter; + AbstractMotor::GearsetRatioPair pair; + double currentProfilePosition{0}; + TimeUtil timeUtil; + + // This must be locked when accessing the current path + CrossplatformMutex currentPathMutex; + + std::string currentPath{""}; + std::atomic_bool isRunning{false}; + std::atomic_int direction{1}; + std::atomic_bool disabled{false}; + std::atomic_bool dtorCalled{false}; + CrossplatformThread *task{nullptr}; + + static void trampoline(void *context); + void loop(); + + /** + * Follow the supplied path. Must follow the disabled lifecycle. + */ + virtual void executeSinglePath(const std::vector &path, + std::unique_ptr rate); + + /** + * Converts linear "chassis" speed to rotational motor speed. + * + * @param linear "chassis" frame speed + * @return motor frame speed + */ + QAngularSpeed convertLinearToRotational(QSpeed linear) const; + + std::string getPathErrorMessage(const std::vector &points, + const std::string &ipathId, + int length); +}; +} // namespace okapi diff --git a/pros/okapi/api/control/async/asyncMotionProfileController.hpp b/pros/okapi/api/control/async/asyncMotionProfileController.hpp new file mode 100644 index 00000000..3c8b74a4 --- /dev/null +++ b/pros/okapi/api/control/async/asyncMotionProfileController.hpp @@ -0,0 +1,326 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisScales.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/control/async/asyncPositionController.hpp" +#include "okapi/api/control/util/pathfinderUtil.hpp" +#include "okapi/api/units/QAngularSpeed.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include +#include + +#include "squiggles.hpp" + +namespace okapi { +class AsyncMotionProfileController : public AsyncPositionController { + public: + /** + * An Async Controller which generates and follows 2D motion profiles. Throws a + * `std::invalid_argument` exception if the gear ratio is zero. + * + * @param itimeUtil The TimeUtil. + * @param ilimits The default limits. + * @param imodel The chassis model to control. + * @param iscales The chassis dimensions. + * @param ipair The gearset. + * @param ilogger The logger this instance will log to. + */ + AsyncMotionProfileController(const TimeUtil &itimeUtil, + const PathfinderLimits &ilimits, + const std::shared_ptr &imodel, + const ChassisScales &iscales, + const AbstractMotor::GearsetRatioPair &ipair, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + AsyncMotionProfileController(AsyncMotionProfileController &&other) = delete; + + AsyncMotionProfileController &operator=(AsyncMotionProfileController &&other) = delete; + + ~AsyncMotionProfileController() override; + + /** + * Generates a path which intersects the given waypoints and saves it internally with a key of + * pathId. Call `executePath()` with the same pathId to run it. + * + * If the waypoints form a path which is impossible to achieve, an instance of + * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there + * are no waypoints, no path is generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ipathId A unique identifier to save the path with. + */ + void generatePath(std::initializer_list iwaypoints, const std::string &ipathId); + + /** + * Generates a path which intersects the given waypoints and saves it internally with a key of + * pathId. Call `executePath()` with the same pathId to run it. + * + * If the waypoints form a path which is impossible to achieve, an instance of + * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there + * are no waypoints, no path is generated. + * + * NOTE: The waypoints are expected to be in the + * okapi::State::FRAME_TRANSFORMATION format where +x is forward, +y is right, + * and 0 theta is measured from the +x axis to the +y axis. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ipathId A unique identifier to save the path with. + * @param ilimits The limits to use for this path only. + */ + void generatePath(std::initializer_list iwaypoints, + const std::string &ipathId, + const PathfinderLimits &ilimits); + + /** + * Removes a path and frees the memory it used. This function returns true if the path was either + * deleted or didn't exist in the first place. It returns false if the path could not be removed + * because it is running. + * + * @param ipathId A unique identifier for the path, previously passed to `generatePath()` + * @return True if the path no longer exists + */ + bool removePath(const std::string &ipathId); + + /** + * Gets the identifiers of all paths saved in this `AsyncMotionProfileController`. + * + * @return The identifiers of all paths + */ + std::vector getPaths(); + + /** + * Executes a path with the given ID. If there is no path matching the ID, the method will + * return. Any targets set while a path is being followed will be ignored. + * + * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. + */ + void setTarget(std::string ipathId) override; + + /** + * Executes a path with the given ID. If there is no path matching the ID, the method will + * return. Any targets set while a path is being followed will be ignored. + * + * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. + * @param ibackwards Whether to follow the profile backwards. + * @param imirrored Whether to follow the profile mirrored. + */ + void setTarget(std::string ipathId, bool ibackwards, bool imirrored = false); + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. This just calls `setTarget()`. + */ + void controllerSet(std::string ivalue) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + std::string getTarget() override; + + /** + * This is overridden to return the current path. + * + * @return The most recent value of the process variable. + */ + std::string getProcessValue() const override; + + /** + * Blocks the current task until the controller has settled. This controller is settled when + * it has finished following a path. If no path is being followed, it is settled. + */ + void waitUntilSettled() override; + + /** + * Generates a new path from the position (typically the current position) to the target and + * blocks until the controller has settled. Does not save the path which was generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ibackwards Whether to follow the profile backwards. + * @param imirrored Whether to follow the profile mirrored. + */ + void moveTo(std::initializer_list iwaypoints, + bool ibackwards = false, + bool imirrored = false); + + /** + * Generates a new path from the position (typically the current position) to the target and + * blocks until the controller has settled. Does not save the path which was generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ilimits The limits to use for this path only. + * @param ibackwards Whether to follow the profile backwards. + * @param imirrored Whether to follow the profile mirrored. + */ + void moveTo(std::initializer_list iwaypoints, + const PathfinderLimits &ilimits, + bool ibackwards = false, + bool imirrored = false); + + /** + * Returns the last error of the controller. Does not update when disabled. This implementation + * always returns zero since the robot is assumed to perfectly follow the path. Subclasses can + * override this to be more accurate using odometry information. + * + * @return the last error + */ + PathfinderPoint getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Resets the controller so it can start from 0 again properly. Keeps configuration from + * before. This implementation also stops movement. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * NOT cause the controller to move to its last set target. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * NOT cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * This implementation does nothing because the API always requires the starting position to be + * specified. + */ + void tarePosition() override; + + /** + * This implementation does nothing because the maximum velocity is configured using + * PathfinderLimits elsewhere. + * + * @param imaxVelocity Ignored. + */ + void setMaxVelocity(std::int32_t imaxVelocity) override; + + /** + * Starts the internal thread. This should not be called by normal users. This method is called + * by the `AsyncMotionProfileControllerBuilder` when making a new instance of this class. + */ + void startThread(); + + /** + * @return The underlying thread handle. + */ + CrossplatformThread *getThread() const; + + /** + * Saves a generated path to a file. Paths are stored as `.csv`. An SD card + * must be inserted into the brain and the directory must exist. `idirectory` can be prefixed with + * `/usd/`, but it this is not required. + * + * @param idirectory The directory to store the path file in + * @param ipathId The path ID of the generated path + */ + void storePath(const std::string &idirectory, const std::string &ipathId); + + /** + * Loads a path from a directory on the SD card containing a path CSV file. `/usd/` is + * automatically prepended to `idirectory` if it is not specified. + * + * @param idirectory The directory that the path files are stored in + * @param ipathId The path ID that the paths are stored under (and will be loaded into) + */ + void loadPath(const std::string &idirectory, const std::string &ipathId); + + /** + * Attempts to remove a path without stopping execution. If that fails, disables the controller + * and removes the path. + * + * @param ipathId The path ID that will be removed + */ + void forceRemovePath(const std::string &ipathId); + + protected: + std::shared_ptr logger; + std::map> paths{}; + PathfinderLimits limits; + std::shared_ptr model; + ChassisScales scales; + AbstractMotor::GearsetRatioPair pair; + TimeUtil timeUtil; + + // This must be locked when accessing the current path + CrossplatformMutex currentPathMutex; + + std::string currentPath{""}; + std::atomic_bool isRunning{false}; + std::atomic_int direction{1}; + std::atomic_bool mirrored{false}; + std::atomic_bool disabled{false}; + std::atomic_bool dtorCalled{false}; + CrossplatformThread *task{nullptr}; + + static void trampoline(void *context); + void loop(); + + /** + * Follow the supplied path. Must follow the disabled lifecycle. + */ + virtual void executeSinglePath(const std::vector &path, + std::unique_ptr rate); + + /** + * Converts linear chassis speed to rotational motor speed. + * + * @param linear chassis frame speed + * @return motor frame speed + */ + QAngularSpeed convertLinearToRotational(QSpeed linear) const; + + std::string getPathErrorMessage(const std::vector &points, + const std::string &ipathId, + int length); + + /** + * Joins and escapes a directory and file name + * + * @param directory The directory path, separated by forward slashes (/) and with or without a + * trailing slash + * @param filename The file name in the directory + * @return the fully qualified and legal path name + */ + static std::string makeFilePath(const std::string &directory, const std::string &filename); + + void internalStorePath(std::ostream &file, const std::string &ipathId); + void internalLoadPath(std::istream &file, const std::string &ipathId); + void internalLoadPathfinderPath(std::istream &leftFile, + std::istream &rightFile, + const std::string &ipathId); + + static constexpr double DT = 0.01; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/async/asyncPosIntegratedController.hpp b/pros/okapi/api/control/async/asyncPosIntegratedController.hpp new file mode 100644 index 00000000..1b479769 --- /dev/null +++ b/pros/okapi/api/control/async/asyncPosIntegratedController.hpp @@ -0,0 +1,145 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncPositionController.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" + +namespace okapi { +/** + * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are whatever + * units the motor is in. + */ +class AsyncPosIntegratedController : public AsyncPositionController { + public: + /** + * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are + * whatever units the motor is in. Throws a std::invalid_argument exception if the gear ratio is + * zero. + * + * @param imotor The motor to control. + * @param ipair The gearset. + * @param imaxVelocity The maximum velocity after gearing. + * @param itimeUtil The TimeUtil. + * @param ilogger The logger this instance will log to. + */ + AsyncPosIntegratedController(const std::shared_ptr &imotor, + const AbstractMotor::GearsetRatioPair &ipair, + std::int32_t imaxVelocity, + const TimeUtil &itimeUtil, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the target for the controller. + */ + void setTarget(double itarget) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() override; + + /** + * @return The most recent value of the process variable. + */ + double getProcessValue() const override; + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * Blocks the current task until the controller has settled. Determining what settling means is + * implementation-dependent. + */ + void waitUntilSettled() override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be [-1, 1]. + * + * @param ivalue the controller's output in the range [-1, 1] + */ + void controllerSet(double ivalue) override; + + /** + * Sets the "absolute" zero position of the controller to its current position. + */ + void tarePosition() override; + + /** + * Sets a new maximum velocity in motor RPM [0-600]. + * + * @param imaxVelocity The new maximum velocity in motor RPM [0-600]. + */ + void setMaxVelocity(std::int32_t imaxVelocity) override; + + /** + * Stops the motor mid-movement. Does not change the last set target. + */ + virtual void stop(); + + protected: + std::shared_ptr logger; + TimeUtil timeUtil; + std::shared_ptr motor; + AbstractMotor::GearsetRatioPair pair; + std::int32_t maxVelocity; + double lastTarget{0}; + double offset{0}; + bool controllerIsDisabled{false}; + bool hasFirstTarget{false}; + std::unique_ptr settledUtil; + + /** + * Resumes moving after the controller is reset. Should not cause movement if the controller is + * turned off, reset, and turned back on. + */ + virtual void resumeMovement(); +}; +} // namespace okapi diff --git a/pros/okapi/api/control/async/asyncPosPidController.hpp b/pros/okapi/api/control/async/asyncPosPidController.hpp new file mode 100644 index 00000000..0621a03e --- /dev/null +++ b/pros/okapi/api/control/async/asyncPosPidController.hpp @@ -0,0 +1,100 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncPositionController.hpp" +#include "okapi/api/control/async/asyncWrapper.hpp" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/control/iterative/iterativePosPidController.hpp" +#include "okapi/api/control/offsettableControllerInput.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include + +namespace okapi { +class AsyncPosPIDController : public AsyncWrapper, + public AsyncPositionController { + public: + /** + * An async position PID controller. + * + * @param iinput The controller input. Will be turned into an OffsettableControllerInput. + * @param ioutput The controller output. + * @param itimeUtil The TimeUtil. + * @param ikP The proportional gain. + * @param ikI The integral gain. + * @param ikD The derivative gain. + * @param ikBias The controller bias. + * @param iratio Any external gear ratio. + * @param iderivativeFilter The derivative filter. + */ + AsyncPosPIDController( + const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + const TimeUtil &itimeUtil, + double ikP, + double ikI, + double ikD, + double ikBias = 0, + double iratio = 1, + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * An async position PID controller. + * + * @param iinput The controller input. + * @param ioutput The controller output. + * @param itimeUtil The TimeUtil. + * @param ikP The proportional gain. + * @param ikI The integral gain. + * @param ikD The derivative gain. + * @param ikBias The controller bias. + * @param iratio Any external gear ratio. + * @param iderivativeFilter The derivative filter. + */ + AsyncPosPIDController( + const std::shared_ptr &iinput, + const std::shared_ptr> &ioutput, + const TimeUtil &itimeUtil, + double ikP, + double ikI, + double ikD, + double ikBias = 0, + double iratio = 1, + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the "absolute" zero position of the controller to its current position. + */ + void tarePosition() override; + + /** + * This implementation does not respect the maximum velocity. + * + * @param imaxVelocity Ignored. + */ + void setMaxVelocity(std::int32_t imaxVelocity) override; + + /** + * Set controller gains. + * + * @param igains The new gains. + */ + void setGains(const IterativePosPIDController::Gains &igains); + + /** + * Gets the current gains. + * + * @return The current gains. + */ + IterativePosPIDController::Gains getGains() const; + + protected: + std::shared_ptr offsettableInput; + std::shared_ptr internalController; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/async/asyncPositionController.hpp b/pros/okapi/api/control/async/asyncPositionController.hpp new file mode 100644 index 00000000..9ed954f7 --- /dev/null +++ b/pros/okapi/api/control/async/asyncPositionController.hpp @@ -0,0 +1,28 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncController.hpp" +#include + +namespace okapi { +template +class AsyncPositionController : virtual public AsyncController { + public: + /** + * Sets the "absolute" zero position of the controller to its current position. + */ + virtual void tarePosition() = 0; + + /** + * Sets a new maximum velocity (typically motor RPM [0-600]). The interpretation of the units + * of this velocity and whether it will be respected is implementation-dependent. + * + * @param imaxVelocity The new maximum velocity. + */ + virtual void setMaxVelocity(std::int32_t imaxVelocity) = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/async/asyncVelIntegratedController.hpp b/pros/okapi/api/control/async/asyncVelIntegratedController.hpp new file mode 100644 index 00000000..19d3ae17 --- /dev/null +++ b/pros/okapi/api/control/async/asyncVelIntegratedController.hpp @@ -0,0 +1,124 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncVelocityController.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include + +namespace okapi { +/** + * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are whatever + * units the motor is in. + */ +class AsyncVelIntegratedController : public AsyncVelocityController { + public: + /** + * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are + * whatever units the motor is in. Throws a std::invalid_argument exception if the gear ratio is + * zero. + * + * @param imotor The motor to control. + * @param ipair The gearset. + * @param imaxVelocity The maximum velocity after gearing. + * @param itimeUtil The TimeUtil. + * @param ilogger The logger this instance will log to. + */ + AsyncVelIntegratedController(const std::shared_ptr &imotor, + const AbstractMotor::GearsetRatioPair &ipair, + std::int32_t imaxVelocity, + const TimeUtil &itimeUtil, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the target for the controller. + */ + void setTarget(double itarget) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() override; + + /** + * @return The most recent value of the process variable. + */ + double getProcessValue() const override; + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * Blocks the current task until the controller has settled. Determining what settling means is + * implementation-dependent. + */ + void waitUntilSettled() override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be [-1, 1]. + * + * @param ivalue the controller's output in the range [-1, 1] + */ + void controllerSet(double ivalue) override; + + protected: + std::shared_ptr logger; + TimeUtil timeUtil; + std::shared_ptr motor; + AbstractMotor::GearsetRatioPair pair; + std::int32_t maxVelocity; + double lastTarget = 0; + bool controllerIsDisabled = false; + bool hasFirstTarget = false; + std::unique_ptr settledUtil; + + virtual void resumeMovement(); +}; +} // namespace okapi diff --git a/pros/okapi/api/control/async/asyncVelPidController.hpp b/pros/okapi/api/control/async/asyncVelPidController.hpp new file mode 100644 index 00000000..cd19d07c --- /dev/null +++ b/pros/okapi/api/control/async/asyncVelPidController.hpp @@ -0,0 +1,64 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncVelocityController.hpp" +#include "okapi/api/control/async/asyncWrapper.hpp" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/control/iterative/iterativeVelPidController.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include + +namespace okapi { +class AsyncVelPIDController : public AsyncWrapper, + public AsyncVelocityController { + public: + /** + * An async velocity PID controller. + * + * @param iinput The controller input. + * @param ioutput The controller output. + * @param itimeUtil The TimeUtil. + * @param ikP The proportional gain. + * @param ikD The derivative gain. + * @param ikF The feed-forward gain. + * @param ikSF A feed-forward gain to counteract static friction. + * @param ivelMath The VelMath used for calculating velocity. + * @param iratio Any external gear ratio. + * @param iderivativeFilter The derivative filter. + */ + AsyncVelPIDController( + const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + const TimeUtil &itimeUtil, + double ikP, + double ikD, + double ikF, + double ikSF, + std::unique_ptr ivelMath, + double iratio = 1, + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Set controller gains. + * + * @param igains The new gains. + */ + void setGains(const IterativeVelPIDController::Gains &igains); + + /** + * Gets the current gains. + * + * @return The current gains. + */ + IterativeVelPIDController::Gains getGains() const; + + protected: + std::shared_ptr internalController; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/async/asyncVelocityController.hpp b/pros/okapi/api/control/async/asyncVelocityController.hpp new file mode 100644 index 00000000..10888130 --- /dev/null +++ b/pros/okapi/api/control/async/asyncVelocityController.hpp @@ -0,0 +1,14 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncController.hpp" +#include + +namespace okapi { +template +class AsyncVelocityController : virtual public AsyncController {}; +} // namespace okapi diff --git a/pros/okapi/api/control/async/asyncWrapper.hpp b/pros/okapi/api/control/async/asyncWrapper.hpp new file mode 100644 index 00000000..d53ef452 --- /dev/null +++ b/pros/okapi/api/control/async/asyncWrapper.hpp @@ -0,0 +1,287 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncController.hpp" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/control/iterative/iterativeController.hpp" +#include "okapi/api/control/util/settledUtil.hpp" +#include "okapi/api/coreProsAPI.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/mathUtil.hpp" +#include "okapi/api/util/supplier.hpp" +#include +#include + +namespace okapi { +template +class AsyncWrapper : virtual public AsyncController { + public: + /** + * A wrapper class that transforms an `IterativeController` into an `AsyncController` by running + * it in another task. The input controller will act like an `AsyncController`. + * + * @param iinput controller input, passed to the `IterativeController` + * @param ioutput controller output, written to from the `IterativeController` + * @param icontroller the controller to use + * @param irateSupplier used for rates used in the main loop and in `waitUntilSettled` + * @param iratio Any external gear ratio. + * @param ilogger The logger this instance will log to. + */ + AsyncWrapper(const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + const std::shared_ptr> &icontroller, + const Supplier> &irateSupplier, + const double iratio = 1, + std::shared_ptr ilogger = Logger::getDefaultLogger()) + : logger(std::move(ilogger)), + rateSupplier(irateSupplier), + input(iinput), + output(ioutput), + controller(icontroller), + ratio(iratio) { + } + + AsyncWrapper(AsyncWrapper &&other) = delete; + + AsyncWrapper &operator=(AsyncWrapper &&other) = delete; + + ~AsyncWrapper() override { + dtorCalled.store(true, std::memory_order_release); + delete task; + } + + /** + * Sets the target for the controller. + */ + void setTarget(const Input itarget) override { + LOG_INFO("AsyncWrapper: Set target to " + std::to_string(itarget)); + hasFirstTarget = true; + controller->setTarget(itarget * ratio); + lastTarget = itarget; + } + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. + * + * @param ivalue the controller's output + */ + void controllerSet(const Input ivalue) override { + controller->controllerSet(ivalue); + } + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + Input getTarget() override { + return controller->getTarget(); + } + + /** + * @return The most recent value of the process variable. + */ + Input getProcessValue() const override { + return controller->getProcessValue(); + } + + /** + * Returns the last calculated output of the controller. + */ + Output getOutput() const { + return controller->getOutput(); + } + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + Output getError() const override { + return controller->getError(); + } + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override { + return isDisabled() || controller->isSettled(); + } + + /** + * Set time between loops. + * + * @param isampleTime time between loops + */ + void setSampleTime(const QTime &isampleTime) { + controller->setSampleTime(isampleTime); + } + + /** + * Set controller output bounds. + * + * @param imax max output + * @param imin min output + */ + void setOutputLimits(const Output imax, const Output imin) { + controller->setOutputLimits(imax, imin); + } + + /** + * Sets the (soft) limits for the target range that controllerSet() scales into. The target + * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. + * + * @param itargetMax The new max target for controllerSet(). + * @param itargetMin The new min target for controllerSet(). + */ + void setControllerSetTargetLimits(double itargetMax, double itargetMin) { + controller->setControllerSetTargetLimits(itargetMax, itargetMin); + } + + /** + * Get the upper output bound. + * + * @return the upper output bound + */ + Output getMaxOutput() { + return controller->getMaxOutput(); + } + + /** + * Get the lower output bound. + * + * @return the lower output bound + */ + Output getMinOutput() { + return controller->getMinOutput(); + } + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override { + LOG_INFO_S("AsyncWrapper: Reset"); + controller->reset(); + hasFirstTarget = false; + } + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override { + LOG_INFO("AsyncWrapper: flipDisable " + std::to_string(!controller->isDisabled())); + controller->flipDisable(); + resumeMovement(); + } + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(const bool iisDisabled) override { + LOG_INFO("AsyncWrapper: flipDisable " + std::to_string(iisDisabled)); + controller->flipDisable(iisDisabled); + resumeMovement(); + } + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override { + return controller->isDisabled(); + } + + /** + * Blocks the current task until the controller has settled. Determining what settling means is + * implementation-dependent. + */ + void waitUntilSettled() override { + LOG_INFO_S("AsyncWrapper: Waiting to settle"); + + auto rate = rateSupplier.get(); + while (!isSettled()) { + rate->delayUntil(motorUpdateRate); + } + + LOG_INFO_S("AsyncWrapper: Done waiting to settle"); + } + + /** + * Starts the internal thread. This should not be called by normal users. This method is called + * by the AsyncControllerFactory when making a new instance of this class. + */ + void startThread() { + if (!task) { + task = new CrossplatformThread(trampoline, this, "AsyncWrapper"); + } + } + + /** + * Returns the underlying thread handle. + * + * @return The underlying thread handle. + */ + CrossplatformThread *getThread() const { + return task; + } + + protected: + std::shared_ptr logger; + Supplier> rateSupplier; + std::shared_ptr> input; + std::shared_ptr> output; + std::shared_ptr> controller; + bool hasFirstTarget{false}; + Input lastTarget; + double ratio; + std::atomic_bool dtorCalled{false}; + CrossplatformThread *task{nullptr}; + + static void trampoline(void *context) { + if (context) { + static_cast(context)->loop(); + } + } + + void loop() { + auto rate = rateSupplier.get(); + while (!dtorCalled.load(std::memory_order_acquire) && !task->notifyTake(0)) { + if (!isDisabled()) { + output->controllerSet(controller->step(input->controllerGet())); + } + + rate->delayUntil(controller->getSampleTime()); + } + } + + /** + * Resumes moving after the controller is reset. Should not cause movement if the controller is + * turned off, reset, and turned back on. + */ + virtual void resumeMovement() { + if (isDisabled()) { + // This will grab the output *when disabled* + output->controllerSet(controller->getOutput()); + } else { + if (hasFirstTarget) { + setTarget(lastTarget); + } + } + } +}; +} // namespace okapi diff --git a/pros/okapi/api/control/closedLoopController.hpp b/pros/okapi/api/control/closedLoopController.hpp new file mode 100644 index 00000000..90ce6c5f --- /dev/null +++ b/pros/okapi/api/control/closedLoopController.hpp @@ -0,0 +1,86 @@ +/* + * 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 + +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/units/QTime.hpp" + +namespace okapi { +/** + * An abstract closed-loop controller. + * + * @tparam Input The target/input type. + * @tparam Output The error/output type. + */ +template +class ClosedLoopController : public ControllerOutput { + public: + virtual ~ClosedLoopController() = default; + + /** + * Sets the target for the controller. + * + * @param itarget the new target + */ + virtual void setTarget(Input itarget) = 0; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + virtual Input getTarget() = 0; + + /** + * @return The most recent value of the process variable. + */ + virtual Input getProcessValue() const = 0; + + /** + * Returns the last error of the controller. Does not update when disabled. + * + * @return the last error + */ + virtual Output getError() const = 0; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return `true`. + * + * @return whether the controller is settled + */ + virtual bool isSettled() = 0; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + virtual void reset() = 0; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + virtual void flipDisable() = 0; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + virtual void flipDisable(bool iisDisabled) = 0; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + virtual bool isDisabled() const = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/controllerInput.hpp b/pros/okapi/api/control/controllerInput.hpp new file mode 100644 index 00000000..399ed9e8 --- /dev/null +++ b/pros/okapi/api/control/controllerInput.hpp @@ -0,0 +1,19 @@ +/* + * 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 + +namespace okapi { +template class ControllerInput { + public: + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + virtual T controllerGet() = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/controllerOutput.hpp b/pros/okapi/api/control/controllerOutput.hpp new file mode 100644 index 00000000..f016f5e1 --- /dev/null +++ b/pros/okapi/api/control/controllerOutput.hpp @@ -0,0 +1,19 @@ +/* + * 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 + +namespace okapi { +template class ControllerOutput { + public: + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be `[-1, 1]`. + * + * @param ivalue the controller's output in the range `[-1, 1]` + */ + virtual void controllerSet(T ivalue) = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/iterative/iterativeController.hpp b/pros/okapi/api/control/iterative/iterativeController.hpp new file mode 100644 index 00000000..6bf4a077 --- /dev/null +++ b/pros/okapi/api/control/iterative/iterativeController.hpp @@ -0,0 +1,79 @@ +/* + * 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 + +#include "okapi/api/control/closedLoopController.hpp" +#include "okapi/api/units/QTime.hpp" + +namespace okapi { +/** + * Closed-loop controller that steps iteratively using the step method below. + * + * `ControllerOutput::controllerSet()` should set the controller's target to the input scaled by + * the output bounds. + */ +template +class IterativeController : public ClosedLoopController { + public: + /** + * Do one iteration of the controller. + * + * @param ireading A new measurement. + * @return The controller output. + */ + virtual Output step(Input ireading) = 0; + + /** + * Returns the last calculated output of the controller. + */ + virtual Output getOutput() const = 0; + + /** + * Set controller output bounds. + * + * @param imax max output + * @param imin min output + */ + virtual void setOutputLimits(Output imax, Output imin) = 0; + + /** + * Sets the (soft) limits for the target range that controllerSet() scales into. The target + * computed by `controllerSet()` is scaled into the range `[-itargetMin, itargetMax]`. + * + * @param itargetMax The new max target for `controllerSet()`. + * @param itargetMin The new min target for `controllerSet()`. + */ + virtual void setControllerSetTargetLimits(Output itargetMax, Output itargetMin) = 0; + + /** + * Get the upper output bound. + * + * @return the upper output bound + */ + virtual Output getMaxOutput() = 0; + + /** + * Get the lower output bound. + * + * @return the lower output bound + */ + virtual Output getMinOutput() = 0; + + /** + * Set time between loops. + * + * @param isampleTime time between loops + */ + virtual void setSampleTime(QTime isampleTime) = 0; + + /** + * Get the last set sample time. + * + * @return sample time + */ + virtual QTime getSampleTime() const = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/iterative/iterativeMotorVelocityController.hpp b/pros/okapi/api/control/iterative/iterativeMotorVelocityController.hpp new file mode 100644 index 00000000..05e83c9e --- /dev/null +++ b/pros/okapi/api/control/iterative/iterativeMotorVelocityController.hpp @@ -0,0 +1,150 @@ +/* + * 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 + +#include "okapi/api/control/iterative/iterativeVelocityController.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include +#include + +namespace okapi { +class IterativeMotorVelocityController : public IterativeVelocityController { + public: + /** + * Velocity controller that automatically writes to the motor. + */ + IterativeMotorVelocityController( + const std::shared_ptr &imotor, + const std::shared_ptr> &icontroller); + + /** + * Do one iteration of the controller. + * + * @param inewReading new measurement + * @return controller output + */ + double step(double ireading) override; + + /** + * Sets the target for the controller. + */ + void setTarget(double itarget) override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be `[-1, 1]`. + * + * @param ivalue the controller's output in the range `[-1, 1]` + */ + void controllerSet(double ivalue) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() override; + + /** + * @return The most recent value of the process variable. + */ + double getProcessValue() const override; + + /** + * Returns the last calculated output of the controller. + */ + double getOutput() const override; + + /** + * Get the upper output bound. + * + * @return the upper output bound + */ + double getMaxOutput() override; + + /** + * Get the lower output bound. + * + * @return the lower output bound + */ + double getMinOutput() override; + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Set time between loops in ms. + * + * @param isampleTime time between loops in ms + */ + void setSampleTime(QTime isampleTime) override; + + /** + * Set controller output bounds. + * + * @param imax max output + * @param imin min output + */ + void setOutputLimits(double imax, double imin) override; + + /** + * Sets the (soft) limits for the target range that controllerSet() scales into. The target + * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. + * + * @param itargetMax The new max target for controllerSet(). + * @param itargetMin The new min target for controllerSet(). + */ + void setControllerSetTargetLimits(double itargetMax, double itargetMin) override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * Get the last set sample time. + * + * @return sample time + */ + QTime getSampleTime() const override; + + protected: + std::shared_ptr motor; + std::shared_ptr> controller; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/iterative/iterativePosPidController.hpp b/pros/okapi/api/control/iterative/iterativePosPidController.hpp new file mode 100644 index 00000000..eca96fb0 --- /dev/null +++ b/pros/okapi/api/control/iterative/iterativePosPidController.hpp @@ -0,0 +1,276 @@ +/* + * Based on the Arduino PID controller: https://github.com/br3ttb/Arduino-PID-Library + * + * 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 + +#include "okapi/api/control/iterative/iterativePositionController.hpp" +#include "okapi/api/control/util/settledUtil.hpp" +#include "okapi/api/filter/filter.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include + +namespace okapi { +class IterativePosPIDController : public IterativePositionController { + public: + struct Gains { + double kP{0}; + double kI{0}; + double kD{0}; + double kBias{0}; + + bool operator==(const Gains &rhs) const; + bool operator!=(const Gains &rhs) const; + }; + + /** + * Position PID controller. + * + * @param ikP the proportional gain + * @param ikI the integration gain + * @param ikD the derivative gain + * @param ikBias the controller bias + * @param itimeUtil see TimeUtil docs + * @param iderivativeFilter a filter for filtering the derivative term + * @param ilogger The logger this instance will log to. + */ + IterativePosPIDController( + double ikP, + double ikI, + double ikD, + double ikBias, + const TimeUtil &itimeUtil, + std::unique_ptr iderivativeFilter = std::make_unique(), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + /** + * Position PID controller. + * + * @param igains the controller gains + * @param itimeUtil see TimeUtil docs + * @param iderivativeFilter a filter for filtering the derivative term + */ + IterativePosPIDController( + const Gains &igains, + const TimeUtil &itimeUtil, + std::unique_ptr iderivativeFilter = std::make_unique(), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + /** + * Do one iteration of the controller. Returns the reading in the range [-1, 1] unless the + * bounds have been changed with setOutputLimits(). + * + * @param inewReading new measurement + * @return controller output + */ + double step(double inewReading) override; + + /** + * Sets the target for the controller. + * + * @param itarget new target position + */ + void setTarget(double itarget) override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be [-1, 1]. + * + * @param ivalue the controller's output in the range [-1, 1] + */ + void controllerSet(double ivalue) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() const; + + /** + * @return The most recent value of the process variable. + */ + double getProcessValue() const override; + + /** + * Returns the last calculated output of the controller. Output is in the range [-1, 1] + * unless the bounds have been changed with setOutputLimits(). + */ + double getOutput() const override; + + /** + * Get the upper output bound. + * + * @return the upper output bound + */ + double getMaxOutput() override; + + /** + * Get the lower output bound. + * + * @return the lower output bound + */ + double getMinOutput() override; + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Set time between loops in ms. + * + * @param isampleTime time between loops + */ + void setSampleTime(QTime isampleTime) override; + + /** + * Set controller output bounds. Default bounds are [-1, 1]. + * + * @param imax max output + * @param imin min output + */ + void setOutputLimits(double imax, double imin) override; + + /** + * Sets the (soft) limits for the target range that controllerSet() scales into. The target + * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. + * + * @param itargetMax The new max target for controllerSet(). + * @param itargetMin The new min target for controllerSet(). + */ + void setControllerSetTargetLimits(double itargetMax, double itargetMin) override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * Get the last set sample time. + * + * @return sample time + */ + QTime getSampleTime() const override; + + /** + * Set integrator bounds. Default bounds are [-1, 1]. + * + * @param imax max integrator value + * @param imin min integrator value + */ + virtual void setIntegralLimits(double imax, double imin); + + /** + * Set the error sum bounds. Default bounds are [0, std::numeric_limits::max()]. Error + * will only be added to the integral term when its absolute value is between these bounds of + * either side of the target. + * + * @param imax max error value that will be summed + * @param imin min error value that will be summed + */ + virtual void setErrorSumLimits(double imax, double imin); + + /** + * Set whether the integrator should be reset when error is 0 or changes sign. + * + * @param iresetOnZero true to reset + */ + virtual void setIntegratorReset(bool iresetOnZero); + + /** + * Set controller gains. + * + * @param igains The new gains. + */ + virtual void setGains(const Gains &igains); + + /** + * Gets the current gains. + * + * @return The current gains. + */ + Gains getGains() const; + + protected: + std::shared_ptr logger; + double kP, kI, kD, kBias; + QTime sampleTime{10_ms}; + double target{0}; + double lastReading{0}; + double error{0}; + double lastError{0}; + std::unique_ptr derivativeFilter; + + // Integral bounds + double integral{0}; + double integralMax{1}; + double integralMin{-1}; + + // Error will only be added to the integral term within these bounds on either side of the target + double errorSumMin{0}; + double errorSumMax{std::numeric_limits::max()}; + + double derivative{0}; + + // Output bounds + double output{0}; + double outputMax{1}; + double outputMin{-1}; + double controllerSetTargetMax{1}; + double controllerSetTargetMin{-1}; + + // Reset the integrated when the controller crosses 0 or not + bool shouldResetOnCross{true}; + + bool controllerIsDisabled{false}; + + std::unique_ptr loopDtTimer; + std::unique_ptr settledUtil; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/iterative/iterativePositionController.hpp b/pros/okapi/api/control/iterative/iterativePositionController.hpp new file mode 100644 index 00000000..6da33e6a --- /dev/null +++ b/pros/okapi/api/control/iterative/iterativePositionController.hpp @@ -0,0 +1,13 @@ +/* + * 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 + +#include "okapi/api/control/iterative/iterativeController.hpp" + +namespace okapi { +template +class IterativePositionController : public IterativeController {}; +} // namespace okapi diff --git a/pros/okapi/api/control/iterative/iterativeVelPidController.hpp b/pros/okapi/api/control/iterative/iterativeVelPidController.hpp new file mode 100644 index 00000000..910554f1 --- /dev/null +++ b/pros/okapi/api/control/iterative/iterativeVelPidController.hpp @@ -0,0 +1,255 @@ +/* + * 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 + +#include "okapi/api/control/iterative/iterativeVelocityController.hpp" +#include "okapi/api/control/util/settledUtil.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include "okapi/api/filter/velMath.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" + +namespace okapi { +class IterativeVelPIDController : public IterativeVelocityController { + public: + struct Gains { + double kP{0}; + double kD{0}; + double kF{0}; + double kSF{0}; + + bool operator==(const Gains &rhs) const; + bool operator!=(const Gains &rhs) const; + }; + + /** + * Velocity PD controller. + * + * @param ikP the proportional gain + * @param ikD the derivative gain + * @param ikF the feed-forward gain + * @param ikSF a feed-forward gain to counteract static friction + * @param ivelMath The VelMath used for calculating velocity. + * @param itimeUtil see TimeUtil docs + * @param iderivativeFilter a filter for filtering the derivative term + * @param ilogger The logger this instance will log to. + */ + IterativeVelPIDController( + double ikP, + double ikD, + double ikF, + double ikSF, + std::unique_ptr ivelMath, + const TimeUtil &itimeUtil, + std::unique_ptr iderivativeFilter = std::make_unique(), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + /** + * Velocity PD controller. + * + * @param igains The controller gains. + * @param ivelMath The VelMath used for calculating velocity. + * @param itimeUtil see TimeUtil docs + * @param iderivativeFilter a filter for filtering the derivative term + * @param ilogger The logger this instance will log to. + */ + IterativeVelPIDController( + const Gains &igains, + std::unique_ptr ivelMath, + const TimeUtil &itimeUtil, + std::unique_ptr iderivativeFilter = std::make_unique(), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + /** + * Do one iteration of the controller. Returns the reading in the range [-1, 1] unless the + * bounds have been changed with setOutputLimits(). + * + * @param inewReading new measurement + * @return controller output + */ + double step(double inewReading) override; + + /** + * Sets the target for the controller. + * + * @param itarget new target velocity + */ + void setTarget(double itarget) override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be [-1, 1]. + * + * @param ivalue the controller's output in the range [-1, 1] + */ + void controllerSet(double ivalue) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() const; + + /** + * @return The most recent value of the process variable. + */ + double getProcessValue() const override; + + /** + * Returns the last calculated output of the controller. + */ + double getOutput() const override; + + /** + * Get the upper output bound. + * + * @return the upper output bound + */ + double getMaxOutput() override; + + /** + * Get the lower output bound. + * + * @return the lower output bound + */ + double getMinOutput() override; + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Set time between loops in ms. + * + * @param isampleTime time between loops + */ + void setSampleTime(QTime isampleTime) override; + + /** + * Set controller output bounds. Default bounds are [-1, 1]. + * + * @param imax max output + * @param imin min output + */ + void setOutputLimits(double imax, double imin) override; + + /** + * Sets the (soft) limits for the target range that controllerSet() scales into. The target + * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. + * + * @param itargetMax The new max target for controllerSet(). + * @param itargetMin The new min target for controllerSet(). + */ + void setControllerSetTargetLimits(double itargetMax, double itargetMin) override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * Get the last set sample time. + * + * @return sample time + */ + QTime getSampleTime() const override; + + /** + * Do one iteration of velocity calculation. + * + * @param inewReading new measurement + * @return filtered velocity + */ + virtual QAngularSpeed stepVel(double inewReading); + + /** + * Set controller gains. + * + * @param igains The new gains. + */ + virtual void setGains(const Gains &igains); + + /** + * Gets the current gains. + * + * @return The current gains. + */ + Gains getGains() const; + + /** + * Sets the number of encoder ticks per revolution. Default is 1800. + * + * @param tpr number of measured units per revolution + */ + virtual void setTicksPerRev(double tpr); + + /** + * Returns the current velocity. + */ + virtual QAngularSpeed getVel() const; + + protected: + std::shared_ptr logger; + double kP, kD, kF, kSF; + QTime sampleTime{10_ms}; + double error{0}; + double derivative{0}; + double target{0}; + double outputSum{0}; + double output{0}; + double outputMax{1}; + double outputMin{-1}; + double controllerSetTargetMax{1}; + double controllerSetTargetMin{-1}; + bool controllerIsDisabled{false}; + + std::unique_ptr velMath; + std::unique_ptr derivativeFilter; + std::unique_ptr loopDtTimer; + std::unique_ptr settledUtil; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/iterative/iterativeVelocityController.hpp b/pros/okapi/api/control/iterative/iterativeVelocityController.hpp new file mode 100644 index 00000000..5e78264d --- /dev/null +++ b/pros/okapi/api/control/iterative/iterativeVelocityController.hpp @@ -0,0 +1,13 @@ +/* + * 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 + +#include "okapi/api/control/iterative/iterativeController.hpp" + +namespace okapi { +template +class IterativeVelocityController : public IterativeController {}; +} // namespace okapi diff --git a/pros/okapi/api/control/offsettableControllerInput.hpp b/pros/okapi/api/control/offsettableControllerInput.hpp new file mode 100644 index 00000000..8f022019 --- /dev/null +++ b/pros/okapi/api/control/offsettableControllerInput.hpp @@ -0,0 +1,41 @@ +/* + * 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 + +#include "okapi/api/control/controllerInput.hpp" +#include + +namespace okapi { +class OffsetableControllerInput : public ControllerInput { + public: + /** + * A ControllerInput which can be tared to change the zero position. + * + * @param iinput The ControllerInput to reference. + */ + explicit OffsetableControllerInput(const std::shared_ptr> &iinput); + + virtual ~OffsetableControllerInput(); + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or PROS_ERR on a failure. + */ + double controllerGet() override; + + /** + * Sets the "absolute" zero position of this controller input to its current position. This does + * nothing if the underlying controller input returns PROS_ERR. + */ + virtual void tarePosition(); + + protected: + std::shared_ptr> input; + double offset{0}; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/util/controllerRunner.hpp b/pros/okapi/api/control/util/controllerRunner.hpp new file mode 100644 index 00000000..29a1ebd7 --- /dev/null +++ b/pros/okapi/api/control/util/controllerRunner.hpp @@ -0,0 +1,131 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncController.hpp" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/control/iterative/iterativeController.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include + +namespace okapi { +template class ControllerRunner { + public: + /** + * A utility class that runs a closed-loop controller. + * + * @param itimeUtil The TimeUtil. + * @param ilogger The logger this instance will log to. + */ + explicit ControllerRunner(const TimeUtil &itimeUtil, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()) + : logger(ilogger), rate(itimeUtil.getRate()) { + } + + /** + * Runs the controller until it has settled. + * + * @param itarget the new target + * @param icontroller the controller to run + * @return the error when settled + */ + virtual Output runUntilSettled(const Input itarget, AsyncController &icontroller) { + LOG_INFO("ControllerRunner: runUntilSettled(AsyncController): Set target to " + + std::to_string(itarget)); + icontroller.setTarget(itarget); + + while (!icontroller.isSettled()) { + rate->delayUntil(10_ms); + } + + LOG_INFO("ControllerRunner: runUntilSettled(AsyncController): Done waiting to settle"); + return icontroller.getError(); + } + + /** + * Runs the controller until it has settled. + * + * @param itarget the new target + * @param icontroller the controller to run + * @param ioutput the output to write to + * @return the error when settled + */ + virtual Output runUntilSettled(const Input itarget, + IterativeController &icontroller, + ControllerOutput &ioutput) { + LOG_INFO("ControllerRunner: runUntilSettled(IterativeController): Set target to " + + std::to_string(itarget)); + icontroller.setTarget(itarget); + + while (!icontroller.isSettled()) { + ioutput.controllerSet(icontroller.getOutput()); + rate->delayUntil(10_ms); + } + + LOG_INFO("ControllerRunner: runUntilSettled(IterativeController): Done waiting to settle"); + return icontroller.getError(); + } + + /** + * Runs the controller until it has reached its target, but not necessarily settled. + * + * @param itarget the new target + * @param icontroller the controller to run + * @return the error when settled + */ + virtual Output runUntilAtTarget(const Input itarget, + AsyncController &icontroller) { + LOG_INFO("ControllerRunner: runUntilAtTarget(AsyncController): Set target to " + + std::to_string(itarget)); + icontroller.setTarget(itarget); + + double error = icontroller.getError(); + double lastError = error; + while (error != 0 && std::copysign(1.0, error) == std::copysign(1.0, lastError)) { + lastError = error; + rate->delayUntil(10_ms); + error = icontroller.getError(); + } + + LOG_INFO("ControllerRunner: runUntilAtTarget(AsyncController): Done waiting to settle"); + return icontroller.getError(); + } + + /** + * Runs the controller until it has reached its target, but not necessarily settled. + * + * @param itarget the new target + * @param icontroller the controller to run + * @param ioutput the output to write to + * @return the error when settled + */ + virtual Output runUntilAtTarget(const Input itarget, + IterativeController &icontroller, + ControllerOutput &ioutput) { + LOG_INFO("ControllerRunner: runUntilAtTarget(IterativeController): Set target to " + + std::to_string(itarget)); + icontroller.setTarget(itarget); + + double error = icontroller.getError(); + double lastError = error; + while (error != 0 && std::copysign(1.0, error) == std::copysign(1.0, lastError)) { + ioutput.controllerSet(icontroller.getOutput()); + lastError = error; + rate->delayUntil(10_ms); + error = icontroller.getError(); + } + + LOG_INFO("ControllerRunner: runUntilAtTarget(IterativeController): Done waiting to settle"); + return icontroller.getError(); + } + + protected: + std::shared_ptr logger; + std::unique_ptr rate; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/util/flywheelSimulator.hpp b/pros/okapi/api/control/util/flywheelSimulator.hpp new file mode 100644 index 00000000..7f82e69d --- /dev/null +++ b/pros/okapi/api/control/util/flywheelSimulator.hpp @@ -0,0 +1,156 @@ +/* + * 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 + +#include + +namespace okapi { +class FlywheelSimulator { + public: + /** + * A simulator for an inverted pendulum. The center of mass of the system changes as the link + * rotates (by default, you can set a new torque function with setExternalTorqueFunction()). + */ + explicit FlywheelSimulator(double imass = 0.01, + double ilinkLen = 1, + double imuStatic = 0.1, + double imuDynamic = 0.9, + double itimestep = 0.01); + + virtual ~FlywheelSimulator(); + + /** + * Step the simulation by the timestep. + * + * @return the current angle + */ + double step(); + + /** + * Step the simulation by the timestep. + * + * @param itorque new input torque + * @return the current angle + */ + double step(double itorque); + + /** + * Sets the torque function used to calculate the torque due to external forces. This torque gets + * summed with the input torque. + * + * For example, the default torque function has the torque due to gravity vary as the link swings: + * [](double angle, double mass, double linkLength) { + * return (linkLength * std::cos(angle)) * (mass * -1 * gravity); + * } + * + * @param itorqueFunc the torque function. The return value is the torque due to external forces + */ + void setExternalTorqueFunction( + std::function itorqueFunc); + + /** + * Sets the input torque. The input will be bounded by the max torque. + * + * @param itorque new input torque + */ + void setTorque(double itorque); + + /** + * Sets the max torque. The input torque cannot exceed this maximum torque. + * + * @param imaxTorque new maximum torque + */ + void setMaxTorque(double imaxTorque); + + /** + * Sets the current angle. + * + * @param iangle new angle + **/ + void setAngle(double iangle); + + /** + * Sets the mass (kg). + * + * @param imass new mass + */ + void setMass(double imass); + + /** + * Sets the link length (m). + * + * @param ilinkLen new link length + */ + void setLinkLength(double ilinkLen); + + /** + * Sets the static friction (N*m). + * + * @param imuStatic new static friction + */ + void setStaticFriction(double imuStatic); + + /** + * Sets the dynamic friction (N*m). + * + * @param imuDynamic new dynamic friction + */ + void setDynamicFriction(double imuDynamic); + + /** + * Sets the timestep (sec). + * + * @param itimestep new timestep + */ + void setTimestep(double itimestep); + + /** + * Returns the current angle (angle in rad). + * + * @return the current angle + */ + double getAngle() const; + + /** + * Returns the current omgea (angular velocity in rad / sec). + * + * @return the current omega + */ + double getOmega() const; + + /** + * Returns the current acceleration (angular acceleration in rad / sec^2). + * + * @return the current acceleration + */ + double getAcceleration() const; + + /** + * Returns the maximum torque input. + * + * @return the max torque input + */ + double getMaxTorque() const; + + protected: + double inputTorque = 0; // N*m + double maxTorque = 0.5649; // N*m + double angle = 0; // rad + double omega = 0; // rad / sec + double accel = 0; // rad / sec^2 + double mass; // kg + double linkLen; // m + double muStatic; // N*m + double muDynamic; // N*m + double timestep; // sec + double I = 0; // moment of inertia + std::function torqueFunc; + + const double minTimestep = 0.000001; // 1 us + + virtual double stepImpl(); +}; +} // namespace okapi diff --git a/pros/okapi/api/control/util/pathfinderUtil.hpp b/pros/okapi/api/control/util/pathfinderUtil.hpp new file mode 100644 index 00000000..c356adff --- /dev/null +++ b/pros/okapi/api/control/util/pathfinderUtil.hpp @@ -0,0 +1,23 @@ +/* + * 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 + +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QLength.hpp" + +namespace okapi { +struct PathfinderPoint { + QLength x; // X coordinate relative to the start of the movement + QLength y; // Y coordinate relative to the start of the movement + QAngle theta; // Exit angle relative to the start of the movement +}; + +struct PathfinderLimits { + double maxVel; // Maximum robot velocity in m/s + double maxAccel; // Maximum robot acceleration in m/s/s + double maxJerk; // Maximum robot jerk in m/s/s/s +}; +} // namespace okapi diff --git a/pros/okapi/api/control/util/pidTuner.hpp b/pros/okapi/api/control/util/pidTuner.hpp new file mode 100644 index 00000000..d70c6a01 --- /dev/null +++ b/pros/okapi/api/control/util/pidTuner.hpp @@ -0,0 +1,80 @@ +/* + * 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 + +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/control/iterative/iterativePosPidController.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include + +namespace okapi { +class PIDTuner { + public: + struct Output { + double kP, kI, kD; + }; + + PIDTuner(const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + const TimeUtil &itimeUtil, + QTime itimeout, + std::int32_t igoal, + double ikPMin, + double ikPMax, + double ikIMin, + double ikIMax, + double ikDMin, + double ikDMax, + std::size_t inumIterations = 5, + std::size_t inumParticles = 16, + double ikSettle = 1, + double ikITAE = 2, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + virtual ~PIDTuner(); + + virtual Output autotune(); + + protected: + static constexpr double inertia = 0.5; // Particle inertia + static constexpr double confSelf = 1.1; // Self confidence + static constexpr double confSwarm = 1.2; // Particle swarm confidence + static constexpr int increment = 5; + static constexpr int divisor = 5; + static constexpr QTime loopDelta = 10_ms; // NOLINT + + struct Particle { + double pos, vel, best; + }; + + struct ParticleSet { + Particle kP, kI, kD; + double bestError; + }; + + std::shared_ptr logger; + TimeUtil timeUtil; + std::shared_ptr> input; + std::shared_ptr> output; + + const QTime timeout; + const std::int32_t goal; + const double kPMin; + const double kPMax; + const double kIMin; + const double kIMax; + const double kDMin; + const double kDMax; + const std::size_t numIterations; + const std::size_t numParticles; + const double kSettle; + const double kITAE; +}; +} // namespace okapi diff --git a/pros/okapi/api/control/util/settledUtil.hpp b/pros/okapi/api/control/util/settledUtil.hpp new file mode 100644 index 00000000..9b81ba2f --- /dev/null +++ b/pros/okapi/api/control/util/settledUtil.hpp @@ -0,0 +1,51 @@ +/* + * 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 + +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/util/abstractTimer.hpp" +#include + +namespace okapi { +class SettledUtil { + public: + /** + * A utility class to determine if a control loop has settled based on error. A control loop is + * settled if the error is within `iatTargetError` and `iatTargetDerivative` for `iatTargetTime`. + * + * @param iatTargetTimer A timer used to track `iatTargetTime`. + * @param iatTargetError The minimum error to be considered settled. + * @param iatTargetDerivative The minimum error derivative to be considered settled. + * @param iatTargetTime The minimum time within atTargetError to be considered settled. + */ + explicit SettledUtil(std::unique_ptr iatTargetTimer, + double iatTargetError = 50, + double iatTargetDerivative = 5, + QTime iatTargetTime = 250_ms); + + virtual ~SettledUtil(); + + /** + * Returns whether the controller is settled. + * + * @param ierror The current error. + * @return Whether the controller is settled. + */ + virtual bool isSettled(double ierror); + + /** + * Resets the "at target" timer and clears the previous error. + */ + virtual void reset(); + + protected: + double atTargetError = 50; + double atTargetDerivative = 5; + QTime atTargetTime = 250_ms; + std::unique_ptr atTargetTimer; + double lastError = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/coreProsAPI.hpp b/pros/okapi/api/coreProsAPI.hpp new file mode 100644 index 00000000..ab1aa694 --- /dev/null +++ b/pros/okapi/api/coreProsAPI.hpp @@ -0,0 +1,131 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef THREADS_STD +#include +#define CROSSPLATFORM_THREAD_T std::thread + +#include +#define CROSSPLATFORM_MUTEX_T std::mutex +#else +#include "api.h" +#include "pros/apix.h" +#define CROSSPLATFORM_THREAD_T pros::task_t +#define CROSSPLATFORM_MUTEX_T pros::Mutex +#endif + +#define NOT_INITIALIZE_TASK \ + (strcmp(pros::c::task_get_name(pros::c::task_get_current()), "User Initialization (PROS)") != 0) + +#define NOT_COMP_INITIALIZE_TASK \ + (strcmp(pros::c::task_get_name(pros::c::task_get_current()), "User Comp. Init. (PROS)") != 0) + +class CrossplatformThread { + public: +#ifdef THREADS_STD + CrossplatformThread(void (*ptr)(void *), + void *params, + const char *const = "OkapiLibCrossplatformTask") +#else + CrossplatformThread(void (*ptr)(void *), + void *params, + const char *const name = "OkapiLibCrossplatformTask") +#endif + : +#ifdef THREADS_STD + thread(ptr, params) +#else + thread( + pros::c::task_create(ptr, params, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, name)) +#endif + { + } + + ~CrossplatformThread() { +#ifdef THREADS_STD + thread.join(); +#else + if (pros::c::task_get_state(thread) != pros::E_TASK_STATE_DELETED) { + pros::c::task_delete(thread); + } +#endif + } + +#ifdef THREADS_STD + void notifyWhenDeleting(CrossplatformThread *) { + } +#else + void notifyWhenDeleting(CrossplatformThread *parent) { + pros::c::task_notify_when_deleting(parent->thread, thread, 1, pros::E_NOTIFY_ACTION_INCR); + } +#endif + +#ifdef THREADS_STD + void notifyWhenDeletingRaw(CROSSPLATFORM_THREAD_T *) { + } +#else + void notifyWhenDeletingRaw(CROSSPLATFORM_THREAD_T parent) { + pros::c::task_notify_when_deleting(parent, thread, 1, pros::E_NOTIFY_ACTION_INCR); + } +#endif + +#ifdef THREADS_STD + std::uint32_t notifyTake(const std::uint32_t) { + return 0; + } +#else + std::uint32_t notifyTake(const std::uint32_t itimeout) { + return pros::c::task_notify_take(true, itimeout); + } +#endif + + static std::string getName() { +#ifdef THREADS_STD + std::ostringstream ss; + ss << std::this_thread::get_id(); + return ss.str(); +#else + return std::string(pros::c::task_get_name(NULL)); +#endif + } + + CROSSPLATFORM_THREAD_T thread; +}; + +class CrossplatformMutex { + public: + CrossplatformMutex() = default; + + void lock() { +#ifdef THREADS_STD + mutex.lock(); +#else + while (!mutex.take(1)) { + } +#endif + } + + void unlock() { +#ifdef THREADS_STD + mutex.unlock(); +#else + mutex.give(); +#endif + } + + protected: + CROSSPLATFORM_MUTEX_T mutex; +}; diff --git a/pros/okapi/api/device/button/abstractButton.hpp b/pros/okapi/api/device/button/abstractButton.hpp new file mode 100644 index 00000000..4e75f2eb --- /dev/null +++ b/pros/okapi/api/device/button/abstractButton.hpp @@ -0,0 +1,46 @@ +/* + * 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 + +#include "okapi/api/control/controllerInput.hpp" + +namespace okapi { +class AbstractButton : public ControllerInput { + public: + virtual ~AbstractButton(); + + /** + * Return whether the button is currently pressed. + **/ + virtual bool isPressed() = 0; + + /** + * Return whether the state of the button changed since the last time this method was + * called. + **/ + virtual bool changed() = 0; + + /** + * Return whether the state of the button changed to being pressed since the last time this method + * was called. + **/ + virtual bool changedToPressed() = 0; + + /** + * Return whether the state of the button to being not pressed changed since the last time this + * method was called. + **/ + virtual bool changedToReleased() = 0; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value. This is the same as the output of the pressed() method. + */ + virtual bool controllerGet() override; +}; +} // namespace okapi diff --git a/pros/okapi/api/device/button/buttonBase.hpp b/pros/okapi/api/device/button/buttonBase.hpp new file mode 100644 index 00000000..54f1ccd4 --- /dev/null +++ b/pros/okapi/api/device/button/buttonBase.hpp @@ -0,0 +1,52 @@ +/* + * 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 + +#include "okapi/api/device/button/abstractButton.hpp" + +namespace okapi { +class ButtonBase : public AbstractButton { + public: + /** + * @param iinverted Whether the button is inverted (`true` meaning default pressed and `false` + * meaning default not pressed). + */ + explicit ButtonBase(bool iinverted = false); + + /** + * Return whether the button is currently pressed. + **/ + bool isPressed() override; + + /** + * Return whether the state of the button changed since the last time this method was called. + **/ + bool changed() override; + + /** + * Return whether the state of the button changed to pressed since the last time this method was + *called. + **/ + bool changedToPressed() override; + + /** + * Return whether the state of the button to not pressed since the last time this method was + *called. + **/ + bool changedToReleased() override; + + protected: + bool inverted{false}; + bool wasPressedLast_c{false}; + bool wasPressedLast_ctp{false}; + bool wasPressedLast_ctr{false}; + + virtual bool currentlyPressed() = 0; + + private: + bool changedImpl(bool &prevState); +}; +} // namespace okapi diff --git a/pros/okapi/api/device/motor/abstractMotor.hpp b/pros/okapi/api/device/motor/abstractMotor.hpp new file mode 100644 index 00000000..ff46fe07 --- /dev/null +++ b/pros/okapi/api/device/motor/abstractMotor.hpp @@ -0,0 +1,537 @@ +/* + * 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 + +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" +#include + +namespace okapi { +class AbstractMotor : public ControllerOutput { + public: + /** + * Indicates the 'brake mode' of a motor. + */ + enum class brakeMode { + coast = 0, ///< Motor coasts when stopped, traditional behavior + brake = 1, ///< Motor brakes when stopped + hold = 2, ///< Motor actively holds position when stopped + invalid = INT32_MAX + }; + + /** + * Indicates the units used by the motor encoders. + */ + enum class encoderUnits { + degrees = 0, ///< degrees + rotations = 1, ///< rotations + counts = 2, ///< counts + invalid = INT32_MAX ///< invalid + }; + + /** + * Indicates the internal gear ratio of a motor. + */ + enum class gearset { + red = 100, ///< 36:1, 100 RPM, Red gear set + green = 200, ///< 18:1, 200 RPM, Green gear set + blue = 600, ///< 6:1, 600 RPM, Blue gear set + invalid = INT32_MAX + }; + + /** + * A simple structure representing the full ratio between motor and wheel. + */ + struct GearsetRatioPair { + /** + * A simple structure representing the full ratio between motor and wheel. + * + * The ratio is `motor rotation : wheel rotation`, e.x., if one motor rotation + * corresponds to two wheel rotations, the ratio is `1.0/2.0`. + * + * @param igearset The gearset in the motor. + * @param iratio The ratio of motor rotation to wheel rotation. + */ + GearsetRatioPair(const gearset igearset, const double iratio = 1) + : internalGearset(igearset), ratio(iratio) { + } + + ~GearsetRatioPair() = default; + + gearset internalGearset; + double ratio = 1; + }; + + virtual ~AbstractMotor(); + + /******************************************************************************/ + /** Motor movement functions **/ + /** **/ + /** These functions allow programmers to make motors move **/ + /******************************************************************************/ + + /** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with setZeroPosition(). + * + * @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: + * EACCES - Another resource is currently trying to access the port. + * + * @param iposition The absolute position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t moveAbsolute(double iposition, std::int32_t ivelocity) = 0; + + /** + * Sets the relative target position for the motor to move to. + * + * This movement is relative to the current position of the motor. Providing 10.0 as the position + * parameter would result in the motor moving clockwise 10 units, 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. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param iposition The relative position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t moveRelative(double iposition, std::int32_t ivelocity) = 0; + + /** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the gearset + * used for the motor. This results in a range of +-100 for pros::c::red, + * +-200 for green, and +-600 for blue. The velocity + * is held with PID to ensure consistent speed, as opposed to setting the motor's + * voltage. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's + * gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t moveVelocity(std::int16_t ivelocity) = 0; + + /** + * Sets the voltage for the motor from -12000 to 12000. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ivoltage The new voltage value from -12000 to 12000 + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t moveVoltage(std::int16_t ivoltage) = 0; + + /** + * Changes the output velocity for a profiled movement (moveAbsolute or moveRelative). This will + * have no effect if the motor is not following a profiled movement. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's + * gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t modifyProfiledVelocity(std::int32_t ivelocity) = 0; + + /******************************************************************************/ + /** Motor telemetry functions **/ + /** **/ + /** These functions allow programmers to collect telemetry from motors **/ + /******************************************************************************/ + + /** + * Gets the target position set for the motor by the user. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The target position in its encoder units or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual double getTargetPosition() = 0; + + /** + * Gets the absolute position of the motor in its encoder units. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's absolute position in its encoder units or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double getPosition() = 0; + + /** + * Gets the positional error (target position minus actual position) of the motor in its encoder + * units. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's positional error in its encoder units or PROS_ERR_F if the operation + * failed, setting errno. + */ + double getPositionError(); + + /** + * Sets the "absolute" zero position of the motor to its current position. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t tarePosition() = 0; + + /** + * Gets the velocity commanded to the motor by the user. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The commanded motor velocity from +-100, +-200, or +-600, or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t getTargetVelocity() = 0; + + /** + * Gets the actual velocity of the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's actual velocity in RPM or PROS_ERR_F if the operation failed, setting + * errno. + */ + virtual double getActualVelocity() = 0; + + /** + * Gets the difference between the target velocity of the motor and the actual velocity of the + * motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's velocity error in RPM or PROS_ERR_F if the operation failed, setting + * errno. + */ + double getVelocityError(); + + /** + * Gets the current drawn by the motor in mA. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's current in mA or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t getCurrentDraw() = 0; + + /** + * Gets the direction of movement for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return 1 for moving in the positive direction, -1 for moving in the negative direction, and + * PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t getDirection() = 0; + + /** + * Gets the efficiency of the motor in percent. + * + * 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: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's efficiency in percent or PROS_ERR_F if the operation failed, setting errno. + */ + virtual double getEfficiency() = 0; + + /** + * Checks if the motor is drawing over its current limit. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @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. + */ + virtual std::int32_t isOverCurrent() = 0; + + /** + * Checks if the motor's temperature is above its limit. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return 1 if the temperature limit is exceeded and 0 if the the temperature is below the limit, + * or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t isOverTemp() = 0; + + /** + * Checks if the motor is stopped. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns PROS_ERR with errno set to ENOSYS. + * + * @return 1 if the motor is not moving, 0 if the motor is moving, or PROS_ERR if the operation + * failed, setting errno + */ + virtual std::int32_t isStopped() = 0; + + /** + * Checks if the motor is at its zero position. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns PROS_ERR with errno set to ENOSYS. + * + * @return 1 if the motor is at zero absolute position, 0 if the motor has moved from its absolute + * zero, or PROS_ERR if the operation failed, setting errno + */ + virtual std::int32_t getZeroPositionFlag() = 0; + + /** + * Gets 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: + * EACCES - Another resource is currently trying to access the port. + * + * @return A currently unknown bitfield containing the motor's faults. 0b00000100 = Current Limit + * Hit + */ + virtual uint32_t getFaults() = 0; + + /** + * Gets 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: + * EACCES - Another resource is currently trying to access the port. + * + * @return A currently unknown bitfield containing the motor's flags. These seem to be unrelated + * to the individual get_specific_flag functions + */ + virtual uint32_t getFlags() = 0; + + /** + * Gets 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: + * EACCES - Another resource is currently trying to access the port. + * + * @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 The raw encoder count at the given timestamp or PROS_ERR if the operation failed. + */ + virtual std::int32_t getRawPosition(std::uint32_t *timestamp) = 0; + + /** + * Gets the power drawn by the motor in Watts. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's power draw in Watts or PROS_ERR_F if the operation failed, setting errno. + */ + virtual double getPower() = 0; + + /** + * Gets the temperature of the motor in degrees Celsius. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's temperature in degrees Celsius or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual double getTemperature() = 0; + + /** + * Gets the torque generated by the motor in Newton Metres (Nm). + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's torque in NM or PROS_ERR_F if the operation failed, setting errno. + */ + virtual double getTorque() = 0; + + /** + * Gets the voltage delivered to the motor in millivolts. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's voltage in V or PROS_ERR_F if the operation failed, setting errno. + */ + virtual std::int32_t getVoltage() = 0; + + /******************************************************************************/ + /** Motor configuration functions **/ + /** **/ + /** These functions allow programmers to configure the behavior of motors **/ + /******************************************************************************/ + + /** + * Sets one of brakeMode to the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param imode The new motor brake mode to set for the motor + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setBrakeMode(brakeMode imode) = 0; + + /** + * Gets the brake mode that was set for the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return One of brakeMode, according to what was set for the motor, or brakeMode::invalid if the + * operation failed, setting errno. + */ + virtual brakeMode getBrakeMode() = 0; + + /** + * Sets the current limit for the motor in mA. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ilimit The new current limit in mA + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setCurrentLimit(std::int32_t ilimit) = 0; + + /** + * Gets the current limit for the motor in mA. + * + * The default value is 2500 mA. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's current limit in mA or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t getCurrentLimit() = 0; + + /** + * Sets one of encoderUnits for the motor encoder. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param iunits The new motor encoder units + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setEncoderUnits(encoderUnits iunits) = 0; + + /** + * Gets the encoder units that were set for the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return One of encoderUnits according to what is set for the motor or encoderUnits::invalid if + * the operation failed. + */ + virtual encoderUnits getEncoderUnits() = 0; + + /** + * Sets one of gearset for the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param igearset The new motor gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setGearing(gearset igearset) = 0; + + /** + * Gets the gearset that was set for the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return One of gearset according to what is set for the motor, or gearset::invalid if the + * operation failed. + */ + virtual gearset getGearing() = 0; + + /** + * Sets the reverse flag for the motor. + * + * This will invert its movements and the values returned for its position. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ireverse True reverses the motor, false is default + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setReversed(bool ireverse) = 0; + + /** + * Sets the voltage limit for the motor in Volts. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ilimit The new voltage limit in Volts + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setVoltageLimit(std::int32_t ilimit) = 0; + + /** + * Returns the encoder associated with this motor. + * + * @return the encoder for this motor + */ + virtual std::shared_ptr getEncoder() = 0; +}; + +AbstractMotor::GearsetRatioPair operator*(AbstractMotor::gearset gearset, double ratio); + +} // namespace okapi diff --git a/pros/okapi/api/device/rotarysensor/continuousRotarySensor.hpp b/pros/okapi/api/device/rotarysensor/continuousRotarySensor.hpp new file mode 100644 index 00000000..4de4cc5e --- /dev/null +++ b/pros/okapi/api/device/rotarysensor/continuousRotarySensor.hpp @@ -0,0 +1,20 @@ +/* + * 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 + +#include "okapi/api/device/rotarysensor/rotarySensor.hpp" + +namespace okapi { +class ContinuousRotarySensor : public RotarySensor { + public: + /** + * Reset the sensor to zero. + * + * @return `1` on success, `PROS_ERR` on fail + */ + virtual std::int32_t reset() = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/device/rotarysensor/rotarySensor.hpp b/pros/okapi/api/device/rotarysensor/rotarySensor.hpp new file mode 100644 index 00000000..9b010a4b --- /dev/null +++ b/pros/okapi/api/device/rotarysensor/rotarySensor.hpp @@ -0,0 +1,23 @@ +/* + * 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 + +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/coreProsAPI.hpp" + +namespace okapi { +class RotarySensor : public ControllerInput { + public: + virtual ~RotarySensor(); + + /** + * Get the current sensor value. + * + * @return the current sensor value, or `PROS_ERR` on a failure. + */ + virtual double get() const = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/filter/averageFilter.hpp b/pros/okapi/api/filter/averageFilter.hpp new file mode 100644 index 00000000..c2babd07 --- /dev/null +++ b/pros/okapi/api/filter/averageFilter.hpp @@ -0,0 +1,59 @@ +/* + * 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 + +#include "okapi/api/filter/filter.hpp" +#include +#include + +namespace okapi { +/** + * A filter which returns the average of a list of values. + * + * @tparam n number of taps in the filter + */ +template class AverageFilter : public Filter { + public: + /** + * Averaging filter. + */ + AverageFilter() = default; + + /** + * Filters a value, like a sensor reading. + * + * @param ireading new measurement + * @return filtered result + */ + double filter(const double ireading) override { + data[index++] = ireading; + if (index >= n) { + index = 0; + } + + output = 0.0; + for (size_t i = 0; i < n; i++) + output += data[i]; + output /= (double)n; + + return output; + } + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override { + return output; + } + + protected: + std::array data{0}; + std::size_t index = 0; + double output = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/filter/composableFilter.hpp b/pros/okapi/api/filter/composableFilter.hpp new file mode 100644 index 00000000..be494e95 --- /dev/null +++ b/pros/okapi/api/filter/composableFilter.hpp @@ -0,0 +1,50 @@ +/* + * 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 + +#include "okapi/api/filter/filter.hpp" +#include +#include +#include +#include + +namespace okapi { +class ComposableFilter : public Filter { + public: + /** + * A composable filter is a filter that consists of other filters. The input signal is passed + * through each filter in sequence. The final output of this filter is the output of the last + * filter. + * + * @param ilist The filters to use in sequence. + */ + ComposableFilter(const std::initializer_list> &ilist); + + /** + * Filters a value. + * + * @param ireading A new measurement. + * @return The filtered result. + */ + double filter(double ireading) override; + + /** + * @return The previous output from filter. + */ + double getOutput() const override; + + /** + * Adds a filter to the end of the sequence. + * + * @param ifilter The filter to add. + */ + virtual void addFilter(std::shared_ptr ifilter); + + protected: + std::vector> filters; + double output = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/filter/demaFilter.hpp b/pros/okapi/api/filter/demaFilter.hpp new file mode 100644 index 00000000..c3f4ef31 --- /dev/null +++ b/pros/okapi/api/filter/demaFilter.hpp @@ -0,0 +1,52 @@ +/* + * 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 + +#include "okapi/api/filter/filter.hpp" +#include + +namespace okapi { +class DemaFilter : public Filter { + public: + /** + * Double exponential moving average filter. + * + * @param ialpha alpha gain + * @param ibeta beta gain + */ + DemaFilter(double ialpha, double ibeta); + + /** + * Filters a value, like a sensor reading. + * + * @param reading new measurement + * @return filtered result + */ + double filter(double ireading) override; + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override; + + /** + * Set filter gains. + * + * @param ialpha alpha gain + * @param ibeta beta gain + */ + virtual void setGains(double ialpha, double ibeta); + + protected: + double alpha, beta; + double outputS = 0; + double lastOutputS = 0; + double outputB = 0; + double lastOutputB = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/filter/ekfFilter.hpp b/pros/okapi/api/filter/ekfFilter.hpp new file mode 100644 index 00000000..731ad858 --- /dev/null +++ b/pros/okapi/api/filter/ekfFilter.hpp @@ -0,0 +1,71 @@ +/* + * 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 + +#include "okapi/api/filter/filter.hpp" +#include "okapi/api/util/mathUtil.hpp" + +namespace okapi { +class EKFFilter : public Filter { + public: + /** + * One dimensional extended Kalman filter. The default arguments should work fine for most signal + * filtering. It won't hurt to graph your signal and the filtered result, and check if the filter + * is doing its job. + * + * Q is the covariance of the process noise and R is the + * covariance of the observation noise. The default values for Q and R should be a modest balance + * between trust in the sensor and FIR filtering. + * + * Think of R as how noisy your sensor is. Its value can be found mathematically by computing the + * standard deviation of your sensor reading vs. "truth" (of course, "truth" is still an estimate; + * try to calibrate your robot in a controlled setting where you can minimize the error in what + * "truth" is). + * + * Think of Q as how noisy your model is. It decides how much "smoothing" the filter does and how + * far it lags behind the true signal. This parameter is most often used as a "tuning" parameter + * to adjust the response of the filter. + * + * @param iQ process noise covariance + * @param iR measurement noise covariance + */ + explicit EKFFilter(double iQ = 0.0001, double iR = ipow(0.2, 2)); + + /** + * Filters a value, like a sensor reading. Assumes the control input is zero. + * + * @param ireading new measurement + * @return filtered result + */ + double filter(double ireading) override; + + /** + * Filters a reading with a control input. + * + * @param ireading new measurement + * @param icontrol control input + * @return filtered result + */ + virtual double filter(double ireading, double icontrol); + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override; + + protected: + const double Q, R; + double xHat = 0; + double xHatPrev = 0; + double xHatMinus = 0; + double P = 0; + double Pprev = 1; + double Pminus = 0; + double K = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/filter/emaFilter.hpp b/pros/okapi/api/filter/emaFilter.hpp new file mode 100644 index 00000000..f41611c9 --- /dev/null +++ b/pros/okapi/api/filter/emaFilter.hpp @@ -0,0 +1,47 @@ +/* + * 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 + +#include "okapi/api/filter/filter.hpp" + +namespace okapi { +class EmaFilter : public Filter { + public: + /** + * Exponential moving average filter. + * + * @param ialpha alpha gain + */ + explicit EmaFilter(double ialpha); + + /** + * Filters a value, like a sensor reading. + * + * @param reading new measurement + * @return filtered result + */ + double filter(double ireading) override; + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override; + + /** + * Set filter gains. + * + * @param ialpha alpha gain + */ + virtual void setGains(double ialpha); + + protected: + double alpha; + double output = 0; + double lastOutput = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/filter/filter.hpp b/pros/okapi/api/filter/filter.hpp new file mode 100644 index 00000000..24ca2cf1 --- /dev/null +++ b/pros/okapi/api/filter/filter.hpp @@ -0,0 +1,28 @@ +/* + * 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 + +namespace okapi { +class Filter { + public: + virtual ~Filter(); + + /** + * Filters a value, like a sensor reading. + * + * @param ireading new measurement + * @return filtered result + */ + virtual double filter(double ireading) = 0; + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + virtual double getOutput() const = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/filter/filteredControllerInput.hpp b/pros/okapi/api/filter/filteredControllerInput.hpp new file mode 100644 index 00000000..9257fe6a --- /dev/null +++ b/pros/okapi/api/filter/filteredControllerInput.hpp @@ -0,0 +1,48 @@ +/* + * 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 + +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/filter/filter.hpp" +#include + +namespace okapi { +/** + * A ControllerInput with a filter built in. + * + * @tparam InputType the type of the ControllerInput + * @tparam FilterType the type of the Filter + */ +template +class FilteredControllerInput : public ControllerInput { + public: + /** + * A filtered controller input. Applies a filter to the controller input. Useful if you want to + * place a filter between a control input and a control loop. + * + * @param iinput ControllerInput type + * @param ifilter Filter type + */ + FilteredControllerInput(std::unique_ptr> iinput, + std::unique_ptr ifilter) + : input(std::move(iinput)), filter(std::move(ifilter)) { + } + + /** + * Gets the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current filtered sensor value. + */ + double controllerGet() override { + return filter->filter(input->controllerGet()); + } + + protected: + std::unique_ptr> input; + std::unique_ptr filter; +}; +} // namespace okapi diff --git a/pros/okapi/api/filter/medianFilter.hpp b/pros/okapi/api/filter/medianFilter.hpp new file mode 100644 index 00000000..28792117 --- /dev/null +++ b/pros/okapi/api/filter/medianFilter.hpp @@ -0,0 +1,94 @@ +/* + * Uses the median filter algorithm from N. Wirth’s book, implementation by N. Devillard. + * + * 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 + +#include "okapi/api/filter/filter.hpp" +#include +#include +#include + +namespace okapi { +/** + * A filter which returns the median value of list of values. + * + * @tparam n number of taps in the filter + */ +template class MedianFilter : public Filter { + public: + MedianFilter() : middleIndex((((n)&1) ? ((n) / 2) : (((n) / 2) - 1))) { + } + + /** + * Filters a value, like a sensor reading. + * + * @param ireading new measurement + * @return filtered result + */ + double filter(const double ireading) override { + data[index++] = ireading; + if (index >= n) { + index = 0; + } + + output = kth_smallset(); + return output; + } + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override { + return output; + } + + protected: + std::array data{0}; + std::size_t index = 0; + double output = 0; + const size_t middleIndex; + + /** + * Algorithm from N. Wirth’s book, implementation by N. Devillard. + */ + double kth_smallset() { + std::array dataCopy = data; + size_t j, l, m; + l = 0; + m = n - 1; + + while (l < m) { + double x = dataCopy[middleIndex]; + size_t i = l; + j = m; + do { + while (dataCopy[i] < x) { + i++; + } + while (x < dataCopy[j]) { + j--; + } + if (i <= j) { + const double t = dataCopy[i]; + dataCopy[i] = dataCopy[j]; + dataCopy[j] = t; + i++; + j--; + } + } while (i <= j); + if (j < middleIndex) + l = i; + if (middleIndex < i) + m = j; + } + + return dataCopy[middleIndex]; + } +}; +} // namespace okapi diff --git a/pros/okapi/api/filter/passthroughFilter.hpp b/pros/okapi/api/filter/passthroughFilter.hpp new file mode 100644 index 00000000..543fa317 --- /dev/null +++ b/pros/okapi/api/filter/passthroughFilter.hpp @@ -0,0 +1,36 @@ +/* + * 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 + +#include "okapi/api/filter/filter.hpp" + +namespace okapi { +class PassthroughFilter : public Filter { + public: + /** + * A simple filter that does no filtering and just passes the input through. + */ + PassthroughFilter(); + + /** + * Filters a value, like a sensor reading. + * + * @param ireading new measurement + * @return filtered result + */ + double filter(double ireading) override; + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override; + + protected: + double lastOutput = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/filter/velMath.hpp b/pros/okapi/api/filter/velMath.hpp new file mode 100644 index 00000000..a02dd8f2 --- /dev/null +++ b/pros/okapi/api/filter/velMath.hpp @@ -0,0 +1,74 @@ +/* + * 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 + +#include "okapi/api/filter/composableFilter.hpp" +#include "okapi/api/units/QAngularAcceleration.hpp" +#include "okapi/api/units/QAngularSpeed.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/util/abstractTimer.hpp" +#include "okapi/api/util/logging.hpp" +#include + +namespace okapi { +class VelMath { + public: + /** + * Velocity math helper. Calculates filtered velocity. Throws a `std::invalid_argument` exception + * if `iticksPerRev` is zero. + * + * @param iticksPerRev The number of ticks per revolution (or whatever units you are using). + * @param ifilter The filter used for filtering the calculated velocity. + * @param isampleTime The minimum time between velocity measurements. + * @param ilogger The logger this instance will log to. + */ + VelMath(double iticksPerRev, + std::unique_ptr ifilter, + QTime isampleTime, + std::unique_ptr iloopDtTimer, + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + virtual ~VelMath(); + + /** + * Calculates the current velocity and acceleration. Returns the (filtered) velocity. + * + * @param inewPos The new position measurement. + * @return The new velocity estimate. + */ + virtual QAngularSpeed step(double inewPos); + + /** + * Sets ticks per revolution (or whatever units you are using). Throws a `std::invalid_argument` + * exception if iticksPerRev is zero. + * + * @param iTPR The number of ticks per revolution. + */ + virtual void setTicksPerRev(double iTPR); + + /** + * @return The last calculated velocity. + */ + virtual QAngularSpeed getVelocity() const; + + /** + * @return The last calculated acceleration. + */ + virtual QAngularAcceleration getAccel() const; + + protected: + std::shared_ptr logger; + QAngularSpeed vel{0_rpm}; + QAngularSpeed lastVel{0_rpm}; + QAngularAcceleration accel{0.0}; + double lastPos{0}; + double ticksPerRev; + + QTime sampleTime; + std::unique_ptr loopDtTimer; + std::unique_ptr filter; +}; +} // namespace okapi diff --git a/pros/okapi/api/odometry/odomMath.hpp b/pros/okapi/api/odometry/odomMath.hpp new file mode 100644 index 00000000..f32c2cd2 --- /dev/null +++ b/pros/okapi/api/odometry/odomMath.hpp @@ -0,0 +1,95 @@ +/* + * 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 + +#include "okapi/api/odometry/odomState.hpp" +#include "okapi/api/odometry/point.hpp" +#include "okapi/api/util/logging.hpp" +#include + +namespace okapi { +class OdomMath { + public: + /** + * Computes the distance from the given Odometry state to the given point. The point and the + * OdomState must be in `StateMode::FRAME_TRANSFORMATION`. + * + * @param ipoint The point. + * @param istate The Odometry state. + * @return The distance between the Odometry state and the point. + */ + static QLength computeDistanceToPoint(const Point &ipoint, const OdomState &istate); + + /** + * Computes the angle from the given Odometry state to the given point. The point and the + * OdomState must be in `StateMode::FRAME_TRANSFORMATION`. + * + * @param ipoint The point. + * @param istate The Odometry state. + * @return The angle between the Odometry state and the point. + */ + static QAngle computeAngleToPoint(const Point &ipoint, const OdomState &istate); + + /** + * Computes the distance and angle from the given Odometry state to the given point. The point and + * the OdomState must be in `StateMode::FRAME_TRANSFORMATION`. + * + * @param ipoint The point. + * @param istate The Odometry state. + * @return The distance and angle between the Odometry state and the point. + */ + static std::pair computeDistanceAndAngleToPoint(const Point &ipoint, + const OdomState &istate); + + /** + * Constraints the angle to [0,360] degrees. + * + * @param angle The input angle. + * @return The angle normalized to [0,360] degrees. + */ + static QAngle constrainAngle360(const QAngle &angle); + + /** + * Constraints the angle to [-180,180) degrees. + * + * @param angle The input angle. + * @return The angle normalized to [-180,180) degrees. + */ + static QAngle constrainAngle180(const QAngle &angle); + + private: + OdomMath(); + ~OdomMath(); + + /** + * Computes the x and y diffs in meters between the points. + * + * @param ipoint The point. + * @param istate The Odometry state. + * @return The diffs in the order `{xDiff, yDiff}`. + */ + static std::pair computeDiffs(const Point &ipoint, const OdomState &istate); + + /** + * Computes the distance between the points. + * + * @param xDiff The x-axis diff in meters. + * @param yDiff The y-axis diff in meters. + * @return The cartesian distance in meters. + */ + static double computeDistance(double xDiff, double yDiff); + + /** + * Compites the angle between the points. + * + * @param xDiff The x-axis diff in meters. + * @param yDiff The y-axis diff in meters. + * @param theta The current robot's theta in radians. + * @return The angle in radians. + */ + static double computeAngle(double xDiff, double yDiff, double theta); +}; +} // namespace okapi diff --git a/pros/okapi/api/odometry/odomState.hpp b/pros/okapi/api/odometry/odomState.hpp new file mode 100644 index 00000000..842707cf --- /dev/null +++ b/pros/okapi/api/odometry/odomState.hpp @@ -0,0 +1,57 @@ +/* + * 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 + +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/RQuantityName.hpp" +#include + +namespace okapi { +struct OdomState { + QLength x{0_m}; + QLength y{0_m}; + QAngle theta{0_deg}; + + /** + * Get a string for the current odometry state (optionally with the specified units). + * + * Examples: + * - `OdomState::str(1_m, 1_deg)`: The default (no arguments specified). + * - `OdomState::str(1_tile, 1_radian)`: distance tiles and angle radians. + * + * Throws std::domain_error if the units passed are undefined. + * + * @param idistanceUnit The units you want your distance to be in. This must be an exact, predefined QLength (such as foot, meter, inch, tile etc.). + * @param iangleUnit The units you want your angle to be in. This must be an exact, predefined QAngle (degree or radian). + * @return A string representing the state. + */ + std::string str(QLength idistanceUnit, QAngle iangleUnit) const; + + /** + * Get a string for the current odometry state (optionally with the specified units). + * + * Examples: + * - `OdomState::str(1_m, "_m", 1_deg, "_deg")`: The default (no arguments specified), prints in meters and degrees. + * - `OdomState::str(1_in, "_in", 1_deg, "_deg")` or `OdomState::str(1_in, "\"", 1_deg, "°")`: to print values in inches and degrees with different suffixes. + * - `OdomState::str(6_tile / 100, "%", 360_deg / 100, "%")` to get the distance values in % of the vex field, and angle values in % of a full rotation. + * + * @param idistanceUnit The units you want your distance to be in. The x or y position will be output in multiples of this length. + * @param distUnitName The suffix you as your distance unit. + * @param iangleUnit The units you want your angle to be in. The angle will be output in multiples of this unit. + * @param angleUnitName The suffix you want as your angle unit. + * @return A string representing the state. + */ + std::string str(QLength idistanceUnit = meter, + std::string distUnitName = "_m", + QAngle iangleUnit = degree, + std::string angleUnitName = "_deg") const; + + bool operator==(const OdomState &rhs) const; + + bool operator!=(const OdomState &rhs) const; +}; +} // namespace okapi diff --git a/pros/okapi/api/odometry/odometry.hpp b/pros/okapi/api/odometry/odometry.hpp new file mode 100644 index 00000000..823cf3c2 --- /dev/null +++ b/pros/okapi/api/odometry/odometry.hpp @@ -0,0 +1,61 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisScales.hpp" +#include "okapi/api/chassis/model/readOnlyChassisModel.hpp" +#include "okapi/api/odometry/odomState.hpp" +#include "okapi/api/odometry/stateMode.hpp" + +namespace okapi { +class Odometry { + public: + /** + * Odometry. Tracks the movement of the robot and estimates its position in coordinates + * relative to the start (assumed to be (0, 0, 0)). + */ + explicit Odometry() = default; + + virtual ~Odometry() = default; + + /** + * Sets the drive and turn scales. + */ + virtual void setScales(const ChassisScales &ichassisScales) = 0; + + /** + * Do one odometry step. + */ + virtual void step() = 0; + + /** + * Returns the current state. + * + * @param imode The mode to return the state in. + * @return The current state in the given format. + */ + virtual OdomState getState(const StateMode &imode = StateMode::FRAME_TRANSFORMATION) const = 0; + + /** + * Sets a new state to be the current state. + * + * @param istate The new state in the given format. + * @param imode The mode to treat the input state as. + */ + virtual void setState(const OdomState &istate, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION) = 0; + + /** + * @return The internal ChassisModel. + */ + virtual std::shared_ptr getModel() = 0; + + /** + * @return The internal ChassisScales. + */ + virtual ChassisScales getScales() = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/odometry/point.hpp b/pros/okapi/api/odometry/point.hpp new file mode 100644 index 00000000..c55266b5 --- /dev/null +++ b/pros/okapi/api/odometry/point.hpp @@ -0,0 +1,30 @@ +/* + * 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 + +#include "okapi/api/odometry/stateMode.hpp" +#include "okapi/api/units/QLength.hpp" + +namespace okapi { +struct Point { + QLength x{0_m}; + QLength y{0_m}; + + /** + * Computes the value of this point in `StateMode::FRAME_TRANSFORMATION`. + * + * @param imode The StateMode this Point is currently specified in. + * @return This point specified in `StateMode::FRAME_TRANSFORMATION`. + */ + Point inFT(const StateMode &imode) const { + if (imode == StateMode::FRAME_TRANSFORMATION) { + return *this; + } else { + return {y, x}; + } + } +}; +} // namespace okapi diff --git a/pros/okapi/api/odometry/stateMode.hpp b/pros/okapi/api/odometry/stateMode.hpp new file mode 100644 index 00000000..da2b6bc1 --- /dev/null +++ b/pros/okapi/api/odometry/stateMode.hpp @@ -0,0 +1,17 @@ +/* + * 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 + +namespace okapi { +/** + * The mode for the OdomState calculated by Odometry. + */ +enum class StateMode { + FRAME_TRANSFORMATION, ///< +x is forward, +y is right, 0 degrees is along +x + CARTESIAN ///< +x is right, +y is forward, 0 degrees is along +y +}; + +} // namespace okapi diff --git a/pros/okapi/api/odometry/threeEncoderOdometry.hpp b/pros/okapi/api/odometry/threeEncoderOdometry.hpp new file mode 100644 index 00000000..d4a04010 --- /dev/null +++ b/pros/okapi/api/odometry/threeEncoderOdometry.hpp @@ -0,0 +1,43 @@ +/* + * 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 + +#include "okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp" +#include "okapi/api/odometry/twoEncoderOdometry.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include + +namespace okapi { +class ThreeEncoderOdometry : public TwoEncoderOdometry { + public: + /** + * Odometry. Tracks the movement of the robot and estimates its position in coordinates + * relative to the start (assumed to be (0, 0)). + * + * @param itimeUtil The TimeUtil. + * @param imodel The chassis model for reading sensors. + * @param ichassisScales See ChassisScales docs (the middle wheel scale is the third member) + * @param iwheelVelDelta The maximum delta between wheel velocities to consider the robot as + * driving straight. + * @param ilogger The logger this instance will log to. + */ + ThreeEncoderOdometry(const TimeUtil &itimeUtil, + const std::shared_ptr &imodel, + const ChassisScales &ichassisScales, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + protected: + /** + * Does the math, side-effect free, for one odom step. + * + * @param itickDiff The tick difference from the previous step to this step. + * @param ideltaT The time difference from the previous step to this step. + * @return The newly computed OdomState. + */ + OdomState odomMathStep(const std::valarray &itickDiff, + const QTime &ideltaT) override; +}; +} // namespace okapi diff --git a/pros/okapi/api/odometry/twoEncoderOdometry.hpp b/pros/okapi/api/odometry/twoEncoderOdometry.hpp new file mode 100644 index 00000000..c733d450 --- /dev/null +++ b/pros/okapi/api/odometry/twoEncoderOdometry.hpp @@ -0,0 +1,93 @@ +/* + * 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 + +#include "okapi/api/odometry/odometry.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include +#include + +namespace okapi { +class TwoEncoderOdometry : public Odometry { + public: + /** + * TwoEncoderOdometry. Tracks the movement of the robot and estimates its position in coordinates + * relative to the start (assumed to be (0, 0, 0)). + * + * @param itimeUtil The TimeUtil. + * @param imodel The chassis model for reading sensors. + * @param ichassisScales The chassis dimensions. + * @param ilogger The logger this instance will log to. + */ + TwoEncoderOdometry(const TimeUtil &itimeUtil, + const std::shared_ptr &imodel, + const ChassisScales &ichassisScales, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + virtual ~TwoEncoderOdometry() = default; + + /** + * Sets the drive and turn scales. + */ + void setScales(const ChassisScales &ichassisScales) override; + + /** + * Do one odometry step. + */ + void step() override; + + /** + * Returns the current state. + * + * @param imode The mode to return the state in. + * @return The current state in the given format. + */ + OdomState getState(const StateMode &imode = StateMode::FRAME_TRANSFORMATION) const override; + + /** + * Sets a new state to be the current state. + * + * @param istate The new state in the given format. + * @param imode The mode to treat the input state as. + */ + void setState(const OdomState &istate, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION) override; + + /** + * @return The internal ChassisModel. + */ + std::shared_ptr getModel() override; + + /** + * @return The internal ChassisScales. + */ + ChassisScales getScales() override; + + protected: + std::shared_ptr logger; + std::unique_ptr rate; + std::unique_ptr timer; + std::shared_ptr model; + ChassisScales chassisScales; + OdomState state; + std::valarray newTicks{0, 0, 0}, tickDiff{0, 0, 0}, lastTicks{0, 0, 0}; + const std::int32_t maximumTickDiff{1000}; + + /** + * Does the math, side-effect free, for one odom step. + * + * @param itickDiff The tick difference from the previous step to this step. + * @param ideltaT The time difference from the previous step to this step. + * @return The newly computed OdomState. + */ + virtual OdomState odomMathStep(const std::valarray &itickDiff, + const QTime &ideltaT); +}; +} // namespace okapi diff --git a/pros/okapi/api/units/QAcceleration.hpp b/pros/okapi/api/units/QAcceleration.hpp new file mode 100644 index 00000000..50f7193c --- /dev/null +++ b/pros/okapi/api/units/QAcceleration.hpp @@ -0,0 +1,36 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 1, -2, 0, QAcceleration) + +constexpr QAcceleration mps2 = meter / (second * second); +constexpr QAcceleration G = 9.80665 * mps2; + +inline namespace literals { +constexpr QAcceleration operator"" _mps2(long double x) { + return QAcceleration(x); +} +constexpr QAcceleration operator"" _mps2(unsigned long long int x) { + return QAcceleration(static_cast(x)); +} +constexpr QAcceleration operator"" _G(long double x) { + return static_cast(x) * G; +} +constexpr QAcceleration operator"" _G(unsigned long long int x) { + return static_cast(x) * G; +} +} // namespace literals +} // namespace okapi diff --git a/pros/okapi/api/units/QAngle.hpp b/pros/okapi/api/units/QAngle.hpp new file mode 100644 index 00000000..2e80b4d9 --- /dev/null +++ b/pros/okapi/api/units/QAngle.hpp @@ -0,0 +1,35 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/RQuantity.hpp" +#include + +namespace okapi { +QUANTITY_TYPE(0, 0, 0, 1, QAngle) + +constexpr QAngle radian(1.0); +constexpr QAngle degree = static_cast(2_pi / 360.0) * radian; + +inline namespace literals { +constexpr QAngle operator"" _rad(long double x) { + return QAngle(x); +} +constexpr QAngle operator"" _rad(unsigned long long int x) { + return QAngle(static_cast(x)); +} +constexpr QAngle operator"" _deg(long double x) { + return static_cast(x) * degree; +} +constexpr QAngle operator"" _deg(unsigned long long int x) { + return static_cast(x) * degree; +} +} // namespace literals +} // namespace okapi diff --git a/pros/okapi/api/units/QAngularAcceleration.hpp b/pros/okapi/api/units/QAngularAcceleration.hpp new file mode 100644 index 00000000..487acbf8 --- /dev/null +++ b/pros/okapi/api/units/QAngularAcceleration.hpp @@ -0,0 +1,16 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 0, -2, 1, QAngularAcceleration) +} diff --git a/pros/okapi/api/units/QAngularJerk.hpp b/pros/okapi/api/units/QAngularJerk.hpp new file mode 100644 index 00000000..c3fd6c7f --- /dev/null +++ b/pros/okapi/api/units/QAngularJerk.hpp @@ -0,0 +1,16 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 0, -3, 1, QAngularJerk) +} diff --git a/pros/okapi/api/units/QAngularSpeed.hpp b/pros/okapi/api/units/QAngularSpeed.hpp new file mode 100644 index 00000000..30b80523 --- /dev/null +++ b/pros/okapi/api/units/QAngularSpeed.hpp @@ -0,0 +1,39 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QFrequency.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 0, -1, 1, QAngularSpeed) + +constexpr QAngularSpeed radps = radian / second; +constexpr QAngularSpeed rpm = (360 * degree) / minute; +constexpr QAngularSpeed cps = (0.01 * degree) / second; // centidegree per second + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +static QAngularSpeed convertHertzToRadPerSec(QFrequency in) { + return (in.convert(Hz) / 2_pi) * radps; +} +#pragma GCC diagnostic pop + +inline namespace literals { +constexpr QAngularSpeed operator"" _rpm(long double x) { + return x * rpm; +} +constexpr QAngularSpeed operator"" _rpm(unsigned long long int x) { + return static_cast(x) * rpm; +} +} // namespace literals +} // namespace okapi diff --git a/pros/okapi/api/units/QArea.hpp b/pros/okapi/api/units/QArea.hpp new file mode 100644 index 00000000..ed487220 --- /dev/null +++ b/pros/okapi/api/units/QArea.hpp @@ -0,0 +1,26 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 2, 0, 0, QArea) + +constexpr QArea kilometer2 = kilometer * kilometer; +constexpr QArea meter2 = meter * meter; +constexpr QArea decimeter2 = decimeter * decimeter; +constexpr QArea centimeter2 = centimeter * centimeter; +constexpr QArea millimeter2 = millimeter * millimeter; +constexpr QArea inch2 = inch * inch; +constexpr QArea foot2 = foot * foot; +constexpr QArea mile2 = mile * mile; +} // namespace okapi diff --git a/pros/okapi/api/units/QForce.hpp b/pros/okapi/api/units/QForce.hpp new file mode 100644 index 00000000..8439fb7b --- /dev/null +++ b/pros/okapi/api/units/QForce.hpp @@ -0,0 +1,43 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QAcceleration.hpp" +#include "okapi/api/units/QMass.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(1, 1, -2, 0, QForce) + +constexpr QForce newton = (kg * meter) / (second * second); +constexpr QForce poundforce = pound * G; +constexpr QForce kilopond = kg * G; + +inline namespace literals { +constexpr QForce operator"" _n(long double x) { + return QForce(x); +} +constexpr QForce operator"" _n(unsigned long long int x) { + return QForce(static_cast(x)); +} +constexpr QForce operator"" _lbf(long double x) { + return static_cast(x) * poundforce; +} +constexpr QForce operator"" _lbf(unsigned long long int x) { + return static_cast(x) * poundforce; +} +constexpr QForce operator"" _kp(long double x) { + return static_cast(x) * kilopond; +} +constexpr QForce operator"" _kp(unsigned long long int x) { + return static_cast(x) * kilopond; +} +} // namespace literals +} // namespace okapi diff --git a/pros/okapi/api/units/QFrequency.hpp b/pros/okapi/api/units/QFrequency.hpp new file mode 100644 index 00000000..9cd29911 --- /dev/null +++ b/pros/okapi/api/units/QFrequency.hpp @@ -0,0 +1,27 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 0, -1, 0, QFrequency) + +constexpr QFrequency Hz(1.0); + +inline namespace literals { +constexpr QFrequency operator"" _Hz(long double x) { + return QFrequency(x); +} +constexpr QFrequency operator"" _Hz(unsigned long long int x) { + return QFrequency(static_cast(x)); +} +} // namespace literals +} // namespace okapi diff --git a/pros/okapi/api/units/QJerk.hpp b/pros/okapi/api/units/QJerk.hpp new file mode 100644 index 00000000..709df1ed --- /dev/null +++ b/pros/okapi/api/units/QJerk.hpp @@ -0,0 +1,18 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 1, -3, 0, QJerk) +} diff --git a/pros/okapi/api/units/QLength.hpp b/pros/okapi/api/units/QLength.hpp new file mode 100644 index 00000000..c102fcb9 --- /dev/null +++ b/pros/okapi/api/units/QLength.hpp @@ -0,0 +1,84 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 1, 0, 0, QLength) + +constexpr QLength meter(1.0); // SI base unit +constexpr QLength decimeter = meter / 10; +constexpr QLength centimeter = meter / 100; +constexpr QLength millimeter = meter / 1000; +constexpr QLength kilometer = 1000 * meter; +constexpr QLength inch = 2.54 * centimeter; +constexpr QLength foot = 12 * inch; +constexpr QLength yard = 3 * foot; +constexpr QLength mile = 5280 * foot; +constexpr QLength tile = 24 * inch; + +inline namespace literals { +constexpr QLength operator"" _mm(long double x) { + return static_cast(x) * millimeter; +} +constexpr QLength operator"" _cm(long double x) { + return static_cast(x) * centimeter; +} +constexpr QLength operator"" _m(long double x) { + return static_cast(x) * meter; +} +constexpr QLength operator"" _km(long double x) { + return static_cast(x) * kilometer; +} +constexpr QLength operator"" _mi(long double x) { + return static_cast(x) * mile; +} +constexpr QLength operator"" _yd(long double x) { + return static_cast(x) * yard; +} +constexpr QLength operator"" _ft(long double x) { + return static_cast(x) * foot; +} +constexpr QLength operator"" _in(long double x) { + return static_cast(x) * inch; +} +constexpr QLength operator"" _tile(long double x) { + return static_cast(x) * tile; +} +constexpr QLength operator"" _mm(unsigned long long int x) { + return static_cast(x) * millimeter; +} +constexpr QLength operator"" _cm(unsigned long long int x) { + return static_cast(x) * centimeter; +} +constexpr QLength operator"" _m(unsigned long long int x) { + return static_cast(x) * meter; +} +constexpr QLength operator"" _km(unsigned long long int x) { + return static_cast(x) * kilometer; +} +constexpr QLength operator"" _mi(unsigned long long int x) { + return static_cast(x) * mile; +} +constexpr QLength operator"" _yd(unsigned long long int x) { + return static_cast(x) * yard; +} +constexpr QLength operator"" _ft(unsigned long long int x) { + return static_cast(x) * foot; +} +constexpr QLength operator"" _in(unsigned long long int x) { + return static_cast(x) * inch; +} +constexpr QLength operator"" _tile(unsigned long long int x) { + return static_cast(x) * tile; +} +} // namespace literals +} // namespace okapi diff --git a/pros/okapi/api/units/QMass.hpp b/pros/okapi/api/units/QMass.hpp new file mode 100644 index 00000000..0501cbdf --- /dev/null +++ b/pros/okapi/api/units/QMass.hpp @@ -0,0 +1,62 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(1, 0, 0, 0, QMass) + +constexpr QMass kg(1.0); // SI base unit +constexpr QMass gramme = 0.001 * kg; +constexpr QMass tonne = 1000 * kg; +constexpr QMass ounce = 0.028349523125 * kg; +constexpr QMass pound = 16 * ounce; +constexpr QMass stone = 14 * pound; + +inline namespace literals { +constexpr QMass operator"" _kg(long double x) { + return QMass(x); +} +constexpr QMass operator"" _g(long double x) { + return static_cast(x) * gramme; +} +constexpr QMass operator"" _t(long double x) { + return static_cast(x) * tonne; +} +constexpr QMass operator"" _oz(long double x) { + return static_cast(x) * ounce; +} +constexpr QMass operator"" _lb(long double x) { + return static_cast(x) * pound; +} +constexpr QMass operator"" _st(long double x) { + return static_cast(x) * stone; +} +constexpr QMass operator"" _kg(unsigned long long int x) { + return QMass(static_cast(x)); +} +constexpr QMass operator"" _g(unsigned long long int x) { + return static_cast(x) * gramme; +} +constexpr QMass operator"" _t(unsigned long long int x) { + return static_cast(x) * tonne; +} +constexpr QMass operator"" _oz(unsigned long long int x) { + return static_cast(x) * ounce; +} +constexpr QMass operator"" _lb(unsigned long long int x) { + return static_cast(x) * pound; +} +constexpr QMass operator"" _st(unsigned long long int x) { + return static_cast(x) * stone; +} +} // namespace literals +} // namespace okapi diff --git a/pros/okapi/api/units/QPressure.hpp b/pros/okapi/api/units/QPressure.hpp new file mode 100644 index 00000000..23fa384f --- /dev/null +++ b/pros/okapi/api/units/QPressure.hpp @@ -0,0 +1,44 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QAcceleration.hpp" +#include "okapi/api/units/QArea.hpp" +#include "okapi/api/units/QMass.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(1, -1, -2, 0, QPressure) + +constexpr QPressure pascal(1.0); +constexpr QPressure bar = 100000 * pascal; +constexpr QPressure psi = pound * G / inch2; + +inline namespace literals { +constexpr QPressure operator"" _Pa(long double x) { + return QPressure(x); +} +constexpr QPressure operator"" _Pa(unsigned long long int x) { + return QPressure(static_cast(x)); +} +constexpr QPressure operator"" _bar(long double x) { + return static_cast(x) * bar; +} +constexpr QPressure operator"" _bar(unsigned long long int x) { + return static_cast(x) * bar; +} +constexpr QPressure operator"" _psi(long double x) { + return static_cast(x) * psi; +} +constexpr QPressure operator"" _psi(unsigned long long int x) { + return static_cast(x) * psi; +} +} // namespace literals +} // namespace okapi diff --git a/pros/okapi/api/units/QSpeed.hpp b/pros/okapi/api/units/QSpeed.hpp new file mode 100644 index 00000000..d8a19760 --- /dev/null +++ b/pros/okapi/api/units/QSpeed.hpp @@ -0,0 +1,43 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 1, -1, 0, QSpeed) + +constexpr QSpeed mps = meter / second; +constexpr QSpeed miph = mile / hour; +constexpr QSpeed kmph = kilometer / hour; + +inline namespace literals { +constexpr QSpeed operator"" _mps(long double x) { + return static_cast(x) * mps; +} +constexpr QSpeed operator"" _miph(long double x) { + return static_cast(x) * mile / hour; +} +constexpr QSpeed operator"" _kmph(long double x) { + return static_cast(x) * kilometer / hour; +} +constexpr QSpeed operator"" _mps(unsigned long long int x) { + return static_cast(x) * mps; +} +constexpr QSpeed operator"" _miph(unsigned long long int x) { + return static_cast(x) * mile / hour; +} +constexpr QSpeed operator"" _kmph(unsigned long long int x) { + return static_cast(x) * kilometer / hour; +} +} // namespace literals +} // namespace okapi diff --git a/pros/okapi/api/units/QTime.hpp b/pros/okapi/api/units/QTime.hpp new file mode 100644 index 00000000..be9d824b --- /dev/null +++ b/pros/okapi/api/units/QTime.hpp @@ -0,0 +1,55 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 0, 1, 0, QTime) + +constexpr QTime second(1.0); // SI base unit +constexpr QTime millisecond = second / 1000; +constexpr QTime minute = 60 * second; +constexpr QTime hour = 60 * minute; +constexpr QTime day = 24 * hour; + +inline namespace literals { +constexpr QTime operator"" _s(long double x) { + return QTime(x); +} +constexpr QTime operator"" _ms(long double x) { + return static_cast(x) * millisecond; +} +constexpr QTime operator"" _min(long double x) { + return static_cast(x) * minute; +} +constexpr QTime operator"" _h(long double x) { + return static_cast(x) * hour; +} +constexpr QTime operator"" _day(long double x) { + return static_cast(x) * day; +} +constexpr QTime operator"" _s(unsigned long long int x) { + return QTime(static_cast(x)); +} +constexpr QTime operator"" _ms(unsigned long long int x) { + return static_cast(x) * millisecond; +} +constexpr QTime operator"" _min(unsigned long long int x) { + return static_cast(x) * minute; +} +constexpr QTime operator"" _h(unsigned long long int x) { + return static_cast(x) * hour; +} +constexpr QTime operator"" _day(unsigned long long int x) { + return static_cast(x) * day; +} +} // namespace literals +} // namespace okapi diff --git a/pros/okapi/api/units/QTorque.hpp b/pros/okapi/api/units/QTorque.hpp new file mode 100644 index 00000000..b7b6c717 --- /dev/null +++ b/pros/okapi/api/units/QTorque.hpp @@ -0,0 +1,43 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QForce.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(1, 2, -2, 0, QTorque) + +constexpr QTorque newtonMeter = newton * meter; +constexpr QTorque footPound = 1.355817948 * newtonMeter; +constexpr QTorque inchPound = 0.083333333 * footPound; + +inline namespace literals { +constexpr QTorque operator"" _nM(long double x) { + return QTorque(x); +} +constexpr QTorque operator"" _nM(unsigned long long int x) { + return QTorque(static_cast(x)); +} +constexpr QTorque operator"" _inLb(long double x) { + return static_cast(x) * inchPound; +} +constexpr QTorque operator"" _inLb(unsigned long long int x) { + return static_cast(x) * inchPound; +} +constexpr QTorque operator"" _ftLb(long double x) { + return static_cast(x) * footPound; +} +constexpr QTorque operator"" _ftLb(unsigned long long int x) { + return static_cast(x) * footPound; +} +} // namespace literals +} // namespace okapi diff --git a/pros/okapi/api/units/QVolume.hpp b/pros/okapi/api/units/QVolume.hpp new file mode 100644 index 00000000..1c76b9cb --- /dev/null +++ b/pros/okapi/api/units/QVolume.hpp @@ -0,0 +1,28 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include "okapi/api/units/QArea.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 3, 0, 0, QVolume) + +constexpr QVolume kilometer3 = kilometer2 * kilometer; +constexpr QVolume meter3 = meter2 * meter; +constexpr QVolume decimeter3 = decimeter2 * decimeter; +constexpr QVolume centimeter3 = centimeter2 * centimeter; +constexpr QVolume millimeter3 = millimeter2 * millimeter; +constexpr QVolume inch3 = inch2 * inch; +constexpr QVolume foot3 = foot2 * foot; +constexpr QVolume mile3 = mile2 * mile; +constexpr QVolume litre = decimeter3; +} // namespace okapi diff --git a/pros/okapi/api/units/RQuantity.hpp b/pros/okapi/api/units/RQuantity.hpp new file mode 100644 index 00000000..2232ebcc --- /dev/null +++ b/pros/okapi/api/units/RQuantity.hpp @@ -0,0 +1,419 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * 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 + +#include +#include + +namespace okapi { +template +class RQuantity { + public: + explicit constexpr RQuantity() : value(0.0) { + } + + explicit constexpr RQuantity(double val) : value(val) { + } + + explicit constexpr RQuantity(long double val) : value(static_cast(val)) { + } + + // The intrinsic operations for a quantity with a unit is addition and subtraction + constexpr RQuantity const &operator+=(const RQuantity &rhs) { + value += rhs.value; + return *this; + } + + constexpr RQuantity const &operator-=(const RQuantity &rhs) { + value -= rhs.value; + return *this; + } + + constexpr RQuantity operator-() { + return RQuantity(value * -1); + } + + constexpr RQuantity const &operator*=(const double rhs) { + value *= rhs; + return *this; + } + + constexpr RQuantity const &operator/=(const double rhs) { + value /= rhs; + return *this; + } + + // Returns the value of the quantity in multiples of the specified unit + constexpr double convert(const RQuantity &rhs) const { + return value / rhs.value; + } + + // returns the raw value of the quantity (should not be used) + constexpr double getValue() const { + return value; + } + + constexpr RQuantity abs() const { + return RQuantity(std::fabs(value)); + } + + constexpr RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>> + sqrt() const { + return RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>>(std::sqrt(value)); + } + + private: + double value; +}; + +// Predefined (physical unit) quantity types: +// ------------------------------------------ +#define QUANTITY_TYPE(_Mdim, _Ldim, _Tdim, _Adim, name) \ + typedef RQuantity, std::ratio<_Ldim>, std::ratio<_Tdim>, std::ratio<_Adim>> \ + name; + +// Unitless +QUANTITY_TYPE(0, 0, 0, 0, Number) +constexpr Number number(1.0); + +// Standard arithmetic operators: +// ------------------------------ +template +constexpr RQuantity operator+(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(lhs.getValue() + rhs.getValue()); +} +template +constexpr RQuantity operator-(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(lhs.getValue() - rhs.getValue()); +} +template +constexpr RQuantity, + std::ratio_add, + std::ratio_add, + std::ratio_add> +operator*(const RQuantity &lhs, const RQuantity &rhs) { + return RQuantity, + std::ratio_add, + std::ratio_add, + std::ratio_add>(lhs.getValue() * rhs.getValue()); +} +template +constexpr RQuantity operator*(const double &lhs, const RQuantity &rhs) { + return RQuantity(lhs * rhs.getValue()); +} +template +constexpr RQuantity operator*(const RQuantity &lhs, const double &rhs) { + return RQuantity(lhs.getValue() * rhs); +} +template +constexpr RQuantity, + std::ratio_subtract, + std::ratio_subtract, + std::ratio_subtract> +operator/(const RQuantity &lhs, const RQuantity &rhs) { + return RQuantity, + std::ratio_subtract, + std::ratio_subtract, + std::ratio_subtract>(lhs.getValue() / rhs.getValue()); +} +template +constexpr RQuantity, M>, + std::ratio_subtract, L>, + std::ratio_subtract, T>, + std::ratio_subtract, A>> +operator/(const double &x, const RQuantity &rhs) { + return RQuantity, M>, + std::ratio_subtract, L>, + std::ratio_subtract, T>, + std::ratio_subtract, A>>(x / rhs.getValue()); +} +template +constexpr RQuantity operator/(const RQuantity &rhs, const double &x) { + return RQuantity(rhs.getValue() / x); +} + +// Comparison operators for quantities: +// ------------------------------------ +template +constexpr bool operator==(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() == rhs.getValue()); +} +template +constexpr bool operator!=(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() != rhs.getValue()); +} +template +constexpr bool operator<=(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() <= rhs.getValue()); +} +template +constexpr bool operator>=(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() >= rhs.getValue()); +} +template +constexpr bool operator<(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() < rhs.getValue()); +} +template +constexpr bool operator>(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() > rhs.getValue()); +} + +// Common math functions: +// ------------------------------ + +template +constexpr RQuantity abs(const RQuantity &rhs) { + return RQuantity(std::abs(rhs.getValue())); +} + +template +constexpr RQuantity, + std::ratio_multiply, + std::ratio_multiply, + std::ratio_multiply> +pow(const RQuantity &lhs) { + return RQuantity, + std::ratio_multiply, + std::ratio_multiply, + std::ratio_multiply>(std::pow(lhs.getValue(), double(R::num) / R::den)); +} + +template +constexpr RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>> +pow(const RQuantity &lhs) { + return RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>>(std::pow(lhs.getValue(), R)); +} + +template +constexpr RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>> +root(const RQuantity &lhs) { + return RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>>(std::pow(lhs.getValue(), 1.0 / R)); +} + +template +constexpr RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>> +sqrt(const RQuantity &rhs) { + return RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>>(std::sqrt(rhs.getValue())); +} + +template +constexpr RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>> +cbrt(const RQuantity &rhs) { + return RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>>(std::cbrt(rhs.getValue())); +} + +template +constexpr RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>> +square(const RQuantity &rhs) { + return RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>>(std::pow(rhs.getValue(), 2)); +} + +template +constexpr RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>> +cube(const RQuantity &rhs) { + return RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>>(std::pow(rhs.getValue(), 3)); +} + +template +constexpr RQuantity hypot(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::hypot(lhs.getValue(), rhs.getValue())); +} + +template +constexpr RQuantity mod(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::fmod(lhs.getValue(), rhs.getValue())); +} + +template +constexpr RQuantity copysign(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::copysign(lhs.getValue(), rhs.getValue())); +} + +template +constexpr RQuantity ceil(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::ceil(lhs.getValue() / rhs.getValue()) * rhs.getValue()); +} + +template +constexpr RQuantity floor(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::floor(lhs.getValue() / rhs.getValue()) * rhs.getValue()); +} + +template +constexpr RQuantity trunc(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::trunc(lhs.getValue() / rhs.getValue()) * rhs.getValue()); +} + +template +constexpr RQuantity round(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::round(lhs.getValue() / rhs.getValue()) * rhs.getValue()); +} + +// Common trig functions: +// ------------------------------ + +constexpr Number +sin(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::sin(rhs.getValue())); +} + +constexpr Number +cos(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::cos(rhs.getValue())); +} + +constexpr Number +tan(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::tan(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +asin(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::asin(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +acos(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::acos(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +atan(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::atan(rhs.getValue())); +} + +constexpr Number +sinh(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::sinh(rhs.getValue())); +} + +constexpr Number +cosh(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::cosh(rhs.getValue())); +} + +constexpr Number +tanh(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::tanh(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +asinh(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::asinh(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +acosh(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::acosh(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +atanh(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::atanh(rhs.getValue())); +} + +template +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +atan2(const RQuantity &lhs, const RQuantity &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::atan2(lhs.getValue(), rhs.getValue())); +} + +inline namespace literals { +constexpr long double operator"" _pi(long double x) { + return static_cast(x) * 3.1415926535897932384626433832795; +} +constexpr long double operator"" _pi(unsigned long long int x) { + return static_cast(x) * 3.1415926535897932384626433832795; +} +} // namespace literals +} // namespace okapi + +// Conversion macro, which utilizes the string literals +#define ConvertTo(_x, _y) (_x).convert(1.0_##_y) diff --git a/pros/okapi/api/units/RQuantityName.hpp b/pros/okapi/api/units/RQuantityName.hpp new file mode 100644 index 00000000..28e62984 --- /dev/null +++ b/pros/okapi/api/units/RQuantityName.hpp @@ -0,0 +1,46 @@ +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include +#include +#include + +#pragma once + +namespace okapi { + +/** +* Returns a short name for a unit. +* For example: `str(1_ft)` will return "ft", so will `1 * foot` or `0.3048_m`. +* Throws std::domain_error when `q` is a unit not defined in this function. +* +* @param q Your unit. Currently only QLength and QAngle are supported. +* @return The short string suffix for that unit. +*/ +template std::string getShortUnitName(QType q) { + const std::unordered_map> shortNameMap = + {{typeid(meter), + { + {meter.getValue(), "m"}, + {decimeter.getValue(), "dm"}, + {centimeter.getValue(), "cm"}, + {millimeter.getValue(), "mm"}, + {kilometer.getValue(), "km"}, + {inch.getValue(), "in"}, + {foot.getValue(), "ft"}, + {yard.getValue(), "yd"}, + {mile.getValue(), "mi"}, + {tile.getValue(), "tile"}, + }}, + {typeid(degree), {{degree.getValue(), "deg"}, {radian.getValue(), "rad"}}}}; + + try { + return shortNameMap.at(typeid(q)).at(q.getValue()); + } catch (const std::out_of_range &e) { + throw std::domain_error( + "You have requested the shortname of an unknown unit somewhere (likely odometry strings). " + "Shortname for provided unit is unspecified. You can override this function to add more " + "names or manually specify the name instead."); + } +} +} // namespace okapi diff --git a/pros/okapi/api/util/abstractRate.hpp b/pros/okapi/api/util/abstractRate.hpp new file mode 100644 index 00000000..987b3149 --- /dev/null +++ b/pros/okapi/api/util/abstractRate.hpp @@ -0,0 +1,41 @@ +/* + * 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 + +#include "okapi/api/coreProsAPI.hpp" +#include "okapi/api/units/QFrequency.hpp" +#include "okapi/api/units/QTime.hpp" + +namespace okapi { +class AbstractRate { + public: + virtual ~AbstractRate(); + + /** + * Delay the current task such that it runs at the given frequency. The first delay will run for + * 1000/(ihz). Subsequent delays will adjust according to the previous runtime of the task. + * + * @param ihz the frequency + */ + virtual void delay(QFrequency ihz) = 0; + + /** + * Delay the current task until itime has passed. This method can be used by periodic tasks to + * ensure a consistent execution frequency. + * + * @param itime the time period + */ + virtual void delayUntil(QTime itime) = 0; + + /** + * Delay the current task until ims milliseconds have passed. This method can be used by + * periodic tasks to ensure a consistent execution frequency. + * + * @param ims the time period + */ + virtual void delayUntil(uint32_t ims) = 0; +}; +} // namespace okapi diff --git a/pros/okapi/api/util/abstractTimer.hpp b/pros/okapi/api/util/abstractTimer.hpp new file mode 100644 index 00000000..db9a488e --- /dev/null +++ b/pros/okapi/api/util/abstractTimer.hpp @@ -0,0 +1,125 @@ +/* + * 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 + +#include "okapi/api/units/QFrequency.hpp" +#include "okapi/api/units/QTime.hpp" + +namespace okapi { +class AbstractTimer { + public: + /** + * A Timer base class which implements its methods in terms of millis(). + * + * @param ifirstCalled the current time + */ + explicit AbstractTimer(QTime ifirstCalled); + + virtual ~AbstractTimer(); + + /** + * Returns the current time in units of QTime. + * + * @return the current time + */ + virtual QTime millis() const = 0; + + /** + * Returns the time passed in ms since the previous call of this function. + * + * @return The time passed in ms since the previous call of this function + */ + virtual QTime getDt(); + + /** + * Returns the time passed in ms since the previous call of getDt(). Does not change the time + * recorded by getDt(). + * + * @return The time passed in ms since the previous call of getDt() + */ + virtual QTime readDt() const; + + /** + * Returns the time the timer was first constructed. + * + * @return The time the timer was first constructed + */ + virtual QTime getStartingTime() const; + + /** + * Returns the time since the timer was first constructed. + * + * @return The time since the timer was first constructed + */ + virtual QTime getDtFromStart() const; + + /** + * Place a time marker. Placing another marker will overwrite the previous one. + */ + virtual void placeMark(); + + /** + * Clears the marker. + * + * @return The old marker + */ + virtual QTime clearMark(); + + /** + * Place a hard time marker. Placing another hard marker will not overwrite the previous one; + * instead, call clearHardMark() and then place another. + */ + virtual void placeHardMark(); + + /** + * Clears the hard marker. + * + * @return The old hard marker + */ + virtual QTime clearHardMark(); + + /** + * Returns the time since the time marker. Returns 0_ms if there is no marker. + * + * @return The time since the time marker + */ + virtual QTime getDtFromMark() const; + + /** + * Returns the time since the hard time marker. Returns 0_ms if there is no hard marker set. + * + * @return The time since the hard time marker + */ + virtual QTime getDtFromHardMark() const; + + /** + * Returns true when the input time period has passed, then resets. Meant to be used in loops + * to run an action every time period without blocking. + * + * @param time time period + * @return true when the input time period has passed, false after reading true until the + * period has passed again + */ + virtual bool repeat(QTime time); + + /** + * Returns true when the input time period has passed, then resets. Meant to be used in loops + * to run an action every time period without blocking. + * + * @param frequency the repeat frequency + * @return true when the input time period has passed, false after reading true until the + * period has passed again + */ + virtual bool repeat(QFrequency frequency); + + protected: + QTime firstCalled; + QTime lastCalled; + QTime mark; + QTime hardMark; + QTime repeatMark; +}; +} // namespace okapi diff --git a/pros/okapi/api/util/logging.hpp b/pros/okapi/api/util/logging.hpp new file mode 100644 index 00000000..b3a6c303 --- /dev/null +++ b/pros/okapi/api/util/logging.hpp @@ -0,0 +1,192 @@ +/* + * 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 + +#include "okapi/api/coreProsAPI.hpp" +#include "okapi/api/util/abstractTimer.hpp" +#include "okapi/api/util/mathUtil.hpp" +#include +#include + +#if defined(THREADS_STD) +#else +#include "okapi/impl/util/timer.hpp" +#endif + +#define LOG_DEBUG(msg) logger->debug([=]() { return msg; }) +#define LOG_INFO(msg) logger->info([=]() { return msg; }) +#define LOG_WARN(msg) logger->warn([=]() { return msg; }) +#define LOG_ERROR(msg) logger->error([=]() { return msg; }) + +#define LOG_DEBUG_S(msg) LOG_DEBUG(std::string(msg)) +#define LOG_INFO_S(msg) LOG_INFO(std::string(msg)) +#define LOG_WARN_S(msg) LOG_WARN(std::string(msg)) +#define LOG_ERROR_S(msg) LOG_ERROR(std::string(msg)) + +namespace okapi { +class Logger { + public: + enum class LogLevel { + debug = 4, ///< debug + info = 3, ///< info + warn = 2, ///< warn + error = 1, ///< error + off = 0 ///< off + }; + + /** + * A logger that does nothing. + */ + Logger() noexcept; + + /** + * A logger that opens the input file by name. If the file contains `/ser/`, the file will be + * opened in write mode. Otherwise, the file will be opened in append mode. The file will be + * closed when the logger is destructed. + * + * @param itimer A timer used to get the current time for log statements. + * @param ifileName The name of the log file to open. + * @param ilevel The log level. Log statements more verbose than this level will be disabled. + */ + Logger(std::unique_ptr itimer, + std::string_view ifileName, + const LogLevel &ilevel) noexcept; + + /** + * A logger that uses an existing file handle. The file will be closed when the logger is + * destructed. + * + * @param itimer A timer used to get the current time for log statements. + * @param ifile The log file to open. Will be closed by the logger! + * @param ilevel The log level. Log statements more verbose than this level will be disabled. + */ + Logger(std::unique_ptr itimer, FILE *ifile, const LogLevel &ilevel) noexcept; + + ~Logger(); + + constexpr bool isDebugLevelEnabled() const noexcept { + return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::debug); + } + + template void debug(T ilazyMessage) noexcept { + if (isDebugLevelEnabled() && logfile && timer) { + std::scoped_lock lock(logfileMutex); + fprintf(logfile, + "%ld (%s) DEBUG: %s\n", + static_cast(timer->millis().convert(millisecond)), + CrossplatformThread::getName().c_str(), + ilazyMessage().c_str()); + } + } + + constexpr bool isInfoLevelEnabled() const noexcept { + return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::info); + } + + template void info(T ilazyMessage) noexcept { + if (isInfoLevelEnabled() && logfile && timer) { + std::scoped_lock lock(logfileMutex); + fprintf(logfile, + "%ld (%s) INFO: %s\n", + static_cast(timer->millis().convert(millisecond)), + CrossplatformThread::getName().c_str(), + ilazyMessage().c_str()); + } + } + + constexpr bool isWarnLevelEnabled() const noexcept { + return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::warn); + } + + template void warn(T ilazyMessage) noexcept { + if (isWarnLevelEnabled() && logfile && timer) { + std::scoped_lock lock(logfileMutex); + fprintf(logfile, + "%ld (%s) WARN: %s\n", + static_cast(timer->millis().convert(millisecond)), + CrossplatformThread::getName().c_str(), + ilazyMessage().c_str()); + } + } + + constexpr bool isErrorLevelEnabled() const noexcept { + return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::error); + } + + template void error(T ilazyMessage) noexcept { + if (isErrorLevelEnabled() && logfile && timer) { + std::scoped_lock lock(logfileMutex); + fprintf(logfile, + "%ld (%s) ERROR: %s\n", + static_cast(timer->millis().convert(millisecond)), + CrossplatformThread::getName().c_str(), + ilazyMessage().c_str()); + } + } + + /** + * Closes the connection to the log file. + */ + constexpr void close() noexcept { + if (logfile) { + fclose(logfile); + logfile = nullptr; + } + } + + /** + * @return The default logger. + */ + static std::shared_ptr getDefaultLogger(); + + /** + * Sets a new default logger. OkapiLib classes use the default logger unless given another logger + * in their constructor. + * + * @param ilogger The new logger instance. + */ + static void setDefaultLogger(std::shared_ptr ilogger); + + private: + const std::unique_ptr timer; + const LogLevel logLevel; + FILE *logfile; + CrossplatformMutex logfileMutex; + + static bool isSerialStream(std::string_view filename); +}; + +extern std::shared_ptr defaultLogger; + +struct DefaultLoggerInitializer { + DefaultLoggerInitializer() { + if (count++ == 0) { + init(); + } + } + ~DefaultLoggerInitializer() { + if (--count == 0) { + cleanup(); + } + } + + static int count; + + static void init() { +#if defined(THREADS_STD) + defaultLogger = std::make_shared(); +#else + defaultLogger = + std::make_shared(std::make_unique(), "/ser/sout", Logger::LogLevel::warn); +#endif + } + + static void cleanup() { + } +}; + +static DefaultLoggerInitializer defaultLoggerInitializer; // NOLINT(cert-err58-cpp) +} // namespace okapi diff --git a/pros/okapi/api/util/mathUtil.hpp b/pros/okapi/api/util/mathUtil.hpp new file mode 100644 index 00000000..424a8623 --- /dev/null +++ b/pros/okapi/api/util/mathUtil.hpp @@ -0,0 +1,255 @@ +/* + * 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 + +#include "okapi/api/device/motor/abstractMotor.hpp" +#include +#include +#include +#include + +namespace okapi { +/** + * Converts inches to millimeters. + */ +static constexpr double inchToMM = 25.4; + +/** + * Converts millimeters to inches. + */ +static constexpr double mmToInch = 0.0393700787; + +/** + * Converts degrees to radians. + */ +static constexpr double degreeToRadian = 0.01745329252; + +/** + * Converts radians to degrees. + */ +static constexpr double radianToDegree = 57.2957795; + +/** + * The ticks per rotation of the 393 IME with torque gearing. + */ +static constexpr double imeTorqueTPR = 627.2; + +/** + * The ticks per rotation of the 393 IME with speed gearing. + */ +static constexpr std::int32_t imeSpeedTPR = 392; + +/** + * The ticks per rotation of the 393 IME with turbo gearing. + */ +static constexpr double imeTurboTPR = 261.333; + +/** + * The ticks per rotation of the 269 IME. + */ +static constexpr double ime269TPR = 240.448; + +/** + * The ticks per rotation of the V5 motor with a red gearset. + */ +static constexpr std::int32_t imev5RedTPR = 1800; + +/** + * The ticks per rotation of the V5 motor with a green gearset. + */ +static constexpr std::int32_t imev5GreenTPR = 900; + +/** + * The ticks per rotation of the V5 motor with a blue gearset. + */ +static constexpr std::int32_t imev5BlueTPR = 300; + +/** + * The ticks per rotation of the red quadrature encoders. + */ +static constexpr std::int32_t quadEncoderTPR = 360; + +/** + * The value of pi. + */ +static constexpr double pi = 3.1415926535897932; + +/** + * The value of pi divided by 2. + */ +static constexpr double pi2 = 1.5707963267948966; + +/** + * The conventional value of gravity of Earth. + */ +static constexpr double gravity = 9.80665; + +/** + * Same as PROS_ERR. + */ +static constexpr auto OKAPI_PROS_ERR = INT32_MAX; + +/** + * Same as PROS_ERR_F. + */ +static constexpr auto OKAPI_PROS_ERR_F = INFINITY; + +/** + * The maximum voltage that can be sent to V5 motors. + */ +static constexpr double v5MotorMaxVoltage = 12000; + +/** + * The polling frequency of V5 motors in milliseconds. + */ +static constexpr std::int8_t motorUpdateRate = 10; + +/** + * The polling frequency of the ADI ports in milliseconds. + */ +static constexpr std::int8_t adiUpdateRate = 10; + +/** + * Integer power function. Computes `base^expo`. + * + * @param base The base. + * @param expo The exponent. + * @return `base^expo`. + */ +constexpr double ipow(const double base, const int expo) { + return (expo == 0) ? 1 + : expo == 1 ? base + : expo > 1 ? ((expo & 1) ? base * ipow(base, expo - 1) + : ipow(base, expo / 2) * ipow(base, expo / 2)) + : 1 / ipow(base, -expo); +} + +/** + * Cuts out a range from the number. The new range of the input number will be + * `(-inf, min]U[max, +inf)`. If value sits equally between `min` and `max`, `max` will be returned. + * + * @param value The number to bound. + * @param min The lower bound of range. + * @param max The upper bound of range. + * @return The remapped value. + */ +constexpr double cutRange(const double value, const double min, const double max) { + const double middle = max - ((max - min) / 2); + + if (value > min && value < middle) { + return min; + } else if (value <= max && value >= middle) { + return max; + } + + return value; +} + +/** + * Deadbands a range of the number. Returns the input value, or `0` if it is in the range `[min, + * max]`. + * + * @param value The number to deadband. + * @param min The lower bound of deadband. + * @param max The upper bound of deadband. + * @return The input value or `0` if it is in the range `[min, max]`. + */ +constexpr double deadband(const double value, const double min, const double max) { + return std::clamp(value, min, max) == value ? 0 : value; +} + +/** + * Remap a value in the range `[oldMin, oldMax]` to the range `[newMin, newMax]`. + * + * @param value The value in the old range. + * @param oldMin The old range lower bound. + * @param oldMax The old range upper bound. + * @param newMin The new range lower bound. + * @param newMax The new range upper bound. + * @return The input value in the new range `[newMin, newMax]`. + */ +constexpr double remapRange(const double value, + const double oldMin, + const double oldMax, + const double newMin, + const double newMax) { + return (value - oldMin) * ((newMax - newMin) / (oldMax - oldMin)) + newMin; +} + +/** + * Converts an enum to its value type. + * + * @param e The enum value. + * @return The corresponding value. + */ +template constexpr auto toUnderlyingType(const E e) noexcept { + return static_cast>(e); +} + +/** + * Converts a bool to a sign. + * + * @param b The bool. + * @return True corresponds to `1` and false corresponds to `-1`. + */ +constexpr auto boolToSign(const bool b) noexcept { + return b ? 1 : -1; +} + +/** + * Computes `lhs mod rhs` using Euclidean division. C's `%` symbol computes the remainder, not + * modulus. + * + * @param lhs The left-hand side. + * @param rhs The right-hand side. + * @return `lhs` mod `rhs`. + */ +constexpr long modulus(const long lhs, const long rhs) noexcept { + return ((lhs % rhs) + rhs) % rhs; +} + +/** + * Converts a gearset to its TPR. + * + * @param igearset The gearset. + * @return The corresponding TPR. + */ +constexpr std::int32_t gearsetToTPR(const AbstractMotor::gearset igearset) noexcept { + switch (igearset) { + case AbstractMotor::gearset::red: + return imev5RedTPR; + case AbstractMotor::gearset::green: + return imev5GreenTPR; + case AbstractMotor::gearset::blue: + case AbstractMotor::gearset::invalid: + default: + return imev5BlueTPR; + } +} + +/** + * Maps ADI port numbers/chars to numbers: + * ``` + * when (port) { + * in ['a', 'h'] -> [1, 8] + * in ['A', 'H'] -> [1, 8] + * else -> [1, 8] + * } + * ``` + * + * @param port The ADI port number or char. + * @return An equivalent ADI port number. + */ +constexpr std::int8_t transformADIPort(const std::int8_t port) { + if (port >= 'a' && port <= 'h') { + return port - ('a' - 1); + } else if (port >= 'A' && port <= 'H') { + return port - ('A' - 1); + } else { + return port; + } +} +} // namespace okapi diff --git a/pros/okapi/api/util/supplier.hpp b/pros/okapi/api/util/supplier.hpp new file mode 100644 index 00000000..9c92ed06 --- /dev/null +++ b/pros/okapi/api/util/supplier.hpp @@ -0,0 +1,34 @@ +/* + * 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 + +#include + +namespace okapi { +/** + * A supplier of instances of T. + * + * @tparam T the type to supply + */ +template class Supplier { + public: + explicit Supplier(std::function ifunc) : func(ifunc) { + } + + virtual ~Supplier() = default; + + /** + * Get an instance of type T. This is usually a new instance, but it does not have to be. + * @return an instance of T + */ + T get() const { + return func(); + } + + protected: + std::function func; +}; +} // namespace okapi diff --git a/pros/okapi/api/util/timeUtil.hpp b/pros/okapi/api/util/timeUtil.hpp new file mode 100644 index 00000000..a79a7f2c --- /dev/null +++ b/pros/okapi/api/util/timeUtil.hpp @@ -0,0 +1,41 @@ +/* + * 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 + +#include "okapi/api/control/util/settledUtil.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/abstractTimer.hpp" +#include "okapi/api/util/supplier.hpp" + +namespace okapi { +/** + * Utility class for holding an AbstractTimer, AbstractRate, and SettledUtil together in one + * class since they are commonly used together. + */ +class TimeUtil { + public: + TimeUtil(const Supplier> &itimerSupplier, + const Supplier> &irateSupplier, + const Supplier> &isettledUtilSupplier); + + std::unique_ptr getTimer() const; + + std::unique_ptr getRate() const; + + std::unique_ptr getSettledUtil() const; + + Supplier> getTimerSupplier() const; + + Supplier> getRateSupplier() const; + + Supplier> getSettledUtilSupplier() const; + + protected: + Supplier> timerSupplier; + Supplier> rateSupplier; + Supplier> settledUtilSupplier; +}; +} // namespace okapi diff --git a/pros/okapi/impl/chassis/controller/chassisControllerBuilder.hpp b/pros/okapi/impl/chassis/controller/chassisControllerBuilder.hpp new file mode 100644 index 00000000..7d11896f --- /dev/null +++ b/pros/okapi/impl/chassis/controller/chassisControllerBuilder.hpp @@ -0,0 +1,506 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisControllerIntegrated.hpp" +#include "okapi/api/chassis/controller/chassisControllerPid.hpp" +#include "okapi/api/chassis/controller/defaultOdomChassisController.hpp" +#include "okapi/api/chassis/model/hDriveModel.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/chassis/model/xDriveModel.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/mathUtil.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/device/rotarysensor/adiEncoder.hpp" +#include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" +#include "okapi/impl/device/rotarysensor/rotationSensor.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +class ChassisControllerBuilder { + public: + /** + * A builder that creates ChassisControllers. Use this to create your ChassisController. + * + * @param ilogger The logger this instance will log to. + */ + explicit ChassisControllerBuilder( + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the motors using a skid-steer layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const Motor &ileft, const Motor &iright); + + /** + * Sets the motors using a skid-steer layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const MotorGroup &ileft, const MotorGroup &iright); + + /** + * Sets the motors using a skid-steer layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const std::shared_ptr &ileft, + const std::shared_ptr &iright); + + /** + * Sets the motors using an x-drive layout. + * + * @param itopLeft The top left motor. + * @param itopRight The top right motor. + * @param ibottomRight The bottom right motor. + * @param ibottomLeft The bottom left motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const Motor &itopLeft, + const Motor &itopRight, + const Motor &ibottomRight, + const Motor &ibottomLeft); + + /** + * Sets the motors using an x-drive layout. + * + * @param itopLeft The top left motor. + * @param itopRight The top right motor. + * @param ibottomRight The bottom right motor. + * @param ibottomLeft The bottom left motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const MotorGroup &itopLeft, + const MotorGroup &itopRight, + const MotorGroup &ibottomRight, + const MotorGroup &ibottomLeft); + + /** + * Sets the motors using an x-drive layout. + * + * @param itopLeft The top left motor. + * @param itopRight The top right motor. + * @param ibottomRight The bottom right motor. + * @param ibottomLeft The bottom left motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const std::shared_ptr &itopLeft, + const std::shared_ptr &itopRight, + const std::shared_ptr &ibottomRight, + const std::shared_ptr &ibottomLeft); + + /** + * Sets the motors using an h-drive layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @param imiddle The middle motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withMotors(const Motor &ileft, const Motor &iright, const Motor &imiddle); + + /** + * Sets the motors using an h-drive layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @param imiddle The middle motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withMotors(const MotorGroup &ileft, const MotorGroup &iright, const MotorGroup &imiddle); + + /** + * Sets the motors using an h-drive layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @param imiddle The middle motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withMotors(const MotorGroup &ileft, const MotorGroup &iright, const Motor &imiddle); + + /** + * Sets the motors using an h-drive layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @param imiddle The middle motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const std::shared_ptr &ileft, + const std::shared_ptr &iright, + const std::shared_ptr &imiddle); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const ADIEncoder &ileft, const ADIEncoder &iright); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @param imiddle The middle sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withSensors(const ADIEncoder &ileft, const ADIEncoder &iright, const ADIEncoder &imiddle); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const RotationSensor &ileft, const RotationSensor &iright); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @param imiddle The middle sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const RotationSensor &ileft, + const RotationSensor &iright, + const RotationSensor &imiddle); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const IntegratedEncoder &ileft, + const IntegratedEncoder &iright); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @param imiddle The middle sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const IntegratedEncoder &ileft, + const IntegratedEncoder &iright, + const ADIEncoder &imiddle); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const std::shared_ptr &ileft, + const std::shared_ptr &iright); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @param imiddle The middle sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const std::shared_ptr &ileft, + const std::shared_ptr &iright, + const std::shared_ptr &imiddle); + + /** + * Sets the PID controller gains, causing the builder to generate a ChassisControllerPID. Uses the + * turn controller's gains for the angle controller's gains. + * + * @param idistanceGains The distance controller's gains. + * @param iturnGains The turn controller's gains. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withGains(const IterativePosPIDController::Gains &idistanceGains, + const IterativePosPIDController::Gains &iturnGains); + + /** + * Sets the PID controller gains, causing the builder to generate a ChassisControllerPID. + * + * @param idistanceGains The distance controller's gains. + * @param iturnGains The turn controller's gains. + * @param iangleGains The angle controller's gains. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withGains(const IterativePosPIDController::Gains &idistanceGains, + const IterativePosPIDController::Gains &iturnGains, + const IterativePosPIDController::Gains &iangleGains); + + /** + * Sets the odometry information, causing the builder to generate an Odometry variant. + * + * @param imode The new default StateMode used to interpret target points and query the Odometry + * state. + * @param imoveThreshold The minimum length movement. + * @param iturnThreshold The minimum angle turn. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withOdometry(const StateMode &imode = StateMode::FRAME_TRANSFORMATION, + const QLength &imoveThreshold = 0_mm, + const QAngle &iturnThreshold = 0_deg); + + /** + * Sets the odometry information, causing the builder to generate an Odometry variant. + * + * @param iodomScales The ChassisScales used just for odometry (if they are different than those + * for the drive). + * @param imode The new default StateMode used to interpret target points and query the Odometry + * state. + * @param imoveThreshold The minimum length movement. + * @param iturnThreshold The minimum angle turn. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withOdometry(const ChassisScales &iodomScales, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION, + const QLength &imoveThreshold = 0_mm, + const QAngle &iturnThreshold = 0_deg); + + /** + * Sets the odometry information, causing the builder to generate an Odometry variant. + * + * @param iodometry The odometry object. + * @param imode The new default StateMode used to interpret target points and query the Odometry + * state. + * @param imoveThreshold The minimum length movement. + * @param iturnThreshold The minimum angle turn. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withOdometry(std::shared_ptr iodometry, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION, + const QLength &imoveThreshold = 0_mm, + const QAngle &iturnThreshold = 0_deg); + + /** + * Sets the derivative filters. Uses a PassthroughFilter by default. + * + * @param idistanceFilter The distance controller's filter. + * @param iturnFilter The turn controller's filter. + * @param iangleFilter The angle controller's filter. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withDerivativeFilters( + std::unique_ptr idistanceFilter, + std::unique_ptr iturnFilter = std::make_unique(), + std::unique_ptr iangleFilter = std::make_unique()); + + /** + * Sets the chassis dimensions. + * + * @param igearset The gearset in the drive motors. + * @param iscales The ChassisScales for the base. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withDimensions(const AbstractMotor::GearsetRatioPair &igearset, + const ChassisScales &iscales); + + /** + * Sets the max velocity. Overrides the max velocity of the gearset. + * + * @param imaxVelocity The max velocity. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMaxVelocity(double imaxVelocity); + + /** + * Sets the max voltage. The default is `12000`. + * + * @param imaxVoltage The max voltage. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMaxVoltage(double imaxVoltage); + + /** + * Sets the TimeUtilFactory used when building a ChassisController. This instance will be given + * to the ChassisController (not to controllers it uses). The default is the static + * TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withChassisControllerTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Sets the TimeUtilFactory used when building a ClosedLoopController. This instance will be given + * to any ClosedLoopController instances. The default is the static TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withClosedLoopControllerTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Creates a new ConfigurableTimeUtilFactory with the given parameters. Given to any + * ClosedLoopController instances. + * + * @param iatTargetError The minimum error to be considered settled. + * @param iatTargetDerivative The minimum error derivative to be considered settled. + * @param iatTargetTime The minimum time within atTargetError to be considered settled. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withClosedLoopControllerTimeUtil(double iatTargetError = 50, + double iatTargetDerivative = 5, + const QTime &iatTargetTime = 250_ms); + + /** + * Sets the TimeUtilFactory used when building an Odometry. The default is the static + * TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withOdometryTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Sets the logger used for the ChassisController and ClosedLoopControllers. + * + * @param ilogger The logger. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withLogger(const std::shared_ptr &ilogger); + + /** + * Parents the internal tasks started by this builder to the current task, meaning they will be + * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks + * are never parented to. This is the default behavior. + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + ChassisControllerBuilder &parentedToCurrentTask(); + + /** + * Prevents parenting the internal tasks started by this builder to the current task, meaning they + * will not be deleted once the current task is deleted. This can cause runaway tasks, but is + * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and + * then again in `opcontrol`). + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + ChassisControllerBuilder ¬ParentedToCurrentTask(); + + /** + * Builds the ChassisController. Throws a std::runtime_exception if no motors were set or if no + * dimensions were set. + * + * @return A fully built ChassisController. + */ + std::shared_ptr build(); + + /** + * Builds the OdomChassisController. Throws a std::runtime_exception if no motors were set, if no + * dimensions were set, or if no odometry information was passed. + * + * @return A fully built OdomChassisController. + */ + std::shared_ptr buildOdometry(); + + private: + std::shared_ptr logger; + + struct SkidSteerMotors { + std::shared_ptr left; + std::shared_ptr right; + }; + + struct XDriveMotors { + std::shared_ptr topLeft; + std::shared_ptr topRight; + std::shared_ptr bottomRight; + std::shared_ptr bottomLeft; + }; + + struct HDriveMotors { + std::shared_ptr left; + std::shared_ptr right; + std::shared_ptr middle; + }; + + enum class DriveMode { SkidSteer, XDrive, HDrive }; + + bool hasMotors{false}; // Used to verify motors were passed + DriveMode driveMode{DriveMode::SkidSteer}; + SkidSteerMotors skidSteerMotors; + XDriveMotors xDriveMotors; + HDriveMotors hDriveMotors; + + bool sensorsSetByUser{false}; // Used so motors don't overwrite sensors set manually + std::shared_ptr leftSensor{nullptr}; + std::shared_ptr rightSensor{nullptr}; + std::shared_ptr middleSensor{nullptr}; + + bool hasGains{false}; // Whether gains were passed, no gains means CCI + IterativePosPIDController::Gains distanceGains; + std::unique_ptr distanceFilter = std::make_unique(); + IterativePosPIDController::Gains angleGains; + std::unique_ptr angleFilter = std::make_unique(); + IterativePosPIDController::Gains turnGains; + std::unique_ptr turnFilter = std::make_unique(); + TimeUtilFactory chassisControllerTimeUtilFactory = TimeUtilFactory(); + TimeUtilFactory closedLoopControllerTimeUtilFactory = TimeUtilFactory(); + TimeUtilFactory odometryTimeUtilFactory = TimeUtilFactory(); + + AbstractMotor::GearsetRatioPair gearset{AbstractMotor::gearset::invalid, 1.0}; + ChassisScales driveScales{{1, 1}, imev5GreenTPR}; + bool differentOdomScales{false}; + ChassisScales odomScales{{1, 1}, imev5GreenTPR}; + std::shared_ptr controllerLogger = Logger::getDefaultLogger(); + + bool hasOdom{false}; // Whether odometry was passed + std::shared_ptr odometry; + StateMode stateMode; + QLength moveThreshold; + QAngle turnThreshold; + + bool maxVelSetByUser{false}; // Used so motors don't overwrite maxVelocity + double maxVelocity{600}; + + double maxVoltage{12000}; + + bool isParentedToCurrentTask{true}; + + std::shared_ptr buildCCPID(); + std::shared_ptr buildCCI(); + std::shared_ptr + buildDOCC(std::shared_ptr chassisController); + + std::shared_ptr makeChassisModel(); + std::shared_ptr makeSkidSteerModel(); + std::shared_ptr makeXDriveModel(); + std::shared_ptr makeHDriveModel(); +}; +} // namespace okapi diff --git a/pros/okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp b/pros/okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp new file mode 100644 index 00000000..7faf8271 --- /dev/null +++ b/pros/okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp @@ -0,0 +1,177 @@ +/* + * 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 + +#include "okapi/api/chassis/controller/chassisController.hpp" +#include "okapi/api/control/async/asyncLinearMotionProfileController.hpp" +#include "okapi/api/control/async/asyncMotionProfileController.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +class AsyncMotionProfileControllerBuilder { + public: + /** + * A builder that creates async motion profile controllers. Use this to build an + * AsyncMotionProfileController or an AsyncLinearMotionProfileController. + * + * @param ilogger The logger this instance will log to. + */ + explicit AsyncMotionProfileControllerBuilder( + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the output. This must be used with buildLinearMotionProfileController(). + * + * @param ioutput The output. + * @param idiameter The diameter of the mechanical part the motor spins. + * @param ipair The gearset. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withOutput(const Motor &ioutput, + const QLength &idiameter, + const AbstractMotor::GearsetRatioPair &ipair); + + /** + * Sets the output. This must be used with buildLinearMotionProfileController(). + * + * @param ioutput The output. + * @param idiameter The diameter of the mechanical part the motor spins. + * @param ipair The gearset. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withOutput(const MotorGroup &ioutput, + const QLength &idiameter, + const AbstractMotor::GearsetRatioPair &ipair); + + /** + * Sets the output. This must be used with buildLinearMotionProfileController(). + * + * @param ioutput The output. + * @param idiameter The diameter of the mechanical part the motor spins. + * @param ipair The gearset. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder & + withOutput(const std::shared_ptr> &ioutput, + const QLength &idiameter, + const AbstractMotor::GearsetRatioPair &ipair); + + /** + * Sets the output. This must be used with buildMotionProfileController(). + * + * @param icontroller The chassis controller to use. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withOutput(ChassisController &icontroller); + + /** + * Sets the output. This must be used with buildMotionProfileController(). + * + * @param icontroller The chassis controller to use. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder & + withOutput(const std::shared_ptr &icontroller); + + /** + * Sets the output. This must be used with buildMotionProfileController(). + * + * @param imodel The chassis model to use. + * @param iscales The chassis dimensions. + * @param ipair The gearset. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withOutput(const std::shared_ptr &imodel, + const ChassisScales &iscales, + const AbstractMotor::GearsetRatioPair &ipair); + + /** + * Sets the limits. + * + * @param ilimits The limits. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withLimits(const PathfinderLimits &ilimits); + + /** + * Sets the TimeUtilFactory used when building the controller. The default is the static + * TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Sets the logger. + * + * @param ilogger The logger. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withLogger(const std::shared_ptr &ilogger); + + /** + * Parents the internal tasks started by this builder to the current task, meaning they will be + * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks + * are never parented to. This is the default behavior. + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &parentedToCurrentTask(); + + /** + * Prevents parenting the internal tasks started by this builder to the current task, meaning they + * will not be deleted once the current task is deleted. This can cause runaway tasks, but is + * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and + * then again in `opcontrol`). + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder ¬ParentedToCurrentTask(); + + /** + * Builds the AsyncLinearMotionProfileController. + * + * @return A fully built AsyncLinearMotionProfileController. + */ + std::shared_ptr buildLinearMotionProfileController(); + + /** + * Builds the AsyncMotionProfileController. + * + * @return A fully built AsyncMotionProfileController. + */ + std::shared_ptr buildMotionProfileController(); + + private: + std::shared_ptr logger; + + bool hasLimits{false}; + PathfinderLimits limits; + + bool hasOutput{false}; + std::shared_ptr> output; + QLength diameter; + + bool hasModel{false}; + std::shared_ptr model; + ChassisScales scales{{1, 1}, imev5GreenTPR}; + AbstractMotor::GearsetRatioPair pair{AbstractMotor::gearset::invalid}; + TimeUtilFactory timeUtilFactory = TimeUtilFactory(); + std::shared_ptr controllerLogger = Logger::getDefaultLogger(); + + bool isParentedToCurrentTask{true}; +}; +} // namespace okapi diff --git a/pros/okapi/impl/control/async/asyncPosControllerBuilder.hpp b/pros/okapi/impl/control/async/asyncPosControllerBuilder.hpp new file mode 100644 index 00000000..124558b3 --- /dev/null +++ b/pros/okapi/impl/control/async/asyncPosControllerBuilder.hpp @@ -0,0 +1,190 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncPosIntegratedController.hpp" +#include "okapi/api/control/async/asyncPosPidController.hpp" +#include "okapi/api/control/async/asyncPositionController.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/device/rotarysensor/adiEncoder.hpp" +#include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +class AsyncPosControllerBuilder { + public: + /** + * A builder that creates async position controllers. Use this to create an + * AsyncPosIntegratedController or an AsyncPosPIDController. + * + * @param ilogger The logger this instance will log to. + */ + explicit AsyncPosControllerBuilder( + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withMotor(const Motor &imotor); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withMotor(const MotorGroup &imotor); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withMotor(const std::shared_ptr &imotor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withSensor(const ADIEncoder &isensor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withSensor(const IntegratedEncoder &isensor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withSensor(const std::shared_ptr &isensor); + + /** + * Sets the controller gains, causing the builder to generate an AsyncPosPIDController. This does + * not set the integrated control's gains. + * + * @param igains The gains. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withGains(const IterativePosPIDController::Gains &igains); + + /** + * Sets the derivative filter which filters the derivative term before it is scaled by kD. The + * filter is ignored when using integrated control. The default derivative filter is a + * PassthroughFilter. + * + * @param iderivativeFilter The derivative filter. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withDerivativeFilter(std::unique_ptr iderivativeFilter); + + /** + * Sets the gearset. The default gearset is derived from the motor's. + * + * @param igearset The gearset. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withGearset(const AbstractMotor::GearsetRatioPair &igearset); + + /** + * Sets the maximum velocity. The default maximum velocity is derived from the motor's gearset. + * This parameter is ignored when using an AsyncPosPIDController. + * + * @param imaxVelocity The maximum velocity. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withMaxVelocity(double imaxVelocity); + + /** + * Sets the TimeUtilFactory used when building the controller. The default is the static + * TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Sets the logger. + * + * @param ilogger The logger. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withLogger(const std::shared_ptr &ilogger); + + /** + * Parents the internal tasks started by this builder to the current task, meaning they will be + * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks + * are never parented to. This is the default behavior. + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &parentedToCurrentTask(); + + /** + * Prevents parenting the internal tasks started by this builder to the current task, meaning they + * will not be deleted once the current task is deleted. This can cause runaway tasks, but is + * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and + * then again in `opcontrol`). + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncPosControllerBuilder ¬ParentedToCurrentTask(); + + /** + * Builds the AsyncPositionController. Throws a std::runtime_exception is no motors were set. + * + * @return A fully built AsyncPositionController. + */ + std::shared_ptr> build(); + + private: + std::shared_ptr logger; + + bool hasMotors{false}; // Used to verify motors were passed + std::shared_ptr motor; + + bool sensorsSetByUser{false}; // Used so motors don't overwrite sensors set manually + std::shared_ptr sensor; + + bool hasGains{false}; // Whether gains were passed, no gains means integrated control + IterativePosPIDController::Gains gains; + std::unique_ptr derivativeFilter = std::make_unique(); + + bool gearsetSetByUser{false}; // Used so motor's don't overwrite a gearset set manually + AbstractMotor::GearsetRatioPair pair{AbstractMotor::gearset::invalid}; + + bool maxVelSetByUser{false}; // Used so motors don't overwrite maxVelocity + double maxVelocity{600}; + + TimeUtilFactory timeUtilFactory = TimeUtilFactory(); + std::shared_ptr controllerLogger = Logger::getDefaultLogger(); + + bool isParentedToCurrentTask{true}; + + std::shared_ptr buildAPIC(); + std::shared_ptr buildAPPC(); +}; +} // namespace okapi diff --git a/pros/okapi/impl/control/async/asyncVelControllerBuilder.hpp b/pros/okapi/impl/control/async/asyncVelControllerBuilder.hpp new file mode 100644 index 00000000..8643e892 --- /dev/null +++ b/pros/okapi/impl/control/async/asyncVelControllerBuilder.hpp @@ -0,0 +1,203 @@ +/* + * 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 + +#include "okapi/api/control/async/asyncVelIntegratedController.hpp" +#include "okapi/api/control/async/asyncVelPidController.hpp" +#include "okapi/api/control/async/asyncVelocityController.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/device/rotarysensor/adiEncoder.hpp" +#include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +class AsyncVelControllerBuilder { + public: + /** + * A builder that creates async velocity controllers. Use this to create an + * AsyncVelIntegratedController or an AsyncVelPIDController. + * + * @param ilogger The logger this instance will log to. + */ + explicit AsyncVelControllerBuilder( + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withMotor(const Motor &imotor); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withMotor(const MotorGroup &imotor); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withMotor(const std::shared_ptr &imotor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withSensor(const ADIEncoder &isensor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withSensor(const IntegratedEncoder &isensor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withSensor(const std::shared_ptr &isensor); + + /** + * Sets the controller gains, causing the builder to generate an AsyncVelPIDController. This does + * not set the integrated control's gains. + * + * @param igains The gains. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withGains(const IterativeVelPIDController::Gains &igains); + + /** + * Sets the VelMath which calculates and filters velocity. This is ignored when using integrated + * controller. If using a PID controller (by setting the gains), this is required. + * + * @param ivelMath The VelMath. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withVelMath(std::unique_ptr ivelMath); + + /** + * Sets the derivative filter which filters the derivative term before it is scaled by kD. The + * filter is ignored when using integrated control. The default derivative filter is a + * PassthroughFilter. + * + * @param iderivativeFilter The derivative filter. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withDerivativeFilter(std::unique_ptr iderivativeFilter); + + /** + * Sets the gearset. The default gearset is derived from the motor's. + * + * @param igearset The gearset. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withGearset(const AbstractMotor::GearsetRatioPair &igearset); + + /** + * Sets the maximum velocity. The default maximum velocity is derived from the motor's gearset. + * This parameter is ignored when using an AsyncVelPIDController. + * + * @param imaxVelocity The maximum velocity. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withMaxVelocity(double imaxVelocity); + + /** + * Sets the TimeUtilFactory used when building the controller. The default is the static + * TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Sets the logger. + * + * @param ilogger The logger. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withLogger(const std::shared_ptr &ilogger); + + /** + * Parents the internal tasks started by this builder to the current task, meaning they will be + * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks + * are never parented to. This is the default behavior. + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &parentedToCurrentTask(); + + /** + * Prevents parenting the internal tasks started by this builder to the current task, meaning they + * will not be deleted once the current task is deleted. This can cause runaway tasks, but is + * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and + * then again in `opcontrol`). + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncVelControllerBuilder ¬ParentedToCurrentTask(); + + /** + * Builds the AsyncVelocityController. Throws a std::runtime_exception is no motors were set. + * + * @return A fully built AsyncVelocityController. + */ + std::shared_ptr> build(); + + private: + std::shared_ptr logger; + + bool hasMotors{false}; // Used to verify motors were passed + std::shared_ptr motor; + + bool sensorsSetByUser{false}; // Used so motors don't overwrite sensors set manually + std::shared_ptr sensor; + + bool hasGains{false}; // Whether gains were passed, no gains means integrated control + IterativeVelPIDController::Gains gains; + + bool hasVelMath{false}; // Used to verify velMath was passed + std::unique_ptr velMath; + + std::unique_ptr derivativeFilter = std::make_unique(); + + bool gearsetSetByUser{false}; // Used so motor's don't overwrite a gearset set manually + AbstractMotor::GearsetRatioPair pair{AbstractMotor::gearset::invalid}; + + bool maxVelSetByUser{false}; // Used so motors don't overwrite maxVelocity + double maxVelocity{600}; + + TimeUtilFactory timeUtilFactory = TimeUtilFactory(); + std::shared_ptr controllerLogger = Logger::getDefaultLogger(); + + bool isParentedToCurrentTask{true}; + + std::shared_ptr buildAVIC(); + std::shared_ptr buildAVPC(); +}; +} // namespace okapi diff --git a/pros/okapi/impl/control/iterative/iterativeControllerFactory.hpp b/pros/okapi/impl/control/iterative/iterativeControllerFactory.hpp new file mode 100644 index 00000000..85b05a58 --- /dev/null +++ b/pros/okapi/impl/control/iterative/iterativeControllerFactory.hpp @@ -0,0 +1,120 @@ +/* + * 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 + +#include "okapi/api/control/iterative/iterativeMotorVelocityController.hpp" +#include "okapi/api/control/iterative/iterativePosPidController.hpp" +#include "okapi/api/control/iterative/iterativeVelPidController.hpp" +#include "okapi/api/util/mathUtil.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/filter/velMathFactory.hpp" + +namespace okapi { +class IterativeControllerFactory { + public: + /** + * Position PID controller. + * + * @param ikP proportional gain + * @param ikI integral gain + * @param ikD derivative gain + * @param ikBias controller bias (constant offset added to the output) + * @param iderivativeFilter A filter for filtering the derivative term. + * @param ilogger The logger this instance will log to. + */ + static IterativePosPIDController + posPID(double ikP, + double ikI, + double ikD, + double ikBias = 0, + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity PD controller. + * + * @param ikP proportional gain + * @param ikD derivative gain + * @param ikF feed-forward gain + * @param ikSF a feed-forward gain to counteract static friction + * @param iderivativeFilter A filter for filtering the derivative term. + * @param ilogger The logger this instance will log to. + */ + static IterativeVelPIDController + velPID(double ikP, + double ikD, + double ikF = 0, + double ikSF = 0, + std::unique_ptr ivelMath = VelMathFactory::createPtr(imev5GreenTPR), + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity PD controller that automatically writes to the motor. + * + * @param imotor output motor + * @param ikP proportional gain + * @param ikD derivative gain + * @param ikF feed-forward gain + * @param ikSF a feed-forward gain to counteract static friction + * @param ivelMath The VelMath. + * @param iderivativeFilter A filter for filtering the derivative term. + * @param ilogger The logger this instance will log to. + */ + static IterativeMotorVelocityController + motorVelocity(Motor imotor, + double ikP, + double ikD, + double ikF = 0, + double ikSF = 0, + std::unique_ptr ivelMath = VelMathFactory::createPtr(imev5GreenTPR), + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity PD controller that automatically writes to the motor. + * + * @param imotor output motor + * @param ikP proportional gain + * @param ikD derivative gain + * @param ikF feed-forward gain + * @param ikSF a feed-forward gain to counteract static friction + * @param ivelMath The VelMath. + * @param iderivativeFilter A filter for filtering the derivative term. + * @param ilogger The logger this instance will log to. + */ + static IterativeMotorVelocityController + motorVelocity(MotorGroup imotor, + double ikP, + double ikD, + double ikF = 0, + double ikSF = 0, + std::unique_ptr ivelMath = VelMathFactory::createPtr(imev5GreenTPR), + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity PD controller that automatically writes to the motor. + * + * @param imotor output motor + * @param icontroller controller to use + */ + static IterativeMotorVelocityController + motorVelocity(Motor imotor, + std::shared_ptr> icontroller); + + /** + * Velocity PD controller that automatically writes to the motor. + * + * @param imotor output motor + * @param icontroller controller to use + */ + static IterativeMotorVelocityController + motorVelocity(MotorGroup imotor, + std::shared_ptr> icontroller); +}; +} // namespace okapi diff --git a/pros/okapi/impl/control/util/controllerRunnerFactory.hpp b/pros/okapi/impl/control/util/controllerRunnerFactory.hpp new file mode 100644 index 00000000..16ab592f --- /dev/null +++ b/pros/okapi/impl/control/util/controllerRunnerFactory.hpp @@ -0,0 +1,25 @@ +/* + * 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 + +#include "okapi/api/control/util/controllerRunner.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +template class ControllerRunnerFactory { + public: + /** + * A utility class that runs a closed-loop controller. + * + * @param ilogger The logger this instance will log to. + * @return + */ + static ControllerRunner + create(const std::shared_ptr &ilogger = Logger::getDefaultLogger()) { + return ControllerRunner(TimeUtilFactory::createDefault(), ilogger); + } +}; +} // namespace okapi diff --git a/pros/okapi/impl/control/util/pidTunerFactory.hpp b/pros/okapi/impl/control/util/pidTunerFactory.hpp new file mode 100644 index 00000000..332b55fc --- /dev/null +++ b/pros/okapi/impl/control/util/pidTunerFactory.hpp @@ -0,0 +1,47 @@ +/* + * 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 + +#include "okapi/api/control/util/pidTuner.hpp" +#include + +namespace okapi { +class PIDTunerFactory { + public: + static PIDTuner create(const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + QTime itimeout, + std::int32_t igoal, + double ikPMin, + double ikPMax, + double ikIMin, + double ikIMax, + double ikDMin, + double ikDMax, + std::int32_t inumIterations = 5, + std::int32_t inumParticles = 16, + double ikSettle = 1, + double ikITAE = 2, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + static std::unique_ptr + createPtr(const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + QTime itimeout, + std::int32_t igoal, + double ikPMin, + double ikPMax, + double ikIMin, + double ikIMax, + double ikDMin, + double ikDMax, + std::int32_t inumIterations = 5, + std::int32_t inumParticles = 16, + double ikSettle = 1, + double ikITAE = 2, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/adiUltrasonic.hpp b/pros/okapi/impl/device/adiUltrasonic.hpp new file mode 100644 index 00000000..6a525f4d --- /dev/null +++ b/pros/okapi/impl/device/adiUltrasonic.hpp @@ -0,0 +1,71 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include + +namespace okapi { +class ADIUltrasonic : public ControllerInput { + public: + /** + * An ultrasonic sensor in the ADI (3-wire) ports. + * + * ```cpp + * auto ultra = ADIUltrasonic('A', 'B'); + * auto filteredUltra = ADIUltrasonic('A', 'B', std::make_unique>()); + * ``` + * + * @param iportPing The port connected to the orange OUTPUT cable. This must be in port ``1``, + * ``3``, ``5``, or ``7`` (``A``, ``C``, ``E``, or ``G``). + * @param iportEcho The port connected to the yellow INPUT cable. This must be in the next highest + * port following iportPing. + * @param ifilter The filter to use for filtering the distance measurements. + */ + ADIUltrasonic(std::uint8_t iportPing, + std::uint8_t iportEcho, + std::unique_ptr ifilter = std::make_unique()); + + /** + * An ultrasonic sensor in the ADI (3-wire) ports. + * + * ```cpp + * auto ultra = ADIUltrasonic({1, 'A', 'B'}); + * auto filteredUltra = ADIUltrasonic({1, 'A', 'B'}, std::make_unique>()); + * ``` + * + * @param iports The ports the ultrasonic is plugged in to in the order ``{smart port, ping port, + * echo port}``. The smart port is the smart port number (``[1, 21]``). The ping port is the port + * connected to the orange OUTPUT cable. This must be in port ``1``, ``3``, ``5``, or ``7`` + * (``A``, ``C``, ``E``, or ``G``). The echo port is the port connected to the yellow INPUT cable. + * This must be in the next highest port following the ping port. + * @param ifilter The filter to use for filtering the distance measurements. + */ + ADIUltrasonic(std::tuple iports, + std::unique_ptr ifilter = std::make_unique()); + + virtual ~ADIUltrasonic(); + + /** + * Returns the current filtered sensor value. + * + * @return current value + */ + virtual double get(); + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. Calls get(). + */ + virtual double controllerGet() override; + + protected: + pros::c::ext_adi_ultrasonic_t ultra; + std::unique_ptr filter; +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/button/adiButton.hpp b/pros/okapi/impl/device/button/adiButton.hpp new file mode 100644 index 00000000..32e59a8a --- /dev/null +++ b/pros/okapi/impl/device/button/adiButton.hpp @@ -0,0 +1,50 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/device/button/buttonBase.hpp" + +namespace okapi { +class ADIButton : public ButtonBase { + public: + /** + * A button in an ADI port. + * + * ```cpp + * auto btn = ADIButton('A', false); + * auto invertedBtn = ADIButton('A', true); + * ``` + * + * @param iport The ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). + * @param iinverted Whether the button is inverted (``true`` meaning default pressed and ``false`` + * meaning default not pressed). + */ + ADIButton(std::uint8_t iport, bool iinverted = false); + + /** + * A button in an ADI port. + * + * ```cpp + * auto btn = ADIButton({1, 'A'}, false); + * auto invertedBtn = ADIButton({1, 'A'}, true); + * ``` + * + * @param iports The ports the button is plugged in to in the order ``{smart port, button port}``. + * The smart port is the smart port number (``[1, 21]``). The button port is the ADI port number + * (``[1, 8]``, ``[a, h]``, ``[A, H]``). + * @param iinverted Whether the button is inverted (``true`` meaning default pressed and ``false`` + * meaning default not pressed). + */ + ADIButton(std::pair iports, bool iinverted = false); + + protected: + std::uint8_t smartPort; + std::uint8_t port; + + virtual bool currentlyPressed() override; +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/button/controllerButton.hpp b/pros/okapi/impl/device/button/controllerButton.hpp new file mode 100644 index 00000000..3d7e5e58 --- /dev/null +++ b/pros/okapi/impl/device/button/controllerButton.hpp @@ -0,0 +1,38 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/device/button/buttonBase.hpp" +#include "okapi/impl/device/controllerUtil.hpp" + +namespace okapi { +class ControllerButton : public ButtonBase { + public: + /** + * A button on a Controller. + * + * @param ibtn The button id. + * @param iinverted Whether the button is inverted (default pressed instead of default released). + */ + ControllerButton(ControllerDigital ibtn, bool iinverted = false); + + /** + * A button on a Controller. + * + * @param icontroller The Controller the button is on. + * @param ibtn The button id. + * @param iinverted Whether the button is inverted (default pressed instead of default released). + */ + ControllerButton(ControllerId icontroller, ControllerDigital ibtn, bool iinverted = false); + + protected: + pros::controller_id_e_t id; + pros::controller_digital_e_t btn; + + virtual bool currentlyPressed() override; +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/controller.hpp b/pros/okapi/impl/device/controller.hpp new file mode 100644 index 00000000..81f92298 --- /dev/null +++ b/pros/okapi/impl/device/controller.hpp @@ -0,0 +1,118 @@ +/* + * 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 + +#include "api.h" +#include "okapi/impl/device/button/controllerButton.hpp" +#include "okapi/impl/device/controllerUtil.hpp" +#include + +namespace okapi { +class Controller { + public: + Controller(ControllerId iid = ControllerId::master); + + virtual ~Controller(); + + /** + * Returns whether the controller is connected. + * + * @return true if the controller is connected + */ + virtual bool isConnected(); + + /** + * Returns the current analog reading for the channel in the range [-1, 1]. Returns 0 if the + * controller is not connected. + * + * @param ichannel the channel to read + * @return the value of that channel in the range [-1, 1] + */ + virtual float getAnalog(ControllerAnalog ichannel); + + /** + * Returns whether the digital button is currently pressed. Returns false if the controller is + * not connected. + * + * @param ibutton the button to check + * @return true if the button is pressed, false if the controller is not connected + */ + virtual bool getDigital(ControllerDigital ibutton); + + /** + * Returns a ControllerButton for the given button on this controller. + * + * @param ibtn the button + * @return a ControllerButton on this controller + */ + virtual ControllerButton &operator[](ControllerDigital ibtn); + + /** + * Sets text to the controller LCD screen. + * + * @param iline the line number in the range [0-2] at which the text will be displayed + * @param icol the column number in the range [0-14] at which the text will be displayed + * @param itext the string to display + * @return 1 if the operation was successful, PROS_ERR otherwise + */ + virtual std::int32_t setText(std::uint8_t iline, std::uint8_t icol, std::string itext); + + /** + * Clears all of the lines of the controller screen. On vexOS version 1.0.0 this function will + * block for 110ms. + * + * @return 1 if the operation was successful, PROS_ERR otherwise + */ + virtual std::int32_t clear(); + + /** + * Clears an individual line of the controller screen. + * + * @param iline the line number to clear in the range [0, 2]. + * @return 1 if the operation was successful, PROS_ERR otherwise + */ + virtual std::int32_t clearLine(std::uint8_t iline); + + /** + * Rumble the controller. + * + * Controller rumble activation is currently in beta, so continuous, fast + * updates will not work well. + * + * @param irumblePattern A string consisting of the characters '.', '-', and ' ', where dots are + * short rumbles, dashes are long rumbles, and spaces are pauses. Maximum supported length is 8 + * characters. + * + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t rumble(std::string irumblePattern); + + /** + * Gets the battery capacity of the given controller. + * + * 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. + * + * @return the controller's battery capacity + */ + virtual std::int32_t getBatteryCapacity(); + + /** + * Gets the battery level of the given controller. + * + * 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. + * + * @return the controller's battery level + */ + virtual std::int32_t getBatteryLevel(); + + protected: + ControllerId okapiId; + pros::controller_id_e_t prosId; + std::array buttonArray{}; +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/controllerUtil.hpp b/pros/okapi/impl/device/controllerUtil.hpp new file mode 100644 index 00000000..d62df3ab --- /dev/null +++ b/pros/okapi/impl/device/controllerUtil.hpp @@ -0,0 +1,64 @@ +/* + * 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 + +#include "api.h" + +namespace okapi { +/** + * Which controller role this has. + */ +enum class ControllerId { + master = 0, ///< master + partner = 1 ///< partner +}; + +/** + * The analog sticks. + */ +enum class ControllerAnalog { + leftX = 0, ///< leftX + leftY = 1, ///< leftY + rightX = 2, ///< rightX + rightY = 3 ///< rightY +}; + +/** + * Various buttons. + */ +enum class ControllerDigital { + L1 = 6, ///< L1 + L2 = 7, ///< L2 + R1 = 8, ///< R1 + R2 = 9, ///< R2 + up = 10, ///< up + down = 11, ///< down + left = 12, ///< left + right = 13, ///< right + X = 14, ///< X + B = 15, ///< B + Y = 16, ///< Y + A = 17 ///< A +}; + +class ControllerUtil { + public: + /** + * Maps an `id` to the PROS enum equivalent. + */ + static pros::controller_id_e_t idToProsEnum(ControllerId in); + + /** + * Maps an `analog` to the PROS enum equivalent. + */ + static pros::controller_analog_e_t analogToProsEnum(ControllerAnalog in); + + /** + * Maps a `digital` to the PROS enum equivalent. + */ + static pros::controller_digital_e_t digitalToProsEnum(ControllerDigital in); +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/distanceSensor.hpp b/pros/okapi/impl/device/distanceSensor.hpp new file mode 100644 index 00000000..af2816a4 --- /dev/null +++ b/pros/okapi/impl/device/distanceSensor.hpp @@ -0,0 +1,76 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include + +namespace okapi { +class DistanceSensor : public ControllerInput { + public: + /** + * A distance sensor on a V5 port. + * + * ```cpp + * auto ds = DistanceSensor(1); + * auto filteredDistSensor = DistanceSensor(1, std::make_unique>()); + * ``` + * + * @param iport The V5 port the device uses. + * @param ifilter The filter to use for filtering the distance measurements. + */ + DistanceSensor(std::uint8_t iport, + std::unique_ptr ifilter = std::make_unique()); + + virtual ~DistanceSensor() = default; + + /** + * Get the current filtered sensor value in mm. + * + * @return The current filtered sensor value in mm. + */ + double get(); + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return The same as [get](@ref okapi::DistanceSensor::get). + */ + double controllerGet() override; + + /** + * Get the confidence in the distance reading. This value has a range of ``[0, 63]``. ``63`` means + * high confidence, lower values imply less confidence. Confidence is only available when distance + * is greater than ``200`` mm. + * + * @return The confidence value in the range ``[0, 63]``. + */ + std::int32_t getConfidence() const; + + /** + * Get the current guess at relative object size. This value has a range of ``[0, 400]``. A 18" x + * 30" grey card will return a value of approximately ``75`` in typical room lighting. + * + * @return The size value in the range ``[0, 400]`` or ``PROS_ERR`` if the operation failed, + * setting errno. + */ + std::int32_t getObjectSize() const; + + /** + * Get the object velocity in m/s. + * + * @return The object velocity in m/s. + */ + double getObjectVelocity() const; + + protected: + std::uint8_t port; + std::unique_ptr filter; +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/motor/adiMotor.hpp b/pros/okapi/impl/device/motor/adiMotor.hpp new file mode 100644 index 00000000..f39bd417 --- /dev/null +++ b/pros/okapi/impl/device/motor/adiMotor.hpp @@ -0,0 +1,69 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/util/logging.hpp" + +namespace okapi { +class ADIMotor : public ControllerOutput { + public: + /** + * A motor in an ADI port. + * + * ```cpp + * auto mtr = ADIMotor('A'); + * auto reversedMtr = ADIMotor('A', true); + * ``` + * + * @param iport The ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). + * @param ireverse Whether the motor is reversed. + * @param logger The logger that initialization warnings will be logged to. + */ + ADIMotor(std::uint8_t iport, + bool ireverse = false, + const std::shared_ptr &logger = Logger::getDefaultLogger()); + + /** + * A motor in an ADI port. + * + * ```cpp + * auto mtr = ADIMotor({1, 'A'}, false); + * auto reversedMtr = ADIMotor({1, 'A'}, true); + * ``` + * + * @param iports The ports the motor is plugged in to in the order ``{smart port, motor port}``. + * The smart port is the smart port number (``[1, 21]``). The motor port is the ADI port number + * (``[1, 8]``, ``[a, h]``, ``[A, H]``). + * @param ireverse Whether the motor is reversed. + * @param logger The logger that initialization warnings will be logged to. + */ + ADIMotor(std::pair iports, + bool ireverse = false, + const std::shared_ptr &logger = Logger::getDefaultLogger()); + + /** + * Set the voltage to the motor. + * + * @param ivoltage voltage in the range [-127, 127]. + */ + virtual void moveVoltage(std::int8_t ivoltage) const; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be [-1, 1]. + * + * @param ivalue the controller's output in the range [-1, 1] + */ + void controllerSet(double ivalue) override; + + protected: + std::uint8_t smartPort; + std::uint8_t port; + std::int8_t reversed; +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/motor/motor.hpp b/pros/okapi/impl/device/motor/motor.hpp new file mode 100644 index 00000000..78c5b3b0 --- /dev/null +++ b/pros/okapi/impl/device/motor/motor.hpp @@ -0,0 +1,457 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/util/logging.hpp" + +namespace okapi { +class Motor : public AbstractMotor { + public: + /** + * A V5 motor. + * + * @param iport The port number in the range ``[1, 21]``. A negative port number is shorthand for + * reversing the motor. + */ + Motor(std::int8_t iport); + + /** + * A V5 motor. + * + * @param iport The port number in the range [1, 21]. + * @param ireverse Whether the motor is reversed (this setting is not written to the motor, it is + * maintained by okapi::Motor instead). + * @param igearset The internal gearset to set in the motor. + * @param iencoderUnits The encoder units to set in the motor. + * @param logger The logger that initialization warnings will be logged to. + */ + Motor(std::uint8_t iport, + bool ireverse, + AbstractMotor::gearset igearset, + AbstractMotor::encoderUnits iencoderUnits, + const std::shared_ptr &logger = Logger::getDefaultLogger()); + + /******************************************************************************/ + /** Motor movement functions **/ + /** **/ + /** These functions allow programmers to make motors move **/ + /******************************************************************************/ + + /** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with setZeroPosition(). + * + * @note This function simply sets the target for the motor, it does not block program execution + * until the movement finishes. + * + * @param iposition The absolute position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t moveAbsolute(double iposition, std::int32_t ivelocity) override; + + /** + * Sets the relative target position for the motor to move to. + * + * This movement is relative to the current position of the motor. Providing 10.0 as the position + * parameter would result in the motor moving clockwise 10 units, 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. + * + * @param iposition The relative position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t moveRelative(double iposition, std::int32_t ivelocity) override; + + /** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the gearset + * used for the motor. This results in a range of +-100 for pros::c::red, + * +-200 for green, and +-600 for blue. The velocity + * is held with PID to ensure consistent speed, as opposed to setting the motor's + * voltage. + * + * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's + * gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t moveVelocity(std::int16_t ivelocity) override; + + /** + * Sets the voltage for the motor from -12000 to 12000. + * + * @param ivoltage The new voltage value from -12000 to 12000. + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t moveVoltage(std::int16_t ivoltage) override; + + /** + * Changes the output velocity for a profiled movement (moveAbsolute or moveRelative). This will + * have no effect if the motor is not following a profiled movement. + * + * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's + * gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t modifyProfiledVelocity(std::int32_t ivelocity) override; + + /******************************************************************************/ + /** Motor telemetry functions **/ + /** **/ + /** These functions allow programmers to collect telemetry from motors **/ + /******************************************************************************/ + + /** + * Gets the target position set for the motor by the user. + * + * @return The target position in its encoder units or PROS_ERR_F if the operation failed, + * setting errno. + */ + double getTargetPosition() override; + + /** + * Gets the absolute position of the motor in its encoder units. + * + * @return The motor's absolute position in its encoder units or PROS_ERR_F if the operation + * failed, setting errno. + */ + double getPosition() override; + + /** + * Sets the "absolute" zero position of the motor to its current position. + * + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t tarePosition() override; + + /** + * Gets the velocity commanded to the motor by the user. + * + * @return The commanded motor velocity from +-100, +-200, or +-600, or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t getTargetVelocity() override; + + /** + * Gets the actual velocity of the motor. + * + * @return The motor's actual velocity in RPM or PROS_ERR_F if the operation failed, setting + * errno. + */ + double getActualVelocity() override; + + /** + * Gets the current drawn by the motor in mA. + * + * @return The motor's current in mA or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t getCurrentDraw() override; + + /** + * Gets the direction of movement for the motor. + * + * @return 1 for moving in the positive direction, -1 for moving in the negative direction, and + * PROS_ERR if the operation failed, setting errno. + */ + std::int32_t getDirection() override; + + /** + * Gets the efficiency of the motor in percent. + * + * 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. + * + * @return The motor's efficiency in percent or PROS_ERR_F if the operation failed, setting errno. + */ + double getEfficiency() override; + + /** + * Checks if the motor is drawing over its current limit. + * + * @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. + */ + std::int32_t isOverCurrent() override; + + /** + * Checks if the motor's temperature is above its limit. + * + * @return 1 if the temperature limit is exceeded and 0 if the the temperature is below the limit, + * or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t isOverTemp() override; + + /** + * Checks if the motor is stopped. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns PROS_ERR with errno set to ENOSYS. + * + * @return 1 if the motor is not moving, 0 if the motor is moving, or PROS_ERR if the operation + * failed, setting errno + */ + std::int32_t isStopped() override; + + /** + * Checks if the motor is at its zero position. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns PROS_ERR with errno set to ENOSYS. + * + * @return 1 if the motor is at zero absolute position, 0 if the motor has moved from its absolute + * zero, or PROS_ERR if the operation failed, setting errno + */ + std::int32_t getZeroPositionFlag() override; + + /** + * Gets the faults experienced by the motor. Compare this bitfield to the bitmasks in + * pros::motor_fault_e_t. + * + * @return A currently unknown bitfield containing the motor's faults. 0b00000100 = Current Limit + * Hit + */ + uint32_t getFaults() override; + + /** + * Gets the flags set by the motor's operation. Compare this bitfield to the bitmasks in + * pros::motor_flag_e_t. + * + * @return A currently unknown bitfield containing the motor's flags. These seem to be unrelated + * to the individual get_specific_flag functions + */ + uint32_t getFlags() override; + + /** + * Gets the raw encoder count of the motor at a given timestamp. + * + * @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 The raw encoder count at the given timestamp or PROS_ERR if the operation failed. + */ + std::int32_t getRawPosition(std::uint32_t *timestamp) override; + + /** + * Gets the power drawn by the motor in Watts. + * + * @return The motor's power draw in Watts or PROS_ERR_F if the operation failed, setting errno. + */ + double getPower() override; + + /** + * Gets the temperature of the motor in degrees Celsius. + * + * @return The motor's temperature in degrees Celsius or PROS_ERR_F if the operation failed, + * setting errno. + */ + double getTemperature() override; + + /** + * Gets the torque generated by the motor in Newton Metres (Nm). + * + * @return The motor's torque in NM or PROS_ERR_F if the operation failed, setting errno. + */ + double getTorque() override; + + /** + * Gets the voltage delivered to the motor in millivolts. + * + * @return The motor's voltage in V or PROS_ERR_F if the operation failed, setting errno. + */ + std::int32_t getVoltage() override; + + /******************************************************************************/ + /** Motor configuration functions **/ + /** **/ + /** These functions allow programmers to configure the behavior of motors **/ + /******************************************************************************/ + + /** + * Sets one of AbstractMotor::brakeMode to the motor. + * + * @param imode The new motor brake mode to set for the motor + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setBrakeMode(AbstractMotor::brakeMode imode) override; + + /** + * Gets the brake mode that was set for the motor. + * + * @return One of brakeMode, according to what was set for the motor, or brakeMode::invalid if the + * operation failed, setting errno. + */ + brakeMode getBrakeMode() override; + + /** + * Sets the current limit for the motor in mA. + * + * @param ilimit The new current limit in mA + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setCurrentLimit(std::int32_t ilimit) override; + + /** + * Gets the current limit for the motor in mA. The default value is 2500 mA. + * + * @return The motor's current limit in mA or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t getCurrentLimit() override; + + /** + * Sets one of AbstractMotor::encoderUnits for the motor encoder. + * + * @param iunits The new motor encoder units + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setEncoderUnits(AbstractMotor::encoderUnits iunits) override; + + /** + * Gets the encoder units that were set for the motor. + * + * @return One of encoderUnits according to what is set for the motor or encoderUnits::invalid if + * the operation failed. + */ + encoderUnits getEncoderUnits() override; + + /** + * Sets one of AbstractMotor::gearset for the motor. + * + * @param igearset The new motor gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setGearing(AbstractMotor::gearset igearset) override; + + /** + * Gets the gearset that was set for the motor. + * + * @return One of gearset according to what is set for the motor, or gearset::invalid if the + * operation failed. + */ + gearset getGearing() override; + + /** + * Sets the reverse flag for the motor. This will invert its movements and the values returned for + * its position. + * + * @param ireverse True reverses the motor, false is default + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setReversed(bool ireverse) override; + + /** + * Sets the voltage limit for the motor in Volts. + * + * @param ilimit The new voltage limit in Volts + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setVoltageLimit(std::int32_t ilimit) override; + + /** + * Sets new PID constants. + * + * @param ikF the feed-forward constant + * @param ikP the proportional constant + * @param ikI the integral constant + * @param ikD the derivative constant + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setPosPID(double ikF, double ikP, double ikI, double ikD); + + /** + * Sets new PID constants. + * + * @param ikF the feed-forward constant + * @param ikP the proportional constant + * @param ikI the integral constant + * @param ikD the derivative constant + * @param ifilter a constant used for filtering the profile acceleration + * @param ilimit the integral limit + * @param ithreshold the threshold for determining if a position movement has reached its goal + * @param iloopSpeed the rate at which the PID computation is run (in ms) + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setPosPIDFull(double ikF, + double ikP, + double ikI, + double ikD, + double ifilter, + double ilimit, + double ithreshold, + double iloopSpeed); + + /** + * Sets new PID constants. + * + * @param ikF the feed-forward constant + * @param ikP the proportional constant + * @param ikI the integral constant + * @param ikD the derivative constant + * @return `1` if the operation was successful or `PROS_ERR` if the operation failed, setting + * errno. + */ + virtual std::int32_t setVelPID(double ikF, double ikP, double ikI, double ikD); + + /** + * Sets new PID constants. + * + * @param ikF the feed-forward constant + * @param ikP the proportional constant + * @param ikI the integral constant + * @param ikD the derivative constant + * @param ifilter a constant used for filtering the profile acceleration + * @param ilimit the integral limit + * @param ithreshold the threshold for determining if a position movement has reached its goal + * @param iloopSpeed the rate at which the PID computation is run (in ms) + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setVelPIDFull(double ikF, + double ikP, + double ikI, + double ikD, + double ifilter, + double ilimit, + double ithreshold, + double iloopSpeed); + + /** + * Get the encoder associated with this motor. + * + * @return The encoder for this motor. + */ + std::shared_ptr getEncoder() override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be `[-1, 1]`. + * + * @param ivalue The controller's output in the range `[-1, 1]`. + */ + void controllerSet(double ivalue) override; + + /** + * @return The port number. + */ + std::uint8_t getPort() const; + + /** + * @return Whether this motor is reversed. + */ + bool isReversed() const; + + protected: + std::uint8_t port; + std::int8_t reversed{1}; +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/motor/motorGroup.hpp b/pros/okapi/impl/device/motor/motorGroup.hpp new file mode 100644 index 00000000..6187c4c6 --- /dev/null +++ b/pros/okapi/impl/device/motor/motorGroup.hpp @@ -0,0 +1,400 @@ +/* + * 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 + +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include +#include + +namespace okapi { +class MotorGroup : public AbstractMotor { + public: + /** + * A group of V5 motors which act as one motor (i.e. they are mechanically linked). A MotorGroup + * requires at least one motor. If no motors are supplied, a `std::invalid_argument` exception is + * thrown. + * + * @param imotors The motors in this group. + * @param ilogger The logger this instance will log initialization warnings to. + */ + MotorGroup(const std::initializer_list &imotors, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * A group of V5 motors which act as one motor (i.e. they are mechanically linked). A MotorGroup + * requires at least one motor. If no motors are supplied, a `std::invalid_argument` exception is + * thrown. + * + * @param imotors The motors in this group. + * @param ilogger The logger this instance will log initialization warnings to. + */ + MotorGroup(const std::initializer_list> &imotors, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /******************************************************************************/ + /** Motor movement functions **/ + /** **/ + /** These functions allow programmers to make motors move **/ + /******************************************************************************/ + + /** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with setZeroPosition(). + * + * @note This function simply sets the target for the motor, it does not block program execution + * until the movement finishes. + * + * @param iposition The absolute position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t moveAbsolute(double iposition, std::int32_t ivelocity) override; + + /** + * Sets the relative target position for the motor to move to. + * + * This movement is relative to the current position of the motor. Providing 10.0 as the position + * parameter would result in the motor moving clockwise 10 units, 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. + * + * @param iposition The relative position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t moveRelative(double iposition, std::int32_t ivelocity) override; + + /** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the gearset + * used for the motor. This results in a range of +-100 for pros::c::red, + * +-200 for green, and +-600 for blue. The velocity + * is held with PID to ensure consistent speed, as opposed to setting the motor's + * voltage. + * + * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's + * gearset + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t moveVelocity(std::int16_t ivelocity) override; + + /** + * Sets the voltage for the motor from `-12000` to `12000`. + * + * @param ivoltage The new voltage value from `-12000` to `12000`. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t moveVoltage(std::int16_t ivoltage) override; + + /** + * Changes the output velocity for a profiled movement (moveAbsolute or moveRelative). This will + * have no effect if the motor is not following a profiled movement. + * + * @param ivelocity The new motor velocity from `+-100`, `+-200`, or `+-600` depending on the + * motor's gearset. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t modifyProfiledVelocity(std::int32_t ivelocity) override; + + /******************************************************************************/ + /** Motor telemetry functions **/ + /** **/ + /** These functions allow programmers to collect telemetry from motors **/ + /******************************************************************************/ + + /** + * Gets the target position set for the motor by the user. + * + * @return The target position in its encoder units or `PROS_ERR_F` if the operation failed, + * setting errno. + */ + double getTargetPosition() override; + + /** + * Gets the absolute position of the motor in its encoder units. + * + * @return The motor's absolute position in its encoder units or `PROS_ERR_F` if the operation + * failed, setting errno. + */ + double getPosition() override; + + /** + * Sets the "absolute" zero position of the motor to its current position. + * + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t tarePosition() override; + + /** + * Gets the velocity commanded to the motor by the user. + * + * @return The commanded motor velocity from +-100, +-200, or +-600, or `PROS_ERR` if the + * operation failed, setting errno. + */ + std::int32_t getTargetVelocity() override; + + /** + * Gets the actual velocity of the motor. + * + * @return The motor's actual velocity in RPM or `PROS_ERR_F` if the operation failed, setting + * errno. + */ + double getActualVelocity() override; + + /** + * Gets the current drawn by the motor in mA. + * + * @return The motor's current in mA or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t getCurrentDraw() override; + + /** + * Gets the direction of movement for the motor. + * + * @return 1 for moving in the positive direction, -1 for moving in the negative direction, and + * `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t getDirection() override; + + /** + * Gets the efficiency of the motor in percent. + * + * 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. + * + * @return The motor's efficiency in percent or `PROS_ERR_F` if the operation failed, setting + * errno. + */ + double getEfficiency() override; + + /** + * Checks if the motor is drawing over its current limit. + * + * @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. + */ + std::int32_t isOverCurrent() override; + + /** + * Checks if the motor's temperature is above its limit. + * + * @return 1 if the temperature limit is exceeded and 0 if the the temperature is below the limit, + * or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t isOverTemp() override; + + /** + * Checks if the motor is stopped. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns `PROS_ERR` with errno set to `ENOSYS`. + * + * @return 1 if the motor is not moving, 0 if the motor is moving, or `PROS_ERR` if the operation + * failed, setting errno + */ + std::int32_t isStopped() override; + + /** + * Checks if the motor is at its zero position. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns `PROS_ERR` with errno set to `ENOSYS`. + * + * @return 1 if the motor is at zero absolute position, `0` if the motor has moved from its + * absolute zero, or `PROS_ERR` if the operation failed, setting errno + */ + std::int32_t getZeroPositionFlag() override; + + /** + * Gets the faults experienced by the motor. Compare this bitfield to the bitmasks in + * pros::motor_fault_e_t. + * + * @return A currently unknown bitfield containing the motor's faults. `0b00000100` = Current + * Limit Hit + */ + uint32_t getFaults() override; + + /** + * Gets the flags set by the motor's operation. Compare this bitfield to the bitmasks in + * pros::motor_flag_e_t. + * + * @return A currently unknown bitfield containing the motor's flags. These seem to be unrelated + * to the individual get_specific_flag functions + */ + uint32_t getFlags() override; + + /** + * Gets the raw encoder count of the motor at a given timestamp. + * + * @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 The raw encoder count at the given timestamp or `PROS_ERR` if the operation failed. + */ + std::int32_t getRawPosition(std::uint32_t *timestamp) override; + + /** + * Gets the power drawn by the motor in Watts. + * + * @return The motor's power draw in Watts or `PROS_ERR_F` if the operation failed, setting errno. + */ + double getPower() override; + + /** + * Gets the temperature of the motor in degrees Celsius. + * + * @return The motor's temperature in degrees Celsius or `PROS_ERR_F` if the operation failed, + * setting errno. + */ + double getTemperature() override; + + /** + * Gets the torque generated by the motor in Newton Metres (Nm). + * + * @return The motor's torque in NM or `PROS_ERR_F` if the operation failed, setting errno. + */ + double getTorque() override; + + /** + * Gets the voltage delivered to the motor in millivolts. + * + * @return The motor's voltage in V or `PROS_ERR_F` if the operation failed, setting errno. + */ + std::int32_t getVoltage() override; + + /******************************************************************************/ + /** Motor configuration functions **/ + /** **/ + /** These functions allow programmers to configure the behavior of motors **/ + /******************************************************************************/ + + /** + * Sets one of AbstractMotor::brakeMode to the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param imode The new motor brake mode to set for the motor. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setBrakeMode(AbstractMotor::brakeMode imode) override; + + /** + * Gets the brake mode that was set for the motor. + * + * @return One of brakeMode, according to what was set for the motor, or brakeMode::invalid if the + * operation failed, setting errno. + */ + brakeMode getBrakeMode() override; + + /** + * Sets the current limit for the motor in mA. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ilimit The new current limit in mA. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setCurrentLimit(std::int32_t ilimit) override; + + /** + * Gets the current limit for the motor in mA. The default value is `2500` mA. + * + * @return The motor's current limit in mA or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t getCurrentLimit() override; + + /** + * Sets one of AbstractMotor::encoderUnits for the motor encoder. + * + * @param iunits The new motor encoder units. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setEncoderUnits(AbstractMotor::encoderUnits iunits) override; + + /** + * Gets the encoder units that were set for the motor. + * + * @return One of encoderUnits according to what is set for the motor or encoderUnits::invalid if + * the operation failed. + */ + encoderUnits getEncoderUnits() override; + + /** + * Sets one of AbstractMotor::gearset for the motor. + * + * @param igearset The new motor gearset. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setGearing(AbstractMotor::gearset igearset) override; + + /** + * Gets the gearset that was set for the motor. + * + * @return One of gearset according to what is set for the motor, or `gearset::invalid` if the + * operation failed. + */ + gearset getGearing() override; + + /** + * Sets the reverse flag for the motor. This will invert its movements and the values returned for + * its position. + * + * @param ireverse True reverses the motor, false is default. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setReversed(bool ireverse) override; + + /** + * Sets the voltage limit for the motor in Volts. + * + * @param ilimit The new voltage limit in Volts. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setVoltageLimit(std::int32_t ilimit) override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be `[-1, 1]`. + * + * @param ivalue the controller's output in the range `[-1, 1]` + */ + void controllerSet(double ivalue) override; + + /** + * Gets the number of motors in the motor group. + * + * @return size_t + */ + size_t getSize(); + + /** + * Get the encoder associated with the first motor in this group. + * + * @return The encoder for the motor at index `0`. + */ + std::shared_ptr getEncoder() override; + + /** + * Get the encoder associated with this motor. + * + * @param index The index in `motors` to get the encoder from. + * @return The encoder for the motor at `index`. + */ + virtual std::shared_ptr getEncoder(std::size_t index); + + protected: + std::vector> motors; +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/opticalSensor.hpp b/pros/okapi/impl/device/opticalSensor.hpp new file mode 100644 index 00000000..6b8b0be8 --- /dev/null +++ b/pros/okapi/impl/device/opticalSensor.hpp @@ -0,0 +1,140 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include + +namespace okapi { +enum class OpticalSensorOutput { + hue, ///< The color. + saturation, ///< The color's intensity relative to its brightness. + brightness ///< The amount of light. +}; + +class OpticalSensor : public ControllerInput { + public: + /** + * An optical sensor on a V5 port. + * + * ```cpp + * auto osHue = OpticalSensor(1); + * auto osSat = OpticalSensor(1, OpticalSensorOutput::saturation); + * ``` + * + * @param iport The V5 port the device uses. + * @param ioutput Which sensor output to return from (@ref okapi::OpticalSensor::get). + * @param idisableGestures Whether to automatically disable the gesture sensor. Typically, the + * gesture sensor should be disabled unless you are going to use gestures because the optical + * sensor does not update color information while detecting a gesture. + * @param ifilter The filter to use to filter the sensor output. Only the selected output (via + * ``ioutput``) is filtered; the other outputs are untouched. + */ + OpticalSensor(std::uint8_t iport, + OpticalSensorOutput ioutput = OpticalSensorOutput::hue, + bool idisableGestures = true, + std::unique_ptr ifilter = std::make_unique()); + + virtual ~OpticalSensor() = default; + + /** + * Get the current filtered value of the selected output (configured by the constructor). + * + * @return The current filtered value of the selected output (configured by the constructor). + */ + double get(); + + /** + * Get the current hue value in the range ``[0, 360)``. + * + * @return The current hue value in the range ``[0, 360)``. + */ + double getHue() const; + + /** + * Get the current brightness value in the range ``[0, 1]``. + * + * @return The current brightness value in the range ``[0, 1]``. + */ + double getBrightness() const; + + /** + * Get the current saturation value in the range ``[0, 1]``. + * + * @return The current saturation value in the range ``[0, 1]``. + */ + double getSaturation() const; + + /** + * Get the PWM value of the white LED in the range ``[0, 100]``. + * + * @return The PWM value of the white LED in the range ``[0, 100]`` or ``PROS_ERR`` if the + * operation failed, setting ``errno``. + */ + int32_t getLedPWM() const; + + /** + * Set the PWM value of the white LED in the range ``[0, 100]``. + * + * @param value The PWM value in the range ``[0, 100]``. + * @return ``1`` if the operation was successful or ``PROS_ERR`` if the operation failed, setting + * ``errno``. + */ + int32_t setLedPWM(std::uint8_t ivalue) const; + + /** + * Get the current proximity value in the range ``[0, 255]``. This is not available if gestures + * are being detected. + * + * @return The current proximity value in the range ``[0, 255]``. + */ + int32_t getProximity() const; + + /** + * Get the processed RGBC data from the sensor. + * + * @return The RGBC value if the operation was successful. If the operation failed, all field are + * set to ``PROS_ERR`` and ``errno`` is set. + */ + pros::c::optical_rgb_s_t getRGB() const; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return The same as [get](@ref okapi::OpticalSensor::get). + */ + double controllerGet() override; + + /** + * Enable gestures. + * + * @return ``1`` if the operation was successful or ``PROS_ERR`` if the operation failed, setting + * ``errno``. + */ + int32_t enableGestures() const; + + /** + * Disable gestures. + * + * @return ``1`` if the operation was successful or ``PROS_ERR`` if the operation failed, setting + * ``errno``. + */ + int32_t disableGestures() const; + + protected: + std::uint8_t port; + OpticalSensorOutput output; + std::unique_ptr filter; + + /** + * Gets the output directly from the sensor using the selected output. + */ + double getSelectedOutput(); +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/rotarysensor/IMU.hpp b/pros/okapi/impl/device/rotarysensor/IMU.hpp new file mode 100644 index 00000000..98b97dcd --- /dev/null +++ b/pros/okapi/impl/device/rotarysensor/IMU.hpp @@ -0,0 +1,109 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +enum class IMUAxes { + z, ///< Yaw Axis + y, ///< Pitch Axis + x ///< Roll Axis +}; + +class IMU : public ContinuousRotarySensor { + public: + /** + * An inertial sensor on the given port. The IMU returns an angle about the selected axis in + * degrees. + * + * ```cpp + * auto imuZ = IMU(1); + * auto imuX = IMU(1, IMUAxes::x); + * ``` + * + * @param iport The port number in the range ``[1, 21]``. + * @param iaxis The axis of the inertial sensor to measure, default `IMUAxes::z`. + */ + IMU(std::uint8_t iport, IMUAxes iaxis = IMUAxes::z); + + /** + * Get the current rotation about the configured axis. + * + * @return The current sensor value or ``PROS_ERR``. + */ + double get() const override; + + /** + * Get the current sensor value remapped into the target range (``[-1800, 1800]`` by default). + * + * @param iupperBound The upper bound of the range. + * @param ilowerBound The lower bound of the range. + * @return The remapped sensor value. + */ + double getRemapped(double iupperBound = 1800, double ilowerBound = -1800) const; + + /** + * Get the current acceleration along the configured axis. + * + * @return The current sensor value or ``PROS_ERR``. + */ + double getAcceleration() const; + + /** + * Reset the rotation value to zero. + * + * @return ``1`` or ``PROS_ERR``. + */ + std::int32_t reset() override; + + /** + * Resets rotation value to desired value + * For example, ``reset(0)`` will reset the sensor to zero. + * But ``reset(90)`` will reset the sensor to 90 degrees. + * + * @param inewAngle desired reset value + * @return ``1`` or ``PROS_ERR``. + */ + std::int32_t reset(double inewAngle); + + /** + * Calibrate the IMU. Resets the rotation value to zero. Calibration is expected to take two + * seconds, but is bounded to five seconds. + * + * @return ``1`` or ``PROS_ERR``. + */ + std::int32_t calibrate(); + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return The current sensor value or ``PROS_ERR``. + */ + double controllerGet() override; + + /** + * @return Whether the IMU is calibrating. + */ + bool isCalibrating() const; + + protected: + std::uint8_t port; + IMUAxes axis; + double offset = 0; + + /** + * Get the current rotation about the configured axis. The internal offset is not accounted for + * or modified. This just reads from the sensor. + * + * @return The current sensor value or ``PROS_ERR``. + */ + double readAngle() const; +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/rotarysensor/adiEncoder.hpp b/pros/okapi/impl/device/rotarysensor/adiEncoder.hpp new file mode 100644 index 00000000..da2eb3bd --- /dev/null +++ b/pros/okapi/impl/device/rotarysensor/adiEncoder.hpp @@ -0,0 +1,73 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +class ADIEncoder : public ContinuousRotarySensor { + public: + /** + * An encoder in an ADI port. + * + * ```cpp + * auto enc = ADIEncoder('A', 'B', false); + * auto reversedEnc = ADIEncoder('A', 'B', true); + * ``` + * + * @param iportTop The "top" wire from the encoder with the removable cover side up. This must be + * in port ``1``, ``3``, ``5``, or ``7`` (``A``, ``C``, ``E``, or ``G``). + * @param iportBottom The "bottom" wire from the encoder. This must be in port ``2``, ``4``, + * ``6``, or ``8`` (``B``, ``D``, ``F``, or ``H``). + * @param ireversed Whether the encoder is reversed. + */ + ADIEncoder(std::uint8_t iportTop, std::uint8_t iportBottom, bool ireversed = false); + + /** + * An encoder in an ADI port. + * + * ```cpp + * auto enc = ADIEncoder({1, 'A', 'B'}, false); + * auto reversedEnc = ADIEncoder({1, 'A', 'B'}, true); + * ``` + * + * @param iports The ports the encoder is plugged in to in the order ``{smart port, top port, + * bottom port}``. The smart port is the smart port number (``[1, 21]``). The top port is the + * "top" wire from the encoder with the removable cover side up. This must be in port ``1``, + * ``3``, ``5``, or + * ``7`` (``A``, ``C``, ``E``, or ``G``). The bottom port is the "bottom" wire from the encoder. + * This must be in port ``2``, ``4``, ``6``, or ``8`` (``B``, ``D``, ``F``, or ``H``). + * @param ireversed Whether the encoder is reversed. + */ + ADIEncoder(std::tuple iports, bool ireversed = false); + + /** + * Get the current sensor value. + * + * @return the current sensor value, or `PROS_ERR` on a failure. + */ + virtual double get() const override; + + /** + * Reset the sensor to zero. + * + * @return `1` on success, `PROS_ERR` on fail + */ + virtual std::int32_t reset() override; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or `PROS_ERR` on a failure. + */ + virtual double controllerGet() override; + + protected: + pros::c::ext_adi_encoder_t enc; +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/rotarysensor/adiGyro.hpp b/pros/okapi/impl/device/rotarysensor/adiGyro.hpp new file mode 100644 index 00000000..f8a34a76 --- /dev/null +++ b/pros/okapi/impl/device/rotarysensor/adiGyro.hpp @@ -0,0 +1,82 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +class ADIGyro : public ContinuousRotarySensor { + public: + /** + * A gyroscope on the given ADI port. If the port has not previously been configured as a gyro, + * then the constructor will block for 1 second for calibration. The gyro measures in tenths of a + * degree, so there are ``3600`` measurement points per revolution. + * + * ```cpp + * auto gyro = ADIGyro('A'); + * ``` + * + * @param iport The ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). + * @param imultiplier A value multiplied by the gyro heading value. + */ + ADIGyro(std::uint8_t iport, double imultiplier = 1); + + /** + * A gyroscope on the given ADI port. If the port has not previously been configured as a gyro, + * then the constructor will block for 1 second for calibration. The gyro measures in tenths of a + * degree, so there are 3600 measurement points per revolution. + * + * ```cpp + * auto gyro = ADIGyro({1, 'A'}, 1); + * ``` + * + * Note to developers: Keep the default value on imultiplier so that users get an error if they do + * ADIGyro({1, 'A'}). Without it, this calls the non-ext-adi constructor. + * + * @param iports The ports the gyro is plugged in to in the order ``{smart port, gyro port}``. The + * smart port is the smart port number (``[1, 21]``). The gyro port is the ADI port number (``[1, + * 8]``, ``[a, h]``, ``[A, H]``). + * @param imultiplier A value multiplied by the gyro heading value. + */ + ADIGyro(std::pair iports, double imultiplier = 1); + + /** + * Get the current sensor value. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + double get() const override; + + /** + * Get the current sensor value remapped into the target range (``[-1800, 1800]`` by default). + * + * @param iupperBound the upper bound of the range. + * @param ilowerBound the lower bound of the range. + * @return the remapped sensor value. + */ + double getRemapped(double iupperBound = 1800, double ilowerBound = -1800) const; + + /** + * Reset the sensor to zero. + * + * @return `1` on success, `PROS_ERR` on fail + */ + std::int32_t reset() override; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + double controllerGet() override; + + protected: + pros::c::ext_adi_gyro_t gyro; +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/rotarysensor/integratedEncoder.hpp b/pros/okapi/impl/device/rotarysensor/integratedEncoder.hpp new file mode 100644 index 00000000..8b3473b5 --- /dev/null +++ b/pros/okapi/impl/device/rotarysensor/integratedEncoder.hpp @@ -0,0 +1,56 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" +#include "okapi/impl/device/motor/motor.hpp" + +namespace okapi { +class IntegratedEncoder : public ContinuousRotarySensor { + public: + /** + * Integrated motor encoder. Uses the encoder inside the V5 motor. + * + * @param imotor The motor to use the encoder from. + */ + IntegratedEncoder(const okapi::Motor &imotor); + + /** + * Integrated motor encoder. Uses the encoder inside the V5 motor. + * + * @param iport The motor's port number in the range [1, 21]. + * @param ireversed Whether the encoder is reversed. + */ + IntegratedEncoder(std::int8_t iport, bool ireversed = false); + + /** + * Get the current sensor value. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + virtual double get() const override; + + /** + * Reset the sensor to zero. + * + * @return `1` on success, `PROS_ERR` on fail + */ + virtual std::int32_t reset() override; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + virtual double controllerGet() override; + + protected: + std::uint8_t port; + std::int8_t reversed{1}; +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/rotarysensor/potentiometer.hpp b/pros/okapi/impl/device/rotarysensor/potentiometer.hpp new file mode 100644 index 00000000..7842c3f3 --- /dev/null +++ b/pros/okapi/impl/device/rotarysensor/potentiometer.hpp @@ -0,0 +1,57 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/device/rotarysensor/rotarySensor.hpp" + +namespace okapi { +class Potentiometer : public RotarySensor { + public: + /** + * A potentiometer in an ADI port. + * + * ```cpp + * auto pot = Potentiometer('A'); + * ``` + * + * @param iport The ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). + */ + Potentiometer(std::uint8_t iport); + + /** + * A potentiometer in an ADI port. + * + * ```cpp + * auto pot = Potentiometer({1, 'A'}); + * ``` + * + * @param iports The ports the potentiometer is plugged in to in the order ``{smart port, + * potentiometer port}``. The smart port is the smart port number (``[1, 21]``). The potentiometer + * port is the ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). + */ + Potentiometer(std::pair iports); + + /** + * Get the current sensor value. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + virtual double get() const override; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + virtual double controllerGet() override; + + protected: + std::uint8_t smartPort; + std::uint8_t port; +}; +} // namespace okapi diff --git a/pros/okapi/impl/device/rotarysensor/rotationSensor.hpp b/pros/okapi/impl/device/rotarysensor/rotationSensor.hpp new file mode 100644 index 00000000..9e645410 --- /dev/null +++ b/pros/okapi/impl/device/rotarysensor/rotationSensor.hpp @@ -0,0 +1,64 @@ +/* + * 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 + +#include "api.h" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +class RotationSensor : public ContinuousRotarySensor { + public: + /** + * A rotation sensor in a V5 port. + * + * ```cpp + * auto r = RotationSensor(1); + * auto reversedR = RotationSensor(1, true); + * ``` + * + * @param iport The V5 port the device uses. + * @param ireversed Whether the sensor is reversed. This will set the reversed state in the + * kernel. + */ + RotationSensor(std::uint8_t iport, bool ireversed = false); + + /** + * Get the current rotation in degrees. + * + * @return The current rotation in degrees or ``PROS_ERR_F`` if the operation failed, setting + * ``errno``. + */ + double get() const override; + + /** + * Reset the sensor to zero. + * + * @return ``1`` if the operation was successful or ``PROS_ERR`` if the operation failed, setting + * ``errno``. + */ + std::int32_t reset() override; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return The same as [get](@ref okapi::RotationSensor::get). + */ + double controllerGet() override; + + /** + * Get the current rotational velocity estimate in degrees per second. + * + * @return The current rotational velocity estimate in degrees per second or ``PROS_ERR_F`` if the + * operation failed, setting ``errno``. + */ + double getVelocity() const; + + protected: + std::uint8_t port; + std::int8_t reversed{1}; +}; +} // namespace okapi diff --git a/pros/okapi/impl/filter/velMathFactory.hpp b/pros/okapi/impl/filter/velMathFactory.hpp new file mode 100644 index 00000000..af223d44 --- /dev/null +++ b/pros/okapi/impl/filter/velMathFactory.hpp @@ -0,0 +1,68 @@ +/* + * 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 + +#include "okapi/api/filter/velMath.hpp" +#include + +namespace okapi { +class VelMathFactory { + public: + /** + * Velocity math helper. Calculates filtered velocity. Throws a std::invalid_argument exception + * if iticksPerRev is zero. Averages the last two readings. + * + * @param iticksPerRev The number of ticks per revolution. + * @param isampleTime The minimum time between samples. + * @param ilogger The logger this instance will log to. + */ + static VelMath create(double iticksPerRev, + QTime isampleTime = 0_ms, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity math helper. Calculates filtered velocity. Throws a std::invalid_argument exception + * if iticksPerRev is zero. Averages the last two readings. + * + * @param iticksPerRev The number of ticks per revolution. + * @param isampleTime The minimum time between samples. + * @param ilogger The logger this instance will log to. + */ + static std::unique_ptr + createPtr(double iticksPerRev, + QTime isampleTime = 0_ms, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity math helper. Calculates filtered velocity. Throws a std::invalid_argument exception + * if iticksPerRev is zero. + * + * @param iticksPerRev The number of ticks per revolution. + * @param ifilter The filter used for filtering the calculated velocity. + * @param isampleTime The minimum time between samples. + * @param ilogger The logger this instance will log to. + */ + static VelMath create(double iticksPerRev, + std::unique_ptr ifilter, + QTime isampleTime = 0_ms, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity math helper. Calculates filtered velocity. Throws a std::invalid_argument exception + * if iticksPerRev is zero. + * + * @param iticksPerRev The number of ticks per revolution. + * @param ifilter The filter used for filtering the calculated velocity. + * @param isampleTime The minimum time between samples. + * @param ilogger The logger this instance will log to. + */ + static std::unique_ptr + createPtr(double iticksPerRev, + std::unique_ptr ifilter, + QTime isampleTime = 0_ms, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); +}; +} // namespace okapi diff --git a/pros/okapi/impl/util/configurableTimeUtilFactory.hpp b/pros/okapi/impl/util/configurableTimeUtilFactory.hpp new file mode 100644 index 00000000..3775460f --- /dev/null +++ b/pros/okapi/impl/util/configurableTimeUtilFactory.hpp @@ -0,0 +1,34 @@ +/* + * 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 + +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +/** + * A TimeUtilFactory that supplies the SettledUtil parameters passed in the constructor to every + * new TimeUtil instance. + */ +class ConfigurableTimeUtilFactory : public TimeUtilFactory { + public: + ConfigurableTimeUtilFactory(double iatTargetError = 50, + double iatTargetDerivative = 5, + const QTime &iatTargetTime = 250_ms); + + /** + * Creates a TimeUtil with the SettledUtil parameters specified in the constructor by + * delegating to TimeUtilFactory::withSettledUtilParams. + * + * @return A TimeUtil with the SettledUtil parameters specified in the constructor. + */ + TimeUtil create() override; + + private: + double atTargetError; + double atTargetDerivative; + QTime atTargetTime; +}; +} // namespace okapi diff --git a/pros/okapi/impl/util/rate.hpp b/pros/okapi/impl/util/rate.hpp new file mode 100644 index 00000000..b76be723 --- /dev/null +++ b/pros/okapi/impl/util/rate.hpp @@ -0,0 +1,42 @@ +/* + * 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 + +#include "okapi/api/util/abstractRate.hpp" + +namespace okapi { +class Rate : public AbstractRate { + public: + Rate(); + + /** + * Delay the current task such that it runs at the given frequency. The first delay will run for + * 1000/(ihz). Subsequent delays will adjust according to the previous runtime of the task. + * + * @param ihz the frequency + */ + void delay(QFrequency ihz) override; + + /** + * Delay the current task until itime has passed. This method can be used by periodic tasks to + * ensure a consistent execution frequency. + * + * @param itime the time period + */ + void delayUntil(QTime itime) override; + + /** + * Delay the current task until ims milliseconds have passed. This method can be used by + * periodic tasks to ensure a consistent execution frequency. + * + * @param ims the time period + */ + void delayUntil(uint32_t ims) override; + + protected: + std::uint32_t lastTime{0}; +}; +} // namespace okapi diff --git a/pros/okapi/impl/util/timeUtilFactory.hpp b/pros/okapi/impl/util/timeUtilFactory.hpp new file mode 100644 index 00000000..5d4f116c --- /dev/null +++ b/pros/okapi/impl/util/timeUtilFactory.hpp @@ -0,0 +1,32 @@ +/* + * 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 + +#include "okapi/api/util/timeUtil.hpp" + +namespace okapi { +class TimeUtilFactory { + public: + virtual ~TimeUtilFactory() = default; + + /** + * Creates a default TimeUtil. + */ + virtual TimeUtil create(); + + /** + * Creates a default TimeUtil. + */ + static TimeUtil createDefault(); + + /** + * Creates a TimeUtil with custom SettledUtil params. See SettledUtil docs. + */ + static TimeUtil withSettledUtilParams(double iatTargetError = 50, + double iatTargetDerivative = 5, + const QTime &iatTargetTime = 250_ms); +}; +} // namespace okapi diff --git a/pros/okapi/impl/util/timer.hpp b/pros/okapi/impl/util/timer.hpp new file mode 100644 index 00000000..13d77c92 --- /dev/null +++ b/pros/okapi/impl/util/timer.hpp @@ -0,0 +1,22 @@ +/* + * 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 + +#include "okapi/api/util/abstractTimer.hpp" + +namespace okapi { +class Timer : public AbstractTimer { + public: + Timer(); + + /** + * Returns the current time in units of QTime. + * + * @return the current time + */ + QTime millis() const override; +}; +} // namespace okapi diff --git a/pros/okapi/squiggles/constraints.hpp b/pros/okapi/squiggles/constraints.hpp new file mode 100644 index 00000000..f59089be --- /dev/null +++ b/pros/okapi/squiggles/constraints.hpp @@ -0,0 +1,65 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _SQUIGGLES_CONSTRAINTS_HPP_ +#define _SQUIGGLES_CONSTRAINTS_HPP_ + +#include +#include + +namespace squiggles { +struct Constraints { + /** + * Defines the motion constraints for a path. + * + * @param imax_vel The maximum allowable velocity for the robot in meters per + * second. + * @param imax_accel The maximum allowable acceleration for the robot in + * meters per second per second. + * @param imax_jerk The maximum allowable jerk for the robot in meters per + * second per second per second (m/s^3). + * @param imax_curvature The maximum allowable change in heading in radians + * per second. This is not set to the numeric limits by + * default as that will allow for wild paths. + * @param imin_accel The minimum allowable acceleration for the robot in + * meters per second per second. + */ + Constraints(double imax_vel, + double imax_accel = std::numeric_limits::max(), + double imax_jerk = std::numeric_limits::max(), + double imax_curvature = 1000, + double imin_accel = std::nan("")) + : max_vel(imax_vel), + max_accel(imax_accel), + max_jerk(imax_jerk), + max_curvature(imax_curvature) { + if (imax_accel == std::numeric_limits::max()) { + min_accel = std::numeric_limits::lowest(); + } else { + min_accel = std::isnan(imin_accel) ? -imax_accel : imin_accel; + } + } + + /** + * Serializes the Constraints data for debugging. + * + * @return The Constraints data. + */ + std::string to_string() const { + return "Constraints: {max_vel: " + std::to_string(max_vel) + + ", max_accel: " + std::to_string(max_accel) + + ", max_jerk: " + std::to_string(max_jerk) + + ", min_accel: " + std::to_string(min_accel) + "}"; + } + + double max_vel; + double max_accel; + double max_jerk; + double min_accel; + double max_curvature; +}; +} // namespace squiggles +#endif diff --git a/pros/okapi/squiggles/geometry/controlvector.hpp b/pros/okapi/squiggles/geometry/controlvector.hpp new file mode 100644 index 00000000..c279bd49 --- /dev/null +++ b/pros/okapi/squiggles/geometry/controlvector.hpp @@ -0,0 +1,62 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _GEOMETRY_CONTROL_VECTOR_HPP_ +#define _GEOMETRY_CONTROL_VECTOR_HPP_ + +#include +#include + +#include "pose.hpp" + +namespace squiggles { +class ControlVector { + public: + /** + * A vector used to specify a state along a hermite spline. + * + * @param ipose The 2D position and heading. + * @param ivel The velocity component of the vector. + * @param iaccel The acceleration component of the vector. + * @param ijerk The jerk component of the vector. + */ + ControlVector(Pose ipose, + double ivel = std::nan(""), + double iaccel = 0.0, + double ijerk = 0.0) + : pose(ipose), vel(ivel), accel(iaccel), jerk(ijerk) {} + + ControlVector() = default; + + /** + * Serializes the Control Vector data for debugging. + * + * @return The Control Vector data. + */ + std::string to_string() const { + return "ControlVector: {" + pose.to_string() + + ", v: " + std::to_string(vel) + ", a: " + std::to_string(accel) + + ", j: " + std::to_string(jerk) + "}"; + } + + std::string to_csv() const { + return pose.to_csv() + "," + std::to_string(vel) + "," + + std::to_string(accel) + "," + std::to_string(jerk); + } + + bool operator==(const ControlVector& other) const { + return pose == other.pose && nearly_equal(vel, other.vel) && + nearly_equal(accel, other.accel) && nearly_equal(jerk, other.jerk); + } + + Pose pose; + double vel; + double accel; + double jerk; +}; +} // namespace squiggles + +#endif \ No newline at end of file diff --git a/pros/okapi/squiggles/geometry/pose.hpp b/pros/okapi/squiggles/geometry/pose.hpp new file mode 100644 index 00000000..b3b76907 --- /dev/null +++ b/pros/okapi/squiggles/geometry/pose.hpp @@ -0,0 +1,67 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _GEOMETRY_POSE_HPP_ +#define _GEOMETRY_POSE_HPP_ + +#include +#include + +#include "math/utils.hpp" + +namespace squiggles { +class Pose { + public: + /** + * Specifies a point and heading in 2D space. + * + * @param ix The x position of the point in meters. + * @param iy The y position of the point in meters. + * @param iyaw The heading at the point in radians. + */ + Pose(double ix, double iy, double iyaw) : x(ix), y(iy), yaw(iyaw) {} + + Pose() = default; + + /** + * Calculates the Euclidean distance between this pose and another. + * + * @param other The point from which the distance will be calculated. + * + * @return The distance between this pose and Other. + */ + double dist(const Pose& other) const { + return std::sqrt((x - other.x) * (x - other.x) + + (y - other.y) * (y - other.y)); + } + + /** + * Serializes the Pose data for debugging. + * + * @return The Pose data. + */ + std::string to_string() const { + return "Pose: {x: " + std::to_string(x) + ", y: " + std::to_string(y) + + ", yaw: " + std::to_string(yaw) + "}"; + } + + std::string to_csv() const { + return std::to_string(x) + "," + std::to_string(y) + "," + + std::to_string(yaw); + } + + bool operator==(const Pose& other) const { + return nearly_equal(x, other.x) && nearly_equal(y, other.y) && + nearly_equal(yaw, other.yaw); + } + + double x; + double y; + double yaw; +}; +} // namespace squiggles + +#endif \ No newline at end of file diff --git a/pros/okapi/squiggles/geometry/profilepoint.hpp b/pros/okapi/squiggles/geometry/profilepoint.hpp new file mode 100644 index 00000000..e6eed094 --- /dev/null +++ b/pros/okapi/squiggles/geometry/profilepoint.hpp @@ -0,0 +1,100 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _GEOMETRY_PROFILE_POINT_HPP_ +#define _GEOMETRY_PROFILE_POINT_HPP_ + +#include +#include +#include + +#include "controlvector.hpp" +#include "math/utils.hpp" + +namespace squiggles { +struct ProfilePoint { + /** + * Defines a state along a motion profiled path. + * + * @param ivector The pose and associated dynamics at this state in the path. + * @param iwheel_velocities The component of the robot's velocity provided by + * each wheel in meters per second. + * @param icurvature The degree to which the curve deviates from a straight + * line at this point in 1 / meters. + * @param itime The timestamp for this state relative to the start of the + * path in seconds. + */ + ProfilePoint(ControlVector ivector, + std::vector iwheel_velocities, + double icurvature, + double itime) + : vector(ivector), + wheel_velocities(iwheel_velocities), + curvature(icurvature), + time(itime) {} + + ProfilePoint() = default; + + /** + * Serializes the Profile Point data for debugging. + * + * @return The Profile Point data. + */ + std::string to_string() const { + std::string wheels = "{"; + for (auto& w : wheel_velocities) { + wheels += std::to_string(w); + wheels += ", "; + } + wheels += "}"; + return "ProfilePoint: {" + vector.to_string() + ", wheels: " + wheels + + ", k: " + std::to_string(curvature) + + ", t: " + std::to_string(time) + "}"; + } + + std::string to_csv() const { + std::string wheels = ""; + for (auto& w : wheel_velocities) { + wheels += ","; + wheels += std::to_string(w); + } + return vector.to_csv() + "," + std::to_string(curvature) + "," + + std::to_string(time) + wheels; + } + + bool operator==(const ProfilePoint& other) const { + for (std::size_t i = 0; i < wheel_velocities.size(); ++i) { + if (!nearly_equal(wheel_velocities[i], other.wheel_velocities[i])) { + return false; + } + } + return vector == other.vector && nearly_equal(curvature, other.curvature) && + nearly_equal(time, other.time); + } + + friend std::ostream& operator<<(std::ostream& os, const ProfilePoint& p) { + return os << "ProfilePoint(ControlVector(Pose(" + + std::to_string(p.vector.pose.x) + "," + + std::to_string(p.vector.pose.y) + "," + + std::to_string(p.vector.pose.yaw) + ")," + + std::to_string(p.vector.vel) + "," + + std::to_string(p.vector.accel) + "," + + std::to_string(p.vector.jerk) + "),{" + + std::to_string(p.wheel_velocities[0]) + "," + + std::to_string(p.wheel_velocities[1]) + "}," + + std::to_string(p.curvature) + "," + std::to_string(p.time) + + "),"; + // return os << p.to_string(); + } + + ControlVector vector; + std::vector wheel_velocities; + double curvature; + double time; +}; +} // namespace squiggles + +#endif \ No newline at end of file diff --git a/pros/okapi/squiggles/io.hpp b/pros/okapi/squiggles/io.hpp new file mode 100644 index 00000000..c22ed970 --- /dev/null +++ b/pros/okapi/squiggles/io.hpp @@ -0,0 +1,56 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _SQUIGGLES_IO_HPP_ +#define _SQUIGGLES_IO_HPP_ + +#include +#include + +#include "geometry/profilepoint.hpp" + +namespace squiggles { +/** + * Writes the path data to a CSV file. + * + * @param out The output stream to write the CSV data to. This is usually a + * file. + * @param path The path to serialized + * + * @return 0 if the path was serialized succesfully or -1 if an error occurred. + */ +int serialize_path(std::ostream& out, std::vector path); + +/** + * Converts CSV data into a path. + * + * @param in The input stream containing the CSV data. This is usually a file. + * + * @return The path specified by the CSV data or std::nullopt if de-serializing + * the path was unsuccessful. + */ +std::optional> deserialize_path(std::istream& in); + +/** + * Converts CSV data from the Pathfinder library's format to a Squiggles path. + * + * NOTE: this code translates data from Jaci Brunning's Pathfinder library. + * The source for that library can be found at: + * https://github.com/JaciBrunning/Pathfinder/ + * + * @param left The input stream containing the left wheels' CSV data. This is + * usually a file. + * @param right The input stream containing the right wheels' CSV data. This is + * usually a file. + * + * @return The path specified by the CSV data or std::nullopt if de-serializing + * the path was unsuccessful. + */ +std::optional> +deserialize_pathfinder_path(std::istream& left, std::istream& right); +} // namespace squiggles + +#endif diff --git a/pros/okapi/squiggles/math/quinticpolynomial.hpp b/pros/okapi/squiggles/math/quinticpolynomial.hpp new file mode 100644 index 00000000..f12580fc --- /dev/null +++ b/pros/okapi/squiggles/math/quinticpolynomial.hpp @@ -0,0 +1,65 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _MATH_QUINTIC_POLYNOMIAL_HPP_ +#define _MATH_QUINTIC_POLYNOMIAL_HPP_ + +#include + +namespace squiggles { +class QuinticPolynomial { + public: + /** + * Defines the polynomial function for a spline in one dimension. + * + * @param s_p The starting position of the curve in meters. + * @param s_v The starting velocity of the curve in meters per second. + * @param s_a The starting acceleration of the curve in meters per second per + * second. + * @param g_p The goal or ending position of the curve in meters. + * @param g_v The goal or ending velocity of the curve in meters per second. + * @param g_a The goal or ending acceleration of the curve in meters per + * second per second. + * @param t The desired duration for the curve in seconds. + */ + QuinticPolynomial(double s_p, + double s_v, + double s_a, + double g_p, + double g_v, + double g_a, + double t); + + /** + * Calculates the values of the polynomial and its derivatives at the given + * time stamp. + */ + double calc_point(double t); + double calc_first_derivative(double t); + double calc_second_derivative(double t); + double calc_third_derivative(double t); + + /** + * Serializes the Quintic Polynomial data for debugging. + * + * @return The Quintic Polynomial data. + */ + std::string to_string() const { + return "QuinticPolynomial: {0: " + std::to_string(a0) + + " 1: " + std::to_string(a1) + " 2: " + std::to_string(a2) + + " 3: " + std::to_string(a3) + " 4: " + std::to_string(a4) + + " 5: " + std::to_string(a5) + "}"; + } + + protected: + /** + * The coefficients for each term of the polynomial. + */ + double a0, a1, a2, a3, a4, a5; +}; +} // namespace squiggles + +#endif \ No newline at end of file diff --git a/pros/okapi/squiggles/math/utils.hpp b/pros/okapi/squiggles/math/utils.hpp new file mode 100644 index 00000000..cca3da0c --- /dev/null +++ b/pros/okapi/squiggles/math/utils.hpp @@ -0,0 +1,61 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _MATH_UTILS_HPP_ +#define _MATH_UTILS_HPP_ + +#include +#include + +namespace squiggles { +/** + * Returns the sign value of the given value. + * + * @return 1 if the value is positive, -1 if the value is negative, and 0 if + * the value is 0. + */ +template inline int sgn(T v) { + return (v > T(0)) - (v < T(0)); +} + +inline bool +nearly_equal(const double& a, const double& b, double epsilon = 1e-5) { + return std::fabs(a - b) < epsilon; +} +} // namespace squiggles + +namespace std { +// Copied from https://github.com/emsr/cxx_linear +template +constexpr std::enable_if_t< + std::is_floating_point_v<_Float> && + __cplusplus <= 201703L, // Only defines this function if C++ standard < 20 + _Float> +lerp(_Float __a, _Float __b, _Float __t) { + if (std::isnan(__a) || std::isnan(__b) || std::isnan(__t)) + return std::numeric_limits<_Float>::quiet_NaN(); + else if ((__a <= _Float{0} && __b >= _Float{0}) || + (__a >= _Float{0} && __b <= _Float{0})) + // ab <= 0 but product could overflow. +#ifndef FMA + return __t * __b + (_Float{1} - __t) * __a; +#else + return std::fma(__t, __b, (_Float{1} - __t) * __a); +#endif + else if (__t == _Float{1}) + return __b; + else { // monotonic near t == 1. +#ifndef FMA + const auto __x = __a + __t * (__b - __a); +#else + const auto __x = std::fma(__t, __b - __a, __a); +#endif + return (__t > _Float{1}) == (__b > __a) ? std::max(__b, __x) + : std::min(__b, __x); + } +} +} // namespace std +#endif \ No newline at end of file diff --git a/pros/okapi/squiggles/physicalmodel/passthroughmodel.hpp b/pros/okapi/squiggles/physicalmodel/passthroughmodel.hpp new file mode 100644 index 00000000..1db2a17a --- /dev/null +++ b/pros/okapi/squiggles/physicalmodel/passthroughmodel.hpp @@ -0,0 +1,38 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _PHYSICAL_MODEL_PASSTHROUGH_MODEL_HPP_ +#define _PHYSICAL_MODEL_PASSTHROUGH_MODEL_HPP_ + +#include "physicalmodel/physicalmodel.hpp" + +namespace squiggles { +class PassthroughModel : public PhysicalModel { + public: + /** + * Defines a Physical Model that imposes no constraints of its own. + */ + PassthroughModel() = default; + + Constraints constraints([[maybe_unused]] const Pose pose, + [[maybe_unused]] double curvature, + double vel) override { + return Constraints(vel); + }; + + std::vector + linear_to_wheel_vels([[maybe_unused]] double lin_vel, + [[maybe_unused]] double curvature) override { + return std::vector{}; + } + + std::string to_string() const override { + return "PassthroughModel {}"; + } +}; +} // namespace squiggles + +#endif diff --git a/pros/okapi/squiggles/physicalmodel/physicalmodel.hpp b/pros/okapi/squiggles/physicalmodel/physicalmodel.hpp new file mode 100644 index 00000000..5c22a4ca --- /dev/null +++ b/pros/okapi/squiggles/physicalmodel/physicalmodel.hpp @@ -0,0 +1,43 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _PHYSICAL_MODEL_PHYSICAL_MODEL_HPP_ +#define _PHYSICAL_MODEL_PHYSICAL_MODEL_HPP_ + +#include "constraints.hpp" +#include "geometry/pose.hpp" + +namespace squiggles { +class PhysicalModel { + public: + /** + * Calculate a set of stricter constraints for the path at the given state + * than the general constraints based on the robot's kinematics. + * + * @param pose The 2D pose for this state in the path. + * @param curvature The change in heading at this state in the path in 1 / + * meters. + * @param vel The linear velocity at this state in the path in meters per + * second. + */ + virtual Constraints + constraints(const Pose pose, double curvature, double vel) = 0; + + /** + * Converts a linear velocity and desired curvature into the component for + * each wheel of the robot. + * + * @param linear The linear velocity for the robot in meters per second. + * @param curvature The change in heading for the robot in 1 / meters. + */ + virtual std::vector linear_to_wheel_vels(double linear, + double curvature) = 0; + + virtual std::string to_string() const = 0; +}; +} // namespace squiggles + +#endif diff --git a/pros/okapi/squiggles/physicalmodel/tankmodel.hpp b/pros/okapi/squiggles/physicalmodel/tankmodel.hpp new file mode 100644 index 00000000..9f0709b2 --- /dev/null +++ b/pros/okapi/squiggles/physicalmodel/tankmodel.hpp @@ -0,0 +1,45 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _PHYSICAL_MODEL_TANK_MODEL_HPP_ +#define _PHYSICAL_MODEL_TANK_MODEL_HPP_ + +#include +#include + +#include "physicalmodel/physicalmodel.hpp" + +namespace squiggles { +class TankModel : public PhysicalModel { + public: + /** + * Defines a model of a tank drive or differential drive robot. + * + * @param itrack_width The distance between the the wheels on each side of the + * robot in meters. + * @param ilinear_constraints The maximum values for the robot's movement. + */ + TankModel(double itrack_width, Constraints ilinear_constraints); + + Constraints + constraints(const Pose pose, double curvature, double vel) override; + + std::vector linear_to_wheel_vels(double lin_vel, + double curvature) override; + + std::string to_string() const override; + + private: + double vel_constraint(const Pose pose, double curvature, double vel); + std::tuple + accel_constraint(const Pose pose, double curvature, double vel) const; + + double track_width; + Constraints linear_constraints; +}; +} // namespace squiggles + +#endif \ No newline at end of file diff --git a/pros/okapi/squiggles/spline.hpp b/pros/okapi/squiggles/spline.hpp new file mode 100644 index 00000000..4ee5991f --- /dev/null +++ b/pros/okapi/squiggles/spline.hpp @@ -0,0 +1,310 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _SQUIGGLES_SPLINE_HPP_ +#define _SQUIGGLES_SPLINE_HPP_ + +#include +#include +#include + +#include "constraints.hpp" +#include "geometry/controlvector.hpp" +#include "geometry/profilepoint.hpp" +#include "math/quinticpolynomial.hpp" +#include "physicalmodel/passthroughmodel.hpp" +#include "physicalmodel/physicalmodel.hpp" + +namespace squiggles { +class SplineGenerator { + public: + /** + * Generates curves that match the given motion constraints. + * + * @param iconstraints The maximum allowable values for the robot's motion. + * @param imodel The robot's physical characteristics and constraints + * @param idt The difference in time in seconds between each state for the + * generated paths. + */ + SplineGenerator(Constraints iconstraints, + std::shared_ptr imodel = + std::make_shared(), + double idt = 0.1); + + /** + * Creates a motion profiled path between the given waypoints. + * + * @param iwaypoints The list of poses that the robot should reach along the + * path. + * @param fast If true, the path optimization process will stop as soon as the + * constraints are met. If false, the optimizer will find the + * smoothest possible path between the points. + * + * @return A series of robot states defining a path between the poses. + */ + std::vector generate(std::vector iwaypoints, + bool fast = false); + std::vector generate(std::initializer_list iwaypoints, + bool fast = false); + + /** + * Creates a motion profiled path between the given waypoints. + * + * @param iwaypoints The list of vectors that the robot should reach along the + * path. + * + * @return A series of robot states defining a path between the vectors. + */ + std::vector generate(std::vector iwaypoints); + std::vector + generate(std::initializer_list iwaypoints); + + protected: + /** + * The maximum allowable values for the robot's motion. + */ + Constraints constraints; + + /** + * Defines the physical structure of the robot and translates the linear + * kinematics to wheel velocities. + */ + std::shared_ptr model; + + /** + * The time difference between each value in the generated path. + */ + double dt; + + /** + * The minimum and maximum durations for a path to take. A larger range allows + * for longer possible paths at the expense of a longer path generation time. + */ + const int T_MIN = 2; + const int T_MAX = 15; + const int MAX_GRAD_DESCENT_ITERATIONS = 10; + + /** + * This is factor is used to create a "dummy velocity" in the initial path + * generation step one or both of the preferred start or end velocities is + * zero. The velocity will be replaced with the preferred start/end velocity + * in parameterization but a nonzero velocity is needed for the spline + * calculation. + * + * This was 1.2 in the WPILib example but that large of a value seems to + * create wild paths, 0.12 worked better in testing with VEX-sized paths. + */ + public: + const double K_DEFAULT_VEL = 1.0; + + /** + * The output of the initial, "naive" generation step. We discard the + * derivative values to replace them with values from a motion profile. + */ + + struct GeneratedPoint { + GeneratedPoint(Pose ipose, double icurvature = 0.0) + : pose(ipose), curvature(icurvature) {} + + std::string to_string() const { + return "GeneratedPoint: {" + pose.to_string() + + ", curvature: " + std::to_string(curvature) + "}"; + } + + Pose pose; + double curvature; + }; + + /** + * An intermediate value used in the "naive" generation step. Contains the + * final GeneratedPoint value that will be returned as well as the spline's + * derivative values to perform the initial check against the constraints. + */ + struct GeneratedVector { + GeneratedVector(GeneratedPoint ipoint, + double ivel, + double iaccel, + double ijerk) + : point(ipoint), vel(ivel), accel(iaccel), jerk(ijerk) {} + + GeneratedPoint point; + double vel; + double accel; + double jerk; + + std::string to_string() const { + return "GeneratedVector: {" + point.to_string() + + ", vel: " + std::to_string(vel) + + ", accel: " + std::to_string(accel) + + ", jerk: " + std::to_string(jerk) + "}"; + } + }; + + std::vector gen_single_raw_path(ControlVector start, + ControlVector end, + int duration, + double start_vel, + double end_vel); + /** + * Runs a Gradient Descent algorithm to minimize the linear acceleration, + * linear jerk, and curvature for the generated path. + * + * This is used when there is not a start/end velocity specified for a given + * path. + */ + std::vector + gradient_descent(ControlVector& start, ControlVector& end, bool fast); + + /** + * An intermediate value used in the parameterization step. Adds the + * constrained values from the motion profile to the output from the "naive" + * generation step. + */ + struct ConstrainedState { + ConstrainedState(Pose ipose, + double icurvature, + double idistance, + double imax_vel, + double imin_accel, + double imax_accel) + : pose(ipose), + curvature(icurvature), + distance(idistance), + max_vel(imax_vel), + min_accel(imin_accel), + max_accel(imax_accel) {} + + ConstrainedState() = default; + + Pose pose = Pose(); + double curvature = 0; + double distance = 0; + double max_vel = 0; + double min_accel = 0; + double max_accel = 0; + + std::string to_string() const { + return "ConstrainedState: {x: " + std::to_string(pose.x) + + ", y: " + std::to_string(pose.y) + + ", yaw: " + std::to_string(pose.yaw) + + ", k: " + std::to_string(curvature) + + ", dist: " + std::to_string(distance) + + ", v: " + std::to_string(max_vel) + + ", min_a: " + std::to_string(min_accel) + + ", max_a: " + std::to_string(max_accel) + "}"; + } + }; + + /** + * The actual function called by the "generate" functions. + * + * @param start An iterator pointing to the first ControlVector in the path + * @param end An iterator pointting to the last ControlVector in the path + * + * @return The points from each path concatenated together + */ + template + std::vector _generate(Iter start, Iter end, bool fast); + + public: + /** + * Performs the "naive" generation step. + * + * This step calculates the spline polynomials that fit within the + * SplineGenerator's acceleration and jerk constraints and returns the points + * that form the curve. + */ + std::vector + gen_raw_path(ControlVector& start, ControlVector& end, bool fast); + + /** + * Imposes a linear motion profile on the raw path. + * + * This step creates the velocity and acceleration values to command the robot + * at each point along the curve. + */ + std::vector + parameterize(const ControlVector start, + const ControlVector end, + const std::vector& raw_path, + const double preferred_start_vel, + const double preferred_end_vel, + const double start_time); + + /** + * Finds the new timestamps for each point along the curve based on the motion + * profile. + */ + std::vector + integrate_constrained_states(std::vector constrainedStates); + + /** + * Finds the ProfilePoint on the profiled curve for the given timestamp. + * + * This with interpolate between points on the curve if a point with an exact + * matching timestamp is not found. + */ + ProfilePoint get_point_at_time(const ControlVector start, + const ControlVector end, + std::vector points, + double t); + + /** + * Linearly interpolates between points along the profiled curve. + */ + ProfilePoint lerp_point(QuinticPolynomial x_qp, + QuinticPolynomial y_qp, + ProfilePoint start, + ProfilePoint end, + double i); + + /** + * Returns the spline curve for the given control vectors and path duration. + */ + QuinticPolynomial get_x_spline(const ControlVector start, + const ControlVector end, + const double duration); + QuinticPolynomial get_y_spline(const ControlVector start, + const ControlVector end, + const double duration); + + /** + * Applies the general constraints and model constraints to the given state. + */ + void enforce_accel_lims(ConstrainedState* state); + + /** + * Imposes the motion profile constraints on a segment of the path from the + * perspective of iterating forwards through the path. + */ + void forward_pass(ConstrainedState* predecessor, ConstrainedState* successor); + + /** + * Imposes the motion profile constraints on a segment of the path from the + * perspective of iterating backwards through the path. + */ + void backward_pass(ConstrainedState* predecessor, + ConstrainedState* successor); + + /** + * Calculates the final velocity for a path segment. + */ + double vf(double vi, double a, double ds); + + /** + * Calculates the initial acceleration needed to match the segments' + * velocities. + */ + double ai(double vf, double vi, double s); + + /** + * Values that are closer to each other than this value are considered equal. + */ + static constexpr double K_EPSILON = 1e-5; +}; +} // namespace squiggles + +#endif diff --git a/pros/okapi/squiggles/squiggles.hpp b/pros/okapi/squiggles/squiggles.hpp new file mode 100644 index 00000000..86c1bfa9 --- /dev/null +++ b/pros/okapi/squiggles/squiggles.hpp @@ -0,0 +1,22 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _ROBOT_SQUIGGLES_H_ +#define _ROBOT_SQUIGGLES_H_ + +#include "geometry/controlvector.hpp" +#include "geometry/pose.hpp" +#include "geometry/profilepoint.hpp" + +#include "physicalmodel/passthroughmodel.hpp" +#include "physicalmodel/physicalmodel.hpp" +#include "physicalmodel/tankmodel.hpp" + +#include "constraints.hpp" +#include "io.hpp" +#include "spline.hpp" + +#endif \ No newline at end of file diff --git a/pros/pros.h b/pros/pros.h new file mode 100644 index 00000000..c2ecf761 --- /dev/null +++ b/pros/pros.h @@ -0,0 +1,81 @@ +/** + * \file pros.h + * + * Contains common definitions and header files used throughout your PROS + * project. + * + * Copyright (c) 2017-2022, 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/. + */ + +#ifndef _PROS_MAIN_H_ +#define _PROS_MAIN_H_ + +/** + * If defined, some commonly used enums will have preprocessor macros which give + * a shorter, more convenient naming pattern. If this isn't desired, simply + * comment the following line out. + * + * For instance, E_CONTROLLER_MASTER has a shorter name: CONTROLLER_MASTER. + * E_CONTROLLER_MASTER is pedantically correct within the PROS styleguide, but + * not convienent for most student programmers. + */ +#define PROS_USE_SIMPLE_NAMES + +/** + * If defined, C++ literals will be available for use. All literals are in the + * pros::literals namespace. + * + * For instance, you can do `4_mtr = 50` to set motor 4's target velocity to 50 + */ +#define PROS_USE_LITERALS + +#include "api.h" + +/** + * You should add more #includes here + */ +// #include "okapi/api.hpp" +// #include "pros/api_legacy.h" + +/** + * If you find doing pros::Motor() to be tedious and you'd prefer just to do + * Motor, you can use the namespace with the following commented out line. + * + * IMPORTANT: Only the okapi or pros namespace may be used, not both + * concurrently! The okapi namespace will export all symbols inside the pros + * namespace. + */ +// using namespace pros; +// using namespace pros::literals; +// using namespace okapi; + +/** + * Prototypes for the competition control tasks are redefined here to ensure + * that they can be called from user code (i.e. calling autonomous from a + * button press in opcontrol() for testing purposes). + */ +#ifdef __cplusplus +extern "C" { +#endif +void autonomous(void); +void initialize(void); +void disabled(void); +void competition_initialize(void); +void opcontrol(void); +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +/** + * You can add C++-only headers here + */ +// #include +#endif + +#endif // _PROS_MAIN_H_ diff --git a/pros/pros/adi.h b/pros/pros/adi.h new file mode 100644 index 00000000..c06176ad --- /dev/null +++ b/pros/pros/adi.h @@ -0,0 +1,875 @@ +/** + * \file pros/adi.h + * + * Contains prototypes for interfacing with the ADI. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/adi.html to learn more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_ADI_H_ +#define _PROS_ADI_H_ + +#include +#include +#ifndef PROS_ERR +#define PROS_ERR (INT32_MAX) +#endif + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +/** + * Represents the port type for an ADI port. + */ +typedef enum adi_port_config_e { + E_ADI_ANALOG_IN = 0, + E_ADI_ANALOG_OUT = 1, + E_ADI_DIGITAL_IN = 2, + E_ADI_DIGITAL_OUT = 3, + +#ifdef _INTELLISENSE +#define _DEPRECATE_DIGITAL_IN = E_ADI_DIGITAL_IN +#define _DEPRECATE_ANALOG_IN = E_ADI_ANALOG_IN +#else +#define _DEPRECATE_DIGITAL_IN __attribute__((deprecated("use E_ADI_DIGITAL_IN instead"))) = E_ADI_DIGITAL_IN +#define _DEPRECATE_ANALOG_IN __attribute__((deprecated("use E_ADI_ANALOG_IN instead"))) = E_ADI_ANALOG_IN +#endif + + E_ADI_SMART_BUTTON _DEPRECATE_DIGITAL_IN, + E_ADI_SMART_POT _DEPRECATE_ANALOG_IN, + + E_ADI_LEGACY_BUTTON _DEPRECATE_DIGITAL_IN, + E_ADI_LEGACY_POT _DEPRECATE_ANALOG_IN, + E_ADI_LEGACY_LINE_SENSOR _DEPRECATE_ANALOG_IN, + E_ADI_LEGACY_LIGHT_SENSOR _DEPRECATE_ANALOG_IN, + E_ADI_LEGACY_GYRO = 10, + E_ADI_LEGACY_ACCELEROMETER _DEPRECATE_ANALOG_IN, + +#undef _DEPRECATE_DIGITAL_IN +#undef _DEPRECATE_ANALOG_IN + + E_ADI_LEGACY_SERVO = 12, + E_ADI_LEGACY_PWM = 13, + + E_ADI_LEGACY_ENCODER = 14, + E_ADI_LEGACY_ULTRASONIC = 15, + + E_ADI_TYPE_UNDEFINED = 255, + E_ADI_ERR = PROS_ERR +} adi_port_config_e_t; + +/** + * Represents the potentiometer version type. + */ +typedef enum adi_potentiometer_type_e { + E_ADI_POT_EDR = 0, + E_ADI_POT_V2 +} adi_potentiometer_type_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define ADI_ANALOG_IN pros::E_ADI_ANALOG_IN +#define ADI_ANALOG_OUT pros::E_ADI_ANALOG_OUT +#define ADI_DIGITAL_IN pros::E_ADI_DIGITAL_IN +#define ADI_DIGITAL_OUT pros::E_ADI_DIGITAL_OUT +#define ADI_SMART_BUTTON pros::E_ADI_SMART_BUTTON +#define ADI_SMART_POT pros::E_ADI_SMART_POT +#define ADI_LEGACY_BUTTON pros::E_ADI_LEGACY_BUTTON +#define ADI_LEGACY_POT pros::E_ADI_LEGACY_POT +#define ADI_LEGACY_LINE_SENSOR pros::E_ADI_LEGACY_LINE_SENSOR +#define ADI_LEGACY_LIGHT_SENSOR pros::E_ADI_LEGACY_LIGHT_SENSOR +#define ADI_LEGACY_GYRO pros::E_ADI_LEGACY_GYRO +#define ADI_LEGACY_ACCELEROMETER pros::E_ADI_LEGACY_ACCELEROMETER +#define ADI_LEGACY_SERVO pros::E_ADI_LEGACY_SERVO +#define ADI_LEGACY_PWM pros::E_ADI_LEGACY_PWM +#define ADI_LEGACY_ENCODER pros::E_ADI_LEGACY_ENCODER +#define ADI_LEGACY_ULTRASONIC pros::E_ADI_LEGACY_ULTRASONIC +#define ADI_TYPE_UNDEFINED pros::E_ADI_TYPE_UNDEFINED +#define ADI_ERR pros::E_ADI_ERR +#else +#define ADI_ANALOG_IN E_ADI_ANALOG_IN +#define ADI_ANALOG_OUT E_ADI_ANALOG_OUT +#define ADI_DIGITAL_IN E_ADI_DIGITAL_IN +#define ADI_DIGITAL_OUT E_ADI_DIGITAL_OUT +#define ADI_SMART_BUTTON E_ADI_SMART_BUTTON +#define ADI_SMART_POT E_ADI_SMART_POT +#define ADI_LEGACY_BUTTON E_ADI_LEGACY_BUTTON +#define ADI_LEGACY_POT E_ADI_LEGACY_POT +#define ADI_LEGACY_LINE_SENSOR E_ADI_LEGACY_LINE_SENSOR +#define ADI_LEGACY_LIGHT_SENSOR E_ADI_LEGACY_LIGHT_SENSOR +#define ADI_LEGACY_GYRO E_ADI_LEGACY_GYRO +#define ADI_LEGACY_ACCELEROMETER E_ADI_LEGACY_ACCELEROMETER +#define ADI_LEGACY_SERVO E_ADI_LEGACY_SERVO +#define ADI_LEGACY_PWM E_ADI_LEGACY_PWM +#define ADI_LEGACY_ENCODER E_ADI_LEGACY_ENCODER +#define ADI_LEGACY_ULTRASONIC E_ADI_LEGACY_ULTRASONIC +#define ADI_TYPE_UNDEFINED E_ADI_TYPE_UNDEFINED +#define ADI_ERR E_ADI_ERR +#endif +#endif + +#define INTERNAL_ADI_PORT 22 +#define NUM_ADI_PORTS 8 + +#ifdef __cplusplus +namespace c { +#endif + +/******************************************************************************/ +/** General ADI Use Functions **/ +/** **/ +/** These functions allow for interaction with any ADI port type **/ +/******************************************************************************/ + +/** + * Gets the configuration for the given ADI 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 port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which to return + * the configuration + * + * \return The ADI configuration for the given port + */ +adi_port_config_e_t adi_port_get_config(uint8_t port); + +/** + * Gets the value for the given ADI 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 port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which the value + * will be returned + * + * \return The value stored for the given port + */ +int32_t adi_port_get_value(uint8_t port); + +/** + * Configures an ADI port to act as a given sensor type. + * + * 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 + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param type + * The configuration type for the port + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_port_set_config(uint8_t port, adi_port_config_e_t type); + +/** + * Sets the value for the given ADI port. + * + * This only works on ports configured as outputs, and the behavior will change + * depending on the configuration of the 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 port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which the value + * will be set + * \param value + * The value to set the ADI port to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_port_set_value(uint8_t port, int32_t value); + +/******************************************************************************/ +/** PROS 2 Compatibility Functions **/ +/** **/ +/** These functions provide similar functionality to the PROS 2 API **/ +/******************************************************************************/ + +/** + * Used for adi_digital_write() to specify a logic HIGH state to output. + * + * In reality, using any non-zero expression or "true" will work to set a pin to + * HIGH. + */ +#define HIGH 1 +/** + * Used for adi_digital_write() to specify a logic LOW state to output. + * + * In reality, using a zero expression or "false" will work to set a pin to LOW. + */ +#define LOW 0 + +/** + * adi_pin_mode() state for a digital input. + */ +#define INPUT 0x00 +/** + * adi_pin_mode() state for a digital output. + */ +#define OUTPUT 0x01 +/** + * adi_pin_mode() state for an analog input. + */ +#define INPUT_ANALOG 0x02 + +/** + * adi_pin_mode() state for an analog output. + */ +#define OUTPUT_ANALOG 0x03 + +/** + * Calibrates the analog sensor on the specified port and returns the new + * calibration value. + * + * This method assumes that the true sensor value is not actively changing at + * this time and computes an average from approximately 500 samples, 1 ms apart, + * for a 0.5 s period of calibration. The average value thus calculated is + * returned and stored for later calls to the adi_analog_read_calibrated() and + * adi_analog_read_calibrated_HR() functions. These functions will return + * the difference between this value and the current sensor value when called. + * + * Do not use this function when the sensor value might be unstable + * (gyro rotation, accelerometer movement). + * + * 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 + * The ADI port to calibrate (from 1-8, 'a'-'h', 'A'-'H') + * + * \return The average sensor value computed by this function + */ +int32_t adi_analog_calibrate(uint8_t port); + +/** + * Gets the 12-bit value of the specified port. + * + * The value returned is undefined if the analog pin has been switched to a + * different mode. + * + * 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 + * EADDRINUSE - The port is not configured as an analog input + * + * \param port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \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 + */ +int32_t adi_analog_read(uint8_t port); + +/** + * Gets the 12 bit calibrated value of an analog input port. + * + * The adi_analog_calibrate() function must be run first. This function is + * inappropriate for sensor values intended for integration, as round-off error + * can accumulate causing drift over time. Use adi_analog_read_calibrated_HR() + * instead. + * + * 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 + * EADDRINUSE - The port is not configured as an analog input + * + * \param port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \return The difference of the sensor value from its calibrated default from + * -4095 to 4095 + */ +int32_t adi_analog_read_calibrated(uint8_t port); + +/** + * Gets the 16 bit calibrated value of an analog input port. + * + * The adi_analog_calibrate() function must be run first. This is intended for + * integrated sensor values such as gyros and accelerometers to reduce drift due + * to round-off, and should not be used on a sensor such as a line tracker + * or potentiometer. + * + * The value returned actually has 16 bits of "precision", even though the ADC + * only reads 12 bits, so that error induced by the average value being between + * two values when integrated over time is trivial. Think of the value as the + * true value times 16. + * + * 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 + * EADDRINUSE - The port is not configured as an analog input + * + * \param port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \return The difference of the sensor value from its calibrated default from + * -16384 to 16384 + */ +int32_t adi_analog_read_calibrated_HR(uint8_t port); + +/** + * Gets the digital value (1 or 0) of a port configured as a digital input. + * + * If the port is configured as some other mode, the digital value which + * reflects the current state of the port is returned, which may or may not + * differ from the currently set value. The return value is undefined for ports + * configured as any mode other than a Digital Input. + * + * 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 + * EADDRINUSE - The port is not configured as a digital input + * + * \param port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * + * \return True if the pin is HIGH, or false if it is LOW + */ +int32_t adi_digital_read(uint8_t port); + +/** + * Gets a rising-edge case for a digital 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 + * presses, and not in any other tasks. + * + * 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 + * EADDRINUSE - The port is not configured as a digital input + * + * \param port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * + * \return 1 if the button is pressed and had not been pressed + * the last time this function was called, 0 otherwise. + */ +int32_t adi_digital_get_new_press(uint8_t port); + +/** + * Sets the digital value (1 or 0) of a port configured as a digital output. + * + * If the port is configured as some other mode, behavior 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 ADI Ports + * EADDRINUSE - The port is not configured as a digital output + * + * \param port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * \param value + * An expression evaluating to "true" or "false" to set the output to + * HIGH or LOW respectively, or the constants HIGH or LOW themselves + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_digital_write(uint8_t port, bool value); + +/** + * Configures the port as an input or output with a variety of settings. + * + * 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 + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * \param mode + * One of INPUT, INPUT_ANALOG, INPUT_FLOATING, OUTPUT, or OUTPUT_OD + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_pin_mode(uint8_t port, uint8_t mode); + +/** + * Sets the speed of the motor 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 ADI Ports + * EADDRINUSE - The port is not configured as an motor + * + * \param port + * The ADI port to set (from 1-8, 'a'-'h', 'A'-'H') + * \param speed + * The new signed speed; -127 is full reverse and 127 is full forward, + * with 0 being off + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_motor_set(uint8_t port, int8_t speed); + +/** + * Gets the last set speed of the motor 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 ADI Ports + * EADDRINUSE - The port is not configured as an motor + * + * \param port + * The ADI port to get (from 1-8, 'a'-'h', 'A'-'H') + * + * \return The last set speed of the motor on the given port + */ +int32_t adi_motor_get(uint8_t port); + +/** + * Stops the motor 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 ADI Ports + * EADDRINUSE - The port is not configured as an motor + * + * \param port + * The ADI port to set (from 1-8, 'a'-'h', 'A'-'H') + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_motor_stop(uint8_t port); + +/** + * Reference type for an initialized encoder. + * + * This merely contains the port number for the encoder, unlike its use as an + * object to store encoder data in PROS 2. + */ +typedef int32_t adi_encoder_t; + +/** + * Gets the number of ticks recorded by the encoder. + * + * There are 360 ticks in one revolution. + * + * 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 + * EADDRINUSE - The port is not configured as an encoder + + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to read + * + * \return The signed and cumulative number of counts since the last start or + * reset + */ +int32_t adi_encoder_get(adi_encoder_t enc); + +/** + * Creates an encoder object and configures the specified ports accordingly. + * + * 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 + * EADDRINUSE - The port is not configured as an encoder + + * + * \param port_top + * The "top" wire from the encoder sensor with the removable cover side + * up. This should be in port 1, 3, 5, or 7 ('A', 'C', 'E', or 'G'). + * \param port_bottom + * The "bottom" wire from the encoder sensor + * \param reverse + * If "true", the sensor will count in the opposite direction + * + * \return An adi_encoder_t object to be stored and used for later calls to + * encoder functions + */ +adi_encoder_t adi_encoder_init(uint8_t port_top, uint8_t port_bottom, bool reverse); + +/** + * Sets the encoder value to zero. + * + * It is safe to use this method while an encoder is enabled. It is not + * necessary to call this method before stopping or starting an encoder. + * + * 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 + * EADDRINUSE - The port is not configured as an encoder + + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to reset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_encoder_reset(adi_encoder_t enc); + +/** + * Disables the encoder and voids the configuration on its ports. + * + * 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 + * EADDRINUSE - The port is not configured as an encoder + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to stop + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_encoder_shutdown(adi_encoder_t enc); + +/** + * Reference type for an initialized ultrasonic. + * + * This merely contains the port number for the ultrasonic, unlike its use as an + * object to store ultrasonic data in PROS 2. + */ +typedef int32_t adi_ultrasonic_t; + +/** + * Gets the current ultrasonic sensor value in centimeters. + * + * If no object was found, zero is returned. If the ultrasonic sensor was never + * started, the return value is undefined. Round and fluffy objects can cause + * inaccurate values to be returned. + * + * 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 + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param ult + * The adi_ultrasonic_t object from adi_ultrasonic_init() to read + * + * \return The distance to the nearest object in m^-4 (10000 indicates 1 meter), + * measured from the sensor's mounting points. + */ +int32_t adi_ultrasonic_get(adi_ultrasonic_t ult); + +/** + * Creates an ultrasonic object and configures the specified ports accordingly. + * + * 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 + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param port_ping + * The port connected to the orange OUTPUT cable. This should be in port + * 1, 3, 5, or 7 ('A', 'C', 'E', 'G'). + * \param port_echo + * The port connected to the yellow INPUT cable. This should be in the + * next highest port following port_ping. + * + * \return An adi_ultrasonic_t object to be stored and used for later calls to + * ultrasonic functions + */ +adi_ultrasonic_t adi_ultrasonic_init(uint8_t port_ping, uint8_t port_echo); + +/** + * Disables the ultrasonic sensor and voids the configuration on its ports. + * + * 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 + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param ult + * The adi_ultrasonic_t object from adi_ultrasonic_init() to stop + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_ultrasonic_shutdown(adi_ultrasonic_t ult); + +/** + * Reference type for an initialized gyroscope. + * + * This merely contains the port number for the gyroscope, unlike its use as an + * object to store gyro data in PROS 2. + */ +typedef int32_t adi_gyro_t; + +/** + * 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 + * the number of degrees of rotation times 10. + * + * There are 360 degrees in a circle, thus the gyro will return 3600 for one + * whole rotation. + * + * 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 + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object for which the angle will be returned + * + * \return The gyro angle in degrees. + */ +double adi_gyro_get(adi_gyro_t gyro); + +/** + * Initializes a gyroscope on the given port. If the given port has not + * previously been configured as a gyro, then this function starts a 1300 ms + * calibration period. + * + * It is highly recommended that this function be called from initialize() when + * the robot is stationary to ensure proper calibration. + * + * 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 + * EADDRINUSE - The port is not configured as a gyro + * + * \param 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 ADI + * + * \return An adi_gyro_t object containing the given port, or PROS_ERR if the + * initialization failed. + */ +adi_gyro_t adi_gyro_init(uint8_t port, double multiplier); + +/** + * Resets the gyroscope value to zero. + * + * 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 + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object for which the angle will be returned + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_gyro_reset(adi_gyro_t gyro); + +/** + * Disables the gyro and voids the configuration on its 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 + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object to be shut down + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t adi_gyro_shutdown(adi_gyro_t gyro); + +/** + * Reference type for an initialized potentiometer. + * + * This merely contains the port number for the potentiometer, unlike its use as an + * object to store potentiometer data in PROS 2. + */ +typedef int32_t adi_potentiometer_t; + +/** + * Initializes a potentiometer on the given port of the original potentiometer. + * + * 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 + * EADDRINUSE - The port is not configured as a potentiometer + * + * \param port + * The ADI port to initialize as a gyro (from 1-8, 'a'-'h', 'A'-'H') + * + * \return An adi_potentiometer_t object containing the given port, or PROS_ERR if the + * initialization failed. + */ +adi_potentiometer_t adi_potentiometer_init(uint8_t port); + +/** + * Initializes a potentiometer 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 ADI Ports + * EADDRINUSE - The port is not configured as a potentiometer + * + * \param port + * The ADI port to initialize as a gyro (from 1-8, 'a'-'h', 'A'-'H') + * \param potentiometer_type + * An adi_potentiometer_type_e_t enum value specifying the potentiometer version type + * + * \return An adi_potentiometer_t object containing the given port, or PROS_ERR if the + * initialization failed. + */ +adi_potentiometer_t adi_potentiometer_type_init(uint8_t port, adi_potentiometer_type_e_t potentiometer_type); + +/** + * Gets the current potentiometer angle in tenths of a degree. + * + * The original potentiometer rotates 250 degrees thus returning an angle between 0-250 degrees. + * Potentiometer V2 rotates 330 degrees thus returning an angle between 0-330 degrees. + * + * 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 + * EADDRINUSE - The port is not configured as a potentiometer + * + * \param potentiometer + * The adi_potentiometer_t object for which the angle will be returned + * + * \return The potentiometer angle in degrees. + */ +double adi_potentiometer_get_angle(adi_potentiometer_t potentiometer); + +/** + * Reference type for an initialized addressable led. + * + * This merely contains the port number for the led, unlike its use as an + * object to store led data in PROS 2. + */ +typedef int32_t adi_led_t; + +/** + * Initializes a led on the given port of the original led. + * + * 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 - The ADI port given is not a valid port as defined below + * EADDRINUSE - The port is not configured for ADI output + * + * \param port + * The ADI port to initialize as a led (from 1-8, 'a'-'h', 'A'-'H') + * + * \return An adi_led_t object containing the given port, or PROS_ERR if the + * initialization failed, setting errno + */ +adi_led_t adi_led_init(uint8_t port); + +/** + * @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 given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of buffer to clear + * @return PROS_SUCCESS if successful, PROS_ERR if not + */ +int32_t adi_led_clear_all(adi_led_t led, uint32_t* buffer, uint32_t buffer_length); + +/** + * @brief Set the entire led strip using the colors contained in the buffer + * + * 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 given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of buffer to clear + * @return PROS_SUCCESS if successful, PROS_ERR if not + */ +int32_t adi_led_set(adi_led_t led, uint32_t* buffer, uint32_t buffer_length); + +/** + * @brief Set the entire led strip to one 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 given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of buffer to clear + * @param color color to set all the led strip value to + * @return PROS_SUCCESS if successful, PROS_ERR if not + */ +int32_t adi_led_set_all(adi_led_t led, uint32_t* buffer, uint32_t buffer_length, 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: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of the input buffer + * @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 + */ +int32_t adi_led_set_pixel(adi_led_t led, uint32_t* buffer, uint32_t buffer_length, 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: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of the input buffer + * @param pixel_position position of the pixel to clear + * @return PROS_SUCCESS if successful, PROS_ERR if not + */ +int32_t adi_led_clear_pixel(adi_led_t led, uint32_t* buffer, uint32_t buffer_length, uint32_t pixel_position); + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_ADI_H_ diff --git a/pros/pros/adi.hpp b/pros/pros/adi.hpp new file mode 100644 index 00000000..6dc99ef5 --- /dev/null +++ b/pros/pros/adi.hpp @@ -0,0 +1,894 @@ +/** + * \file pros/adi.hpp + * + * Contains prototypes for interfacing with the ADI. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/adi.html to learn more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_ADI_HPP_ +#define _PROS_ADI_HPP_ + +#include +#include +#include +#include + +#include "pros/adi.h" + +namespace pros { + +/** 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; + +class ADIPort { + public: + /** + * Configures an ADI port to act as a given sensor type. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param type + * The configuration type for the port + */ + explicit ADIPort(std::uint8_t adi_port, adi_port_config_e_t type = E_ADI_TYPE_UNDEFINED); + + /** + * Configures an ADI port on an adi expander to act as a given sensor type. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + * \param type + * The configuration type for the port + */ + ADIPort(ext_adi_port_pair_t port_pair, adi_port_config_e_t type = E_ADI_TYPE_UNDEFINED); + + /** + * Gets the configuration for the given ADI port. + * + * \return The ADI configuration for the given port + */ + std::int32_t get_config() const; + + /** + * Gets the value for the given ADI port. + * + * \return The value stored for the given port + */ + std::int32_t get_value() const; + + /** + * Configures an ADI port to act as a given sensor type. + * + * \param type + * The configuration type for the port + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_config(adi_port_config_e_t type) const; + + /** + * Sets the value for the given ADI port. + * + * This only works on ports configured as outputs, and the behavior will + * change depending on the configuration of the port. + * + * \param value + * The value to set the ADI port to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_value(std::int32_t value) const; + + protected: + std::uint8_t _smart_port; + std::uint8_t _adi_port; +}; + +class ADIAnalogIn : protected ADIPort { + public: + /** + * Configures an ADI port to act as an Analog Input. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + explicit ADIAnalogIn(std::uint8_t adi_port); + + /** + * Configures an ADI port on an adi expander to act as an Analog Input. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + ADIAnalogIn(ext_adi_port_pair_t port_pair); + + /** + * Calibrates the analog sensor on the specified port and returns the new + * calibration value. + * + * This method assumes that the true sensor value is not actively changing at + * this time and computes an average from approximately 500 samples, 1 ms + * apart, for a 0.5 s period of calibration. The average value thus calculated + * is returned and stored for later calls to the + * pros::ADIAnalogIn::get_value_calibrated() and + * pros::ADIAnalogIn::get_value_calibrated_HR() functions. These functions + * will return the difference between this value and the current sensor value + * when called. + * + * Do not use this function when the sensor value might be unstable (gyro + * rotation, accelerometer movement). + * + * 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 + */ + std::int32_t calibrate() const; + + /** + * Gets the 12 bit calibrated value of an analog input port. + * + * The pros::ADIAnalogIn::calibrate() function must be run first. This + * function is inappropriate for sensor values intended for integration, as + * round-off error can accumulate causing drift over time. Use + * pros::ADIAnalogIn::get_value_calibrated_HR() instead. + * + * 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 difference of the sensor value from its calibrated default from + * -4095 to 4095 + */ + std::int32_t get_value_calibrated() const; + + /** + * Gets the 16 bit calibrated value of an analog input port. + * + * The pros::ADIAnalogIn::calibrate() function must be run first. This is + * intended for integrated sensor values such as gyros and accelerometers to + * reduce drift due to round-off, and should not be used on a sensor such as a + * line tracker or potentiometer. + * + * The value returned actually has 16 bits of "precision", even though the ADC + * only reads 12 bits, so that error induced by the average value being + * between two values when integrated over time is trivial. Think of the value + * as the true value times 16. + * + * 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 difference of the sensor value from its calibrated default from + * -16384 to 16384 + */ + std::int32_t get_value_calibrated_HR() const; + + /** + * Gets the 12-bit value of the specified port. + * + * The value returned is undefined if the analog pin has been switched to a + * different mode. + * + * 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 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 + */ + using ADIPort::get_value; +}; + +// using ADIPotentiometer = ADIAnalogIn; +using ADILineSensor = ADIAnalogIn; +using ADILightSensor = ADIAnalogIn; +using ADIAccelerometer = ADIAnalogIn; + +class ADIAnalogOut : private ADIPort { + public: + /** + * Configures an ADI port to act as an Analog Output. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + */ + explicit ADIAnalogOut(std::uint8_t adi_port); + + /** + * Configures an ADI port on an adi_expander to act as an Analog Output. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + * + */ + ADIAnalogOut(ext_adi_port_pair_t port_pair); + + /** + * Sets the value for the given ADI port. + * + * This only works on ports configured as outputs, and the behavior will + * change depending on the configuration of the port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as an analog output + * + * \param value + * The value to set the ADI port to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + using ADIPort::set_value; +}; + +class ADIDigitalOut : private ADIPort { + public: + /** + * Configures an ADI port to act as a Digital Output. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param init_state + * The initial state for the port + */ + explicit ADIDigitalOut(std::uint8_t adi_port, bool init_state = LOW); + + /** + * Configures an ADI port on an adi_expander to act as a Digital Output. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + * \param init_state + * The initial state for the port + */ + ADIDigitalOut(ext_adi_port_pair_t port_pair, bool init_state = LOW); + + /** + * Sets the value for the given ADI port. + * + * This only works on ports configured as outputs, and the behavior will + * change depending on the configuration of the port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a digital output + * + * \param value + * The value to set the ADI port to + * + * \return if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + using ADIPort::set_value; +}; + +class ADIDigitalIn : private ADIPort { + public: + /** + * Configures an ADI port to act as a Digital Input. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + */ + explicit ADIDigitalIn(std::uint8_t adi_port); + + /** + * Configures an ADI port on an adi_expander to act as a Digital Input. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + */ + ADIDigitalIn(ext_adi_port_pair_t port_pair); + + /** + * Gets a rising-edge case for a digital 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 presses, and not in any other tasks. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a digital input + * + * \return 1 if the button is pressed and had not been pressed the last time + * this function was called, 0 otherwise. + */ + std::int32_t get_new_press() const; + + /** + * Gets the value for the given ADI port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a digital input + * + * \return The value stored for the given port + */ + using ADIPort::get_value; +}; + +using ADIButton = ADIDigitalIn; + +class ADIMotor : private ADIPort { + public: + /** + * Configures an ADI port to act as a Motor. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + */ + explicit ADIMotor(std::uint8_t adi_port); + + /** + * Configures an ADI port on an adi_expander to act as a Motor. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + */ + ADIMotor(ext_adi_port_pair_t port_pair); + + /** + * Stops the motor on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t stop() const; + + /** + * Sets the speed of the motor on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a motor + * + * \param value + * The new signed speed; -127 is full reverse and 127 is full forward, + * with 0 being off + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + using ADIPort::set_value; + + /** + * Gets the last set speed of the motor on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a motor + * + * \return The last set speed of the motor on the given port + */ + using ADIPort::get_value; +}; + +class ADIEncoder : private ADIPort { + public: + /** + * Configures a set of ADI ports to act as an Encoder. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port_top + * The "top" wire from the encoder sensor with the removable cover side up + * \param adi_port_bottom + * The "bottom" wire from the encoder sensor + * \param reverse + * If "true", the sensor will count in the opposite direction + */ + ADIEncoder(std::uint8_t adi_port_top, std::uint8_t adi_port_bottom, bool reversed = false); + + /** + * Configures a set of ADI ports on an adi_expander to act as an Encoder. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_tuple + * The tuple of the smart port number, the "top" wire from the encoder + * sensor with the removable cover side up, and the "bottom" wire from + * the encoder sensor + * \param reverse + * If "true", the sensor will count in theopposite direction + */ + ADIEncoder(ext_adi_port_tuple_t port_tuple, bool reversed = false); + + /** + * Sets the encoder value to zero. + * + * It is safe to use this method while an encoder is enabled. It is not + * necessary to call this method before stopping or starting an encoder. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t reset() const; + + /** + * Gets the number of ticks recorded by the encoder. + * + * There are 360 ticks in one revolution. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a motor + * + * \return The signed and cumulative number of counts since the last start or + * reset + */ + std::int32_t get_value() const; +}; + +class ADIUltrasonic : private ADIPort { + public: + /** + * Configures a set of ADI ports to act as an Ultrasonic sensor. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_ping + * The port connected to the orange OUTPUT cable. This should be in port + * 1, 3, 5, or 7 ('A', 'C', 'E', 'G'). + * \param port_echo + * The port connected to the yellow INPUT cable. This should be in the + * next highest port following port_ping. + */ + ADIUltrasonic(std::uint8_t adi_port_ping, std::uint8_t adi_port_echo); + + /** + * Configures a set of ADI ports on an adi_expander to act as an Ultrasonic sensor. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_tuple + * The tuple of the smart port number, the port connected to the orange + * 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). + */ + ADIUltrasonic(ext_adi_port_tuple_t port_tuple); + + /** + * Gets the current ultrasonic sensor value in centimeters. + * + * If no object was found, zero is returned. If the ultrasonic sensor was + * never started, the return value is undefined. Round and fluffy objects can + * cause inaccurate values to be returned. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as an ultrasonic + * + * \return The distance to the nearest object in m^-4 (10000 indicates 1 + * meter), measured from the sensor's mounting points. + */ + std::int32_t get_value() const; +}; + +class ADIGyro : private ADIPort { + public: + /** + * Initializes a gyroscope on the given port. If the given port has not + * previously been configured as a gyro, then this function starts a 1300ms + * calibration period. + * + * It is highly recommended that an ADIGyro object be created in initialize() + * when the robot is stationary to ensure proper calibration. If an ADIGyro + * object is declared at the global scope, a hardcoded 1300ms delay at the + * beginning of initialize will be necessary to ensure that the gyro's + * returned values are correct at the beginning of autonomous/opcontrol. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_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 ADI + */ + explicit ADIGyro(std::uint8_t adi_port, double multiplier = 1); + + /** + * Initializes a gyroscope on the given port of an adi expander. If the given + * port has not previously been configured as a gyro, then this function starts + * a 1300ms calibration period. + * + * It is highly recommended that an ADIGyro object be created in initialize() + * when the robot is stationary to ensure proper calibration. If an ADIGyro + * object is declared at the global scope, a hardcoded 1300ms delay at the + * beginning of initialize will be necessary to ensure that the gyro's + * returned values are correct at the beginning of autonomous/opcontrol. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + * \param multiplier + * A scalar value that will be multiplied by the gyro heading value + * supplied by the ADI + */ + ADIGyro(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 + * the number of degrees of rotation times 10. + * + * There are 360 degrees in a circle, thus the gyro will return 3600 for one + * whole rotation. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a gyro + * + * \return The gyro angle in degrees. + */ + double get_value() const; + + /** + * Resets the gyroscope value to zero. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a gyro + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t reset() const; +}; + +class ADIPotentiometer : public ADIAnalogIn { + public: + /** + * Configures an ADI port to act as a Potentiometer. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + */ + ADIPotentiometer(std::uint8_t adi_port, adi_potentiometer_type_e_t potentiometer_type = E_ADI_POT_EDR); + + /** + * Configures an ADI port on an adi_expander to act as a Potentiometer. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * 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 + */ + ADIPotentiometer(ext_adi_port_pair_t port_pair, adi_potentiometer_type_e_t potentiometer_type = E_ADI_POT_EDR); + + /** + * Gets the current potentiometer angle in tenths of a degree. + * + * The original potentiometer rotates 250 degrees thus returning an angle between 0-250 degrees. + * Potentiometer V2 rotates 330 degrees thus returning an angle between 0-330 degrees. + * + * 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 + * EADDRINUSE - The port is not configured as a potentiometer + + * \return The potentiometer angle in degrees. + */ + double get_angle() const; + + /** + * Gets the 12-bit value of the specified port. + * + * The value returned is undefined if the analog pin has been switched to a + * different mode. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a potentiometer + * + * \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 + */ + using ADIAnalogIn::get_value; + + /** + * Calibrates the potentiometer on the specified port and returns the new + * calibration value. + * + * This method assumes that the potentiometer value is not actively changing at + * this time and computes an average from approximately 500 samples, 1 ms + * apart, for a 0.5 s period of calibration. The average value thus calculated + * is returned and stored for later calls to the + * pros::ADIPotentiometer::get_value_calibrated() function. This function + * will return the difference between this value and the current sensor value + * when called. + * + * Do not use this function when the potentiometer value might be unstable (rotating the potentiometer) + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a potentiometer + * + * \return The average potentiometer value computed by this function + */ + using ADIAnalogIn::calibrate; + + /** + * Gets the 12 bit calibrated value of a potentiometer port. + * + * The pros::ADIPotentiometer::calibrate() function must be run first. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a potentiometer + * + * \return The difference of the potentiometer value from its calibrated default from + * -4095 to 4095 + */ + using ADIAnalogIn::get_value_calibrated; +}; + +class ADILed : protected ADIPort { + 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param length + * The number of LEDs in the chain + */ + ADILed(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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \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 + * \param length + * The number of LEDs in the chain + */ + ADILed(ext_adi_port_pair_t port_pair, std::uint32_t length); + + /** + * @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 + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + std::int32_t length(); + + protected: + std::vector _buffer; +}; + +// Alias for ADILed +using ADILED = ADILed; + +} // namespace pros + +#endif // _PROS_ADI_HPP_ diff --git a/pros/pros/api_legacy.h b/pros/pros/api_legacy.h new file mode 100644 index 00000000..068f7e8a --- /dev/null +++ b/pros/pros/api_legacy.h @@ -0,0 +1,108 @@ +/** + * \file pros/api_legacy.h + * + * PROS 2 Legacy API header + * + * Contains declarations for functions that are name-compatible with the PROS 2 + * API. Some functions from the PROS 2 API are not useful or cannot be + * implemented in PROS 3, but most common functions are available. + * + * 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. + * 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/. + */ + +#ifndef _PROS_API_LEGACY_H_ +#define _PROS_API_LEGACY_H_ + +#include "api.h" + +#ifdef __cplusplus +#define _NAMESPACE pros:: +#define _CNAMESPACE pros::c:: +#else +#define _NAMESPACE +#define _CNAMESPACE +#endif + +/** + * From adi.h + */ +#define analogCalibrate(port) adi_analog_calibrate(port) +#define analogRead(port) adi_analog_read(port) +#define analogReadCalibrated(port) adi_analog_read_calibrated(port) +#define analogReadCalibratedHR(port) adi_analog_read_calibrated_HR(port) +#define digitalRead(port) adi_digital_read(port) +#define digitalWrite(port, value) adi_digital_write(port, value) +#define pinMode(port, mode) adi_pin_mode(port, mode) +#define adiMotorSet(port, speed) adi_motor_set(port, speed) +#define adiMotorGet(port) adi_motor_get(port) +#define adiMotorStop(port) adi_motor_stop(port) +#define encoderGet(enc) adi_encoder_get(enc) +#define encoderInit(portTop, portBottom, reverse) adi_encoder_init(portTop, portBottom, reverse) +#define encoderShutdown(enc) adi_encoder_shutdown(enc) +#define ultrasonicGet(ult) adi_ultrasonic_get(ult) +#define ultrasonicInit(portEcho, portPing) adi_ultrasonic_init(portEcho, portPing) +#define ultrasonicShutdown(ult) adi_ultrasonic_shutdown(ult) + +typedef _CNAMESPACE adi_encoder_t Encoder; +typedef _CNAMESPACE adi_ultrasonic_t Ultrasonic; + +/** + * From llemu.h + */ +#define lcdInit lcd_initialize +#define lcdReadButtons lcd_read_buttons +#define lcdClear lcd_clear +#define lcdClearLine lcd_clear_line +#define lcdShutdown lcd_shutdown +#define lcdPrint(line, fmt, ...) lcd_print(line, fmt, __VA_ARGS__) +#define lcdSetText(line, text) lcd_set_text(line, text) + +/** + * From misc.h + */ +#define isEnabled() (!competition_is_disabled()) +#define isAutonomous competition_is_autonomous +#define isOnline competition_is_connected +#define isJoystickConnected(id) controller_is_connected(id) +#define joystickGetAnalog(id, channel) controller_get_analog(id, channel) + +/** + * From rtos.h + */ +#define taskCreate(taskCode, stackDepth, parameters, priority) \ + task_create(taskCode, parameters, priority, stackDepth, "") +#define taskDelete(task) task_delete(task) +#define taskDelay task_delay +#define taskDelayUntil(previousWakeTime, cycleTime) task_delay_until(previousWakeTime, cycleTime) +#define taskPriorityGet(task) task_get_priority(task) +#define taskPrioritySet(task, newPriority) task_priority_set(task, newPriority) +#define taskGetState(task) task_get_state(task) +#define taskSuspend(task) task_suspend(task) +#define taskResume(task) task_resume(task) +#define taskGetCount task_get_count +#define mutexCreate mutex_create +#define mutexTake(mutex, blockTime) mutex_take(mutex, blockTime) +#define mutexGive(mutex) mutex_give(mutex) + +typedef _NAMESPACE task_t TaskHandle; +typedef _NAMESPACE mutex_t Mutex; + +/** + * From motors.h + */ +#define motorSet(port, speed) motor_move(port, speed) +#define motorGet(port) motor_get_voltage(port) +#define motorStop(port) motor_move(port, 0) + +#undef _NAMESPACE +#undef _CNAMESPACE + +#endif // _PROS_API_LEGACY_H_ diff --git a/pros/pros/apix.h b/pros/pros/apix.h new file mode 100644 index 00000000..8e7d3068 --- /dev/null +++ b/pros/pros/apix.h @@ -0,0 +1,593 @@ +/** + * \file pros/apix.h + * + * PROS Extended API header + * + * Contains additional declarations for use by advaned users of PROS. These + * functions do not typically have as much error handling or require deeper + * knowledge of real time operating systems. + * + * Visit https://pros.cs.purdue.edu/v5/extended/api.html to learn more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_API_EXTENDED_H_ +#define _PROS_API_EXTENDED_H_ + +#include "api.h" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wall" +#include "display/lvgl.h" +#pragma GCC diagnostic pop +#include "pros/serial.h" + +#ifdef __cplusplus +#include "pros/serial.hpp" +namespace pros::c { +extern "C" { +#endif + +/******************************************************************************/ +/** RTOS FACILITIES **/ +/** **/ +/** **/ +/**See https://pros.cs.purdue.edu/v5/extended/multitasking.html to learn more**/ +/******************************************************************************/ + +typedef void* queue_t; +typedef void* sem_t; + +/** + * Unblocks a task in the Blocked state (e.g. waiting for a delay, on a + * semaphore, etc.). + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#abort_delay for + * details. + */ +bool task_abort_delay(task_t task); + +/** + * Notify a task when a target task is being deleted. + * + * This function will configure the PROS kernel to call + * task_notify_ext(task_to_notify, value, action, NULL) when target_task is + * deleted. + * + * + * \param target_task + * The task being watched for deletion + * \param task_to_notify + * The task to notify when target_task is deleted + * \param value + * The value to supply to task_notify_ext + * \param notify_action + * The action to supply to task_notify_ext + */ +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. + * + * See + * https://pros.cs.purdue.edu/v5/extended/multitasking.html#recursive_mutexes + * for details. + * + * \return A newly created recursive mutex. + */ +mutex_t mutex_recursive_create(void); + +/** + * Takes a recursive mutex. + * + * See + * https://pros.cs.purdue.edu/v5/extended/multitasking.html#recursive_mutexes + * for details. + * + * \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 + */ +bool mutex_recursive_take(mutex_t mutex, uint32_t timeout); + +/** + * Gives a recursive mutex. + * + * See + * https://pros.cs.purdue.edu/v5/extended/multitasking.html#recursive_mutexes + * for details. + * + * \param mutex + * A mutex handle created by mutex_recursive_create + * + * \return 1 if the mutex was obtained, 0 otherwise + */ +bool mutex_recursive_give(mutex_t mutex); + +/** + * Returns a handle to the current owner of a mutex. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#extra for + * details. + * + * \param mutex + * A mutex handle + * + * \return A handle to the current task that owns the mutex, or NULL if the + * mutex isn't owned. + */ +task_t mutex_get_owner(mutex_t mutex); + +/** + * Creates a counting sempahore. + * + * See https://pros.cs.purdue.edu/v5/tutorials/multitasking.html#semaphores for + *details. + * + * \param max_count + * The maximum count value that can be reached. + * \param init_count + * The initial count value assigned to the new semaphore. + * + * \return A newly created semaphore. If an error occurred, NULL will be + * returned and errno can be checked for hints as to why sem_create failed. + */ +sem_t sem_create(uint32_t max_count, uint32_t init_count); + +/** + * Deletes a semaphore (or binary semaphore) + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#semaphores for + * details. + * + * \param sem + * Semaphore to delete + */ +void sem_delete(sem_t sem); + +/** + * Creates a binary semaphore. + * + * See + * https://pros.cs.purdue.edu/v5/extended/multitasking#.htmlbinary_semaphores + * for details. + * + * \return A newly created semaphore. + */ +sem_t sem_binary_create(void); + +/** + * Waits for the semaphore's value to be greater than 0. If the value is already + * greater than 0, this function immediately returns. + * + * See https://pros.cs.purdue.edu/v5/tutorials/multitasking.html#semaphores for + * details. + * + * \param sem + * Semaphore to wait on + * \param timeout + * Time to wait before the semaphore's becomes available. A timeout of 0 + * can be used to poll the sempahore. TIMEOUT_MAX can be used to block + * indefinitely. + * + * \return True if the semaphore was successfully take, false otherwise. If + * false is returned, then errno is set with a hint about why the sempahore + * couldn't be taken. + */ +bool sem_wait(sem_t sem, uint32_t timeout); + +/** + * Increments a semaphore's value. + * + * See https://pros.cs.purdue.edu/v5/tutorials/multitasking.html#semaphores for + * details. + * + * \param sem + * Semaphore to post + * + * \return True if the value was incremented, false otherwise. If false is + * returned, then errno is set with a hint about why the semaphore couldn't be + * taken. + */ +bool sem_post(sem_t sem); + +/** + * Returns the current value of the semaphore. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#extra for + * details. + * + * \param sem + * A semaphore handle + * + * \return The current value of the semaphore (e.g. the number of resources + * available) + */ +uint32_t sem_get_count(sem_t sem); + +/** + * Creates a queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param length + * The maximum number of items that the queue can contain. + * \param item_size + * The number of bytes each item in the queue will require. + * + * \return A handle to a newly created queue, or NULL if the queue cannot be + * created. + */ +queue_t queue_create(uint32_t length, uint32_t item_size); + +/** + * Posts an item to the front of a queue. The item is queued by copy, not by + * reference. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * The queue handle + * \param item + * A pointer to the item that will be placed on the queue. + * \param timeout + * Time to wait for space to become available. A timeout of 0 can be used + * to attempt to post without blocking. TIMEOUT_MAX can be used to block + * indefinitely. + * + * \return True if the item was preprended, false otherwise. + */ +bool queue_prepend(queue_t queue, const void* item, uint32_t timeout); + +/** + * Posts an item to the end of a queue. The item is queued by copy, not by + * reference. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * The queue handle + * \param item + * A pointer to the item that will be placed on the queue. + * \param timeout + * Time to wait for space to become available. A timeout of 0 can be used + * to attempt to post without blocking. TIMEOUT_MAX can be used to block + * indefinitely. + * + * \return True if the item was preprended, false otherwise. + */ +bool queue_append(queue_t queue, const void* item, uint32_t timeout); + +/** + * Receive an item from a queue without removing the item from the queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * The queue handle + * \param buffer + * Pointer to a buffer to which the received item will be copied + * \param timeout + * The maximum amount of time the task should block waiting for an item to receive should the queue be empty at + * the time of the call. TIMEOUT_MAX can be used to block indefinitely. + * + * \return True if an item was copied into the buffer, false otherwise. + */ +bool queue_peek(queue_t queue, void* const buffer, uint32_t timeout); + +/** + * Receive an item from the queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * The queue handle + * \param buffer + * Pointer to a buffer to which the received item will be copied + * \param timeout + * The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. queue_recv() will return immediately if timeout + * is zero and the queue is empty. + * + * \return True if an item was copied into the buffer, false otherwise. + */ +bool queue_recv(queue_t queue, void* const buffer, uint32_t timeout); + +/** + * Return the number of messages stored in a queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * The queue handle. + * + * \return The number of messages available in the queue. + */ +uint32_t queue_get_waiting(const queue_t queue); + +/** + * Return the number of spaces left in a queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * The queue handle. + * + * \return The number of spaces available in the queue. + */ +uint32_t queue_get_available(const queue_t queue); + +/** + * Delete a queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * Queue handle to delete + */ +void queue_delete(queue_t queue); + +/** + * Resets a queue to an empty state + * + * \param queue + * Queue handle to reset + */ +void queue_reset(queue_t queue); + +/******************************************************************************/ +/** Device Registration **/ +/******************************************************************************/ + +/* + * List of possible v5 devices + * + * This list contains all current V5 Devices, and mirrors V5_DeviceType from the + * api. + */ +typedef enum v5_device_e { + E_DEVICE_NONE = 0, + E_DEVICE_MOTOR = 2, + E_DEVICE_ROTATION = 4, + E_DEVICE_IMU = 6, + E_DEVICE_DISTANCE = 7, + E_DEVICE_RADIO = 8, + E_DEVICE_VISION = 11, + E_DEVICE_ADI = 12, + E_DEVICE_OPTICAL = 16, + E_DEVICE_GPS = 20, + E_DEVICE_SERIAL = 129, + E_DEVICE_GENERIC __attribute__((deprecated("use E_DEVICE_SERIAL instead"))) = E_DEVICE_SERIAL, + E_DEVICE_UNDEFINED = 255 +} v5_device_e_t; + +/* + * Registers a device in the given zero-indexed port + * + * Registers a device of the given type in the given port into the registry, if + * that type of device is detected to be plugged in to that 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 (0-20), or a + * a different device than specified is plugged in. + * EADDRINUSE - The port is already registered to another device. + * + * \param port + * The port number to register the device + * \param device + * The type of device to register + * + * \return 1 upon success, PROS_ERR upon failure + */ +int registry_bind_port(uint8_t port, v5_device_e_t device_type); + +/* + * Deregisters a devices from the given zero-indexed port + * + * Removes the device registed in the given port, if there is one. + * + * 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 (0-20). + * + * \param port + * The port number to deregister + * + * \return 1 upon success, PROS_ERR upon failure + */ +int registry_unbind_port(uint8_t port); + +/* + * Returns the type of device registered to the zero-indexed 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 (0-20). + * + * \param port + * The V5 port number from 0-20 + * + * \return The type of device that is registered into the port (NOT what is + * plugged in) + */ +v5_device_e_t registry_get_bound_type(uint8_t port); + +/* + * Returns the type of the device plugged into the zero-indexed 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 (0-20). + * + * \param port + * The V5 port number from 0-20 + * + * \return The type of device that is plugged into the port (NOT what is + * registered) + */ +v5_device_e_t registry_get_plugged_type(uint8_t port); + +/******************************************************************************/ +/** Filesystem **/ +/******************************************************************************/ +/** + * Control settings of the serial driver. + * + * \param action + * An action to perform on the serial driver. See the SERCTL_* macros for + * details on the different actions. + * \param extra_arg + * An argument to pass in based on the action + */ +int32_t serctl(const uint32_t action, void* const extra_arg); + +/** + * Control settings of the microSD card driver. + * + * \param action + * An action to perform on the microSD card driver. See the USDCTL_* macros + * for details on the different actions. + * \param extra_arg + * An argument to pass in based on the action + */ +// Not yet implemented +// int32_t usdctl(const uint32_t action, void* const extra_arg); + +/** + * Control settings of the way the file's driver treats the file + * + * \param file + * A valid file descriptor number + * \param action + * An action to perform on the file's driver. See the *CTL_* macros for + * details on the different actions. Note that the action passed in must + * match the correct driver (e.g. don't perform a SERCTL_* action on a + * microSD card file) + * \param extra_arg + * An argument to pass in based on the action + */ +int32_t fdctl(int file, const uint32_t action, void* const extra_arg); + +/** + * Action macro to pass into serctl or fdctl that activates the stream + * identifier. + * + * When used with serctl, the extra argument must be the little endian + * representation of the stream identifier (e.g. "sout" -> 0x74756f73) + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#define SERCTL_ACTIVATE 10 + +/** + * Action macro to pass into serctl or fdctl that deactivates the stream + * identifier. + * + * When used with serctl, the extra argument must be the little endian + * representation of the stream identifier (e.g. "sout" -> 0x74756f73) + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#define SERCTL_DEACTIVATE 11 + +/** + * Action macro to pass into fdctl that enables blocking writes for the file + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#define SERCTL_BLKWRITE 12 + +/** + * Action macro to pass into fdctl that makes writes non-blocking for the file + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#define SERCTL_NOBLKWRITE 13 + +/** + * Action macro to pass into serctl that enables advanced stream multiplexing + * capabilities + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#define SERCTL_ENABLE_COBS 14 + +/** + * Action macro to pass into serctl that disables advanced stream multiplexing + * capabilities + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#define SERCTL_DISABLE_COBS 15 + +/** + * Action macro to check if there is data available from the Generic Serial + * Device + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + */ +#define DEVCTL_FIONREAD 16 + +/** + * Action macro to check if there is space available in the Generic Serial + * Device's output buffer + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + */ +#define DEVCTL_FIONWRITE 18 + +/** + * Action macro to set the Generic Serial Device's baudrate. + * + * The extra argument is the baudrate. + */ +#define DEVCTL_SET_BAUDRATE 17 + +#ifdef __cplusplus +} +} +#endif + +#endif // _PROS_API_EXTENDED_H_ diff --git a/pros/pros/colors.h b/pros/pros/colors.h new file mode 100644 index 00000000..0aa4cb35 --- /dev/null +++ b/pros/pros/colors.h @@ -0,0 +1,171 @@ +/* + * \file pros/colors.h + * + * Contains macro definitions of colors (as `uint32_t`) + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_COLORS_H_ +#define _PROS_COLORS_H_ + +#define RGB2COLOR(R, G, B) ((R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff)) +#define COLOR2R(COLOR) ((COLOR >> 16) & 0xff) +#define COLOR2G(COLOR) ((COLOR >> 8) & 0xff) +#define COLOR2B(COLOR) (COLOR & 0xff) + +#define COLOR_ALICE_BLUE 0x00F0F8FF +#define COLOR_ANTIQUE_WHITE 0x00FAEBD7 +#define COLOR_AQUA 0x0000FFFF +#define COLOR_AQUAMARINE 0x007FFFD4 +#define COLOR_AZURE 0x00F0FFFF +#define COLOR_BEIGE 0x00F5F5DC +#define COLOR_BISQUE 0x00FFE4C4 +#define COLOR_BLACK 0x00000000 +#define COLOR_BLANCHED_ALMOND 0x00FFEBCD +#define COLOR_BLUE 0x000000FF +#define COLOR_BLUE_VIOLET 0x008A2BE2 +#define COLOR_BROWN 0x00A52A2A +#define COLOR_BURLY_WOOD 0x00DEB887 +#define COLOR_CADET_BLUE 0x005F9EA0 +#define COLOR_CHARTREUSE 0x007FFF00 +#define COLOR_CHOCOLATE 0x00D2691E +#define COLOR_CORAL 0x00FF7F50 +#define COLOR_CORNFLOWER_BLUE 0x006495ED +#define COLOR_CORNSILK 0x00FFF8DC +#define COLOR_CRIMSON 0x00DC143C +#define COLOR_CYAN 0x0000FFFF +#define COLOR_DARK_BLUE 0x0000008B +#define COLOR_DARK_CYAN 0x00008B8B +#define COLOR_DARK_GOLDENROD 0x00B8860B +#define COLOR_DARK_GRAY 0x00A9A9A9 +#define COLOR_DARK_GREEN 0x00006400 +#define COLOR_DARK_KHAKI 0x00BDB76B +#define COLOR_DARK_MAGENTA 0x008B008B +#define COLOR_DARK_OLIVE_GREEN 0x00556B2F +#define COLOR_DARK_ORANGE 0x00FF8C00 +#define COLOR_DARK_ORCHID 0x009932CC +#define COLOR_DARK_RED 0x008B0000 +#define COLOR_DARK_SALMON 0x00E9967A +#define COLOR_DARK_SEA_GREEN 0x008FBC8F +#define COLOR_DARK_SLATE_GRAY 0x002F4F4F +#define COLOR_DARK_TURQUOISE 0x0000CED1 +#define COLOR_DARK_VIOLET 0x009400D3 +#define COLOR_DEEP_PINK 0x00FF1493 +#define COLOR_DEEP_SKY_BLUE 0x0000BFFF +#define COLOR_DIM_GRAY 0x00696969 +#define COLOR_DODGER_BLUE 0x001E90FF +#define COLOR_FIRE_BRICK 0x00B22222 +#define COLOR_FLORAL_WHITE 0x00FFFAF0 +#define COLOR_FOREST_GREEN 0x00228B22 +#define COLOR_FUCHSIA 0x00FF00FF +#define COLOR_GAINSBORO 0x00DCDCDC +#define COLOR_GHOST_WHITE 0x00F8F8FF +#define COLOR_GOLD 0x00FFD700 +#define COLOR_GOLDENROD 0x00DAA520 +#define COLOR_GRAY 0x00808080 +#define COLOR_GREEN 0x00008000 +#define COLOR_GREEN_YELLOW 0x00ADFF2F +#define COLOR_HONEYDEW 0x00F0FFF0 +#define COLOR_HOT_PINK 0x00FF69B4 +#define COLOR_INDIAN_RED 0x00CD5C5C +#define COLOR_INDIGO 0x004B0082 +#define COLOR_IVORY 0x00FFFFF0 +#define COLOR_KHAKI 0x00F0E68C +#define COLOR_LAVENDER 0x00E6E6FA +#define COLOR_LAVENDER_BLUSH 0x00FFF0F5 +#define COLOR_LAWN_GREEN 0x007CFC00 +#define COLOR_LEMON_CHIFFON 0x00FFFACD +#define COLOR_LIGHT_BLUE 0x00ADD8E6 +#define COLOR_LIGHT_CORAL 0x00F08080 +#define COLOR_LIGHT_CYAN 0x00E0FFFF +#define COLOR_LIGHT_GOLDENROD_YELLOW 0x00FAFAD2 +#define COLOR_LIGHT_GREEN 0x0090EE90 +#define COLOR_LIGHT_GRAY 0x00D3D3D3 +#define COLOR_LIGHT_PINK 0x00FFB6C1 +#define COLOR_LIGHT_SALMON 0x00FFA07A +#define COLOR_LIGHT_SEA_GREEN 0x0020B2AA +#define COLOR_LIGHT_SKY_BLUE 0x0087CEFA +#define COLOR_LIGHT_SLATE_GRAY 0x00778899 +#define COLOR_LIGHT_STEEL_BLUE 0x00B0C4DE +#define COLOR_LIGHT_YELLOW 0x00FFFFE0 +#define COLOR_LIME 0x0000FF00 +#define COLOR_LIME_GREEN 0x0032CD32 +#define COLOR_LINEN 0x00FAF0E6 +#define COLOR_MAGENTA 0x00FF00FF +#define COLOR_MAROON 0x00800000 +#define COLOR_MEDIUM_AQUAMARINE 0x0066CDAA +#define COLOR_MEDIUM_BLUE 0x000000CD +#define COLOR_MEDIUM_ORCHID 0x00BA55D3 +#define COLOR_MEDIUM_PURPLE 0x009370DB +#define COLOR_MEDIUM_SEA_GREEN 0x003CB371 +#define COLOR_MEDIUM_SLATE_BLUE 0x007B68EE +#define COLOR_MEDIUM_SPRING_GREEN 0x0000FA9A +#define COLOR_MEDIUM_TURQUOISE 0x0048D1CC +#define COLOR_MEDIUM_VIOLET_RED 0x00C71585 +#define COLOR_MIDNIGHT_BLUE 0x00191970 +#define COLOR_MINT_CREAM 0x00F5FFFA +#define COLOR_MISTY_ROSE 0x00FFE4E1 +#define COLOR_MOCCASIN 0x00FFE4B5 +#define COLOR_NAVAJO_WHITE 0x00FFDEAD +#define COLOR_NAVY 0x00000080 +#define COLOR_OLD_LACE 0x00FDF5E6 +#define COLOR_OLIVE 0x00808000 +#define COLOR_OLIVE_DRAB 0x006B8E23 +#define COLOR_ORANGE 0x00FFA500 +#define COLOR_ORANGE_RED 0x00FF4500 +#define COLOR_ORCHID 0x00DA70D6 +#define COLOR_PALE_GOLDENROD 0x00EEE8AA +#define COLOR_PALE_GREEN 0x0098FB98 +#define COLOR_PALE_TURQUOISE 0x00AFEEEE +#define COLOR_PALE_VIOLET_RED 0x00DB7093 +#define COLOR_PAPAY_WHIP 0x00FFEFD5 +#define COLOR_PEACH_PUFF 0x00FFDAB9 +#define COLOR_PERU 0x00CD853F +#define COLOR_PINK 0x00FFC0CB +#define COLOR_PLUM 0x00DDA0DD +#define COLOR_POWDER_BLUE 0x00B0E0E6 +#define COLOR_PURPLE 0x00800080 +#define COLOR_RED 0x00FF0000 +#define COLOR_ROSY_BROWN 0x00BC8F8F +#define COLOR_ROYAL_BLUE 0x004169E1 +#define COLOR_SADDLE_BROWN 0x008B4513 +#define COLOR_SALMON 0x00FA8072 +#define COLOR_SANDY_BROWN 0x00F4A460 +#define COLOR_SEA_GREEN 0x002E8B57 +#define COLOR_SEASHELL 0x00FFF5EE +#define COLOR_SIENNA 0x00A0522D +#define COLOR_SILVER 0x00C0C0C0 +#define COLOR_SKY_BLUE 0x0087CEEB +#define COLOR_SLATE_BLUE 0x006A5ACD +#define COLOR_SLATE_GRAY 0x00708090 +#define COLOR_SNOW 0x00FFFAFA +#define COLOR_SPRING_GREEN 0x0000FF7F +#define COLOR_STEEL_BLUE 0x004682B4 +#define COLOR_TAN 0x00D2B48C +#define COLOR_TEAL 0x00008080 +#define COLOR_THISTLE 0x00D8BFD8 +#define COLOR_TOMATO 0x00FF6347 +#define COLOR_TURQUOISE 0x0040E0D0 +#define COLOR_VIOLET 0x00EE82EE +#define COLOR_WHEAT 0x00F5DEB3 +#define COLOR_WHITE 0x00FFFFFF +#define COLOR_WHITE_SMOKE 0x00F5F5F5 +#define COLOR_YELLOW 0x00FFFF00 +#define COLOR_YELLOW_GREEN 0x009ACD32 +#define COLOR_DARK_GREY COLOR_DARK_GRAY +#define COLOR_DARK_SLATE_GREY COLOR_DARK_SLATE_GRAY +#define COLOR_DIM_GREY COLOR_DIM_GRAY +#define COLOR_GREY COLOR_GRAY +#define COLOR_LIGHT_GREY COLOR_LIGHT_GRAY +#define COLOR_LIGHT_SLATE_GREY COLOR_LIGHT_SLATE_GRAY +#define COLOR_SLATE_GREY COLOR_SLATE_GRAY + +#endif // _PROS_COLORS_H_ diff --git a/pros/pros/colors.hpp b/pros/pros/colors.hpp new file mode 100644 index 00000000..e3d0ba13 --- /dev/null +++ b/pros/pros/colors.hpp @@ -0,0 +1,170 @@ +/** + * \file pros/colors.hpp + * + * Contains enum class definitions of colors + * + * 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. + * + * 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/. + */ +#ifndef _PROS_COLORS_HPP_ +#define _PROS_COLORS_HPP_ + + +namespace pros{ +enum class Color { + alice_blue = 0x00F0F8FF, + antique_white = 0x00FAEBD7, + aqua = 0x0000FFFF, + aquamarine = 0x007FFFD4, + azure = 0x00F0FFFF, + beige = 0x00F5F5DC, + bisque = 0x00FFE4C4, + black = 0x00000000, + blanched_almond = 0x00FFEBCD, + blue = 0x000000FF, + blue_violet = 0x008A2BE2, + brown = 0x00A52A2A, + burly_wood = 0x00DEB887, + cadet_blue = 0x005F9EA0, + chartreuse = 0x007FFF00, + chocolate = 0x00D2691E, + coral = 0x00FF7F50, + cornflower_blue = 0x006495ED, + cornsilk = 0x00FFF8DC, + crimson = 0x00DC143C, + cyan = 0x0000FFFF, + dark_blue = 0x0000008B, + dark_cyan = 0x00008B8B, + dark_goldenrod = 0x00B8860B, + dark_gray = 0x00A9A9A9, + dark_grey = dark_gray, + dark_green = 0x00006400, + dark_khaki = 0x00BDB76B, + dark_magenta = 0x008B008B, + dark_olive_green = 0x00556B2F, + dark_orange = 0x00FF8C00, + dark_orchid = 0x009932CC, + dark_red = 0x008B0000, + dark_salmon = 0x00E9967A, + dark_sea_green = 0x008FBC8F, + dark_slate_gray = 0x002F4F4F, + dark_slate_grey = dark_slate_gray, + dark_turquoise = 0x0000CED1, + dark_violet = 0x009400D3, + deep_pink = 0x00FF1493, + deep_sky_blue = 0x0000BFFF, + dim_gray = 0x00696969, + dim_grey = dim_gray, + dodger_blue = 0x001E90FF, + fire_brick = 0x00B22222, + floral_white = 0x00FFFAF0, + forest_green = 0x00228B22, + fuchsia = 0x00FF00FF, + gainsboro = 0x00DCDCDC, + ghost_white = 0x00F8F8FF, + gold = 0x00FFD700, + goldenrod = 0x00DAA520, + gray = 0x00808080, + grey = gray, + green = 0x00008000, + green_yellow = 0x00ADFF2F, + honeydew = 0x00F0FFF0, + hot_pink = 0x00FF69B4, + indian_red = 0x00CD5C5C, + indigo = 0x004B0082, + ivory = 0x00FFFFF0, + khaki = 0x00F0E68C, + lavender = 0x00E6E6FA, + lavender_blush = 0x00FFF0F5, + lawn_green = 0x007CFC00, + lemon_chiffon = 0x00FFFACD, + light_blue = 0x00ADD8E6, + light_coral = 0x00F08080, + light_cyan = 0x00E0FFFF, + light_goldenrod_yellow = 0x00FAFAD2, + light_green = 0x0090EE90, + light_gray = 0x00D3D3D3, + light_grey = light_gray, + light_pink = 0x00FFB6C1, + light_salmon = 0x00FFA07A, + light_sea_green = 0x0020B2AA, + light_sky_blue = 0x0087CEFA, + light_slate_gray = 0x00778899, + light_slate_grey = light_slate_gray, + light_steel_blue = 0x00B0C4DE, + light_yellow = 0x00FFFFE0, + lime = 0x0000FF00, + lime_green = 0x0032CD32, + linen = 0x00FAF0E6, + magenta = 0x00FF00FF, + maroon = 0x00800000, + medium_aquamarine = 0x0066CDAA, + medium_blue = 0x000000CD, + medium_orchid = 0x00BA55D3, + medium_purple = 0x009370DB, + medium_sea_green = 0x003CB371, + medium_slate_blue = 0x007B68EE, + medium_spring_green = 0x0000FA9A, + medium_turquoise = 0x0048D1CC, + medium_violet_red = 0x00C71585, + midnight_blue = 0x00191970, + mint_cream = 0x00F5FFFA, + misty_rose = 0x00FFE4E1, + moccasin = 0x00FFE4B5, + navajo_white = 0x00FFDEAD, + navy = 0x00000080, + old_lace = 0x00FDF5E6, + olive = 0x00808000, + olive_drab = 0x006B8E23, + orange = 0x00FFA500, + orange_red = 0x00FF4500, + orchid = 0x00DA70D6, + pale_goldenrod = 0x00EEE8AA, + pale_green = 0x0098FB98, + pale_turquoise = 0x00AFEEEE, + pale_violet_red = 0x00DB7093, + papay_whip = 0x00FFEFD5, + peach_puff = 0x00FFDAB9, + peru = 0x00CD853F, + pink = 0x00FFC0CB, + plum = 0x00DDA0DD, + powder_blue = 0x00B0E0E6, + purple = 0x00800080, + red = 0x00FF0000, + rosy_brown = 0x00BC8F8F, + royal_blue = 0x004169E1, + saddle_brown = 0x008B4513, + salmon = 0x00FA8072, + sandy_brown = 0x00F4A460, + sea_green = 0x002E8B57, + seashell = 0x00FFF5EE, + sienna = 0x00A0522D, + silver = 0x00C0C0C0, + sky_blue = 0x0087CEEB, + slate_blue = 0x006A5ACD, + slate_gray = 0x00708090, + slate_grey = slate_gray, + snow = 0x00FFFAFA, + spring_green = 0x0000FF7F, + steel_blue = 0x004682B4, + tan = 0x00D2B48C, + teal = 0x00008080, + thistle = 0x00D8BFD8, + tomato = 0x00FF6347, + turquoise = 0x0040E0D0, + violet = 0x00EE82EE, + wheat = 0x00F5DEB3, + white = 0x00FFFFFF, + white_smoke = 0x00F5F5F5, + yellow = 0x00FFFF00, + yellow_green = 0x009ACD32, +}; +} // namespace pros + +#endif //_PROS_COLORS_HPP_ diff --git a/pros/pros/distance.h b/pros/pros/distance.h new file mode 100644 index 00000000..b7feda19 --- /dev/null +++ b/pros/pros/distance.h @@ -0,0 +1,101 @@ +/** + * \file pros/distance.h + * + * Contains prototypes for functions related to the VEX Distance sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/distance.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_DISTANCE_H_ +#define _PROS_DISTANCE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/** + * Get the currently measured distance from the sensor in mm + * + * 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 + * + * \param port The V5 Distance Sensor port number from 1-21 + * \return The distance value or PROS_ERR if the operation failed, setting + * errno. + */ +int32_t distance_get(uint8_t port); + +/** + * Get the confidence in the distance reading + * + * This is a value that has a range of 0 to 63. 63 means high confidence, + * lower values imply less confidence. Confidence is only available + * when distance is > 200mm (the value 10 is returned in this scenario). + * + * 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 + * + * \param port The V5 Distance Sensor port number from 1-21 + * \return The confidence value or PROS_ERR if the operation failed, setting + * errno. + */ +int32_t distance_get_confidence(uint8_t port); + +/** + * Get the current guess at relative object size + * + * This is a value that has a range of 0 to 400. + * A 18" x 30" grey card will return a value of approximately 75 + * in typical room lighting. + * + * 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 + * + * \param port The V5 Distance Sensor port number from 1-21 + * \return The size value or PROS_ERR if the operation failed, setting + * errno. + */ +int32_t distance_get_object_size(uint8_t port); + +/** + * Get the object velocity in m/s + * + * 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 + * + * \param port The V5 Distance Sensor port number from 1-21 + * \return The velocity value or PROS_ERR if the operation failed, setting + * errno. + */ +double distance_get_object_velocity(uint8_t port); + +#ifdef __cplusplus +} +} +} +#endif + +#endif diff --git a/pros/pros/distance.hpp b/pros/pros/distance.hpp new file mode 100644 index 00000000..0007035d --- /dev/null +++ b/pros/pros/distance.hpp @@ -0,0 +1,114 @@ +/** + * \file pros/distance.hpp + * + * Contains prototypes for the V5 Distance Sensor-related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/distance.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_DISTANCE_HPP_ +#define _PROS_DISTANCE_HPP_ + +#include + +#include "pros/distance.h" + +namespace pros { +class Distance { + public: + /** + * Creates a Distance Sensor 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). + * ENODEV - The port cannot be configured as a Distance Sensor + * + * \param port + * The V5 port number from 1-21 + */ + explicit Distance(const std::uint8_t port); + + /** + * Get the currently measured distance from the sensor in mm + * + * 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. + */ + virtual std::int32_t get(); + + /** + * Get the confidence in the distance reading + * + * This is a value that has a range of 0 to 63. 63 means high confidence, + * lower values imply less confidence. Confidence is only available + * when distance is > 200mm. + * + * 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 confidence value or PROS_ERR if the operation failed, setting + * errno. + */ + virtual std::int32_t get_confidence(); + + /** + * Get the current guess at relative object size + * + * This is a value that has a range of 0 to 400. + * A 18" x 30" grey card will return a value of approximately 75 + * in typical room lighting. + * + * 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 size value or PROS_ERR if the operation failed, setting + * errno. + */ + virtual std::int32_t get_object_size(); + + /** + * Get the object velocity in m/s + * + * 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 velocity value or PROS_ERR if the operation failed, setting + * errno. + */ + virtual double get_object_velocity(); + + /** + * Gets the port number of the distance sensor. + * + * \return The distance sensor's port number. + */ + std::uint8_t get_port(); + + private: + const std::uint8_t _port; +}; +} // namespace pros + +#endif diff --git a/pros/pros/error.h b/pros/pros/error.h new file mode 100644 index 00000000..8485978a --- /dev/null +++ b/pros/pros/error.h @@ -0,0 +1,29 @@ +/** + * \file pros/error.h + * + * Contains macro definitions for return types, mostly errors + * + * 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. + * + * 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/. + */ +#ifndef _PROS_ERROR_H_ +#define _PROS_ERROR_H_ + +#include "limits.h" + +// Different Byte Size Errors +#define PROS_ERR_BYTE (INT8_MAX) +#define PROS_ERR_2_BYTE (INT16_MAX) +#define PROS_ERR (INT32_MAX) +#define PROS_ERR_F (INFINITY) + +// Return This on Success +#define PROS_SUCCESS (1) + +#endif diff --git a/pros/pros/ext_adi.h b/pros/pros/ext_adi.h new file mode 100644 index 00000000..48e79096 --- /dev/null +++ b/pros/pros/ext_adi.h @@ -0,0 +1,793 @@ +/** + * \file pros/ext_adi.h + * + * Contains prototypes for interfacing with the 3-Wire Expander. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/adi.html to learn more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_EXT_ADI_H_ +#define _PROS_EXT_ADI_H_ + +#include +#include + +#include "adi.h" +#include "pros/adi.h" +#ifndef PROS_ERR +#define PROS_ERR (INT32_MAX) +#endif + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +#ifdef __cplusplus +namespace c { +#endif + +/******************************************************************************/ +/** General ADI Use Functions **/ +/** **/ +/** These functions allow for interaction with any ADI port type **/ +/******************************************************************************/ + +/** + * Gets the configuration for the given ADI port. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which to return + * the configuration + * + * \return The ADI configuration for the given port + */ +adi_port_config_e_t ext_adi_port_get_config(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets the value for the given ADI port. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which to return + * the configuration + * + * \return The value stored for the given port + */ +int32_t ext_adi_port_get_value(uint8_t smart_port, uint8_t adi_port); + +/** + * Configures an ADI port to act as a given sensor type. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param type + * The configuration type for the port + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_port_set_config(uint8_t smart_port, uint8_t adi_port, adi_port_config_e_t type); + +/** + * Sets the value for the given ADI port. + * + * This only works on ports configured as outputs, and the behavior will change + * depending on the configuration of the port. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which the value + * will be set + * \param value + * The value to set the ADI port to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_port_set_value(uint8_t smart_port, uint8_t adi_port, int32_t value); + +/** + * Calibrates the analog sensor on the specified port and returns the new + * calibration value. + * + * This method assumes that the true sensor value is not actively changing at + * this time and computes an average from approximately 500 samples, 1 ms apart, + * for a 0.5 s period of calibration. The average value thus calculated is + * returned and stored for later calls to the adi_analog_read_calibrated() and + * adi_analog_read_calibrated_HR() functions. These functions will return + * the difference between this value and the current sensor value when called. + * + * Do not use this function when the sensor value might be unstable + * (gyro rotation, accelerometer movement). + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to calibrate (from 1-8, 'a'-'h', 'A'-'H') + * + * \return The average sensor value computed by this function + */ +int32_t ext_adi_analog_calibrate(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets the 12-bit value of the specified port. + * + * The value returned is undefined if the analog pin has been switched to a + * different mode. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an analog input + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \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 + */ +int32_t ext_adi_analog_read(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets the 12 bit calibrated value of an analog input port. + * + * The adi_analog_calibrate() function must be run first. This function is + * inappropriate for sensor values intended for integration, as round-off error + * can accumulate causing drift over time. Use adi_analog_read_calibrated_HR() + * instead. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an analog input + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \return The difference of the sensor value from its calibrated default from + * -4095 to 4095 + */ +int32_t ext_adi_analog_read_calibrated(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets the 16 bit calibrated value of an analog input port. + * + * The adi_analog_calibrate() function must be run first. This is intended for + * integrated sensor values such as gyros and accelerometers to reduce drift due + * to round-off, and should not be used on a sensor such as a line tracker + * or potentiometer. + * + * The value returned actually has 16 bits of "precision", even though the ADC + * only reads 12 bits, so that error induced by the average value being between + * two values when integrated over time is trivial. Think of the value as the + * true value times 16. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an analog input + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \return The difference of the sensor value from its calibrated default from + * -16384 to 16384 + */ +int32_t ext_adi_analog_read_calibrated_HR(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets the digital value (1 or 0) of a port configured as a digital input. + * + * If the port is configured as some other mode, the digital value which + * reflects the current state of the port is returned, which may or may not + * differ from the currently set value. The return value is undefined for ports + * configured as any mode other than a Digital Input. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a digital input + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * + * \return True if the pin is HIGH, or false if it is LOW + */ +int32_t ext_adi_digital_read(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets a rising-edge case for a digital 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 + * presses, and not in any other tasks. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a digital input + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * + * \return 1 if the button is pressed and had not been pressed + * the last time this function was called, 0 otherwise. + */ +int32_t ext_adi_digital_get_new_press(uint8_t smart_port, uint8_t adi_port); + +/** + * Sets the digital value (1 or 0) of a port configured as a digital output. + * + * If the port is configured as some other mode, behavior is undefined. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a digital output + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param value + * An expression evaluating to "true" or "false" to set the output to + * HIGH or LOW respectively, or the constants HIGH or LOW themselves + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_digital_write(uint8_t smart_port, uint8_t adi_port, bool value); + +/** + * Configures the port as an input or output with a variety of settings. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param mode + * One of INPUT, INPUT_ANALOG, INPUT_FLOATING, OUTPUT, or OUTPUT_OD + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_pin_mode(uint8_t smart_port, uint8_t adi_port, uint8_t mode); + +/** + * Sets the speed of the motor on the given port. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an motor + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param speed + * The new signed speed; -127 is full reverse and 127 is full forward, + * with 0 being off + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_motor_set(uint8_t smart_port, uint8_t adi_port, int8_t speed); + +/** + * Gets the last set speed of the motor on the given port. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an motor + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to get (from 1-8, 'a'-'h', 'A'-'H') + * + * \return The last set speed of the motor on the given port + */ +int32_t ext_adi_motor_get(uint8_t smart_port, uint8_t adi_port); + +/** + * Stops the motor on the given port. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an motor + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to set (from 1-8, 'a'-'h', 'A'-'H') + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_motor_stop(uint8_t smart_port, uint8_t adi_port); + +/** + * Reference type for an initialized encoder. + * + * This merely contains the port number for the encoder, unlike its use as an + * object to store encoder data in PROS 2. + */ +typedef int32_t ext_adi_encoder_t; + +/** + * Gets the number of ticks recorded by the encoder. + * + * There are 360 ticks in one revolution. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an encoder + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to read + * + * \return The signed and cumulative number of counts since the last start or + * reset + */ +int32_t ext_adi_encoder_get(ext_adi_encoder_t enc); + +/** + * Creates an encoder object and configures the specified ports accordingly. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an encoder + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port_top + * The "top" wire from the encoder sensor with the removable cover side + * up. This should be in port 1, 3, 5, or 7 ('A', 'C', 'E', or 'G'). + * \param adi_port_bottom + * The "bottom" wire from the encoder sensor + * \param reverse + * If "true", the sensor will count in the opposite direction + * + * \return An adi_encoder_t object to be stored and used for later calls to + * encoder functions + */ +ext_adi_encoder_t ext_adi_encoder_init(uint8_t smart_port, uint8_t adi_port_top, uint8_t adi_port_bottom, bool reverse); + +/** + * Sets the encoder value to zero. + * + * It is safe to use this method while an encoder is enabled. It is not + * necessary to call this method before stopping or starting an encoder. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an encoder + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to reset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_encoder_reset(ext_adi_encoder_t enc); + +/** + * Disables the encoder and voids the configuration on its ports. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an encoder + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to stop + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_encoder_shutdown(ext_adi_encoder_t enc); + +/** + * Reference type for an initialized ultrasonic. + * + * This merely contains the port number for the ultrasonic, unlike its use as an + * object to store encoder data in PROS 2. + */ +typedef int32_t ext_adi_ultrasonic_t; + +/** + * Gets the current ultrasonic sensor value in centimeters. + * + * If no object was found, zero is returned. If the ultrasonic sensor was never + * started, the return value is undefined. Round and fluffy objects can cause + * inaccurate values to be returned. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param ult + * The adi_ultrasonic_t object from adi_ultrasonic_init() to read + * + * \return The distance to the nearest object in m^-4 (10000 indicates 1 meter), + * measured from the sensor's mounting points. + */ +int32_t ext_adi_ultrasonic_get(ext_adi_ultrasonic_t ult); + +/** + * Creates an ultrasonic object and configures the specified ports accordingly. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port_ping + * The port connected to the orange OUTPUT cable. This should be in port + * 1, 3, 5, or 7 ('A', 'C', 'E', 'G'). + * \param adi_port_echo + * The port connected to the yellow INPUT cable. This should be in the + * next highest port following port_ping. + * + * \return An adi_ultrasonic_t object to be stored and used for later calls to + * ultrasonic functions + */ +ext_adi_ultrasonic_t ext_adi_ultrasonic_init(uint8_t smart_port, uint8_t adi_port_ping, uint8_t adi_port_echo); + +/** + * Disables the ultrasonic sensor and voids the configuration on its ports. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param ult + * The adi_ultrasonic_t object from adi_ultrasonic_init() to stop + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_ultrasonic_shutdown(ext_adi_ultrasonic_t ult); + +/** + * Reference type for an initialized gyroscope. + * + * This merely contains the port number for the gyroscope, unlike its use as an + * object to store gyro data in PROS 2. + * + * (Might Be useless with the wire expander.) + */ +typedef int32_t ext_adi_gyro_t; + +/** + * 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 + * the number of degrees of rotation times 10. + * + * There are 360 degrees in a circle, thus the gyro will return 3600 for one + * whole rotation. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object for which the angle will be returned + * + * \return The gyro angle in degrees. + */ +double ext_adi_gyro_get(ext_adi_gyro_t gyro); + +/** + * Initializes a gyroscope on the given port. If the given port has not + * previously been configured as a gyro, then this function starts a 1300 ms + * calibration period. + * + * It is highly recommended that this function be called from initialize() when + * the robot is stationary to ensure proper calibration. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a gyro + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_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 ADI + * + * \return An adi_gyro_t object containing the given port, or PROS_ERR if the + * initialization failed. + */ +ext_adi_gyro_t ext_adi_gyro_init(uint8_t smart_port, uint8_t adi_port, double multiplier); + +/** + * Resets the gyroscope value to zero. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object for which the angle will be returned + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_gyro_reset(ext_adi_gyro_t gyro); + +/** + * Disables the gyro and voids the configuration on its port. + * + * 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 + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object to be shut down + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t ext_adi_gyro_shutdown(ext_adi_gyro_t gyro); + +/** + * Reference type for an initialized potentiometer. + * + * This merely contains the port number for the potentiometer, unlike its use as an + * object to store gyro data in PROS 2. + */ +typedef int32_t ext_adi_potentiometer_t; + +/** + * Initializes a potentiometer 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 ADI Ports + * EADDRINUSE - The port is not configured as a potentiometer + * + * \param smart_port + * The smart port with the adi expander (1-21) + * \param adi_port + * The ADI port to initialize as a gyro (from 1-8, 'a'-'h', 'A'-'H') + * \param potentiometer_type + * An adi_potentiometer_type_e_t enum value specifying the potentiometer version type + * + * \return An adi_potentiometer_t object containing the given port, or PROS_ERR if the + * initialization failed. + */ +ext_adi_potentiometer_t ext_adi_potentiometer_init(uint8_t smart_port, uint8_t adi_port, adi_potentiometer_type_e_t potentiometer_type); + +/** + * Gets the current potentiometer angle in tenths of a degree. + * + * The original potentiometer rotates 250 degrees thus returning an angle between 0-250 degrees. + * Potentiometer V2 rotates 333 degrees thus returning an angle between 0-333 degrees. + * + * 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 + * EADDRINUSE - The port is not configured as a potentiometer + * + * \param potentiometer + * The adi_potentiometer_t object for which the angle will be returned + * + * \return The potentiometer angle in degrees. + */ +double ext_adi_potentiometer_get_angle(ext_adi_potentiometer_t potentiometer); + +/** + * Reference type for an initialized addressable led, which stores its smart and adi port. + */ +typedef int32_t ext_adi_led_t; + +/** + * Initializes a led 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 ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * \param smart_port + * The smart port with the adi expander (1-21) + * \param adi_port + * The ADI port to initialize as a led (from 1-8, 'a'-'h', 'A'-'H') + * + * \return An ext_adi_led_t object containing the given port, or PROS_ERR if the + * initialization failed. + */ +ext_adi_led_t ext_adi_led_init(uint8_t smart_port, uint8_t adi_port); + +/** + * @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 given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of buffer to clear + * @return PROS_SUCCESS if successful, PROS_ERR if not + */ +int32_t ext_adi_led_clear_all(ext_adi_led_t led, uint32_t* buffer, uint32_t buffer_length); + +/** + * @brief Set the entire led strip using the colors contained in the buffer + * + * 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 given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of buffer to clear + * @return PROS_SUCCESS if successful, PROS_ERR if not + */ +int32_t ext_adi_led_set(ext_adi_led_t led, uint32_t* buffer, uint32_t buffer_length); + +/** + * @brief Set the entire led strip to one 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 given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of buffer to clear + * @param color color to set all the led strip value to + * @return PROS_SUCCESS if successful, PROS_ERR if not + */ +int32_t ext_adi_led_set_all(ext_adi_led_t led, uint32_t* buffer, uint32_t buffer_length, 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: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of the input buffer + * @param color color to clear all the led strip to + * @param pixel_position position of the pixel to clear (0 indexed) + * @return PROS_SUCCESS if successful, PROS_ERR if not + */ +int32_t ext_adi_led_set_pixel(ext_adi_led_t led, uint32_t* buffer, uint32_t buffer_length, 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: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of the input buffer + * @param pixel_position position of the pixel to clear (0 indexed) + * @return PROS_SUCCESS if successful, PROS_ERR if not + */ +int32_t ext_adi_led_clear_pixel(ext_adi_led_t led, uint32_t* buffer, uint32_t buffer_length, uint32_t pixel_position); + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_ADI_H_ diff --git a/pros/pros/gps.h b/pros/pros/gps.h new file mode 100644 index 00000000..1af417bc --- /dev/null +++ b/pros/pros/gps.h @@ -0,0 +1,313 @@ +/** + * \file pros/gps.h + * + * Contains prototypes for functions related to the VEX GPS. + * + * Visit https://pros.cs.purdue.edu/v5/api/c/gps.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_GPS_H_ +#define _PROS_GPS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +typedef struct __attribute__((__packed__)) gps_status_s { + double x; ///< X Position (meters) + double y; ///< Y Position (meters) + double pitch; ///< Percieved Pitch based on GPS + IMU + double roll; ///< Percieved Roll based on GPS + IMU + double yaw; ///< Percieved Yaw based on GPS + IMU +} gps_status_s_t; + +struct gps_raw_s { + double x; ///< Percieved Pitch based on GPS + IMU + double y; ///< Percieved Roll based on GPS + IMU + double z; ///< Percieved Yaw based on GPS + IMU +}; + +typedef struct gps_raw_s gps_accel_s_t; +typedef struct gps_raw_s gps_gyro_s_t; + +/** + * Set the GPS's offset relative to the center of turning in meters, + * as well as its initial 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 + * + * \param port + * The V5 GPS port number from 1-21 + * \param xOffset + * Cartesian 4-Quadrant X offset from center of turning (meters) + * \param yOffset + * Cartesian 4-Quadrant Y offset from center of turning (meters) + * \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. + */ +int32_t gps_initialize_full(uint8_t port, double xInitial, double yInitial, double headingInitial, double xOffset, + double yOffset); + +/** + * Set the GPS's offset relative to the center of turning 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 + * \param xOffset + * Cartesian 4-Quadrant X offset from center of turning (meters) + * \param yOffset + * Cartesian 4-Quadrant Y offset from center of turning (meters) + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t gps_set_offset(uint8_t port, double xOffset, double yOffset); + +/** + * Get the GPS's 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 + * \param xOffset + * Pointer to cartesian 4-Quadrant X offset from center of turning (meters) + * \param yOffset + * Pointer to cartesian 4-Quadrant Y offset from center of turning (meters) + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t gps_get_offset(uint8_t port, double* xOffset, double* yOffset); + +/** + * Sets the robot's location relative to the center of the field 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 + * \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. + */ +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. + * + * 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. + */ +int32_t gps_set_data_rate(uint8_t port, uint32_t rate); + +/** + * 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: + * 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 Possible RMS (Root Mean Squared) error in meters for GPS position. + * If the operation failed, returns PROS_ERR_F and errno is set. + */ +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. + */ +gps_status_s_t gps_get_status(uint8_t port); + +/** + * Get the heading in [0,360) degree values. + * + * 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 heading in [0,360) degree values. If the operation failed, + * returns PROS_ERR_F and errno is set. + */ +double gps_get_heading(uint8_t port); + +/** + * Get the heading in the max double value and min double value scale. + * + * 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 heading in [DOUBLE_MIN, DOUBLE_MAX] values. If the operation + * fails, returns PROS_ERR_F and errno is set. + */ +double gps_get_heading_raw(uint8_t port); + +/** + * Gets the GPS sensor's elapsed rotation value + * + * 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 elased heading in degrees. If the operation fails, returns + * PROS_ERR_F and errno is set. + */ +double gps_get_rotation(uint8_t port); + +/** + * Set the GPS sensor's rotation value to target value + * + * 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. + */ +int32_t gps_set_rotation(uint8_t port, double target); + +/** + * Tare the GPS sensor's rotation value + * + * 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. + */ +int32_t gps_tare_rotation(uint8_t port); + +/** + * Get the GPS's raw gyroscope values + * + * 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. + */ +gps_gyro_s_t gps_get_gyro_rate(uint8_t port); + +/** + * Get the GPS's raw accelerometer values + * + * 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 values. If the operation failed, all the + * structure's members are filled with PROS_ERR_F and errno is set. + */ +gps_accel_s_t gps_get_accel(uint8_t port); + +#ifdef __cplusplus +} +} +} +#endif + +#endif diff --git a/pros/pros/gps.hpp b/pros/pros/gps.hpp new file mode 100644 index 00000000..0d8b731c --- /dev/null +++ b/pros/pros/gps.hpp @@ -0,0 +1,284 @@ +/** + * \file pros/gps.hpp + * + * Contains prototypes for functions related to the VEX GPS. + * + * Visit https://pros.cs.purdue.edu/v5/api/cpp/gps.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_GPS_HPP_ +#define _PROS_GPS_HPP_ + +#include + +#include + +#include "pros/gps.h" + +namespace pros { +class Gps { + const std::uint8_t _port; + + public: + Gps(const std::uint8_t port) : _port(port){}; + + Gps(const std::uint8_t port, double xInitial, double yInitial, double headingInitial) : _port(port) { + pros::c::gps_set_position(port, xInitial, yInitial, headingInitial); + }; + + Gps(const std::uint8_t port, double xOffset, double yOffset) : _port(port) { + pros::c::gps_set_offset(port, xOffset, yOffset); + }; + + Gps(const std::uint8_t port, double xInitial, double yInitial, double headingInitial, double xOffset, double yOffset) + : _port(port) { + pros::c::gps_initialize_full(port, xInitial, yInitial, headingInitial, xOffset, yOffset); + }; + + /** + * Set the GPS's offset relative to the center of turning in meters, + * as well as its initial 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 + * + * \param xOffset + * Cartesian 4-Quadrant X offset from center of turning (meters) + * \param yOffset + * Cartesian 4-Quadrant Y offset from center of turning (meters) + * \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. + */ + virtual std::int32_t initialize_full(double xInitial, double yInitial, double headingInitial, double xOffset, + double yOffset) const; + + /** + * Set the GPS's offset relative to the center of turning 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 xOffset + * Cartesian 4-Quadrant X offset from center of turning (meters) + * \param yOffset + * Cartesian 4-Quadrant Y offset from center of turning (meters) + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_offset(double xOffset, double yOffset) const; + + /** + * Get the GPS's 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 xOffset + * Pointer to cartesian 4-Quadrant X offset from center of turning (meters) + * \param yOffset + * Pointer to cartesian 4-Quadrant Y offset from center of turning (meters) + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t get_offset(double* xOffset, double* yOffset) const; + + /** + * Sets the robot's location relative to the center of the field 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 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. + */ + virtual std::int32_t set_position(double xInitial, double yInitial, double headingInitial) const; + + /** + * Set the GPS sensor's data rate in milliseconds, only applies to IMU on 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 rate + * Data rate in milliseconds (Minimum: 5 ms) + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_data_rate(std::uint32_t rate) const; + + /** + * 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: + * 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 Possible RMS (Root Mean Squared) error in meters for GPS position. + * If the operation failed, returns PROS_ERR_F and errno is set. + */ + virtual double get_error() const; + + /** + * 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 + * + * + * \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. + */ + virtual pros::c::gps_status_s_t get_status() const; + + /** + * Get the heading in [0,360) degree values. + * + * 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 heading in [0,360) degree values. If the operation failed, + * returns PROS_ERR_F and errno is set. + */ + virtual double get_heading() const; + + /** + * Get the heading in the max double value and min double value scale. + * + * 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 heading in [DOUBLE_MIN, DOUBLE_MAX] values. If the operation + * fails, returns PROS_ERR_F and errno is set. + */ + virtual double get_heading_raw() const; + + /** + * Gets the GPS sensor's elapsed rotation value + * + * 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 elased heading in degrees. If the operation fails, returns + * PROS_ERR_F and errno is set. + */ + virtual double get_rotation() const; + + /** + * Set the GPS sensor's rotation value to target value + * + * 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 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. + */ + virtual std::int32_t set_rotation(double target) const; + + /** + * Tare the GPS sensor's rotation value + * + * 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 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t tare_rotation() const; + + /** + * Get the GPS's raw gyroscope values + * + * 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 raw gyroscope values. If the operation failed, all the + * structure's members are filled with PROS_ERR_F and errno is set. + */ + virtual pros::c::gps_gyro_s_t get_gyro_rate() const; + + /** + * Get the GPS's raw accelerometer values + * + * 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 values. If the operation failed, all the + * structure's members are filled with PROS_ERR_F and errno is set. + */ + virtual pros::c::gps_accel_s_t get_accel() const; + +}; // Gps Class + +using GPS = Gps; + +} // namespace pros +#endif diff --git a/pros/pros/imu.h b/pros/pros/imu.h new file mode 100644 index 00000000..59116eee --- /dev/null +++ b/pros/pros/imu.h @@ -0,0 +1,545 @@ +/** + * \file pros/imu.h + * + * Contains prototypes for functions related to the VEX Inertial sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/imu.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_IMU_H_ +#define _PROS_IMU_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +typedef enum imu_status_e { + E_IMU_STATUS_CALIBRATING = 0x01, + E_IMU_STATUS_ERROR = 0xFF, // NOTE: used for returning an error from the get_status function, not that the IMU is + // necessarily in an error state +} imu_status_e_t; + +typedef struct __attribute__((__packed__)) quaternion_s { + double x; + double y; + double z; + double w; +} quaternion_s_t; + +struct imu_raw_s { + double x; + double y; + double z; +}; + +typedef struct imu_raw_s imu_gyro_s_t; +typedef struct imu_raw_s imu_accel_s_t; + +typedef struct __attribute__((__packed__)) euler_s { + double pitch; + double roll; + double yaw; +} euler_s_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define IMU_STATUS_CALIBRATING pros::E_IMU_STATUS_CALIBRATING +#define IMU_STATUS_ERROR pros::E_IMU_STATUS_ERROR +#else +#define IMU_STATUS_CALIBRATING E_IMU_STATUS_CALIBRATING +#define IMU_STATUS_ERROR E_IMU_STATUS_ERROR +#endif +#endif + +#define IMU_MINIMUM_DATA_RATE 5 + +/** + * Calibrate IMU + * + * Calibration takes approximately 2 seconds, but this function only blocks + * until the IMU status flag is set properly to E_IMU_STATUS_CALIBRATING, + * with a minimum blocking time of 5ms. + * + * 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 + * EAGAIN - The sensor is already calibrating, or time out setting the status flag. + * + * \param port + * 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. + */ +int32_t imu_reset(uint8_t port); + +/** + * Calibrate IMU and Blocks while Calibrating + * + * Calibration takes approximately 2 seconds and blocks during this period, + * with a timeout for this operation being set a 3 seconds as a safety margin. + * Like the other reset function, this function also blocks until the IMU + * status flag is set properly to E_IMU_STATUS_CALIBRATING, with a minimum + * blocking time of 5ms and a timeout of 1 second if it's never 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 an Inertial Sensor + * EAGAIN - The sensor is already calibrating, or time out setting the status flag. + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed (timing out or port claim failure), setting errno. + */ +int32_t imu_reset_blocking(uint8_t port); + +/** + * Set the Inertial Sensor's refresh interval in milliseconds. + * + * The rate may be specified in increments of 5ms, and will be rounded down to + * the nearest increment. The minimum allowable refresh rate is 5ms. The default + * rate is 10ms. + * + * As values are copied into the shared memory buffer only at 10ms intervals, + * setting this value to less than 10ms does not mean that you can poll the + * sensor's values any faster. However, it will guarantee that the data is as + * recent as possible. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param rate The data refresh interval in milliseconds + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t imu_set_data_rate(uint8_t port, uint32_t rate); + +/** + * Get the total number of degrees the Inertial Sensor has spun about the z-axis + * + * This value is theoretically unbounded. Clockwise rotations are represented + * with positive degree values, while counterclockwise rotations are represented + * with negative ones. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The degree value or PROS_ERR_F if the operation failed, setting + * errno. + */ +double imu_get_rotation(uint8_t port); + +/** + * Get the Inertial Sensor's heading relative to the initial direction of its + * x-axis + * + * This value is bounded by [0,360). Clockwise rotations are represented with + * positive degree values, while counterclockwise rotations are represented with + * negative ones. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The degree value or PROS_ERR_F if the operation failed, setting + * errno. + */ +double imu_get_heading(uint8_t port); + +/** + * Get a quaternion representing the Inertial Sensor's 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \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. + */ +quaternion_s_t imu_get_quaternion(uint8_t port); + +/** + * Get the Euler angles representing the Inertial Sensor's 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \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. + */ +euler_s_t imu_get_euler(uint8_t port); + +/** + * Get the Inertial Sensor's pitch angle bounded by (-180,180) + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The pitch angle, or PROS_ERR_F if the operation failed, setting + * errno. + */ +double imu_get_pitch(uint8_t port); + +/** + * Get the Inertial Sensor's roll angle bounded by (-180,180) + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \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. + */ +double imu_get_roll(uint8_t port); + +/** + * Get the Inertial Sensor's yaw angle bounded by (-180,180) + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \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. + */ +double imu_get_yaw(uint8_t port); + +/** + * Get the Inertial Sensor's raw gyroscope values + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ +imu_gyro_s_t imu_get_gyro_rate(uint8_t port); + +/** + * Get the Inertial Sensor's raw acceleroneter values + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ +imu_accel_s_t imu_get_accel(uint8_t port); + +/** + * Get the Inertial Sensor's 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ +imu_status_e_t imu_get_status(uint8_t port); + +// NOTE: not used +// void imu_set_mode(uint8_t port, uint32_t mode); +// uint32_t imu_get_mode(uint8_t port); + +//Value reset functions: +/** + * Resets the current reading of the Inertial Sensor's heading to zero + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ +int32_t imu_tare_heading(uint8_t port); + +/** + * Resets the current reading of the Inertial Sensor's rotation to zero + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ +int32_t imu_tare_rotation(uint8_t port); + +/** + * Resets the current reading of the Inertial Sensor's pitch to zero + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ +int32_t imu_tare_pitch(uint8_t port); + +/** + * Resets the current reading of the Inertial Sensor's roll to zero + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ +int32_t imu_tare_roll(uint8_t port); + +/** + * Resets the current reading of the Inertial Sensor's yaw to zero + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ +int32_t imu_tare_yaw(uint8_t port); + +/** + * Reset all 3 euler values of the Inertial Sensor to 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ +int32_t imu_tare_euler(uint8_t port); + +/** + * Resets all 5 values of the Inertial Sensor to 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ +int32_t imu_tare(uint8_t port); + +//Value set functions: +/** + * Sets the current reading of the Inertial Sensor's euler values to + * target euler values. Will default to +/- 180 if target exceeds +/- 180. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * 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. + */ +int32_t imu_set_euler(uint8_t port, euler_s_t target); + +/** + * Sets the current reading of the Inertial Sensor's rotation to target value + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * 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. + */ +int32_t imu_set_rotation(uint8_t port, double target); + +/** + * Sets the current reading of the Inertial Sensor's heading to target value + * Target will default to 360 if above 360 and default to 0 if below 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * 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. + */ +int32_t imu_set_heading(uint8_t port, double target); + +/** + * Sets the current reading of the Inertial Sensor's pitch to target value + * Will default to +/- 180 if target exceeds +/- 180. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * 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. + */ +int32_t imu_set_pitch(uint8_t port, double target); + +/** + * Sets the current reading of the Inertial Sensor's roll to target value + * Will default to +/- 180 if target exceeds +/- 180. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * Target value for the roll value to be set to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t imu_set_roll(uint8_t port, double target); + +/** + * Sets the current reading of the Inertial Sensor's yaw to target value + * Will default to +/- 180 if target exceeds +/- 180. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * Target value for the yaw value to be set to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t imu_set_yaw(uint8_t port, double target); + +#ifdef __cplusplus +} +} +} +#endif + +#endif diff --git a/pros/pros/imu.hpp b/pros/pros/imu.hpp new file mode 100644 index 00000000..84272b0a --- /dev/null +++ b/pros/pros/imu.hpp @@ -0,0 +1,459 @@ +/** + * \file pros/imu.hpp + * + * Contains prototypes for functions related to the VEX Inertial sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/imu.html to learn + * more. + * + * 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. + * + * 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/. + */ +#ifndef _PROS_IMU_HPP_ +#define _PROS_IMU_HPP_ + +#include +#include "pros/imu.h" + +namespace pros { +class Imu { + const std::uint8_t _port; + + public: + Imu(const std::uint8_t port) : _port(port){}; + + /** + * Calibrate IMU + * + * Calibration takes approximately 2 seconds and blocks during this period if + * the blocking param is true, with a timeout for this operation being set a 3 + * seconds as a safety margin. This function also blocks until the IMU + * status flag is set properly to E_IMU_STATUS_CALIBRATING, with a minimum + * blocking time of 5ms and a timeout of 1 second if it's never 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 an Inertial Sensor + * EAGAIN - The sensor is already calibrating, or time out setting the status flag. + * + * \param blocking + * Whether this function blocks during calibration. + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t reset(bool blocking = false) const; + /** + * Set the Inertial Sensor's refresh interval in milliseconds. + * + * The rate may be specified in increments of 5ms, and will be rounded down to + * the nearest increment. The minimum allowable refresh rate is 5ms. The default + * rate is 10ms. + * + * As values are copied into the shared memory buffer only at 10ms intervals, + * setting this value to less than 10ms does not mean that you can poll the + * sensor's values any faster. However, it will guarantee that the data is as + * recent as possible. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param rate + * The data refresh interval in milliseconds + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_data_rate(std::uint32_t rate) const; + /** + * Get the total number of degrees the Inertial Sensor has spun about the z-axis + * + * This value is theoretically unbounded. Clockwise rotations are represented + * with positive degree values, while counterclockwise rotations are represented + * with negative ones. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The degree value or PROS_ERR_F if the operation failed, setting + * errno. + */ + virtual double get_rotation() const; + /** + * Get the Inertial Sensor's heading relative to the initial direction of its + * x-axis + * + * This value is bounded by [0,360). Clockwise rotations are represented with + * positive degree values, while counterclockwise rotations are represented with + * negative ones. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The degree value or PROS_ERR_F if the operation failed, setting + * errno. + */ + virtual double get_heading() const; + /** + * Get a quaternion representing the Inertial Sensor's 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \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. + */ + virtual pros::c::quaternion_s_t get_quaternion() const; + /** + * Get the Euler angles representing the Inertial Sensor's 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \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. + */ + virtual pros::c::euler_s_t get_euler() const; + /** + * Get the Inertial Sensor's pitch angle bounded by (-180,180) + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The pitch angle, or PROS_ERR_F if the operation failed, setting + * errno. + */ + virtual double get_pitch() const; + /** + * Get the Inertial Sensor's roll angle bounded by (-180,180) + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \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. + */ + virtual double get_roll() const; + /** + * Get the Inertial Sensor's yaw angle bounded by (-180,180) + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \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. + */ + virtual double get_yaw() const; + /** + * Get the Inertial Sensor's raw gyroscope values + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ + virtual pros::c::imu_gyro_s_t get_gyro_rate() const; + /** + * Resets the current reading of the Inertial Sensor's rotation to zero + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ + virtual std::int32_t tare_rotation() const; + /** + * Resets the current reading of the Inertial Sensor's heading to zero + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ + virtual std::int32_t tare_heading() const; + /** + * Resets the current reading of the Inertial Sensor's pitch to zero + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ + virtual std::int32_t tare_pitch() const; + /** + * Resets the current reading of the Inertial Sensor's yaw to zero + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ + virtual std::int32_t tare_yaw() const; + /** + * Resets the current reading of the Inertial Sensor's roll to zero + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ + virtual std::int32_t tare_roll() const; + /** + * Resets all 5 values of the Inertial Sensor to 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ + virtual std::int32_t tare() const; + /** + * Reset all 3 euler values of the Inertial Sensor to 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ + virtual std::int32_t tare_euler() const; + /** + * Sets the current reading of the Inertial Sensor's heading to target value + * Target will default to 360 if above 360 and default to 0 if below 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * 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. + */ + virtual std::int32_t set_heading(const double target) const; + /** + * Sets the current reading of the Inertial Sensor's rotation to target value + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * 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. + */ + virtual std::int32_t set_rotation(const double target) const; + /** + * Sets the current reading of the Inertial Sensor's yaw to target value + * Will default to +/- 180 if target exceeds +/- 180. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * 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. + */ + virtual std::int32_t set_yaw(const double target) const; + /** + * Sets the current reading of the Inertial Sensor's pitch to target value + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * 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. + */ + virtual std::int32_t set_pitch(const double target) const; + /** + * Sets the current reading of the Inertial Sensor's roll to target value + * Will default to +/- 180 if target exceeds +/- 180. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * 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. + */ + virtual std::int32_t set_roll(const double target) const; + /** + * Sets the current reading of the Inertial Sensor's euler values to + * target euler values. Will default to +/- 180 if target exceeds +/- 180. + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * 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. + */ + virtual std::int32_t set_euler(const pros::c::euler_s_t target) const; + /** + * Get the Inertial Sensor's raw accelerometer values + * + * 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 + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ + virtual pros::c::imu_accel_s_t get_accel() const; + /** + * Get the Inertial Sensor's 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 an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * 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. + */ + virtual pros::c::imu_status_e_t get_status() const; + /** + * Check whether the IMU is calibrating + * + * \return true if the V5 Inertial Sensor is calibrating or false + * false if it is not. + */ + virtual bool is_calibrating() const; +}; + +using IMU = Imu; + +} // namespace pros + +#endif diff --git a/pros/pros/link.h b/pros/pros/link.h new file mode 100644 index 00000000..f370b7e3 --- /dev/null +++ b/pros/pros/link.h @@ -0,0 +1,275 @@ +/** + * \file pros/link.h + * + * Contains prototypes for functions related to the robot to robot communications. + * + * Visit https://pros.cs.purdue.edu/v5/api/c/link.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_LINK_H_ +#define _PROS_LINK_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +typedef enum link_type_e { + E_LINK_RECIEVER = 0, + E_LINK_TRANSMITTER, + E_LINK_RX = E_LINK_RECIEVER, + E_LINK_TX = E_LINK_TRANSMITTER +} link_type_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define LINK_RECIEVER pros::E_LINK_RECIEVER +#define LINK_TRANSMITTER pros::E_LINK_TRANSMITTER +#define LINK_RX pros::E_LINK_RX +#define LINK_TX pros::E_LINK_TX +#else +#define LINK_RECIEVER E_LINK_RECIEVER +#define LINK_TRANSMITTER E_LINK_TRANSMITTER +#define LINK_RX E_LINK_RX +#define LINK_TX E_LINK_TX +#endif +#endif + +#define LINK_BUFFER_SIZE 512 + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Initializes a link on a radio port, with an indicated type. There might be a + * 1 to 2 second delay from when this function is called to when the link is initializes. + * PROS currently only supports the use of one radio per brain. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \param port + * The port of the radio for the intended link. + * \param link_id + * Unique link ID in the form of a string, needs to be different from other links in + * the area. + * \param type + * Indicates whether the radio link on the brain is a transmitter or reciever, + * with the transmitter having double the transmitting bandwidth as the recieving + * end (1040 bytes/s vs 520 bytes/s). + * + * \return PROS_ERR if initialization fails, 1 if the initialization succeeds. + */ +uint32_t link_init(uint8_t port, const char* link_id, link_type_e_t type); + +/** + * Initializes a link on a radio port, with an indicated type and the ability for + * vexlink to override the controller radio. There might be a 1 to 2 second delay + * from when this function is called to when the link is initializes. + * PROS currently only supports the use of one radio per brain. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \param port + * The port of the radio for the intended link. + * \param link_id + * Unique link ID in the form of a string, needs to be different from other links in + * the area. + * \param type + * Indicates whether the radio link on the brain is a transmitter or reciever, + * with the transmitter having double the transmitting bandwidth as the recieving + * end (1040 bytes/s vs 520 bytes/s). + * + * \return PROS_ERR if initialization fails, 1 if the initialization succeeds. + */ +uint32_t link_init_override(uint8_t port, const char* link_id, link_type_e_t type); + +/** + * Checks if a radio link on a port is active or not. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \param port + * The port of the radio for the intended link. + * + * \return If a radio is connected to a port and it's connected to a link. + */ +bool link_connected(uint8_t port); + +/** + * Returns the bytes of data available to be read + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \param port + * The port of the radio for the intended link. + * + * \return PROS_ERR if port is not a link/radio, else the bytes available to be + * read by the user. + */ +uint32_t link_raw_receivable_size(uint8_t port); + +/** + * Returns the bytes of data available in transmission buffer. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \param port + * The port of the radio for the intended link. + * + * \return PROS_ERR if port is not a link/radio, + */ +uint32_t link_raw_transmittable_size(uint8_t port); + +/** + * Send raw serial data through vexlink. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EBUSY - The transmitter buffer is still busy with a previous transmission, and there is no + * room in the FIFO buffer (queue) to transmit the data. + * EINVAL - The data given is NULL + * + * \param port + * The port of the radio for the intended link. + * \param data + * Buffer with data to send + * \param data_size + * Bytes of data to be read to the destination buffer + * + * \return PROS_ERR if port is not a link, and the successfully transmitted + * data size if it succeeded. + */ +uint32_t link_transmit_raw(uint8_t port, void* data, uint16_t data_size); + +/** + * Receive raw serial data through vexlink. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EINVAL - The destination given is NULL, or the size given is larger than the FIFO buffer + * or destination buffer. + * + * \param port + * The port of the radio for the intended link. + * \param dest + * Destination buffer to read data to + * \param data_size + * Bytes of data to be read to the destination buffer + * + * \return PROS_ERR if port is not a link, and the successfully received + * data size if it succeeded. + */ +uint32_t link_receive_raw(uint8_t port, void* dest, uint16_t data_size); + +/** + * Send packeted message through vexlink, with a checksum and start byte. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EBUSY - The transmitter buffer is still busy with a previous transmission, and there is no + * room in the FIFO buffer (queue) to transmit the data. + * EINVAL - The data given is NULL + * + * \param port + * The port of the radio for the intended link. + * \param data + * Buffer with data to send + * \param data_size + * Bytes of data to be read to the destination buffer + * + * \return PROS_ERR if port is not a link, and the successfully transmitted + * data size if it succeeded. + */ +uint32_t link_transmit(uint8_t port, void* data, uint16_t data_size); + +/** + * Receive packeted message through vexlink, with a checksum and start byte. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EINVAL - The destination given is NULL, or the size given is larger than the FIFO buffer + * or destination buffer. + * EBADMSG - Protocol error related to start byte, data size, or checksum. + * + * \param port + * The port of the radio for the intended link. + * \param dest + * Destination buffer to read data to + * \param data_size + * Bytes of data to be read to the destination buffer + * + * \return PROS_ERR if port is not a link or protocol error, and the successfully + * transmitted data size if it succeeded. + */ +uint32_t link_receive(uint8_t port, void* dest, uint16_t data_size); + +/** + * Clear the receive buffer of the link, and discarding the data. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \param port + * The port of the radio for the intended link. + * + * \return PROS_ERR if port is not a link, and the successfully received + * data size if it succeeded. + */ +uint32_t link_clear_receive_buf(uint8_t port); + +#ifdef __cplusplus +} +} +} +#endif + +#endif diff --git a/pros/pros/link.hpp b/pros/pros/link.hpp new file mode 100644 index 00000000..d44c6bd5 --- /dev/null +++ b/pros/pros/link.hpp @@ -0,0 +1,200 @@ +/** + * \file pros/link.hpp + * + * Contains prototypes for functions related to robot to robot communications. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/link.html to learn + * more. + * + * 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. + * + * 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/. + */ +#ifndef _PROS_LINK_HPP_ +#define _PROS_LINK_HPP_ + +#include +#include + +#include "pros/link.h" + +namespace pros { +class Link { + private: + std::uint8_t _port; + + public: + /** + * Initializes a link on a radio port, with an indicated type. There might be a + * 1 to 2 second delay from when this function is called to when the link is initializes. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \param port + * The port of the radio for the intended link. + * \param link_id + * Unique link ID in the form of a string, needs to be different from other links in + * the area. + * \param type + * Indicates whether the radio link on the brain is a transmitter or reciever, + * with the transmitter having double the transmitting bandwidth as the recieving + * 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 + * + * \return PROS_ERR if initialization fails, 1 if the initialization succeeds. + */ + Link(const std::uint8_t port, const std::string link_id, link_type_e_t type, bool ov = false); + + /** + * Checks if a radio link on a port is active or not. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \return If a radio is connected to a port and it's connected to a link. + */ + bool connected(); + + /** + * Returns the bytes of data number of without protocol available to be read + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \return PROS_ERR if port is not a link/radio, else the bytes available to be + * read by the user. + */ + std::uint32_t raw_receivable_size(); + + /** + * Returns the bytes of data available in transmission buffer. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \return PROS_ERR if port is not a link/radio, + */ + std::uint32_t raw_transmittable_size(); + + /** + * Send raw serial data through vexlink. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EBUSY - The transmitter buffer is still busy with a previous transmission, and there is no + * room in the FIFO buffer (queue) to transmit the data. + * EINVAL - The data given is NULL + * + * \param data + * Buffer with data to send + * \param data_size + * Buffer with data to send + * + * \return PROS_ERR if port is not a link, and the successfully transmitted + * data size if it succeeded. + */ + std::uint32_t transmit_raw(void* data, std::uint16_t data_size); + + /** + * Receive raw serial data through vexlink. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EINVAL - The destination given is NULL, or the size given is larger than the FIFO buffer + * or destination buffer. + * + * \param dest + * Destination buffer to read data to + * \param data_size + * Bytes of data to be read to the destination buffer + * + * \return PROS_ERR if port is not a link, and the successfully received + * data size if it succeeded. + */ + std::uint32_t receive_raw(void* dest, std::uint16_t data_size); + + /** + * Send packeted message through vexlink, with a checksum and start byte. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EBUSY - The transmitter buffer is still busy with a previous transmission, and there is no + * room in the FIFO buffer (queue) to transmit the data. + * EINVAL - The data given is NULL + * + * \param data + * Buffer with data to send + * \param data_size + * Bytes of data to be read to the destination buffer + * + * \return PROS_ERR if port is not a link, and the successfully transmitted + * data size if it succeeded. + */ + std::uint32_t transmit(void* data, std::uint16_t data_size); + + /** + * Receive packeted message through vexlink, with a checksum and start byte. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EINVAL - The destination given is NULL, or the size given is larger than the FIFO buffer + * or destination buffer. + * EBADMSG - Protocol error related to start byte, data size, or checksum. + + * \param dest + * Destination buffer to read data to + * \param data_size + * Bytes of data to be read to the destination buffer + * + * \return PROS_ERR if port is not a link, and the successfully received + * data size if it succeeded. + */ + std::uint32_t receive(void* dest, std::uint16_t data_size); + + /** + * Clear the receive buffer of the link, and discarding the data. + * + * 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 radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + + * \return PROS_ERR if port is not a link, 1 if the operation succeeded. + */ + std::uint32_t clear_receive_buf(); +}; +} // namespace pros + +#endif diff --git a/pros/pros/llemu.h b/pros/pros/llemu.h new file mode 100644 index 00000000..4cb792b3 --- /dev/null +++ b/pros/pros/llemu.h @@ -0,0 +1,255 @@ +/* + * \file pros/llemu.h + * + * Legacy LCD Emulator + * + * This file defines a high-level API for emulating the three-button, UART-based + * VEX LCD, containing a set of functions that facilitate the use of a software- + * emulated version of the classic VEX LCD module. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/llemu.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_LLEMU_H_ +#define _PROS_LLEMU_H_ + +#include +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#include "display/lvgl.h" +#pragma GCC diagnostic pop + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +typedef void (*lcd_btn_cb_fn_t)(void); + +#define LCD_BTN_LEFT 4 +#define LCD_BTN_CENTER 2 +#define LCD_BTN_RIGHT 1 + +typedef struct lcd_s { + lv_obj_t* frame; + lv_obj_t* screen; + lv_obj_t* lcd_text[8]; + lv_obj_t* btn_container; + lv_obj_t* btns[3]; // < 0 => left; 1 => center; 2 => right + lcd_btn_cb_fn_t callbacks[3]; // < 0 => left; 1 => center; 2 => right + volatile uint8_t touch_bits; // < 4 => left; 2 => center; 1 => right (no + // multitouch support) +} lcd_s_t; + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Checks whether the emulated three-button LCD has already been initialized. + * + * \return True if the LCD has been initialized or false if not. + */ +bool lcd_is_initialized(void); + +/** + * Creates an emulation of the three-button, UART-based VEX LCD on the display. + * + * \return True if the LCD was successfully initialized, or false if it has + * already been initialized. + */ +bool lcd_initialize(void); + +/** + * Turns off the Legacy LCD Emulator. + * + * Calling this function will clear the entire display, and you will not be able + * to call any further LLEMU functions until another call to lcd_initialize. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_shutdown(void); + +/** + * Displays a formatted string on the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line on which to display the text [0-7] + * \param fmt + * Format string + * \param ... + * Optional list of arguments for the format string + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_print(int16_t line, const char* fmt, ...); + +/** + * Displays a string on the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line on which to display the text [0-7] + * \param text + * The text to display + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_set_text(int16_t line, const char* text); + +/** + * Clears the contents of the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_clear(void); + +/** + * Clears the contents of a line of the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line to clear + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_clear_line(int16_t line); + +/** + * Registers a callback function for the leftmost button. + * + * When the leftmost button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t (void (*cb)(void)) + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_register_btn0_cb(lcd_btn_cb_fn_t cb); + +/** + * Registers a callback function for the center button. + * + * When the center button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t (void (*cb)(void)) + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_register_btn1_cb(lcd_btn_cb_fn_t cb); + +/** + * Registers a callback function for the rightmost button. + * + * When the rightmost button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t (void (*cb)(void)) + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool lcd_register_btn2_cb(lcd_btn_cb_fn_t cb); + +/** + * Gets the button status from the emulated three-button LCD. + * + * The value returned is a 3-bit integer where 1 0 0 indicates the left button + * is pressed, 0 1 0 indicates the center button is pressed, and 0 0 1 + * indicates the right button is pressed. 0 is returned if no buttons are + * currently being pressed. + * + * Note that this function is provided for legacy API compatibility purposes, + * with the caveat that the V5 touch screen does not actually support pressing + * multiple points on the screen at the same time. + * + * \return The buttons pressed as a bit mask + */ +uint8_t lcd_read_buttons(void); + +/** + * Changes the color of the LCD background to a provided color expressed in + * type lv_color_t. + * + * \param color + * A color of type lv_color_t + * + * \return void + */ +void lcd_set_background_color(lv_color_t color); + +/** + * Changes the text color of the LCD to a provided color expressed in + * type lv_color_t. + * + * \param color + * A color of type lv_color_t + * + * \return void + */ +void lcd_set_text_color(lv_color_t color); + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif +#endif // _PROS_LLEMU_H_ diff --git a/pros/pros/llemu.hpp b/pros/pros/llemu.hpp new file mode 100644 index 00000000..8818eddb --- /dev/null +++ b/pros/pros/llemu.hpp @@ -0,0 +1,262 @@ +/* + * \file pros/llemu.hpp + * + * Legacy LCD Emulator + * + * This file defines a high-level API for emulating the three-button, UART-based + * VEX LCD, containing a set of functions that facilitate the use of a software- + * emulated version of the classic VEX LCD module. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/llemu.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_LLEMU_HPP_ +#define _PROS_LLEMU_HPP_ + +#include +#include + +#include "pros/llemu.h" + +namespace pros { +namespace lcd { +/** + * Checks whether the emulated three-button LCD has already been initialized. + * + * \return True if the LCD has been initialized or false if not. + */ +bool is_initialized(void); + +/** + * Creates an emulation of the three-button, UART-based VEX LCD on the display. + * + * \return True if the LCD was successfully initialized, or false if it has + * already been initialized. + */ +bool initialize(void); + +/** + * Turns off the Legacy LCD Emulator. + * + * Calling this function will clear the entire display, and you will not be able + * to call any further LLEMU functions until another call to lcd_initialize. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool shutdown(void); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +namespace { +template +T convert_args(T arg) { + return arg; +} +const char* convert_args(const std::string& arg) { + return arg.c_str(); +} +} // namespace +#pragma GCC diagnostic pop + +/** + * Displays a formatted string on the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line on which to display the text [0-7] + * \param fmt + * Format string + * \param ... + * Optional list of arguments for the format string + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +template +bool print(std::int16_t line, const char* fmt, Params... args) { + return pros::c::lcd_print(line, fmt, convert_args(args)...); +} + +/** + * Displays a string on the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line on which to display the text [0-7] + * \param text + * The text to display + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool set_text(std::int16_t line, std::string text); + +/** + * Clears the contents of the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool clear(void); + +/** + * Clears the contents of a line of the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line to clear + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool clear_line(std::int16_t line); + +using lcd_btn_cb_fn_t = void (*)(void); + +/** + * Registers a callback function for the leftmost button. + * + * When the leftmost button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t(void (*cb)(void)) + */ +void register_btn0_cb(lcd_btn_cb_fn_t cb); + +/** + * Registers a callback function for the center button. + * + * When the center button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t(void (*cb)(void)) + */ +void register_btn1_cb(lcd_btn_cb_fn_t cb); + +/** + * Registers a callback function for the rightmost button. + * + * When the rightmost button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t(void (*cb)(void)) + */ +void register_btn2_cb(lcd_btn_cb_fn_t cb); + +/** + * Gets the button status from the emulated three-button LCD. + * + * The value returned is a 3-bit integer where 1 0 0 indicates the left button + * is pressed, 0 1 0 indicates the center button is pressed, and 0 0 1 + * indicates the right button is pressed. 0 is returned if no buttons are + * currently being pressed. + * + * Note that this function is provided for legacy API compatibility purposes, + * with the caveat that the V5 touch screen does not actually support pressing + * multiple points on the screen at the same time. + * + * \return The buttons pressed as a bit mask + */ +std::uint8_t read_buttons(void); + +/** + * Changes the color of the LCD background to a provided color expressed in + * type lv_color_t. + * + * \param color + * A color of type lv_color_t + * + * \return void + */ +void set_background_color(lv_color_t color); + +/** + * Changes the color of the LCD background to a provided color expressed in RGB + * form, with three values of type uint8_t. + * + * \param r + * A value of type uint8_t, with a range of 0 to 255, representing the + * red value of a color + * + * \param g + * A value of type uint8_t, with a range of 0 to 255, representing the + * green value of a color + * + * \param b + * A value of type uint8_t, with a range of 0 to 255, representing the + * blue value of a color + * + * \return void + */ +void set_background_color(std::uint8_t r, std::uint8_t g, std::uint8_t b); + +/** + * Changes the text color of the LCD to a provided color expressed in + * type lv_color_t. + * + * \param color + * A color of type lv_color_t + * + * \return void + */ +void set_text_color(lv_color_t color); + +/** + * Changes the text color of the LCD to a provided color expressed in RGB + * form, with three values of type uint8_t. + * + * \param r + * A value of type uint8_t, with a range of 0 to 255, representing the + * red value of a color + * + * \param g + * A value of type uint8_t, with a range of 0 to 255, representing the + * green value of a color + * + * \param b + * A value of type uint8_t, with a range of 0 to 255, representing the + * blue value of a color + * + * \return void + */ +void set_text_color(std::uint8_t r, std::uint8_t g, std::uint8_t b); + +} // namespace lcd +} // namespace pros + +#endif // _PROS_LLEMU_HPP_ diff --git a/pros/pros/misc.h b/pros/pros/misc.h new file mode 100644 index 00000000..0b6c923f --- /dev/null +++ b/pros/pros/misc.h @@ -0,0 +1,483 @@ +/** + * \file pros/misc.h + * + * Contains prototypes for miscellaneous functions pertaining to the controller, + * battery, and competition control. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/controller.html to + * learn more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_MISC_H_ +#define _PROS_MISC_H_ + +#include + +#define NUM_V5_PORTS (22) + +/******************************************************************************/ +/** V5 Competition **/ +/******************************************************************************/ +#define COMPETITION_DISABLED (1 << 0) +#define COMPETITION_AUTONOMOUS (1 << 1) +#define COMPETITION_CONNECTED (1 << 2) + +/** + * Get the current status of the competition control. + * + * \return The competition control status as a mask of bits with + * COMPETITION_{ENABLED,AUTONOMOUS,CONNECTED}. + */ +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif +uint8_t competition_get_status(void); +#ifdef __cplusplus +} +} +} +#endif +#define competition_is_disabled() ((competition_get_status() & COMPETITION_DISABLED) != 0) +#define competition_is_connected() ((competition_get_status() & COMPETITION_CONNECTED) != 0) +#define competition_is_autonomous() ((competition_get_status() & COMPETITION_AUTONOMOUS) != 0) + +/******************************************************************************/ +/** V5 Controller **/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +typedef enum { E_CONTROLLER_MASTER = 0, E_CONTROLLER_PARTNER } controller_id_e_t; + +typedef enum { + E_CONTROLLER_ANALOG_LEFT_X = 0, + E_CONTROLLER_ANALOG_LEFT_Y, + E_CONTROLLER_ANALOG_RIGHT_X, + E_CONTROLLER_ANALOG_RIGHT_Y +} controller_analog_e_t; + +typedef enum { + E_CONTROLLER_DIGITAL_L1 = 6, + E_CONTROLLER_DIGITAL_L2, + E_CONTROLLER_DIGITAL_R1, + E_CONTROLLER_DIGITAL_R2, + E_CONTROLLER_DIGITAL_UP, + E_CONTROLLER_DIGITAL_DOWN, + E_CONTROLLER_DIGITAL_LEFT, + E_CONTROLLER_DIGITAL_RIGHT, + E_CONTROLLER_DIGITAL_X, + E_CONTROLLER_DIGITAL_B, + E_CONTROLLER_DIGITAL_Y, + E_CONTROLLER_DIGITAL_A +} controller_digital_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define CONTROLLER_MASTER pros::E_CONTROLLER_MASTER +#define CONTROLLER_PARTNER pros::E_CONTROLLER_PARTNER +#define ANALOG_LEFT_X pros::E_CONTROLLER_ANALOG_LEFT_X +#define ANALOG_LEFT_Y pros::E_CONTROLLER_ANALOG_LEFT_Y +#define ANALOG_RIGHT_X pros::E_CONTROLLER_ANALOG_RIGHT_X +#define ANALOG_RIGHT_Y pros::E_CONTROLLER_ANALOG_RIGHT_Y +#define DIGITAL_L1 pros::E_CONTROLLER_DIGITAL_L1 +#define DIGITAL_L2 pros::E_CONTROLLER_DIGITAL_L2 +#define DIGITAL_R1 pros::E_CONTROLLER_DIGITAL_R1 +#define DIGITAL_R2 pros::E_CONTROLLER_DIGITAL_R2 +#define DIGITAL_UP pros::E_CONTROLLER_DIGITAL_UP +#define DIGITAL_DOWN pros::E_CONTROLLER_DIGITAL_DOWN +#define DIGITAL_LEFT pros::E_CONTROLLER_DIGITAL_LEFT +#define DIGITAL_RIGHT pros::E_CONTROLLER_DIGITAL_RIGHT +#define DIGITAL_X pros::E_CONTROLLER_DIGITAL_X +#define DIGITAL_B pros::E_CONTROLLER_DIGITAL_B +#define DIGITAL_Y pros::E_CONTROLLER_DIGITAL_Y +#define DIGITAL_A pros::E_CONTROLLER_DIGITAL_A +#else +#define CONTROLLER_MASTER E_CONTROLLER_MASTER +#define CONTROLLER_PARTNER E_CONTROLLER_PARTNER +#define ANALOG_LEFT_X E_CONTROLLER_ANALOG_LEFT_X +#define ANALOG_LEFT_Y E_CONTROLLER_ANALOG_LEFT_Y +#define ANALOG_RIGHT_X E_CONTROLLER_ANALOG_RIGHT_X +#define ANALOG_RIGHT_Y E_CONTROLLER_ANALOG_RIGHT_Y +#define DIGITAL_L1 E_CONTROLLER_DIGITAL_L1 +#define DIGITAL_L2 E_CONTROLLER_DIGITAL_L2 +#define DIGITAL_R1 E_CONTROLLER_DIGITAL_R1 +#define DIGITAL_R2 E_CONTROLLER_DIGITAL_R2 +#define DIGITAL_UP E_CONTROLLER_DIGITAL_UP +#define DIGITAL_DOWN E_CONTROLLER_DIGITAL_DOWN +#define DIGITAL_LEFT E_CONTROLLER_DIGITAL_LEFT +#define DIGITAL_RIGHT E_CONTROLLER_DIGITAL_RIGHT +#define DIGITAL_X E_CONTROLLER_DIGITAL_X +#define DIGITAL_B E_CONTROLLER_DIGITAL_B +#define DIGITAL_Y E_CONTROLLER_DIGITAL_Y +#define DIGITAL_A E_CONTROLLER_DIGITAL_A +#endif +#endif + +/* +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; \ + } \ +/******************************************************************************/ +/** Date and Time **/ +/******************************************************************************/ + +extern const char* baked_date; +extern const char* baked_time; + +typedef struct { + uint16_t year; // Year - 1980 + uint8_t day; + uint8_t month; // 1 = January +} date_s_t; + +typedef struct { + uint8_t hour; + uint8_t min; + uint8_t sec; + uint8_t sec_hund; // hundredths of a second +} time_s_t; + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Checks if the controller is connected. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * + * \return 1 if the controller is connected, 0 otherwise + */ +int32_t controller_is_connected(controller_id_e_t id); + +/** + * Gets the value of an analog channel (joystick) on a controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param channel + * The analog channel to get. + * Must be one of ANALOG_LEFT_X, ANALOG_LEFT_Y, ANALOG_RIGHT_X, + * ANALOG_RIGHT_Y + * + * \return The current reading of the analog channel: [-127, 127]. + * If the controller was not connected, then 0 is returned + */ +int32_t controller_get_analog(controller_id_e_t id, controller_analog_e_t channel); + +/** + * Gets the battery capacity of the given controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER + * + * \return The controller's battery capacity + */ +int32_t controller_get_battery_capacity(controller_id_e_t id); + +/** + * Gets the battery level of the given controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER + * + * \return The controller's battery level + */ +int32_t controller_get_battery_level(controller_id_e_t id); + +/** + * Checks if a digital channel (button) on the controller is currently pressed. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \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 pressed. + * If the controller was not connected, then 0 is returned + */ +int32_t controller_get_digital(controller_id_e_t id, controller_digital_e_t button); + +/** + * Returns a rising-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 + * presses, and not in any other tasks. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \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 pressed and had not been pressed + * the last time this function was called, 0 otherwise. + */ +int32_t controller_get_digital_new_press(controller_id_e_t id, controller_digital_e_t button); + +/** + * Sets text to the controller LCD screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param line + * The line number at which the text will be displayed [0-2] + * \param col + * The column number at which the text will be displayed [0-14] + * \param fmt + * The format string to print to the controller + * \param ... + * The argument list for the format string + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t controller_print(controller_id_e_t id, uint8_t line, uint8_t col, const char* fmt, ...); + +/** + * Sets text to the controller LCD screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param line + * The line number at which the text will be displayed [0-2] + * \param col + * The column number at which the text will be displayed [0-14] + * \param str + * The pre-formatted string to print to the controller + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t controller_set_text(controller_id_e_t id, uint8_t line, uint8_t col, const char* str); + +/** + * Clears an individual line of the controller screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param line + * The line number to clear [0-2] + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t controller_clear_line(controller_id_e_t id, uint8_t line); + +/** + * Clears all of the lines on the controller screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. On vexOS version 1.0.0 this function will block + * for 110ms. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t controller_clear(controller_id_e_t id); + +/** + * Rumble the controller. + * + * \note Controller rumble activation is currently in beta, so continuous, fast + * updates will not work well. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param rumble_pattern + * A string consisting of the characters '.', '-', and ' ', where dots + * are short rumbles, dashes are long rumbles, and spaces are pauses. + * Maximum supported length is 8 characters. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t controller_rumble(controller_id_e_t id, const char* rumble_pattern); + +/** + * Gets the current voltage of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current voltage of the battery + */ +int32_t battery_get_voltage(void); + +/** + * Gets the current current of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current current of the battery + */ +int32_t battery_get_current(void); + +/** + * Gets the current temperature of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current temperature of the battery + */ +double battery_get_temperature(void); + +/** + * Gets the current capacity of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current capacity of the battery + */ +double battery_get_capacity(void); + +/** + * Checks if the SD card is installed. + * + * \return 1 if the SD card is installed, 0 otherwise + */ +int32_t usd_is_installed(void); + +#ifdef __cplusplus +} +} +} +#endif + +#endif // _PROS_MISC_H_ diff --git a/pros/pros/misc.hpp b/pros/pros/misc.hpp new file mode 100644 index 00000000..2415c2f1 --- /dev/null +++ b/pros/pros/misc.hpp @@ -0,0 +1,331 @@ +/** + * \file pros/misc.hpp + * + * Contains prototypes for miscellaneous functions pertaining to the controller, + * battery, and competition control. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/controller.html to + * learn more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_MISC_HPP_ +#define _PROS_MISC_HPP_ + +#include "pros/misc.h" + +#include +#include + +namespace pros { +class Controller { + public: + /** + * Creates a controller object for the given controller id. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + */ + Controller(controller_id_e_t id); + + /** + * Checks if the controller is connected. + * + * 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. + * + * \return 1 if the controller is connected, 0 otherwise + */ + std::int32_t is_connected(void); + + /** + * Gets the value of an analog channel (joystick) on a controller. + * + * 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 channel + * The analog channel to get. + * Must be one of ANALOG_LEFT_X, ANALOG_LEFT_Y, ANALOG_RIGHT_X, + * ANALOG_RIGHT_Y + * + * \return The current reading of the analog channel: [-127, 127]. + * If the controller was not connected, then 0 is returned + */ + std::int32_t get_analog(controller_analog_e_t channel); + + /** + * Gets the battery capacity of the controller. + * + * 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. + * + * \return The controller's battery capacity + */ + std::int32_t get_battery_capacity(void); + + /** + * Gets the battery level of the controller. + * + * 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. + * + * \return The controller's battery level + */ + std::int32_t get_battery_level(void); + + /** + * Checks if a digital channel (button) on the controller is currently + * pressed. + * + * 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 pressed. + * If the controller was not connected, then 0 is returned + */ + std::int32_t get_digital(controller_digital_e_t button); + + /** + * Returns a rising-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 presses, 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 pressed and had not been + * pressed the last time this function was called, 0 otherwise. + */ + std::int32_t get_digital_new_press(controller_digital_e_t button); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" + template + T convert_args(T arg) { + return arg; + } + const char* convert_args(const std::string& arg) { + return arg.c_str(); + } +#pragma GCC diagnostic pop + + /** + * Sets text to the controller LCD screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * 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 line + * The line number at which the text will be displayed [0-2] + * \param col + * The column number at which the text will be displayed [0-14] + * \param fmt + * The format string to print to the controller + * \param ... + * The argument list for the format string + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + template + std::int32_t print(std::uint8_t line, std::uint8_t col, const char* fmt, Params... args) { + return pros::c::controller_print(_id, line, col, fmt, convert_args(args)...); + } + + /** + * Sets text to the controller LCD screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * 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 line + * The line number at which the text will be displayed [0-2] + * \param col + * The column number at which the text will be displayed [0-14] + * \param str + * The pre-formatted string to print to the controller + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + 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); + + /** + * Clears an individual line of the controller screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * 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 line + * The line number to clear [0-2] + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t clear_line(std::uint8_t line); + + /** + * Rumble the controller. + * + * \note Controller rumble activation is currently in beta, so continuous, fast + * updates will not work well. + * + * 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 rumble_pattern + * A string consisting of the characters '.', '-', and ' ', where dots + * are short rumbles, dashes are long rumbles, and spaces are pauses. + * Maximum supported length is 8 characters. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t rumble(const char* rumble_pattern); + + /** + * Clears all of the lines on the controller screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. On vexOS version 1.0.0 this function will + * block for 110ms. + * + * 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. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t clear(void); + + private: + controller_id_e_t _id; +}; + +namespace battery { +/** + * Gets the current voltage of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current voltage of the battery + */ +double get_capacity(void); + +/** + * Gets the current current of the battery in milliamps, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current current of the battery + */ +int32_t get_current(void); + +/** + * Gets the current temperature of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current temperature of the battery + */ +double get_temperature(void); + +/** + * Gets the current capacity of the battery in millivolts, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current capacity of the battery + */ +int32_t get_voltage(void); +} // namespace battery + +namespace competition { +/** + * Get the current status of the competition control. + * + * \return The competition control status as a mask of bits with + * COMPETITION_{ENABLED,AUTONOMOUS,CONNECTED}. + */ +std::uint8_t get_status(void); +std::uint8_t is_autonomous(void); +std::uint8_t is_connected(void); +std::uint8_t is_disabled(void); +} // namespace competition + +namespace usd { +/** + * Checks if the SD card is installed. + * + * \return 1 if the SD card is installed, 0 otherwise + */ +std::int32_t is_installed(void); +} // namespace usd +} // namespace pros + +#endif // _PROS_MISC_HPP_ diff --git a/pros/pros/motors.h b/pros/pros/motors.h new file mode 100644 index 00000000..51ee02f4 --- /dev/null +++ b/pros/pros/motors.h @@ -0,0 +1,1140 @@ +/** + * \file pros/motors.h + * + * Contains prototypes for the V5 Motor-related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/motors.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_MOTORS_H_ +#define _PROS_MOTORS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/******************************************************************************/ +/** Motor movement functions **/ +/** **/ +/** 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 motor_move_voltage(), or motorSet() from the PROS 2 API. + * + * 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-21 + * \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. + */ +int32_t motor_move(uint8_t port, int32_t voltage); + +/** + * 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 motor_move_absolute(port, 0) + * or motor_move_relative(port, 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 motor + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_brake(uint8_t port); + +/** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with motor_set_zero_position(). + * + * \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: + * 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-21 + * \param position + * The absolute position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_move_absolute(uint8_t port, const double position, const int32_t velocity); + +/** + * Sets the relative target position for the motor to move to. + * + * This movement is relative to the current position of the motor as given in + * motor_get_position(). Providing 10.0 as the position parameter would result + * in the motor moving clockwise 10 units, 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. + * + * 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-21 + * \param position + * The relative position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_move_relative(uint8_t port, const double position, const int32_t velocity); + +/** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the gearset + * used for the motor. This results in a range of +-100 for E_MOTOR_GEARSET_36, + * +-200 for E_MOTOR_GEARSET_18, and +-600 for E_MOTOR_GEARSET_6. The velocity + * is held with PID to ensure consistent speed, as opposed to setting the + * motor's voltage. + * + * 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-21 + * \param velocity + * The new motor velocity from +-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_move_velocity(uint8_t port, const int32_t velocity); + +/** + * Sets the output voltage for the motor from -12000 to 12000 in millivolts + * + * 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-21 + * \param voltage + * The new voltage value from -12000 to 12000 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_move_voltage(uint8_t port, const int32_t voltage); + +/** + * Changes the output velocity for a profiled movement (motor_move_absolute or + * motor_move_relative). This will have no effect if the motor is not following + * a profiled movement. + * + * 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-21 + * \param velocity + * The new motor velocity from +-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_modify_profiled_velocity(uint8_t port, const int32_t velocity); + +/** + * Gets the target position set for the motor by the user. + * + * 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-21 + * + * \return The target position in its encoder units or PROS_ERR_F if the + * operation failed, setting errno. + */ +double motor_get_target_position(uint8_t port); + +/** + * Gets the velocity commanded to the motor by the user. + * + * 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-21 + * + * \return The commanded motor velocity from +-100, +-200, or +-600, or PROS_ERR + * if the operation failed, setting errno. + */ +int32_t motor_get_target_velocity(uint8_t port); + +/******************************************************************************/ +/** Motor telemetry functions **/ +/** **/ +/** These functions allow programmers to collect telemetry from motors **/ +/******************************************************************************/ + +/** + * Gets the actual velocity 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-21 + * + * \return The motor's actual velocity in RPM or PROS_ERR_F if the operation + * failed, setting errno. + */ +double motor_get_actual_velocity(uint8_t port); + +/** + * Gets the current drawn by the motor in mA. + * + * 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-21 + * + * \return The motor's current in mA or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t motor_get_current_draw(uint8_t port); + +/** + * Gets the direction of movement for 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-21 + * + * \return 1 for moving in the positive direction, -1 for moving in the + * negative direction, or PROS_ERR if the operation failed, setting errno. + */ +int32_t motor_get_direction(uint8_t port); + +/** + * Gets the efficiency of the motor in percent. + * + * 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: + * 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-21 + * + * \return The motor's efficiency in percent or PROS_ERR_F if the operation + * failed, setting errno. + */ +double motor_get_efficiency(uint8_t port); + +/** + * Checks if the motor is drawing over its current limit. + * + * 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-21 + * + * \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. + */ +int32_t motor_is_over_current(uint8_t port); + +/** + * Checks if the motor's temperature is above its limit. + * + * 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-21 + * + * \return 1 if the temperature limit is exceeded and 0 if the the temperature + * is below the limit, or PROS_ERR if the operation failed, setting errno. + */ +int32_t motor_is_over_temp(uint8_t port); + +/** + * Checks if the motor is stopped. + * + * \note Although this function forwards data from the motor, the motor + * presently does not provide any value. This function returns PROS_ERR with + * errno set to ENOSYS. + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the motor is not moving, 0 if the motor is moving, or PROS_ERR + * if the operation failed, setting errno + */ +int32_t motor_is_stopped(uint8_t port); + +/** + * Checks if the motor is at its zero position. + * + * \note Although this function forwards data from the motor, the motor + * presently does not provide any value. This function returns PROS_ERR with + * errno set to ENOSYS. + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the motor is at zero absolute position, 0 if the motor has + * moved from its absolute zero, or PROS_ERR if the operation failed, + * setting errno + */ +int32_t motor_get_zero_position_flag(uint8_t port); + +#ifdef __cplusplus +} // namespace c +#endif + +typedef enum motor_fault_e { + E_MOTOR_FAULT_NO_FAULTS = 0x00, + E_MOTOR_FAULT_MOTOR_OVER_TEMP = 0x01, // Analogous to motor_is_over_temp() + E_MOTOR_FAULT_DRIVER_FAULT = 0x02, // Indicates a motor h-bridge fault + E_MOTOR_FAULT_OVER_CURRENT = 0x04, // Analogous to motor_is_over_current() + E_MOTOR_FAULT_DRV_OVER_CURRENT = 0x08 // Indicates an h-bridge over current +} motor_fault_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define MOTOR_FAULT_NO_FAULTS pros::E_MOTOR_FAULT_NO_FAULTS +#define MOTOR_FAULT_MOTOR_OVER_TEMP pros::E_MOTOR_FAULT_MOTOR_OVER_TEMP +#define MOTOR_FAULT_DRIVER_FAULT pros::E_MOTOR_FAULT_DRIVER_FAULT +#define MOTOR_FAULT_OVER_CURRENT pros::E_MOTOR_FAULT_DRV_OVER_CURRENT +#define MOTOR_FAULT_DRV_OVER_CURRENT pros::E_MOTOR_FAULT_DRV_OVER_CURRENT +#else +#define MOTOR_FAULT_NO_FAULTS E_MOTOR_FAULT_NO_FAULTS +#define MOTOR_FAULT_MOTOR_OVER_TEMP E_MOTOR_FAULT_MOTOR_OVER_TEMP +#define MOTOR_FAULT_DRIVER_FAULT E_MOTOR_FAULT_DRIVER_FAULT +#define MOTOR_FAULT_OVER_CURRENT E_MOTOR_FAULT_DRV_OVER_CURRENT +#define MOTOR_FAULT_DRV_OVER_CURRENT E_MOTOR_FAULT_DRV_OVER_CURRENT +#endif +#endif + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Gets the faults experienced by the motor. + * + * Compare this bitfield to the bitmasks in motor_fault_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 motor + * + * \param port + * The V5 port number from 1-21 + * + * \return A bitfield containing the motor's faults. + */ +uint32_t motor_get_faults(uint8_t port); + +#ifdef __cplusplus +} // namespace c +#endif + +typedef enum motor_flag_e { + E_MOTOR_FLAGS_NONE = 0x00, + E_MOTOR_FLAGS_BUSY = 0x01, // Cannot currently communicate to the motor + E_MOTOR_FLAGS_ZERO_VELOCITY = 0x02, // Analogous to motor_is_stopped() + E_MOTOR_FLAGS_ZERO_POSITION = 0x04 // Analogous to motor_get_zero_position_flag() +} motor_flag_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define MOTOR_FLAGS_NONE pros::E_MOTOR_FLAGS_NONE +#define MOTOR_FLAGS_BUSY pros::E_MOTOR_FLAGS_BUSY +#define MOTOR_FLAGS_ZERO_VELOCITY pros::E_MOTOR_FLAGS_ZERO_VELOCITY +#define MOTOR_FLAGS_ZERO_POSITION pros::E_MOTOR_FLAGS_ZERO_POSITION +#else +#define MOTOR_FLAGS_NONE E_MOTOR_FLAGS_NONE +#define MOTOR_FLAGS_BUSY E_MOTOR_FLAGS_BUSY +#define MOTOR_FLAGS_ZERO_VELOCITY E_MOTOR_FLAGS_ZERO_VELOCITY +#define MOTOR_FLAGS_ZERO_POSITION E_MOTOR_FLAGS_ZERO_POSITION +#endif +#endif + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Gets the flags set by the motor's operation. + * + * Compare this bitfield to the bitmasks in motor_flag_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 motor + * + * \param port + * The V5 port number from 1-21 + * + * \return A bitfield containing the motor's flags. + */ +uint32_t motor_get_flags(uint8_t port); + +/** + * Gets 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: + * 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-21 + * \param[in] 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 The raw encoder count at the given timestamp or PROS_ERR if the + * operation failed. + */ +int32_t motor_get_raw_position(uint8_t port, uint32_t* const timestamp); + +/** + * Gets the absolute position of the motor in its encoder units. + * + * 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-21 + * + * \return The motor's absolute position in its encoder units or PROS_ERR_F + * if the operation failed, setting errno. + */ +double motor_get_position(uint8_t port); + +/** + * Gets the power drawn by the motor in Watts. + * + * 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-21 + * + * \return The motor's power draw in Watts or PROS_ERR_F if the operation + * failed, setting errno. + */ +double motor_get_power(uint8_t port); + +/** + * Gets the temperature of the motor 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 motor + * + * \param port + * The V5 port number from 1-21 + * + * \return The motor's temperature in degrees Celsius or PROS_ERR_F if the + * operation failed, setting errno. + */ +double motor_get_temperature(uint8_t port); + +/** + * Gets the torque generated by the motor in Newton Meters (Nm). + * + * 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-21 + * + * \return The motor's torque in Nm or PROS_ERR_F if the operation failed, + * setting errno. + */ +double motor_get_torque(uint8_t port); + +/** + * Gets the voltage delivered to the motor in millivolts. + * + * 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-21 + * + * \return The motor's voltage in mV or PROS_ERR_F if the operation failed, + * setting errno. + */ +int32_t motor_get_voltage(uint8_t port); + +/******************************************************************************/ +/** Motor configuration functions **/ +/** **/ +/** These functions allow programmers to configure the behavior of motors **/ +/******************************************************************************/ + +#ifdef __cplusplus +} // namespace c +#endif + +/** + * Indicates the current 'brake mode' of a motor. + */ +typedef enum motor_brake_mode_e { + E_MOTOR_BRAKE_COAST = 0, // Motor coasts when stopped, traditional behavior + E_MOTOR_BRAKE_BRAKE = 1, // Motor brakes when stopped + E_MOTOR_BRAKE_HOLD = 2, // Motor actively holds position when stopped + E_MOTOR_BRAKE_INVALID = INT32_MAX +} motor_brake_mode_e_t; + +/** + * Indicates the units used by the motor encoders. + */ +typedef enum motor_encoder_units_e { + E_MOTOR_ENCODER_DEGREES = 0, // Position is recorded as angle in degrees + // as a floating point number + E_MOTOR_ENCODER_ROTATIONS = 1, // Position is recorded as angle in rotations + // as a floating point number + E_MOTOR_ENCODER_COUNTS = 2, // Position is recorded as raw encoder ticks + // as a whole number + E_MOTOR_ENCODER_INVALID = INT32_MAX +} motor_encoder_units_e_t; + +/** + * Indicates the current internal gear ratio of a motor. + */ +typedef enum motor_gearset_e { + E_MOTOR_GEARSET_36 = 0, // 36:1, 100 RPM, Red gear set + E_MOTOR_GEAR_RED = E_MOTOR_GEARSET_36, + E_MOTOR_GEAR_100 = E_MOTOR_GEARSET_36, + E_MOTOR_GEARSET_18 = 1, // 18:1, 200 RPM, Green gear set + E_MOTOR_GEAR_GREEN = E_MOTOR_GEARSET_18, + E_MOTOR_GEAR_200 = E_MOTOR_GEARSET_18, + E_MOTOR_GEARSET_06 = 2, // 6:1, 600 RPM, Blue gear set + E_MOTOR_GEAR_BLUE = E_MOTOR_GEARSET_06, + E_MOTOR_GEAR_600 = E_MOTOR_GEARSET_06, + E_MOTOR_GEARSET_INVALID = INT32_MAX +} motor_gearset_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define MOTOR_BRAKE_COAST pros::E_MOTOR_BRAKE_COAST +#define MOTOR_BRAKE_BRAKE pros::E_MOTOR_BRAKE_BRAKE +#define MOTOR_BRAKE_HOLD pros::E_MOTOR_BRAKE_HOLD +#define MOTOR_BRAKE_INVALID pros::E_MOTOR_BRAKE_INVALID +#define MOTOR_ENCODER_DEGREES pros::E_MOTOR_ENCODER_DEGREES +#define MOTOR_ENCODER_ROTATIONS pros::E_MOTOR_ENCODER_ROTATIONS +#define MOTOR_ENCODER_COUNTS pros::E_MOTOR_ENCODER_COUNTS +#define MOTOR_ENCODER_INVALID pros::E_MOTOR_ENCODER_INVALID +#define MOTOR_GEARSET_36 pros::E_MOTOR_GEARSET_36 +#define MOTOR_GEAR_RED pros::E_MOTOR_GEAR_RED +#define MOTOR_GEAR_100 pros::E_MOTOR_GEAR_100 +#define MOTOR_GEARSET_18 pros::E_MOTOR_GEARSET_18 +#define MOTOR_GEAR_GREEN pros::E_MOTOR_GEAR_GREEN +#define MOTOR_GEAR_200 pros::E_MOTOR_GEAR_200 +#define MOTOR_GEARSET_06 pros::E_MOTOR_GEARSET_06 +#define MOTOR_GEARSET_6 pros::E_MOTOR_GEARSET_06 +#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 +#else +#define MOTOR_BRAKE_COAST E_MOTOR_BRAKE_COAST +#define MOTOR_BRAKE_BRAKE E_MOTOR_BRAKE_BRAKE +#define MOTOR_BRAKE_HOLD E_MOTOR_BRAKE_HOLD +#define MOTOR_BRAKE_INVALID E_MOTOR_BRAKE_INVALID +#define MOTOR_ENCODER_DEGREES E_MOTOR_ENCODER_DEGREES +#define MOTOR_ENCODER_ROTATIONS E_MOTOR_ENCODER_ROTATIONS +#define MOTOR_ENCODER_COUNTS E_MOTOR_ENCODER_COUNTS +#define MOTOR_ENCODER_INVALID E_MOTOR_ENCODER_INVALID +#define MOTOR_GEARSET_36 E_MOTOR_GEARSET_36 +#define MOTOR_GEAR_RED E_MOTOR_GEAR_RED +#define MOTOR_GEAR_100 E_MOTOR_GEAR_100 +#define MOTOR_GEARSET_18 E_MOTOR_GEARSET_18 +#define MOTOR_GEAR_GREEN E_MOTOR_GEAR_GREEN +#define MOTOR_GEAR_200 E_MOTOR_GEAR_200 +#define MOTOR_GEARSET_06 E_MOTOR_GEARSET_06 +#define MOTOR_GEARSET_6 E_MOTOR_GEARSET_06 +#define MOTOR_GEAR_BLUE E_MOTOR_GEAR_BLUE +#define MOTOR_GEAR_600 E_MOTOR_GEAR_600 +#define MOTOR_GEARSET_INVALID E_MOTOR_GEARSET_INVALID +#endif +#endif + +/** + * Holds the information about a Motor's position or velocity PID controls. + * + * These values are in 4.4 format, meaning that a value of 0x20 represents 2.0, + * 0x21 represents 2.0625, 0x22 represents 2.125, etc. + */ +typedef struct motor_pid_full_s { + uint8_t kf; // The feedforward constant + uint8_t kp; // The proportional constant + uint8_t ki; // The integral constants + uint8_t kd; // The derivative constant + uint8_t filter; // A constant used for filtering the profile acceleration + uint16_t limit; // The integral limit + uint8_t threshold; // The threshold for determining if a position movement has + // reached its goal. This has no effect for velocity PID + // calculations. + uint8_t loopspeed; // The rate at which the PID computation is run in ms +} motor_pid_full_s_t; + +/** + * Holds just the constants for a Motor's position or velocity PID controls. + * + * These values are in 4.4 format, meaning that a value of 0x20 represents 2.0, + * 0x21 represents 2.0625, 0x22 represents 2.125, etc. + */ +typedef struct motor_pid_s { + uint8_t kf; // The feedforward constant + uint8_t kp; // The proportional constant + uint8_t ki; // The integral constants + uint8_t kd; // The derivative constant +} motor_pid_s_t; + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Sets the position for the motor in its encoder units. + * + * This will be the future reference point for the motor's "absolute" 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 motor + * + * \param port + * The V5 port number from 1-21 + * \param position + * The new reference position in its encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_zero_position(uint8_t port, const double position); + +/** + * Sets the "absolute" zero position of the motor to its current 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 motor + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_tare_position(uint8_t port); + +/** + * Sets one of motor_brake_mode_e_t to 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-21 + * \param mode + * The motor_brake_mode_e_t to set for the motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_brake_mode(uint8_t port, const motor_brake_mode_e_t mode); + +/** + * Sets the current limit for the motor in mA. + * + * 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-21 + * \param limit + * The new current limit in mA + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_current_limit(uint8_t port, const int32_t limit); + +/** + * Sets one of motor_encoder_units_e_t for the motor encoder. + * + * 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-21 + * \param units + * The new motor encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_encoder_units(uint8_t port, const motor_encoder_units_e_t units); + +/** + * Sets one of motor_gearset_e_t for 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-21 + * \param gearset + * The new motor gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_gearing(uint8_t port, const motor_gearset_e_t gearset); + +/** + * Takes in floating point values and returns a properly formatted pid struct. + * The motor_pid_s_t struct is in 4.4 format, i.e. 0x20 is 2.0, 0x21 is 2.0625, + * etc. + * This function will convert the floating point values to the nearest 4.4 + * value. + * + * 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 kf + * The feedforward constant + * \param kp + * The proportional constant + * \param ki + * The integral constant + * \param kd + * The derivative constant + * + * \return A motor_pid_s_t struct formatted properly in 4.4. + */ +motor_pid_s_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_convert_pid(double kf, double kp, double ki, double kd); + +/** + * Takes in floating point values and returns a properly formatted pid struct. + * The motor_pid_s_t struct is in 4.4 format, i.e. 0x20 is 2.0, 0x21 is 2.0625, + * etc. + * This function will convert the floating point values to the nearest 4.4 + * value. + * + * 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 kf + * The feedforward constant + * \param kp + * The proportional constant + * \param ki + * The integral constant + * \param kd + * The derivative constant + * \param filter + * A constant used for filtering the profile acceleration + * \param limit + * The integral limit + * \param threshold + * The threshold for determining if a position movement has reached its + * goal. This has no effect for velocity PID calculations. + * \param loopspeed + * The rate at which the PID computation is run in ms + * + * \return A motor_pid_s_t struct formatted properly in 4.4. + */ +motor_pid_full_s_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_convert_pid_full(double kf, double kp, double ki, double kd, double filter, double limit, + double threshold, double loopspeed); + +/** + * Sets one of motor_pid_s_t for the motor. This intended to just modify the + * main PID constants. + * + * Only non-zero values of the struct will change the existing motor constants. + * + * \note This feature is in beta, it is advised to use caution when modifying + * the PID values. The motor could be damaged by particularly large constants. + * + * 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-21 + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_set_pos_pid(uint8_t port, const motor_pid_s_t pid); + +/** + * Sets one of motor_pid_full_s_t for the motor. + * + * Only non-zero values of the struct will change the existing motor constants. + * + * \note This feature is in beta, it is advised to use caution when modifying + * the PID values. The motor could be damaged by particularly large constants. + * + * 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-21 + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_set_pos_pid_full(uint8_t port, const motor_pid_full_s_t pid); + +/** + * Sets one of motor_pid_s_t for the motor. This intended to just modify the + * main PID constants. + * + * Only non-zero values of the struct will change the existing motor constants. + * + * \note This feature is in beta, it is advised to use caution when modifying + * the PID values. The motor could be damaged by particularly large constants. + * + * 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-21 + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_set_vel_pid(uint8_t port, const motor_pid_s_t pid); + +/** + * Sets one of motor_pid_full_s_t for the motor. + * + * Only non-zero values of the struct will change the existing motor constants. + * + * \note This feature is in beta, it is advised to use caution when modifying + * the PID values. The motor could be damaged by particularly large constants. + * + * 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-21 + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_set_vel_pid_full(uint8_t port, const motor_pid_full_s_t pid); + +/** + * Sets the reverse flag for the motor. + * + * This will invert its movements and the values returned for its 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 motor + * + * \param port + * The V5 port number from 1-21 + * \param reverse + * True reverses the motor, false is default + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_reversed(uint8_t port, const bool reverse); + +/** + * Sets the voltage limit for the motor in Volts. + * + * 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-21 + * \param limit + * The new voltage limit in Volts + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_voltage_limit(uint8_t port, const int32_t limit); + +/** + * Gets the brake mode that was set for 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-21 + * + * \return One of motor_brake_mode_e_t, according to what was set for the motor, + * or E_MOTOR_BRAKE_INVALID if the operation failed, setting errno. + */ +motor_brake_mode_e_t motor_get_brake_mode(uint8_t port); + +/** + * Gets the current limit for the motor in mA. + * + * The default value is 2500 mA. + * + * 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-21 + * + * \return The motor's current limit in mA or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t motor_get_current_limit(uint8_t port); + +/** + * Gets the encoder units that were set for 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-21 + * + * \return One of motor_encoder_units_e_t according to what is set for the motor + * or E_MOTOR_ENCODER_INVALID if the operation failed. + */ +motor_encoder_units_e_t motor_get_encoder_units(uint8_t port); + +/** + * Gets the gearset that was set for 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-21 + * + * \return One of motor_gearset_e_t according to what is set for the motor, + * or E_GEARSET_INVALID if the operation failed. + */ +motor_gearset_e_t motor_get_gearing(uint8_t port); + +/** + * Gets the position PID that was set for the motor. This function will return + * zero for all of the parameters if the motor_set_pos_pid() or + * motor_set_pos_pid_full() functions have not been used. + * + * 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 + * + * Additionally, in an error state all values of the returned struct are set + * to their negative maximum values. + * + * \param port + * The V5 port number from 1-21 + * + * \return A motor_pid_full_s_t containing the position PID constants last set + * to the given motor + */ +motor_pid_full_s_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_get_pos_pid(uint8_t port); + +/** + * Gets the velocity PID that was set for the motor. This function will return + * zero for all of the parameters if the motor_set_vel_pid() or + * motor_set_vel_pid_full() functions have not been used. + * + * 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 + * + * Additionally, in an error state all values of the returned struct are set + * to their negative maximum values. + * + * \param port + * The V5 port number from 1-21 + * + * \return A motor_pid_full_s_t containing the velocity PID constants last set + * to the given motor + */ +motor_pid_full_s_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_get_vel_pid(uint8_t port); + +/** + * Gets the operation direction of the motor as set by the user. + * + * 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-21 + * + * \return 1 if the motor has been reversed and 0 if the motor was not reversed, + * or PROS_ERR if the operation failed, setting errno. + */ +int32_t motor_is_reversed(uint8_t port); + +/** + * Gets the voltage limit set by the user. + * + * Default value is 0V, which means that there is no software limitation imposed + * on the voltage. + * + * 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-21 + * + * \return The motor's voltage limit in V or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t motor_get_voltage_limit(uint8_t port); + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_MOTORS_H_ diff --git a/pros/pros/motors.hpp b/pros/pros/motors.hpp new file mode 100644 index 00000000..30442816 --- /dev/null +++ b/pros/pros/motors.hpp @@ -0,0 +1,1361 @@ +/** + * \file pros/motors.hpp + * + * Contains prototypes for the V5 Motor-related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/motors.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_MOTORS_HPP_ +#define _PROS_MOTORS_HPP_ + +#include +#include +#include + +#include "pros/motors.h" +#include "pros/rtos.hpp" + +namespace pros { +class Motor { + public: + /** + * Creates a Motor object for the given port and specifications. + * + * 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-21 + * \param gearset + * The motor's gearset + * \param reverse + * True reverses the motor, false is default + * \param encoder_units + * The motor's encoder units + */ + explicit Motor( + const std::int8_t port, const motor_gearset_e_t gearset, + const bool reverse, const motor_encoder_units_e_t encoder_units); + + explicit Motor( + const std::int8_t port, const motor_gearset_e_t gearset, + const bool reverse); + + explicit Motor(const std::int8_t port, const motor_gearset_e_t gearset); + + explicit Motor(const std::int8_t port, const bool reverse); + + explicit Motor(const std::int8_t port); + + /****************************************************************************/ + /** 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(), or motorSet from the PROS 2 API. + * + * 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; + + /** + * 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 motor_move(), or motorSet() from the PROS 2 API. + * + * 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 move(std::int32_t voltage) const; + + /** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with + * pros::Motor::set_zero_position(). + * + * \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: + * ENODEV - The port cannot be configured as a motor + * + * \param position + * The absolute position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t move_absolute(const double position, const std::int32_t velocity) const; + + /** + * Sets the relative target position for the motor to move to. + * + * 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, 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. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param position + * The relative position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t move_relative(const double position, const std::int32_t velocity) const; + + /** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the + * gearset used for the motor. This results in a range of +-100 for + * E_MOTOR_GEARSET_36, +-200 for E_MOTOR_GEARSET_18, and +-600 for + * E_MOTOR_GEARSET_6. The velocity is held with PID to ensure consistent + * speed, as opposed to setting the motor's voltage. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param velocity + * The new motor velocity from -+-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t move_velocity(const std::int32_t velocity) const; + + /** + * Sets the output voltage for the motor from -12000 to 12000 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 + * + * \param voltage + * The new voltage value from -12000 to 12000 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual 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) + * or move_relative(0). + * + * 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. + */ + virtual std::int32_t brake(void) const; + + /** + * Changes the output velocity for a profiled movement (motor_move_absolute() + * or motor_move_relative()). This will have no effect if the motor is not + * following a profiled movement. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param velocity + * The new motor velocity from +-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t modify_profiled_velocity(const std::int32_t velocity) const; + + /** + * Gets the target position set for 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 + * + * \return The target position in its encoder units or PROS_ERR_F if the + * operation failed, setting errno. + */ + virtual double get_target_position(void) const; + + /** + * Gets 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 + * + * \return The commanded motor velocity from +-100, +-200, or +-600, or + * PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t get_target_velocity(void) const; + + /****************************************************************************/ + /** Motor telemetry functions **/ + /** **/ + /** These functions allow programmers to collect telemetry from motors **/ + /****************************************************************************/ + + /** + * Gets the actual velocity 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 The motor's actual velocity in RPM or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double get_actual_velocity(void) const; + + /** + * Gets 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 The motor's current in mA or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t get_current_draw(void) const; + + /** + * Gets 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 1 for moving in the positive direction, -1 for moving in the + * negative direction, and PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t get_direction(void) const; + + /** + * Gets the efficiency of the motor in percent. + * + * 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 The motor's efficiency in percent or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double get_efficiency(void) const; + + /** + * Checks if the motor is drawing over its current limit. + * + * 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 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. + */ + virtual std::int32_t is_over_current(void) const; + + /** + * Checks if the motor is stopped. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \note Although this function forwards data from the motor, the motor + * presently does not provide any value. This function returns PROS_ERR with + * errno set to ENOSYS. + * + * \return 1 if the motor is not moving, 0 if the motor is moving, or PROS_ERR + * if the operation failed, setting errno + */ + virtual std::int32_t is_stopped(void) const; + + /** + * Checks if the motor is at its zero position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \note Although this function forwards data from the motor, the motor + * presently does not provide any value. This function returns PROS_ERR with + * errno set to ENOSYS. + * + * \return 1 if the motor is at zero absolute position, 0 if the motor has + * moved from its absolute zero, or PROS_ERR if the operation failed, setting + * errno + */ + virtual std::int32_t get_zero_position_flag(void) const; + + /** + * Gets 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. + */ + virtual std::uint32_t get_faults(void) const; + + /** + * Gets 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 + * + * \return A bitfield containing the motor's flags. + */ + virtual std::uint32_t get_flags(void) const; + + /** + * Gets 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[in] 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 The raw encoder count at the given timestamp or PROS_ERR if the + * operation failed. + */ + virtual std::int32_t get_raw_position(std::uint32_t* const timestamp) 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 + * + * \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. + */ + virtual std::int32_t is_over_temp(void) const; + + /** + * Gets 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 The motor's absolute position in its encoder units or PROS_ERR_F + * if the operation failed, setting errno. + */ + virtual double get_position(void) const; + + /** + * Gets 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 The motor's power draw in Watts or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double get_power(void) const; + + /** + * Gets the temperature of the motor in degrees Celsius. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return The motor's temperature in degrees Celsius or PROS_ERR_F if the + * operation failed, setting errno. + */ + virtual double get_temperature(void) const; + + /** + * Gets the torque generated by the motor in Newton Meters (Nm). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return The motor's torque in Nm or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual double get_torque(void) const; + + /** + * Gets 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 The motor's voltage in mV or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual std::int32_t get_voltage(void) const; + + /****************************************************************************/ + /** Motor configuration functions **/ + /** **/ + /** These functions allow programmers to configure the behavior of motors **/ + /****************************************************************************/ + + /** + * Sets the position for the motor in its encoder units. + * + * This will be the future reference point for the motor's "absolute" + * position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param position + * The new reference position in its encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_zero_position(const double position) const; + + /** + * Sets the "absolute" zero position of the motor to its current position. + * + * 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. + */ + virtual std::int32_t tare_position(void) const; + + /** + * Sets one of motor_brake_mode_e_t to 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 mode + * The motor_brake_mode_e_t to set for the motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_brake_mode(const motor_brake_mode_e_t mode) const; + + /** + * Sets the current limit for 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 + * + * \param limit + * The new current limit in mA + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_current_limit(const std::int32_t limit) const; + + /** + * Sets one of motor_encoder_units_e_t for the motor encoder. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param units + * The new motor encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_encoder_units(const motor_encoder_units_e_t units) const; + + /** + * Sets one of motor_gearset_e_t 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 + * + * \param gearset + * The new motor gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_gearing(const motor_gearset_e_t gearset) const; + + /** + * Takes in floating point values and returns a properly formatted pid struct. + * The motor_pid_s_t struct is in 4.4 format, i.e. 0x20 is 2.0, 0x21 is + * 2.0625, etc. + * This function will convert the floating point values to the nearest 4.4 + * value. + * + * \param kf + * The feedforward constant + * \param kp + * The proportional constant + * \param ki + * The integral constant + * \param kd + * The derivative constant + * + * \return A motor_pid_s_t struct formatted properly in 4.4. + */ + [[deprecated( + "Changing these values is not supported by VEX and may lead to permanent motor damage.")]] static motor_pid_s_t + convert_pid(double kf, double kp, double ki, double kd); + + /** + * Takes in floating point values and returns a properly formatted pid struct. + * The motor_pid_s_t struct is in 4.4 format, i.e. 0x20 is 2.0, 0x21 is + * 2.0625, etc. + * This function will convert the floating point values to the nearest 4.4 + * value. + * + * \param kf + * The feedforward constant + * \param kp + * The proportional constant + * \param ki + * The integral constant + * \param kd + * The derivative constant + * \param filter + * A constant used for filtering the profile acceleration + * \param limit + * The integral limit + * \param threshold + * The threshold for determining if a position movement has reached its + * goal. This has no effect for velocity PID calculations. + * \param loopspeed + * The rate at which the PID computation is run in ms + * + * \return A motor_pid_s_t struct formatted properly in 4.4. + */ + [[deprecated( + "Changing these values is not supported by VEX and may lead to permanent motor " + "damage.")]] static motor_pid_full_s_t + convert_pid_full(double kf, double kp, double ki, double kd, double filter, double limit, double threshold, + double loopspeed); + + /** + * Sets one of motor_pid_s_t for the motor. This intended to just modify the + * main PID constants. + * + * Only non-zero values of the struct will change the existing motor + * constants. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + [[deprecated( + "Changing these values is not supported by VEX and may lead to permanent motor damage.")]] virtual std::int32_t + set_pos_pid(const motor_pid_s_t pid) const; + + /** + * Sets one of motor_pid_full_s_t for the motor. + * + * Only non-zero values of the struct will change the existing motor + * constants. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + [[deprecated( + "Changing these values is not supported by VEX and may lead to permanent motor damage.")]] virtual std::int32_t + set_pos_pid_full(const motor_pid_full_s_t pid) const; + + /** + * Sets one of motor_pid_s_t for the motor. This intended to just modify the + * main PID constants. + * + * Only non-zero values of the struct will change the existing motor + * constants. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + [[deprecated( + "Changing these values is not supported by VEX and may lead to permanent motor damage.")]] virtual std::int32_t + set_vel_pid(const motor_pid_s_t pid) const; + + /** + * Sets one of motor_pid_full_s_t for the motor. + * + * Only non-zero values of the struct will change the existing motor + * constants. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + [[deprecated( + "Changing these values is not supported by VEX and may lead to permanent motor damage.")]] virtual std::int32_t + set_vel_pid_full(const motor_pid_full_s_t pid) const; + + /** + * Sets the reverse flag for the motor. + * + * This will invert its movements and the values returned for its position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param reverse + * True reverses the motor, false is default + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_reversed(const bool reverse) const; + + /** + * Sets the voltage limit for the motor in Volts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param limit + * The new voltage limit in Volts + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_voltage_limit(const std::int32_t limit) const; + + /** + * Gets the brake mode that was set 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 One of motor_brake_mode_e_t, according to what was set for the + * motor, or E_MOTOR_BRAKE_INVALID if the operation failed, setting errno. + */ + virtual motor_brake_mode_e_t get_brake_mode(void) const; + + /** + * Gets the current limit for the motor in mA. + * + * The default value is 2500 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 The motor's current limit in mA or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t get_current_limit(void) const; + + /** + * Gets the encoder units that were set 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 One of motor_encoder_units_e_t according to what is set for the + * motor or E_MOTOR_ENCODER_INVALID if the operation failed. + */ + virtual motor_encoder_units_e_t get_encoder_units(void) const; + + /** + * Gets the gearset that was set 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 One of motor_gearset_e_t according to what is set for the motor, + * or E_GEARSET_INVALID if the operation failed. + */ + virtual motor_gearset_e_t get_gearing(void) const; + + /** + * Gets the position PID that was set for the motor. This function will return + * zero for all of the parameters if the motor_set_pos_pid() or + * motor_set_pos_pid_full() functions have not been used. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * Additionally, in an error state all values of the returned struct are set + * to their negative maximum values. + * + * \return A motor_pid_full_s_t containing the position PID constants last set + * to the given motor + */ + [[deprecated( + "Changing these values is not supported by VEX and may lead to permanent motor " + "damage.")]] virtual motor_pid_full_s_t + get_pos_pid(void) const; + + /** + * Gets the velocity PID that was set for the motor. This function will return + * zero for all of the parameters if the motor_set_vel_pid() or + * motor_set_vel_pid_full() functions have not been used. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * Additionally, in an error state all values of the returned struct are set + * to their negative maximum values. + * + * \return A motor_pid_full_s_t containing the velocity PID constants last set + * to the given motor + */ + [[deprecated( + "Changing these values is not supported by VEX and may lead to permanent motor " + "damage.")]] virtual motor_pid_full_s_t + get_vel_pid(void) const; + + /** + * Gets the operation direction of the motor as set 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 + * + * \return 1 if the motor has been reversed and 0 if the motor was not + * reversed, or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t is_reversed(void) const; + + /** + * Gets the voltage limit set by the user. + * + * Default value is 0V, which means that there is no software limitation + * imposed on the voltage. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return The motor's voltage limit in V or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t get_voltage_limit(void) const; + + /** + * Gets the port number of the motor. + * + * \return The motor's port number. + */ + virtual std::uint8_t get_port(void) const; + + private: + const std::uint8_t _port; +}; + +class Motor_Group { + public: + explicit Motor_Group(const std::initializer_list motors); + explicit Motor_Group(const std::vector motor_ports); + /****************************************************************************/ + /** Motor Group movement functions **/ + /** **/ + /** These functions allow programmers to make motor groups move **/ + /****************************************************************************/ + /** + * Sets the voltage for all the motors in 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() on each motor individually + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - One of the ports cannot be configured as a motor + * EACCESS - The Motor group mutex can't be taken or given + * + * \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. + */ + std::int32_t operator=(std::int32_t); + + /** + * Sets the voltage for the motors in the motor group 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 motor_move(), or motorSet() from the + * PROS 2 API on 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 + * EACCESS - The Motor group mutex can't be taken or given + * + * \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. + */ + std::int32_t move(std::int32_t voltage); + + /** + * Sets the target absolute position for the motors to move to. + * + * This movement is relative to the position of the motors when initialized or + * the position when it was most recently reset with + * pros::Motor::set_zero_position(). + * + * \note This function simply sets the target for the motors, it does not block + * program execution until the movement finishes. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EACCESS - The Motor group mutex can't be taken or given + * + * \param position + * The absolute position to move to in the motors' encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t move_absolute(const double position, const std::int32_t velocity); + + /** + * Sets the relative target position for the motor to move to. + * + * 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, 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. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EACCESS - The Motor group mutex can't be taken or given + * + * \param position + * The relative position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t move_relative(const double position, const std::int32_t velocity); + + /** + * Sets the velocity for the motors. + * + * This velocity corresponds to different actual speeds depending on the + * gearset used for the motor. This results in a range of +-100 for + * E_MOTOR_GEARSET_36, +-200 for E_MOTOR_GEARSET_18, and +-600 for + * E_MOTOR_GEARSET_6. The velocity is held with PID to ensure consistent + * speed, as opposed to setting the motor's voltage. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EACCESS - The Motor group mutex can't be taken or given + * + * \param velocity + * The new motor velocity from -+-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t move_velocity(const std::int32_t velocity); + + /** + * Sets the output voltage for the motors from -12000 to 12000 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 + * EACCESS - The Motor group mutex can't be taken or given + * + * \param voltage + * The new voltage value from -12000 to 12000 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t move_voltage(const std::int32_t voltage); + + /** + * 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) + * or move_relative(0). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EACCESS - The Motor group mutex can't be taken or given + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t brake(void); + /****************************************************************************/ + /** Motor configuration functions **/ + /** **/ + /** These functions let programmers configure the behavior of motor groups **/ + /****************************************************************************/ + + /** + * Indexes Motor in the Motor_Group in the same way as an array. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Out of bounds on indexing the motor groups. + * + * \param i + * The index value in the motor group. + * + * \return the appropriate Motor reference or the erno if the operation + * failed + */ + pros::Motor& operator[](int i); + + + /** + * Indexes Motor in the Motor_Group in the same way as an array. + * + * \return the size of the vector containing motors + */ + std::int32_t size(); + + /** + * Sets the position for the motor in its encoder units. + * + * This will be the future reference point for the motors' "absolute" + * position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EACCESS - The Motor group mutex can't be taken or given + * + * \param position + * The new reference position in its encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_zero_position(const double position); + /** + * Sets one of motor_brake_mode_e_t to 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 + * EACCESS - The Motor group mutex can't be taken or given + * + * \param mode + * The motor_brake_mode_e_t to set for the motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_brake_modes(motor_brake_mode_e_t mode); + + /** + * Sets the reverse flag for all the motors in the motor group. + * + * This will invert its movements and the values returned for its position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EACCESS - The Motor group mutex can't be taken or given + * + * \param reverse + * True reverses the motor, false is default + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_reversed(const bool reversed); + + /** + * Sets the voltage limit for all the motors in Volts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EACCESS - The Motor group mutex can't be taken or given + * + * \param limit + * The new voltage limit in Volts + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_voltage_limit(const std::int32_t limit); + /** + * Sets one of motor_gearset_e_t for all the motors 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 + * EACCESS - The Motor group mutex can't be taken or given + * + * \param gearset + * The new motor gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_gearing(const motor_gearset_e_t gearset); + + /** + * Sets one of motor_encoder_units_e_t for the all the motor encoders + * 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 + * EACCESS - The Motor group mutex can't be taken or given + * + * \param units + * The new motor encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_encoder_units(const motor_encoder_units_e_t units); + + /** + * Sets the "absolute" zero position of the motor group to its current position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EACCESS - The Motor group mutex can't be taken or given + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t tare_position(void); + + /****************************************************************************/ + /** Motor telemetry functions **/ + /** **/ + /** These functions let programmers to collect telemetry from motor groups **/ + /****************************************************************************/ + /** + * Gets the actual velocity 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 + * EACCESS - The Motor group mutex can't be taken or given + * + * \return A vector with the each motor's actual velocity in RPM in the order + * or a vector filled with PROS_ERR_F if the operation failed, setting errno. + */ + std::vector get_actual_velocities(void); + + /** + * Gets 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 + * + * \return A vector filled with The commanded motor velocities from + * +-100, +-200, or +-600, or a vector filled with PROS_ERR if the operation + * failed, setting errno. + */ + std::vector get_target_velocities(void); + + /** + * Gets the target position set for 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 + * EACCESS - The Motor group mutex can't be taken or given + * + * \return A vector filled with the target position in its encoder units + * or a vector filled with PROS_ERR_F if the operation failed, setting errno. + */ + std::vector get_target_positions(void); + + /** + * Gets 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 The motor's absolute position in its encoder units or PROS_ERR_F + * if the operation failed, setting errno. + */ + std::vector get_positions(void); + /** + * Gets the efficiency of the motors in percent. + * + * 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 + * EACCESS - The Motor group mutex can't be taken or given + * + * \return A vector filled with the motor's efficiency in percent + * or a vector filled with PROS_ERR_F if the operation failed, setting errno. + */ + std::vector get_efficiencies(void); + + /** + * Checks if the motors are drawing over its current limit. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EACCESS - The Motor group mutex can't be taken or given + * + * \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. + */ + std::vector are_over_current(void); + + /** + * Gets the temperature limit flag for the motors. + * + * 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 with for each motor a 1 if the temperature limit is + * exceeded and 0 if the temperature is below the limit, + * or a vector filled with PROS_ERR if the operation failed, setting errno. + */ + std::vector are_over_temp(void); + + /** + * Gets the brake mode that was set for the motors. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EACCESS - The Motor group mutex can't be taken or given + * + * \return A Vector with for each motor one of motor_brake_mode_e_t, + * according to what was set for the motor, or a vector filled with + * E_MOTOR_BRAKE_INVALID if the operation failed, setting errno. + */ + std::vector get_brake_modes(void); + + /** + * Gets the gearset that was set 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 + * EACCESS - The Motor group mutex can't be taken or given + * + * \return One of motor_gearset_e_t according to what is set for the motor, + * or E_GEARSET_INVALID if the operation failed. + */ + std::vector get_gearing(void); + + /** + * Gets the current drawn by each 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 + * EACCESS - The Motor group mutex can't be taken or given + * + * \return A vector containing each motor's current in mA + * or a vector filled with PROS_ERR if the operation failed, setting errno. + */ + std::vector get_current_draws(void); + + /** + * Gets the current limit for each motor in mA. + * + * The default value is 2500 mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EACCESS - The Motor group mutex can't be taken or given + * + * \return A vector with each motor's current limit in mA or a vector filled + * with PROS_ERR if the operation failed, setting errno. + */ + std::vector get_current_limits(void); + + /** + * Gets the port number of each motor. + * + * \return a vector with each motor's port number. + */ + std::vector get_ports(void); + /** + * Gets the direction of movement for the motors. + * + * 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 for moving in the positive direction, -1 for moving in the + * negative direction, and PROS_ERR if the operation failed, setting errno. + */ + std::vector get_directions(void); + + /** + * Gets the encoder units that were set for 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 + * EACCESS - The Motor group mutex can't be taken or given + * + * \return A vector filled with one of motor_encoder_units_e_t for each motor + * according to what is set for the motor or a vector filled with + * E_MOTOR_ENCODER_INVALID if the operation failed. + */ + std::vector get_encoder_units(void); + + private: + std::vector _motors; + pros::Mutex _motor_group_mutex; + std::uint8_t _motor_count; +}; + +using MotorGroup = Motor_Group; //alias + +namespace literals { +const pros::Motor operator"" _mtr(const unsigned long long int m); +const pros::Motor operator"" _rmtr(const unsigned long long int m); +} // namespace literals +} // namespace pros +#endif // _PROS_MOTORS_HPP_ diff --git a/pros/pros/optical.h b/pros/pros/optical.h new file mode 100644 index 00000000..c3cace98 --- /dev/null +++ b/pros/pros/optical.h @@ -0,0 +1,274 @@ +/** + * \file pros/optical.h + * + * Contains prototypes for functions related to the VEX Optical sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/imu.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_OPTICAL_H_ +#define _PROS_OPTICAL_H_ + +#include +#include +#include "error.h" + +#define OPT_GESTURE_ERR (INT8_MAX) +#define OPT_COUNT_ERR (INT16_MAX) +#define OPT_TIME_ERR PROS_ERR + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + + +typedef enum optical_direction_e { + NO_GESTURE = 0, + UP = 1, + DOWN = 2, + RIGHT = 3, + LEFT = 4, + ERROR = PROS_ERR +} optical_direction_e_t; + +typedef struct optical_rgb_s { + double red; + double green; + double blue; + double brightness; +} optical_rgb_s_t; + +typedef struct optical_raw_s { + uint32_t clear; + uint32_t red; + uint32_t green; + uint32_t blue; +} optical_raw_s_t; + +typedef struct optical_gesture_s { + uint8_t udata; + uint8_t ddata; + uint8_t ldata; + uint8_t rdata; + uint8_t type; + uint8_t pad; + uint16_t count; + uint32_t time; +} optical_gesture_s_t; + +/** + * Get the detected color hue + * + * This is not available if gestures are being detected. Hue has a + * range of 0 to 359.999 + * + * 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 hue value if the operation was successful or PROS_ERR_F if the operation + * failed, setting errno. + */ +double optical_get_hue(uint8_t port); + +/** + * Get the detected color saturation + * + * This is not available if gestures are being detected. Saturation has a + * range of 0 to 1.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 an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return saturation value if the operation was successful or PROS_ERR_F if + * the operation failed, setting errno. + */ +double optical_get_saturation(uint8_t port); + +/** + * Get the detected color brightness + * + * This is not available if gestures are being detected. Brightness has a + * range of 0 to 1.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 an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return brightness value if the operation was successful or PROS_ERR_F if + * the operation failed, setting errno. + */ +double optical_get_brightness(uint8_t port); + +/** + * Get the detected proximity value + * + * This is not available if gestures are being detected. proximity has + * a range of 0 to 255. + * + * 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 poximity value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + */ +int32_t optical_get_proximity(uint8_t port); + +/** + * Set the pwm value of the White LED + * + * value that ranges from 0 to 100 + * + * 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 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t optical_set_led_pwm(uint8_t port, uint8_t value); + +/** + * Get the pwm value of the White LED + * + * + * 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 LED pwm value that ranges from 0 to 100 if the operation was + * successful or PROS_ERR if the operation failed, setting errno. + */ +int32_t optical_get_led_pwm(uint8_t port); + +/** + * Get the processed RGBC data from the 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 an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \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. + */ +optical_rgb_s_t optical_get_rgb(uint8_t port); + +/** + * Get the raw, unprocessed RGBC data from the 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 an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \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. + */ +optical_raw_s_t optical_get_raw(uint8_t port); + +/** + * Get the most recent gesture data from the sensor + * + * Gestures will be cleared after 500mS + * + * 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 gesture value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + */ +optical_direction_e_t optical_get_gesture(uint8_t port); + +/** + * Get the most recent raw gesture data from the 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 an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \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. + */ +optical_gesture_s_t optical_get_gesture_raw(uint8_t port); + +/** + * Enable gesture detection on the 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 an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t optical_enable_gesture(uint8_t port); + +/** + * Disable gesture detection on the 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 an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t optical_disable_gesture(uint8_t port); + +#ifdef __cplusplus +} +} +} +#endif + +#endif diff --git a/pros/pros/optical.hpp b/pros/pros/optical.hpp new file mode 100644 index 00000000..783520d4 --- /dev/null +++ b/pros/pros/optical.hpp @@ -0,0 +1,234 @@ +/** + * \file pros/optical.hpp + * + * Contains prototypes for functions related to the VEX Optical sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/imu.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_OPTICAL_HPP_ +#define _PROS_OPTICAL_HPP_ + +#include + +#include + +#include "pros/optical.h" + +namespace pros { +class Optical { + public: + /** + * Creates an Optical Sensor 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). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \param port + * The V5 port number from 1-21 + */ + explicit Optical(const std::uint8_t port); + + /** + * Get the detected color hue + * + * This is not available if gestures are being detected. Hue has a + * range of 0 to 359.999 + * + * 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 hue value if the operation was successful or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double get_hue(); + + /** + * Get the detected color saturation + * + * This is not available if gestures are being detected. Saturation has a + * range of 0 to 1.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 an Optical Sensor + * + * \return saturation value if the operation was successful or PROS_ERR_F if + * the operation failed, setting errno. + */ + virtual double get_saturation(); + + /** + * Get the detected color brightness + * + * This is not available if gestures are being detected. Brightness has a + * range of 0 to 1.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 an Optical Sensor + * + * \return brightness value if the operation was successful or PROS_ERR_F if + * the operation failed, setting errno. + */ + virtual double get_brightness(); + + /** + * Get the detected proximity value + * + * This is not available if gestures are being detected. proximity has + * a range of 0 to 255. + * + * 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 poximity value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + */ + virtual std::int32_t get_proximity(); + + /** + * Set the pwm value of the White LED on the sensor + * + * value that ranges from 0 to 100 + * + * 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 The Error code encountered + */ + virtual std::int32_t set_led_pwm(uint8_t value); + + /** + * Get the pwm value of the White LED on the sensor + * + * value that ranges from 0 to 100 + * + * 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 LED pwm value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + */ + virtual std::int32_t get_led_pwm(); + + /** + * Get the processed RGBC data from the 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 an Optical Sensor + * + * \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. + */ + virtual pros::c::optical_rgb_s_t get_rgb(); + + /** + * Get the raw un-processed RGBC data from the 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 an Optical Sensor + * + * \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. + */ + virtual pros::c::optical_raw_s_t get_raw(); + + /** + * 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 + * 4 = left + * + * 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 gesture value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + */ + virtual pros::c::optical_direction_e_t get_gesture(); + + /** + * Get the most recent raw gesture data from the 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 an Optical Sensor + * + * \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. + */ + virtual pros::c::optical_gesture_s_t get_gesture_raw(); + + /** + * Enable gesture detection on the 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 an Optical Sensor + * + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t enable_gesture(); + + /** + * Disable gesture detection on the 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 an Optical Sensor + * + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t disable_gesture(); + + /** + * Gets the port number of the Optical Sensor. + * + * \return The Optical Sensor's port number. + */ + virtual std::uint8_t get_port(); + + private: + const std::uint8_t _port; +}; +} // namespace pros + +#endif diff --git a/pros/pros/rotation.h b/pros/pros/rotation.h new file mode 100644 index 00000000..197936ac --- /dev/null +++ b/pros/pros/rotation.h @@ -0,0 +1,223 @@ +/** + * \file pros/rotation.h + * + * Contains prototypes for functions related to the VEX Rotation Sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/rotation.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_ROTATION_H_ +#define _PROS_ROTATION_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +#define ROTATION_MINIMUM_DATA_RATE 5 + +/** + * Reset Rotation Sensor + * + * Reset the current absolute position to be the same as the + * Rotation Sensor angle. + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t rotation_reset(uint8_t port); + +/** + * Set the Rotation Sensor's refresh interval in milliseconds. + * + * The rate may be specified in increments of 5ms, and will be rounded down to + * the nearest increment. The minimum allowable refresh rate is 5ms. The default + * rate is 10ms. + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \param rate The data refresh interval in milliseconds + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t rotation_set_data_rate(uint8_t port, uint32_t rate); + +/** + * Set the Rotation Sensor position reading to a desired rotation value + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \param position + * The position in terms of ticks + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t rotation_set_position(uint8_t port, uint32_t position); + +/** + * Reset the Rotation Sensor position to 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 an Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t rotation_reset_position(uint8_t port); + +/** + * Get the Rotation Sensor's current position in centidegrees + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \return The position value or PROS_ERR_F if the operation failed, setting + * errno. + */ +int32_t rotation_get_position(uint8_t port); + +/** + * Get the Rotation Sensor's current velocity in centidegrees per second + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \return The velocity value or PROS_ERR_F if the operation failed, setting + * errno. + */ +int32_t rotation_get_velocity(uint8_t port); + +/** + * Get the Rotation Sensor's current angle in centidegrees (0-36000) + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \return The angle value (0-36000) or PROS_ERR_F if the operation failed, setting + * errno. + */ +int32_t rotation_get_angle(uint8_t port); + +/** + * Set the Rotation Sensor's direction reversed flag + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \param value + * Determines if the direction of the Rotation Sensor is reversed or not. + * + * \return 1 if operation succeeded or PROS_ERR if the operation failed, setting + * errno. + */ +int32_t rotation_set_reversed(uint8_t port, bool value); + +/** + * Reverse the Rotation Sensor's direction + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t rotation_reverse(uint8_t port); + +/** + * Initialize the Rotation Sensor with a reverse flag + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \param reverse_flag + * Determines if the Rotation Sensor is reversed or not. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t rotation_init_reverse(uint8_t port, bool reverse_flag); + +/** + * Get the Rotation Sensor's reversed flag + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * + * \return Boolean value of if the Rotation Sensor's direction is reversed or not + * or PROS_ERR if the operation failed, setting errno. + */ +int32_t rotation_get_reversed(uint8_t port); + +#ifdef __cplusplus +} //namespace C +} //namespace pros +} //extern "C" +#endif + +#endif diff --git a/pros/pros/rotation.hpp b/pros/pros/rotation.hpp new file mode 100644 index 00000000..c53ab7b1 --- /dev/null +++ b/pros/pros/rotation.hpp @@ -0,0 +1,190 @@ +/** + * \file pros/rotation.hpp + * + * Contains prototypes for functions related to the VEX Rotation Sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/rotation.html to learn + * more. + * + * 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. + * + * 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/. + */ +#ifndef _PROS_ROTATION_HPP_ +#define _PROS_ROTATION_HPP_ + +#include + +#include "pros/rotation.h" + +namespace pros { +class Rotation { + const std::uint8_t _port; + + public: + Rotation(const std::uint8_t port) : _port(port){}; + + Rotation(const std::uint8_t port, const bool reverse_flag); + + /** + * Reset the Rotation Sensor + * + * Reset the current absolute position to be the same as the + * Rotation Sensor angle. + * + * 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 Rotation Sensor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t reset(); + + /** + * Set the Rotation Sensor's refresh interval in milliseconds. + * + * The rate may be specified in increments of 5ms, and will be rounded down to + * the nearest increment. The minimum allowable refresh rate is 5ms. The default + * rate is 10ms. + * + * As values are copied into the shared memory buffer only at 10ms intervals, + * setting this value to less than 10ms does not mean that you can poll the + * sensor's values any faster. However, it will guarantee that the data is as + * recent as possible. + * + * 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 Rotation Sensor + * + * \param rate The data refresh interval in milliseconds + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_data_rate(std::uint32_t rate) const; + + /** + * Set the Rotation Sensor position reading to a desired rotation value + * + * 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 Rotation Sensor + * + * \param position + * The position in terms of ticks + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_position(std::uint32_t position); + + /** + * Reset the Rotation Sensor to a desired rotation value + * + * 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 Rotation Sensor + * + * \param position + * The position in terms of ticks + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t reset_position(void); + + /** + * Get the Rotation Sensor's current position in centidegrees + * + * 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 Rotation Sensor + * + * \return The position value or PROS_ERR if the operation failed, setting + * errno. + */ + virtual std::int32_t get_position(); + + /** + * Get the Rotation Sensor's current velocity in centidegrees per second + * + * 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 Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \return The + value or PROS_ERR_F if the operation failed, setting + * errno. + */ + virtual std::int32_t get_velocity(); + + /** + * Get the Rotation Sensor's current position in centidegrees + * + * 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 Rotation Sensor + * + * \return The angle value or PROS_ERR if the operation failed, setting + * errno. + */ + virtual std::int32_t get_angle(); + + /** + * Set the Rotation Sensor's direction reversed flag + * + * 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 Rotation Sensor + * + * \param value + * Determines if the direction of the rotational sensor is + * reversed or not. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_reversed(bool value); + + /** + * Reverse the Rotation Sensor's direction. + * + * 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 Rotation Sensor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t reverse(); + + /** + * Get the Rotation Sensor's reversed flag + * + * 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 Rotation Sensor + * + * \return Reversed value or PROS_ERR if the operation failed, setting + * errno. + */ + virtual std::int32_t get_reversed(); +}; +} // namespace pros + +#endif diff --git a/pros/pros/rtos.h b/pros/pros/rtos.h new file mode 100644 index 00000000..3afdb24a --- /dev/null +++ b/pros/pros/rtos.h @@ -0,0 +1,442 @@ +/** + * \file pros/rtos.h + * + * Contains declarations for the PROS RTOS kernel for use by typical VEX + * programmers. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html to + * learn more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_RTOS_H_ +#define _PROS_RTOS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +// The highest priority that can be assigned to a task. Beware of deadlock. +#define TASK_PRIORITY_MAX 16 + +// The lowest priority that can be assigned to a task. +// This may cause severe performance problems and is generally not recommended. +#define TASK_PRIORITY_MIN 1 + +// The default task priority, which should be used for most tasks. +// Default tasks such as autonomous() inherit this priority. +#define TASK_PRIORITY_DEFAULT 8 + +// The recommended stack size for a new task. This stack size is used for +// default tasks such as autonomous(). This equates to 32,768 bytes, or 128 +// times the default stack size for a task in PROS 2. +#define TASK_STACK_DEPTH_DEFAULT 0x2000 + +// The minimal stack size for a task. This equates to 2048 bytes, or 8 times the +// default stack size for a task in PROS 2. +#define TASK_STACK_DEPTH_MIN 0x200 + +// The maximum number of characters allowed in a task's name. +#define TASK_NAME_MAX_LEN 32 + +// The maximum timeout value that can be given to, for instance, a mutex grab. +#define TIMEOUT_MAX ((uint32_t)0xffffffffUL) + +typedef void* task_t; +typedef void (*task_fn_t)(void*); + +typedef enum { + E_TASK_STATE_RUNNING = 0, + E_TASK_STATE_READY, + E_TASK_STATE_BLOCKED, + E_TASK_STATE_SUSPENDED, + E_TASK_STATE_DELETED, + E_TASK_STATE_INVALID +} task_state_e_t; + +typedef enum { + E_NOTIFY_ACTION_NONE, + E_NOTIFY_ACTION_BITS, + E_NOTIFY_ACTION_INCR, + E_NOTIFY_ACTION_OWRITE, + E_NOTIFY_ACTION_NO_OWRITE +} notify_action_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define TASK_STATE_RUNNING pros::E_TASK_STATE_RUNNING +#define TASK_STATE_READY pros::E_TASK_STATE_READY +#define TASK_STATE_BLOCKED pros::E_TASK_STATE_BLOCKED +#define TASK_STATE_SUSPENDED pros::E_TASK_STATE_SUSPENDED +#define TASK_STATE_DELETED pros::E_TASK_STATE_DELETED +#define TASK_STATE_INVALID pros::E_TASK_STATE_INVALID +#define NOTIFY_ACTION_NONE pros::E_NOTIFY_ACTION_NONE +#define NOTIFY_ACTION_BITS pros::E_NOTIFY_ACTION_BITS +#define NOTIFY_ACTION_INCR pros::E_NOTIFY_ACTION_INCR +#define NOTIFY_ACTION_OWRITE pros::E_NOTIFY_ACTION_OWRITE +#define NOTIFY_ACTION_NO_OWRITE pros::E_NOTIFY_ACTION_NO_OWRITE +#else +#define TASK_STATE_RUNNING E_TASK_STATE_RUNNING +#define TASK_STATE_READY E_TASK_STATE_READY +#define TASK_STATE_BLOCKED E_TASK_STATE_BLOCKED +#define TASK_STATE_SUSPENDED E_TASK_STATE_SUSPENDED +#define TASK_STATE_DELETED E_TASK_STATE_DELETED +#define TASK_STATE_INVALID E_TASK_STATE_INVALID +#define NOTIFY_ACTION_NONE E_NOTIFY_ACTION_NONE +#define NOTIFY_ACTION_BITS E_NOTIFY_ACTION_BITS +#define NOTIFY_ACTION_INCR E_NOTIFY_ACTION_INCR +#define NOTIFY_ACTION_OWRITE E_NOTIFY_ACTION_OWRITE +#define NOTIFY_ACTION_NO_OWRITE E_NOTIFY_ACTION_NO_OWRITE +#endif +#endif + +typedef void* mutex_t; + +/** + * Refers to the current task handle + */ +#ifdef __cplusplus +#define CURRENT_TASK ((pros::task_t)NULL) +#else +#define CURRENT_TASK ((task_t)NULL) +#endif + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Gets the number of milliseconds since PROS initialized. + * + * \return The number of milliseconds since PROS initialized + */ +uint32_t millis(void); + +/** + * Gets the number of microseconds since PROS initialized, + * + * \return The number of microseconds since PROS initialized + */ +uint64_t micros(void); + +/** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Pointer to the task entry function + * \param parameters + * Pointer to memory that will be used as a parameter for the task being + * created. This memory should not typically come from stack, but rather + * from dynamically (i.e., malloc'd) or statically allocated memory. + * \param prio + * The priority at which the task should run. + * TASK_PRIO_DEFAULT plus/minus 1 or 2 is typically used. + * \param stack_depth + * The number of words (i.e. 4 * stack_depth) available on the task's + * stack. TASK_STACK_DEPTH_DEFAULT is typically sufficienct. + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + * \return A handle by which the newly created task can be referenced. If an + * error occurred, NULL will be returned and errno can be checked for hints as + * to why task_create failed. + */ +task_t task_create(task_fn_t function, void* const parameters, uint32_t prio, const uint16_t stack_depth, + const char* const name); + +/** + * Removes a task from the RTOS real time kernel's management. The task being + * deleted will be removed from all ready, blocked, suspended and event lists. + * + * Memory dynamically allocated by the task is not automatically freed, and + * should be freed before the task is deleted. + * + * \param task + * The handle of the task to be deleted. Passing NULL will cause the + * calling task to be deleted. + */ +void task_delete(task_t task); + +/** + * Delays a task for a given number of milliseconds. + * + * This is not the best method to have a task execute code at predefined + * intervals, as the delay time is measured from when the delay is requested. + * To delay cyclically, use task_delay_until(). + * + * \param milliseconds + * The number of milliseconds to wait (1000 milliseconds per second) + */ +void task_delay(const uint32_t milliseconds); + +void delay(const uint32_t milliseconds); + +/** + * Delays a task until a specified time. This function can be used by periodic + * tasks to ensure a constant execution frequency. + * + * The task will be woken up at the time *prev_time + delta, and *prev_time will + * be updated to reflect the time at which the task will unblock. + * + * \param prev_time + * A pointer to the location storing the setpoint time. This should + * typically be initialized to the return value of millis(). + * \param delta + * The number of milliseconds to wait (1000 milliseconds per second) + */ +void task_delay_until(uint32_t* const prev_time, const uint32_t delta); + +/** + * Gets the priority of the specified task. + * + * \param task + * The task to check + * + * \return The priority of the task + */ +uint32_t task_get_priority(task_t task); + +/** + * Sets the priority of the specified task. + * + * If the specified task's state is available to be scheduled (e.g. not blocked) + * and new priority is higher than the currently running task, a context switch + * may occur. + * + * \param task + * The task to set + * \param prio + * The new priority of the task + */ +void task_set_priority(task_t task, uint32_t prio); + +/** + * Gets the state of the specified task. + * + * \param task + * The task to check + * + * \return The state of the task + */ +task_state_e_t task_get_state(task_t task); + +/** + * Suspends the specified task, making it ineligible to be scheduled. + * + * \param task + * The task to suspend + */ +void task_suspend(task_t task); + +/** + * Resumes the specified task, making it eligible to be scheduled. + * + * \param task + * The task to resume + */ +void task_resume(task_t task); + +/** + * Gets the number of tasks the kernel is currently managing, including all + * ready, blocked, or suspended tasks. A task that has been deleted, but not yet + * reaped by the idle task will also be included in the count. Tasks recently + * created may take one context switch to be counted. + * + * \return The number of tasks that are currently being managed by the kernel. + */ +uint32_t task_get_count(void); + +/** + * Gets the name of the specified task. + * + * \param task + * The task to check + * + * \return A pointer to the name of the task + */ +char* task_get_name(task_t task); + +/** + * Gets a task handle from the specified name + * + * The operation takes a relatively long time and should be used sparingly. + * + * \param name + * The name to query + * + * \return A task handle with a matching name, or NULL if none were found. + */ +task_t task_get_by_name(const char* name); + +/** + * Get the currently running task handle. This could be useful if a task + * wants to tell another task about itself. + * + * \return The currently running task handle. + */ +task_t task_get_current(); + +/** + * Sends a simple notification to task and increments the notification counter. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param task + * The task to notify + * + * \return Always returns true. + */ +uint32_t task_notify(task_t task); + +/** + * + * Utilizes task notifications to wait until specified task is complete and deleted, + * then continues to execute the program. Analogous to std::thread::join in C++. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param task + * The task to wait on. + * + * \return void + */ +void task_join(task_t task); + +/** + * Sends a notification to a task, optionally performing some action. Will also + * retrieve the value of the notification in the target task before modifying + * the notification value. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param task + * The task to notify + * \param value + * The value used in performing the action + * \param action + * An action to optionally perform on the receiving task's notification + * value + * \param prev_value + * A pointer to store the previous value of the target task's + * notification, may be NULL + * + * \return Dependent on the notification action. + * For NOTIFY_ACTION_NO_WRITE: return 0 if the value could be written without + * needing to overwrite, 1 otherwise. + * For all other NOTIFY_ACTION values: always return 0 + */ +uint32_t task_notify_ext(task_t task, uint32_t value, notify_action_e_t action, uint32_t* prev_value); + +/** + * Waits for a notification to be nonzero. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param clear_on_exit + * If true (1), then the notification value is cleared. + * If false (0), then the notification value is decremented. + * \param timeout + * Specifies the amount of time to be spent waiting for a notification + * to occur. + * + * \return The value of the task's notification value before it is decremented + * or cleared + */ +uint32_t task_notify_take(bool clear_on_exit, uint32_t timeout); + +/** + * Clears the notification for a task. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param task + * The task to clear + * + * \return False if there was not a notification waiting, true if there was + */ +bool task_notify_clear(task_t task); + +/** + * Creates a mutex. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes + * for details. + * + * \return A handle to a newly created mutex. If an error occurred, NULL will be + * returned and errno can be checked for hints as to why mutex_create failed. + */ +mutex_t mutex_create(void); + +/** + * 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 mutex + * Mutex to attempt to lock. + * \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. + */ +bool mutex_take(mutex_t mutex, uint32_t timeout); + +/** + * Unlocks a mutex. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes + * for details. + * + * \param mutex + * Mutex to unlock. + * + * \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. + */ +bool mutex_give(mutex_t mutex); + +/** + * Deletes a mutex + * + * \param mutex + * Mutex to unlock. + */ +void mutex_delete(mutex_t mutex); + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_RTOS_H_ diff --git a/pros/pros/rtos.hpp b/pros/pros/rtos.hpp new file mode 100644 index 00000000..0cd0d6c6 --- /dev/null +++ b/pros/pros/rtos.hpp @@ -0,0 +1,658 @@ +/** + * \file pros/rtos.hpp + * + * Contains declarations for the PROS RTOS kernel for use by typical VEX + * programmers. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html to + * learn more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_RTOS_HPP_ +#define _PROS_RTOS_HPP_ + +#include "pros/rtos.h" +#undef delay +#include +#include +#include +#include +#include +#include +#include + +namespace pros { +class Task { + public: + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Pointer to the task entry function + * \param parameters + * Pointer to memory that will be used as a parameter for the task + * being created. This memory should not typically come from stack, + * but rather from dynamically (i.e., malloc'd) or statically + * allocated memory. + * \param prio + * The priority at which the task should run. + * TASK_PRIO_DEFAULT plus/minus 1 or 2 is typically used. + * \param stack_depth + * The number of words (i.e. 4 * stack_depth) available on the task's + * stack. TASK_STACK_DEPTH_DEFAULT is typically sufficienct. + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + */ + Task(task_fn_t function, void* parameters = nullptr, std::uint32_t prio = TASK_PRIORITY_DEFAULT, + std::uint16_t stack_depth = TASK_STACK_DEPTH_DEFAULT, const char* name = ""); + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Pointer to the task entry function + * \param parameters + * Pointer to memory that will be used as a parameter for the task + * being created. This memory should not typically come from stack, + * but rather from dynamically (i.e., malloc'd) or statically + * allocated memory. + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + */ + Task(task_fn_t function, void* parameters, const char* name); + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Callable object to use as entry function + * \param prio + * The priority at which the task should run. + * TASK_PRIO_DEFAULT plus/minus 1 or 2 is typically used. + * \param stack_depth + * The number of words (i.e. 4 * stack_depth) available on the task's + * stack. TASK_STACK_DEPTH_DEFAULT is typically sufficienct. + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + */ + template + static task_t create(F&& function, std::uint32_t prio = TASK_PRIORITY_DEFAULT, + std::uint16_t stack_depth = TASK_STACK_DEPTH_DEFAULT, const char* name = "") { + static_assert(std::is_invocable_r_v); + return pros::c::task_create( + [](void* parameters) { + std::unique_ptr> ptr{static_cast*>(parameters)}; + (*ptr)(); + }, + new std::function(std::forward(function)), prio, stack_depth, name); + } + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Callable object to use as entry function + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + */ + template + static task_t create(F&& function, const char* name) { + return Task::create(std::forward(function), TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, name); + } + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Callable object to use as entry function + * \param prio + * The priority at which the task should run. + * TASK_PRIO_DEFAULT plus/minus 1 or 2 is typically used. + * \param stack_depth + * The number of words (i.e. 4 * stack_depth) available on the task's + * stack. TASK_STACK_DEPTH_DEFAULT is typically sufficient. + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + */ + template + explicit Task(F&& function, std::uint32_t prio = TASK_PRIORITY_DEFAULT, + std::uint16_t stack_depth = TASK_STACK_DEPTH_DEFAULT, const char* name = "") + : Task( + [](void* parameters) { + std::unique_ptr> ptr{static_cast*>(parameters)}; + (*ptr)(); + }, + new std::function(std::forward(function)), prio, stack_depth, name) { + static_assert(std::is_invocable_r_v); + } + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Callable object to use as entry function + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + */ + template + Task(F&& function, const char* name) + : Task(std::forward(function), TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, name) {} + + /** + * Create a C++ task object from a task handle + * + * \param task + * A task handle from task_create() for which to create a pros::Task + * object. + */ + explicit Task(task_t task); + + /** + * Get the currently running Task + */ + static Task current(); + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * \param in + * A task handle from task_create() for which to create a pros::Task + * object. + */ + Task& operator=(task_t in); + + /** + * Removes the Task from the RTOS real time kernel's management. This task + * will be removed from all ready, blocked, suspended and event lists. + * + * Memory dynamically allocated by the task is not automatically freed, and + * should be freed before the task is deleted. + */ + void remove(); + + /** + * Gets the priority of the specified task. + * + * \return The priority of the task + */ + std::uint32_t get_priority(); + + /** + * Sets the priority of the specified task. + * + * If the specified task's state is available to be scheduled (e.g. not + * blocked) and new priority is higher than the currently running task, + * a context switch may occur. + * + * \param prio + * The new priority of the task + */ + void set_priority(std::uint32_t prio); + + /** + * Gets the state of the specified task. + * + * \return The state of the task + */ + std::uint32_t get_state(); + + /** + * Suspends the specified task, making it ineligible to be scheduled. + */ + void suspend(); + + /** + * Resumes the specified task, making it eligible to be scheduled. + * + * \param task + * The task to resume + */ + void resume(); + + /** + * Gets the name of the specified task. + * + * \return A pointer to the name of the task + */ + const char* get_name(); + + /** + * Convert this object to a C task_t handle + */ + explicit operator task_t() { + return task; + } + + /** + * Sends a simple notification to task and increments the notification + * counter. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \return Always returns true. + */ + std::uint32_t notify(); + + /** + * Utilizes task notifications to wait until specified task is complete and deleted, + * then continues to execute the program. Analogous to std::thread::join in C++. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \return void + */ + void join(); + + /** + * Sends a notification to a task, optionally performing some action. Will + * also retrieve the value of the notification in the target task before + * modifying the notification value. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param value + * The value used in performing the action + * \param action + * An action to optionally perform on the receiving task's notification + * value + * \param prev_value + * A pointer to store the previous value of the target task's + * notification, may be NULL + * + * \return Dependent on the notification action. + * For NOTIFY_ACTION_NO_WRITE: return 0 if the value could be written without + * needing to overwrite, 1 otherwise. + * For all other NOTIFY_ACTION values: always return 0 + */ + std::uint32_t notify_ext(std::uint32_t value, notify_action_e_t action, std::uint32_t* prev_value); + + /** + * Waits for a notification to be nonzero. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param clear_on_exit + * If true (1), then the notification value is cleared. + * If false (0), then the notification value is decremented. + * \param timeout + * Specifies the amount of time to be spent waiting for a notification + * to occur. + * + * \return The value of the task's notification value before it is decremented + * or cleared + */ + static std::uint32_t notify_take(bool clear_on_exit, std::uint32_t timeout); + + /** + * Clears the notification for a task. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \return False if there was not a notification waiting, true if there was + */ + bool notify_clear(); + + /** + * Delays a task for a given number of milliseconds. + * + * This is not the best method to have a task execute code at predefined + * intervals, as the delay time is measured from when the delay is requested. + * To delay cyclically, use task_delay_until(). + * + * \param milliseconds + * The number of milliseconds to wait (1000 milliseconds per second) + */ + static void delay(const std::uint32_t milliseconds); + + /** + * Delays a task until a specified time. This function can be used by + * periodic tasks to ensure a constant execution frequency. + * + * The task will be woken up at the time *prev_time + delta, and *prev_time + * will be updated to reflect the time at which the task will unblock. + * + * \param prev_time + * A pointer to the location storing the setpoint time. This should + * typically be initialized to the return value from pros::millis(). + * \param delta + * The number of milliseconds to wait (1000 milliseconds per second) + */ + static void delay_until(std::uint32_t* const prev_time, const std::uint32_t delta); + + /** + * Gets the number of tasks the kernel is currently managing, including all + * ready, blocked, or suspended tasks. A task that has been deleted, but not + * yet reaped by the idle task will also be included in the count. + * Tasks recently created may take one context switch to be counted. + * + * \return The number of tasks that are currently being managed by the kernel. + */ + static std::uint32_t get_count(); + + private: + task_t task{}; +}; + +// STL Clock compliant clock +struct Clock { + using rep = std::uint32_t; + using period = std::milli; + using duration = std::chrono::duration; + using time_point = std::chrono::time_point; + const bool is_steady = true; + + /** + * Gets the current time. + * + * Effectively a wrapper around pros::millis() + * + * \return The current time + */ + static time_point now(); +}; + +class Mutex { + std::shared_ptr> mutex; + + public: + Mutex(); + + // disable copy and move construction and assignment per Mutex requirements + // (see https://en.cppreference.com/w/cpp/named_req/Mutex) + Mutex(const Mutex&) = delete; + Mutex(Mutex&&) = delete; + + Mutex& operator=(const Mutex&) = delete; + Mutex& operator=(Mutex&&) = 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. + */ + 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. + */ + 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. + */ + bool give(); + + /** + * Takes and locks a mutex, waiting for up to TIMEOUT_MAX milliseconds. + * + * Effectively equivalent to calling pros::Mutex::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. + */ + void lock(); + + /** + * Unlocks a mutex. + * + * Equivalent to calling pros::Mutex::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. + */ + 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. + */ + bool try_lock(); + + /** + * Takes and locks a mutex, waiting for a specified duration. + * + * Equivalent to calling pros::Mutex::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. + */ + template + 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. + */ + template + bool try_lock_until(const std::chrono::time_point& abs_time) { + return take(std::max(static_cast(0), (abs_time - Clock::now()).count())); + } +}; + +template +class MutexVar; + +template +class MutexVarLock { + Mutex& mutex; + Var& var; + + friend class MutexVar; + + constexpr MutexVarLock(Mutex& mutex, Var& var) : mutex(mutex), var(var) {} + + public: + /** + * Accesses the value of the mutex-protected variable. + */ + constexpr Var& operator*() const { + return var; + } + + /** + * Accesses the value of the mutex-protected variable. + */ + constexpr Var* operator->() const { + return &var; + } + + ~MutexVarLock() { + mutex.unlock(); + } +}; + +template +class MutexVar { + Mutex mutex; + Var var; + + public: + /** + * Creates a mutex-protected variable which is initialized with the given + * constructor arguments. + * + * \param args + The arguments to provide to the Var constructor. + */ + template + MutexVar(Args&&... args) : mutex(), var(std::forward(args)...) {} + + /** + * Try to lock the mutex-protected variable. + * + * \param timeout + * Time to wait before the mutex becomes available, in milliseconds. A + * timeout of 0 can be used to poll the mutex. + * + * \return A std::optional which contains a MutexVarLock providing access to + * the protected variable if locking is successful. + */ + std::optional> try_lock(std::uint32_t timeout) { + if (mutex.take(timeout)) { + return {{mutex, var}}; + } else { + return {}; + } + } + + /** + * Try to lock the mutex-protected variable. + * + * \param timeout + * Time to wait before the mutex becomes available. A timeout of 0 can + * be used to poll the mutex. + * + * \return A std::optional which contains a MutexVarLock providing access to + * the protected variable if locking is successful. + */ + template + std::optional> try_lock(const std::chrono::duration& rel_time) { + try_lock(std::chrono::duration_cast(rel_time).count()); + } + + /** + * Lock the mutex-protected variable, waiting indefinitely. + * + * \return A MutexVarLock providing access to the protected variable. + */ + MutexVarLock lock() { + while (!mutex.take(TIMEOUT_MAX)) + ; + return {mutex, var}; + } +}; + +/** + * Gets the number of milliseconds since PROS initialized. + * + * \return The number of milliseconds since PROS initialized + */ +using pros::c::millis; + +/** + * Gets the number of microseconds since PROS initialized. + * + * \return The number of microseconds since PROS initialized + */ +using pros::c::micros; + +/** + * Delays a task for a given number of milliseconds. + * + * This is not the best method to have a task execute code at predefined + * intervals, as the delay time is measured from when the delay is requested. + * To delay cyclically, use task_delay_until(). + * + * \param milliseconds + * The number of milliseconds to wait (1000 milliseconds per second) + */ +using pros::c::delay; +} // namespace pros + +#endif // _PROS_RTOS_HPP_ diff --git a/pros/pros/screen.h b/pros/pros/screen.h new file mode 100644 index 00000000..4cffe76c --- /dev/null +++ b/pros/pros/screen.h @@ -0,0 +1,499 @@ +/** + * \file screen.h + * + * Brain screen display and touch functions. + * + * Contains user calls to the v5 screen for touching and displaying graphics. + * + * \copyright (c) 2017-2021, 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/. + */ + +#ifndef _PROS_SCREEN_H_ +#define _PROS_SCREEN_H_ + +#include +#include +#define _GNU_SOURCE +#include +#undef _GNU_SOURCE +#include + +#include "pros/colors.h" // c color macros + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +/** + * ! Different font sizes that can be used in printing text. + */ +typedef enum { + E_TEXT_SMALL = 0, ///< Small text font size + E_TEXT_MEDIUM, ///< Normal/Medium text font size + E_TEXT_LARGE, ///< Large text font size + E_TEXT_MEDIUM_CENTER, ///< Medium centered text + E_TEXT_LARGE_CENTER ///< Large centered text +} text_format_e_t; + +/** + * ! Enum indicating what the current touch status is for the touchscreen. + */ +typedef enum { + E_TOUCH_RELEASED = 0, ///< Last interaction with screen was a quick press + E_TOUCH_PRESSED, ///< Last interaction with screen was a release + E_TOUCH_HELD, ///< User is holding screen down + E_TOUCH_ERROR ///< An error occured while taking/returning the mutex +} last_touch_e_t; + +/** + * ! Struct representing screen touch status, screen last x, screen last y, press count, release count. + */ +typedef struct screen_touch_status_s { + 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 +#ifdef __cplusplus +#define TEXT_SMALL pros::E_TEXT_SMALL +#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 TOUCH_RELEASED pros::E_TOUCH_RELEASED +#define TOUCH_PRESSED pros::E_TOUCH_PRESSED +#define TOUCH_HELD pros::E_TOUCH_HELD +#else +#define TEXT_SMALL E_TEXT_SMALL +#define TEXT_MEDIUM E_TEXT_MEDIUM +#define TEXT_LARGE E_TEXT_LARGE +#define TEXT_MEDIUM_CENTER E_TEXT_MEDIUM_CENTER +#define TEXT_LARGE_CENTER E_TEXT_LARGE_CENTER +#define TOUCH_RELEASED E_TOUCH_RELEASED +#define TOUCH_PRESSED E_TOUCH_PRESSED +#define TOUCH_HELD E_TOUCH_HELD +#endif +#endif + +typedef void (*touch_event_cb_fn_t)(); + +#ifdef __cplusplus +namespace c { +#endif + +/******************************************************************************/ +/** Screen Graphical Display Functions **/ +/** **/ +/** These functions allow programmers to display shapes on the v5 screen **/ +/******************************************************************************/ + +/** + * Set the pen color for subsequent graphics operations + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param color The pen color to set (it is recommended to use values + * from the enum defined in colors.h) + * + * \return Returns 1 if the mutex was successfully returned, or PROS_ERR if + * there was an error either taking or returning the screen mutex. + */ +uint32_t screen_set_pen(uint32_t color); + +/** + * Set the eraser color for erasing and the current background. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param color The background color to set (it is recommended to use values + * from the enum defined in colors.h) + * + * \return Returns 1 if the mutex was successfully returned, or + * PROS_ERR if there was an error either taking or returning the screen mutex. + */ +uint32_t screen_set_eraser(uint32_t color); + +/** + * Get the current pen color. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \return The current pen color in the form of a value from the enum defined + * in colors.h, or PROS_ERR if there was an error taking or returning + * the screen mutex. + */ +uint32_t screen_get_pen(void); + +/** + * Get the current eraser color. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \return The current eraser color in the form of a value from the enum + * defined in colors.h, or PROS_ERR if there was an error taking or + * returning the screen mutex. + */ +uint32_t screen_get_eraser(void); + +/** + * Clear display with eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_erase(void); + +/** + * Scroll lines on the display upwards. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param start_line The line from which scrolling will start + * \param lines The number of lines to scroll up + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_scroll(int16_t start_line, int16_t lines); + +/** + * Scroll lines within a region on the display + * + * This function behaves in the same way as `screen_scroll`, except that you + * specify a rectangular region within which to scroll lines instead of a start + * line. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first corner of the + * rectangular region + * \param x1, y1 The (x,y) coordinates of the second corner of the + * rectangular region + * \param lines The number of lines to scroll upwards + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_scroll_area(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t lines); + +/** + * Copy a screen region (designated by a rectangle) from an off-screen buffer + * to the screen + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first corner of the + * rectangular region of the screen + * \param x1, y1 The (x,y) coordinates of the second corner of the + * rectangular region of the screen + * \param buf Off-screen buffer containing screen data + * \param stride Off-screen buffer width in pixels, such that image size + * is stride-padding + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_copy_area(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint32_t* buf, int32_t stride); + +/** + * Draw a single pixel on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the pixel + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_draw_pixel(int16_t x, int16_t y); + +/** + * Erase a pixel from the screen (Sets the location) + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the erased + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_erase_pixel(int16_t x, int16_t y); + +/** + * Draw a line on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x, y) coordinates of the first point of the line + * \param x1, y1 The (x, y) coordinates of the second point of the line + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_draw_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1); + +/** + * Erase a line on the screen using the current eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x, y) coordinates of the first point of the line + * \param x1, y1 The (x, y) coordinates of the second point of the line + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_erase_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1); + +/** + * Draw a rectangle on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first point of the rectangle + * \param x1, y1 The (x,y) coordinates of the second point of the rectangle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_draw_rect(int16_t x0, int16_t y0, int16_t x1, int16_t y1); + +/** + * Erase a rectangle on the screen using the current eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first point of the rectangle + * \param x1, y1 The (x,y) coordinates of the second point of the rectangle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_erase_rect(int16_t x0, int16_t y0, int16_t x1, int16_t y1); + +/** + * Fill a rectangular region of the screen using the current pen + * color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first point of the rectangle + * \param x1, y1 The (x,y) coordinates of the second point of the rectangle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_fill_rect(int16_t x0, int16_t y0, int16_t x1, int16_t y1); + +/** + * Draw a circle on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the center of the circle + * \param r The radius of the circle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_draw_circle(int16_t x, int16_t y, int16_t radius); + +/** + * Erase a circle on the screen using the current eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the center of the circle + * \param r The radius of the circle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_erase_circle(int16_t x, int16_t y, int16_t radius); + +/** + * Fill a circular region of the screen using the current pen + * color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the center of the circle + * \param r The radius of the circle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_fill_circle(int16_t x, int16_t y, int16_t radius); + +/******************************************************************************/ +/** Screen Text Display Functions **/ +/** **/ +/** These functions allow programmers to display text on the v5 screen **/ +/******************************************************************************/ + +/** + * Print a formatted string to the screen on the specified line + * + * Will default to a medium sized font by default if invalid txt_fmt is given. + * + * \param txt_fmt Text format enum that determines if the text is medium, large, medium_center, or large_center. (DOES NOT SUPPORT SMALL) + * \param line The line number on which to print + * \param text Format string + * \param ... Optional list of arguments for the format string + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_print(text_format_e_t txt_fmt, const int16_t line, const char* text, ...); + +/** + * Print a formatted string to the screen at the specified point + * + * Will default to a medium sized font by default if invalid txt_fmt is given. + * + * Text formats medium_center and large_center will default to medium and large respectively. + * + * \param txt_fmt Text format enum that determines if the text is small, medium, or large. + * \param x The y coordinate of the top left corner of the string + * \param y The x coordinate of the top left corner of the string + * \param text Format string + * \param ... Optional list of arguments for the format string + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ +uint32_t screen_print_at(text_format_e_t txt_fmt, const int16_t x, const int16_t y, const char* text, ...); + +/** + * Print a formatted string to the screen on the specified line + * + * Same as `display_printf` except that this uses a `va_list` instead of the + * ellipsis operator so this can be used by other functions. + * + * Will default to a medium sized font by default if invalid txt_fmt is given. + * Exposed mostly for writing libraries and custom functions. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param txt_fmt Text format enum that determines if the text is medium, large, medium_center, or large_center. (DOES NOT SUPPORT SMALL) + * \param line The line number on which to print + * \param text Format string + * \param args List of arguments for the format string + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * while taking or returning the screen mutex. + */ +uint32_t screen_vprintf(text_format_e_t txt_fmt, const int16_t line, const char* text, va_list args); + +/** + * Print a formatted string to the screen at the specified coordinates + * + * Same as `display_printf_at` except that this uses a `va_list` instead of the + * ellipsis operator so this can be used by other functions. + * + * Will default to a medium sized font by default if invalid txt_fmt is given. + * + * Text formats medium_center and large_center will default to medium and large respectively. + * Exposed mostly for writing libraries and custom functions. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param txt_fmt Text format enum that determines if the text is small, medium, or large. + * \param x, y The (x,y) coordinates of the top left corner of the string + * \param text Format string + * \param args List of arguments for the format string + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * while taking or returning the screen mutex. + */ +uint32_t screen_vprintf_at(text_format_e_t txt_fmt, const int16_t x, const int16_t y, const char* text, va_list args); + +/******************************************************************************/ +/** Screen Touch Functions **/ +/** **/ +/** These functions allow programmers to access **/ +/** information about screen touches **/ +/******************************************************************************/ + +/** + * Gets the touch status of the last touch of the screen. + * + * \return The last_touch_e_t enum specifier that indicates the last touch status of the screen (E_TOUCH_EVENT_RELEASE, E_TOUCH_EVENT_PRESS, or E_TOUCH_EVENT_PRESS_AND_HOLD). + * This will be released by default if no action was taken. + * If an error occured, the screen_touch_status_s_t will have its last_touch_e_t + * enum specifier set to E_TOUCH_ERR, and other values set to -1. + */ +screen_touch_status_s_t screen_touch_status(void); + +/** + * Assigns a callback function to be called when a certain touch event happens. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param cb Function pointer to callback when event type happens + * \param event_type Touch event that will trigger the callback. + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * while taking or returning the screen mutex. + */ +uint32_t screen_touch_callback(touch_event_cb_fn_t cb, last_touch_e_t event_type); + +#ifdef __cplusplus +} //namespace c +} //namespace pros +} +#endif + +#endif diff --git a/pros/pros/screen.hpp b/pros/pros/screen.hpp new file mode 100644 index 00000000..3aecd188 --- /dev/null +++ b/pros/pros/screen.hpp @@ -0,0 +1,385 @@ +/** + * \file screen.hpp + * + * Brain screen display and touch functions. + * + * Contains user calls to the v5 screen for touching and displaying graphics. + * + * \copyright (c) 2017, 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/. + */ + +#ifndef _PROS_SCREEN_HPP_ +#define _PROS_SCREEN_HPP_ + +#include "pros/screen.h" +#include +#include + +namespace pros { +namespace screen { + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" + +namespace { +template +T convert_args(T arg) { + return arg; +} +const char* convert_args(const std::string& arg) { + return arg.c_str(); +} +} // namespace + +#pragma GCC diagnostic pop + + /******************************************************************************/ + /** Screen Graphical Display Functions **/ + /** **/ + /** These functions allow programmers to display shapes on the v5 screen **/ + /******************************************************************************/ + + /** + * Set the pen color for subsequent graphics operations + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param color The pen color to set (it is recommended to use values + * from the enum defined in colors.h) + * + * \return Returns 1 if the mutex was successfully returned, or PROS_ERR if + * there was an error either taking or returning the screen mutex. + */ + std::uint32_t set_pen(const std::uint32_t color); + + /** + * Set the eraser color for erasing and the current background. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param color The background color to set (it is recommended to use values + * from the enum defined in colors.h) + * + * \return Returns 1 if the mutex was successfully returned, or PROS_ERR + * if there was an error either taking or returning the screen mutex. + */ + std::uint32_t set_eraser(const std::uint32_t color); + + /** + * Get the current pen color. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \return The current pen color in the form of a value from the enum + * defined in colors.h, or PROS_ERR if there was an error taking or + * returning the screen mutex. + */ + std::uint32_t get_pen(); + + /** + * Get the current eraser color. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \return The current eraser color in the form of a value from the enum + * defined in colors.h, or PROS_ERR if there was an error taking or + * returning the screen mutex. + */ + std::uint32_t get_eraser(); + + /** + * Clear display with eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ + std::uint32_t erase(); + + /** + * Scroll lines on the display upwards. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param start_line The line from which scrolling will start + * \param lines The number of lines to scroll up + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ + std::uint32_t scroll(const std::int16_t start_line, const std::int16_t lines); + + /** + * Scroll lines within a region on the display + * + * This function behaves in the same way as `screen_scroll`, except that you + * specify a rectangular region within which to scroll lines instead of a start + * line. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first corner of the + * rectangular region + * \param x1, y1 The (x,y) coordinates of the second corner of the + * rectangular region + * \param lines The number of lines to scroll upwards + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ + std::uint32_t scroll_area(const std::int16_t x0, const std::int16_t y0, const std::int16_t x1, const std::int16_t y1, std::int16_t lines); + + /** + * Copy a screen region (designated by a rectangle) from an off-screen buffer + * to the screen + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first corner of the + * rectangular region of the screen + * \param x1, y1 The (x,y) coordinates of the second corner of the + * rectangular region of the screen + * \param buf Off-screen buffer containing screen data + * \param stride Off-screen buffer width in pixels, such that image size + * is stride-padding + * + * \return 1 if there were no errors, or PROS_ERR if an error occured taking + * or returning the screen mutex. + */ + std::uint32_t copy_area(const std::int16_t x0, const std::int16_t y0, const std::int16_t x1, const std::int16_t y1, uint32_t* buf, const std::int32_t stride); + + /** + * Draw a single pixel on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the pixel + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ + std::uint32_t draw_pixel(const std::int16_t x, const std::int16_t y); + + /** + * Erase a pixel from the screen (Sets the location) + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the erased + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ + std::uint32_t erase_pixel(const std::int16_t x, const std::int16_t y); + + /** + * Draw a line on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x, y) coordinates of the first point of the line + * \param x1, y1 The (x, y) coordinates of the second point of the line + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ + std::uint32_t draw_line(const std::int16_t x0, const std::int16_t y0, const std::int16_t x1, const std::int16_t y1); + + /** + * Erase a line on the screen using the current eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x, y) coordinates of the first point of the line + * \param x1, y1 The (x, y) coordinates of the second point of the line + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ + std::uint32_t erase_line(const std::int16_t x0, const std::int16_t y0, const std::int16_t x1, const std::int16_t y1); + + /** + * Draw a rectangle on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first point of the rectangle + * \param x1, y1 The (x,y) coordinates of the second point of the rectangle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ + std::uint32_t draw_rect(const std::int16_t x0, const std::int16_t y0, const std::int16_t x1, const std::int16_t y1); + + /** + * Erase a rectangle on the screen using the current eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first point of the rectangle + * \param x1, y1 The (x,y) coordinates of the second point of the rectangle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ + std::uint32_t erase_rect(const std::int16_t x0, const std::int16_t y0, const std::int16_t x1, const std::int16_t y1); + + /** + * Fill a rectangular region of the screen using the current pen + * color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first point of the rectangle + * \param x1, y1 The (x,y) coordinates of the second point of the rectangle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ + std::uint32_t fill_rect(const std::int16_t x0, const std::int16_t y0, const std::int16_t x1, const std::int16_t y1); + + /** + * Draw a circle on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the center of the circle + * \param r The radius of the circle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ + std::uint32_t draw_circle(const std::int16_t x, const std::int16_t y, const std::int16_t radius); + + /** + * Erase a circle on the screen using the current eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the center of the circle + * \param r The radius of the circle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ + std::uint32_t erase_circle(const std::int16_t x, const std::int16_t y, const std::int16_t radius); + + /** + * Fill a circular region of the screen using the current pen + * color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the center of the circle + * \param r The radius of the circle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + */ + std::uint32_t fill_circle(const std::int16_t x, const std::int16_t y, const std::int16_t radius); + + /******************************************************************************/ + /** Screen Text Display Functions **/ + /** **/ + /** These functions allow programmers to display text on the v5 screen **/ + /******************************************************************************/ + + /** + * Print a formatted string to the screen, overwrite available for printing at location too. + * + * Will default to a medium sized font by default if invalid txt_fmt is given. + * + * \param txt_fmt Text format enum that determines if the text is medium, large, medium_center, or large_center. (DOES NOT SUPPORT SMALL) + * \param line The line number on which to print + * \param x The (x,y) coordinates of the top left corner of the string + * \param y The (x,y) coordinates of the top left corner of the string + * \param fmt Format string + * \param ... Optional list of arguments for the format string + */ + template + void print(pros::text_format_e_t txt_fmt, const std::int16_t line, const char* text, Params... args){ + pros::c::screen_print(txt_fmt, line, text, convert_args(args)...); + } + + template + void print(pros::text_format_e_t txt_fmt, const std::int16_t x, const std::int16_t y, const char* text, Params... args){ + pros::c::screen_print_at(txt_fmt, x, y, text, convert_args(args)...); + } + + /******************************************************************************/ + /** Screen Touch Functions **/ + /** **/ + /** These functions allow programmers to access **/ + /** information about screen touches **/ + /******************************************************************************/ + + /** + * Gets the touch status of the last touch of the screen. + * + * \return The last_touch_e_t enum specifier that indicates the last touch status of the screen (E_TOUCH_EVENT_RELEASE, E_TOUCH_EVENT_PRESS, or E_TOUCH_EVENT_PRESS_AND_HOLD). + * This will be released by default if no action was taken. + * If an error occured, the screen_touch_status_s_t will have its + * last_touch_e_t enum specifier set to E_TOUCH_ERR, and other values set to -1. + */ + screen_touch_status_s_t touch_status(); + + /** + * Assigns a callback function to be called when a certain touch event happens. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param cb Function pointer to callback when event type happens + * \param event_type Touch event that will trigger the callback. + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * while taking or returning the screen mutex. + */ + std::uint32_t touch_callback(touch_event_cb_fn_t cb, last_touch_e_t event_type); + +} //namespace screen +} //namespace pros + +#endif //header guard diff --git a/pros/pros/serial.h b/pros/pros/serial.h new file mode 100644 index 00000000..6db69cd0 --- /dev/null +++ b/pros/pros/serial.h @@ -0,0 +1,247 @@ +/** + * \file pros/serial.h + * + * Contains prototypes for the V5 Generic Serial related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/serial.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_SERIAL_H_ +#define _PROS_SERIAL_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/******************************************************************************/ +/** Serial communication functions **/ +/** **/ +/** These functions allow programmers to communicate using UART over RS485 **/ +/******************************************************************************/ + +/** + * Enables generic serial on the given port. + * + * \note This function must be called before any of the generic serial + * functions will work. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t serial_enable(uint8_t port); + +/** + * Sets the baudrate for the serial port to operate at. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * \param baudrate + * The baudrate to operate at + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t serial_set_baudrate(uint8_t port, int32_t baudrate); + +/** + * Clears the internal input and output FIFO buffers. + * + * This can be useful to reset state and remove old, potentially unneeded data + * from the input FIFO buffer or to cancel sending any data in the output FIFO + * buffer. + * + * \note This function does not cause the data in the output buffer to be + * written, it simply clears the internal buffers. Unlike stdout, generic + * serial does not use buffered IO (the FIFO buffers are written as soon + * as possible). + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t serial_flush(uint8_t port); + +/** + * Returns the number of bytes available to be read in the the port's FIFO + * input buffer. + * + * \note This function does not actually read any bytes, is simply returns the + * number of bytes available to be read. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return The number of bytes avaliable to be read or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t serial_get_read_avail(uint8_t port); + +/** + * Returns the number of bytes free in the port's FIFO output buffer. + * + * \note This function does not actually write any bytes, is simply returns the + * number of bytes free in the port's buffer. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return The number of bytes free or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t serial_get_write_free(uint8_t port); + +/** + * Reads the next byte avaliable in the port's input buffer without removing it. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return The next byte avaliable to be read, -1 if none are available, or + * PROS_ERR if the operation failed, setting errno. + */ +int32_t serial_peek_byte(uint8_t port); + +/** + * Reads the next byte avaliable in the port's input buffer. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return The next byte avaliable to be read, -1 if none are available, or + * PROS_ERR if the operation failed, setting errno. + */ +int32_t serial_read_byte(uint8_t port); + +/** + * Reads up to the next length bytes from the port's input buffer and places + * them in the user supplied buffer. + * + * \note This function will only return bytes that are currently avaliable to be + * read and will not block waiting for any to arrive. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * \param buffer + * The location to place the data read + * \param length + * The maximum number of bytes to read + * + * \return The number of bytes read or PROS_ERR if the operation failed, setting + * errno. + */ +int32_t serial_read(uint8_t port, uint8_t* buffer, int32_t length); + +/** + * Write the given byte to the port's output buffer. + * + * \note Data in the port's output buffer is written to the serial port as soon + * as possible on a FIFO basis and can not be done manually by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * EIO - Serious internal write error. + * + * \param port + * The V5 port number from 1-21 + * \param buffer + * The byte to write + * + * \return The number of bytes written or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t serial_write_byte(uint8_t port, uint8_t buffer); + +/** + * Writes up to length bytes from the user supplied buffer to the port's output + * buffer. + * + * \note Data in the port's output buffer is written to the serial port as soon + * as possible on a FIFO basis and can not be done manually by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * EIO - Serious internal write error. + * + * \param port + * The V5 port number from 1-21 + * \param buffer + * The data to write + * \param length + * The maximum number of bytes to write + * + * \return The number of bytes written or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t serial_write(uint8_t port, uint8_t* buffer, int32_t length); + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_SERIAL_H_ \ No newline at end of file diff --git a/pros/pros/serial.hpp b/pros/pros/serial.hpp new file mode 100644 index 00000000..60e82c1c --- /dev/null +++ b/pros/pros/serial.hpp @@ -0,0 +1,228 @@ +/** + * \file pros/serial.hpp + * + * Contains prototypes for the V5 Generic Serial related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/serial.html to learn + * more. + * + * 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. + * + * 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/. + */ + +#ifndef _PROS_SERIAL_HPP_ +#define _PROS_SERIAL_HPP_ + +#include +#include "pros/serial.h" + +namespace pros { +class Serial { + public: + /** + * Creates a Serial object for the given port and specifications. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * \param baudrate + * The baudrate to run the port at + */ + explicit Serial(std::uint8_t port, std::int32_t baudrate); + + explicit Serial(std::uint8_t port); + + /******************************************************************************/ + /** Serial communication functions **/ + /** **/ + /** These functions allow programmers to communicate using UART over RS485 **/ + /******************************************************************************/ + + /** + * Sets the baudrate for the serial port to operate at. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param baudrate + * The baudrate to operate at + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_baudrate(std::int32_t baudrate) const; + + /** + * Clears the internal input and output FIFO buffers. + * + * This can be useful to reset state and remove old, potentially unneeded data + * from the input FIFO buffer or to cancel sending any data in the output FIFO + * buffer. + * + * \note This function does not cause the data in the output buffer to be + * written, it simply clears the internal buffers. Unlike stdout, generic + * serial does not use buffered IO (the FIFO buffers are written as soon + * as possible). + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t flush() const; + + /** + * Returns the number of bytes available to be read in the the port's FIFO + * input buffer. + * + * \note This function does not actually read any bytes, is simply returns the + * number of bytes available to be read. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \return The number of bytes avaliable to be read or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t get_read_avail() const; + + /** + * Returns the number of bytes free in the port's FIFO output buffer. + * + * \note This function does not actually write any bytes, is simply returns the + * number of bytes free in the port's buffer. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \return The number of bytes free or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t get_write_free() const; + + /** + * Gets the port number of the serial port. + * + * \return The serial port's port number. + */ + std::uint8_t get_port() const; + + /** + * Reads the next byte avaliable in the port's input buffer without removing it. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \return The next byte avaliable to be read, -1 if none are available, or + * PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t peek_byte() const; + + /** + * Reads the next byte avaliable in the port's input buffer. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \return The next byte avaliable to be read, -1 if none are available, or + * PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t read_byte() const; + + /** + * Reads up to the next length bytes from the port's input buffer and places + * them in the user supplied buffer. + * + * \note This function will only return bytes that are currently avaliable to be + * read and will not block waiting for any to arrive. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param buffer + * The location to place the data read + * \param length + * The maximum number of bytes to read + * + * \return The number of bytes read or PROS_ERR if the operation failed, setting + * errno. + */ + virtual std::int32_t read(std::uint8_t* buffer, std::int32_t length) const; + + /** + * Write the given byte to the port's output buffer. + * + * \note Data in the port's output buffer is written to the serial port as soon + * as possible on a FIFO basis and can not be done manually by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * EIO - Serious internal write error. + * + * \param buffer + * The byte to write + * + * \return The number of bytes written or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t write_byte(std::uint8_t buffer) const; + + /** + * Writes up to length bytes from the user supplied buffer to the port's output + * buffer. + * + * \note Data in the port's output buffer is written to the serial port as soon + * as possible on a FIFO basis and can not be done manually by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * EIO - Serious internal write error. + * + * \param buffer + * The data to write + * \param length + * The maximum number of bytes to write + * + * \return The number of bytes written or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t write(std::uint8_t* buffer, std::int32_t length) const; + + private: + const std::uint8_t _port; +}; + +namespace literals { +const pros::Serial operator"" _ser(const unsigned long long int m); +} // namespace literals +} // namespace pros +#endif // _PROS_SERIAL_HPP_ diff --git a/pros/pros/vision.h b/pros/pros/vision.h new file mode 100644 index 00000000..8464b6c3 --- /dev/null +++ b/pros/pros/vision.h @@ -0,0 +1,557 @@ +/** + * \file pros/vision.h + * + * Contains prototypes for the VEX Vision Sensor-related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html to learn + * more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_VISION_H_ +#define _PROS_VISION_H_ + +#define VISION_OBJECT_ERR_SIG 255 +// Parameters given by VEX +#define VISION_FOV_WIDTH 316 +#define VISION_FOV_HEIGHT 212 + +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif +/** + * This enumeration defines the different types of objects + * that can be detected by the Vision Sensor + */ +typedef enum vision_object_type { + E_VISION_OBJECT_NORMAL = 0, + E_VISION_OBJECT_COLOR_CODE = 1, + E_VISION_OBJECT_LINE = 2 +} vision_object_type_e_t; + +/** + * This structure contains the parameters used by the Vision Sensor + * to detect objects. + */ +typedef struct __attribute__((__packed__)) vision_signature { + uint8_t id; + uint8_t _pad[3]; + float range; + int32_t u_min; + int32_t u_max; + int32_t u_mean; + int32_t v_min; + int32_t v_max; + int32_t v_mean; + uint32_t rgb; + uint32_t type; +} vision_signature_s_t; + +/** + * Color codes are just signatures with multiple IDs and a different type. + */ +typedef uint16_t vision_color_code_t; + +/** + * This structure contains a descriptor of an object detected + * by the Vision Sensor + */ +typedef struct __attribute__((__packed__)) vision_object { + // Object signature + uint16_t signature; + // Object type, e.g. normal, color code, or line detection + vision_object_type_e_t type; + // left boundary coordinate of the object + int16_t left_coord; + // top boundary coordinate of the object + int16_t top_coord; + // width of the object + int16_t width; + // height of the object + int16_t height; + // Angle of a color code object in 0.1 degree units (e.g. 10 -> 1 degree, 155 + // -> 15.5 degrees) + uint16_t angle; + + // coordinates of the middle of the object (computed from the values above) + int16_t x_middle_coord; + int16_t y_middle_coord; +} vision_object_s_t; + +typedef enum vision_zero { + E_VISION_ZERO_TOPLEFT = 0, // (0,0) coordinate is the top left of the FOV + E_VISION_ZERO_CENTER = 1 // (0,0) coordinate is the center of the FOV +} vision_zero_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define VISION_OBJECT_NORMAL pros::E_VISION_OBJECT_NORMAL +#define VISION_OBJECT_COLOR_CODE pros::E_VISION_OBJECT_COLOR_CODE +#define VISION_OBJECT_LINE pros::E_VISION_OBJECT_LINE +#define VISION_ZERO_TOPLEFT pros::E_VISION_ZERO_TOPLEFT +#define VISION_ZERO_CENTER pros::E_VISION_ZERO_CENTER +#else +#define VISION_OBJECT_NORMAL E_VISION_OBJECT_NORMAL +#define VISION_OBJECT_COLOR_CODE E_VISION_OBJECT_COLOR_CODE +#define VISION_OBJECT_LINE E_VISION_OBJECT_LINE +#define VISION_ZERO_TOPLEFT E_VISION_ZERO_TOPLEFT +#define VISION_ZERO_CENTER E_VISION_ZERO_CENTER +#endif +#endif + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Clears the vision sensor LED color, reseting it back to its default behavior, + * displaying the most prominent object signature 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 V5 ports (1-21). + * ENODEV - The port cannot be configured as a vision sensor + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t vision_clear_led(uint8_t port); + +/** + * Creates a signature from the vision sensor utility + * + * \param id + * The signature ID + * \param u_min + * Minimum value on U axis + * \param u_max + * Maximum value on U axis + * \param u_mean + * Mean value on U axis + * \param v_min + * Minimum value on V axis + * \param v_max + * Maximum value on V axis + * \param v_mean + * Mean value on V axis + * \param range + * Scale factor + * \param type + * Signature type + * + * \return A vision_signature_s_t that can be set using vision_set_signature + */ +vision_signature_s_t vision_signature_from_utility(const int32_t id, const int32_t u_min, const int32_t u_max, + const int32_t u_mean, const int32_t v_min, const int32_t v_max, + const int32_t v_mean, const float range, const int32_t type); + +/** + * Creates a color code that represents a combination of the given signature + * IDs. If fewer than 5 signatures are to be a part of the color code, pass 0 + * for the additional function parameters. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - Fewer than two signatures have been provided or one of the + * signatures is out of its [1-7] range (or 0 when omitted). + * + * \param port + * The V5 port number from 1-21 + * \param sig_id1 + * The first signature id [1-7] to add to the color code + * \param sig_id2 + * The second signature id [1-7] to add to the color code + * \param sig_id3 + * The third signature id [1-7] to add to the color code + * \param sig_id4 + * The fourth signature id [1-7] to add to the color code + * \param sig_id5 + * The fifth signature id [1-7] to add to the color code + * + * \return A vision_color_code_t object containing the color code information. + */ +vision_color_code_t vision_create_color_code(uint8_t port, const uint32_t sig_id1, const uint32_t sig_id2, + const uint32_t sig_id3, const uint32_t sig_id4, const uint32_t sig_id5); + +/** + * Gets the nth largest object according to size_id. + * + * 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 + * EDOM - size_id is greater than the number of available objects. + * EHOSTDOWN - Reading the vision sensor failed for an unknown reason. + * + * \param port + * The V5 port number from 1-21 + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * + * \return The vision_object_s_t object corresponding to the given size id, or + * PROS_ERR if an error occurred. + */ +vision_object_s_t vision_get_by_size(uint8_t port, const uint32_t size_id); + +/** + * Gets the nth largest object of the given signature according to size_id. + * + * 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 + * EINVAL - sig_id is outside the range [1-8] + * EDOM - size_id is greater than the number of available objects. + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param port + * The V5 port number from 1-21 + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param signature + * The signature ID [1-7] for which an object will be returned. + * + * \return The vision_object_s_t object corresponding to the given signature and + * size_id, or PROS_ERR if an error occurred. + */ +vision_object_s_t vision_get_by_sig(uint8_t port, const uint32_t size_id, const uint32_t sig_id); + +/** + * Gets the nth largest object of the given color code according to size_id. + * + * 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 + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param port + * The V5 port number from 1-21 + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param color_code + * The vision_color_code_t for which an object will be returned + * + * \return The vision_object_s_t object corresponding to the given color code + * and size_id, or PROS_ERR if an error occurred. + */ +vision_object_s_t vision_get_by_code(uint8_t port, const uint32_t size_id, const vision_color_code_t color_code); + +/** + * Gets the exposure parameter of the Vision Sensor. See + * https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html#exposure-setting + * for more detials. + * + * 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 current exposure setting from [0,150], PROS_ERR if an error + * occurred + */ +int32_t vision_get_exposure(uint8_t port); + +/** + * Gets the number of objects currently detected by the 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 detected on the specified vision sensor. + * Returns PROS_ERR if the port was invalid or an error occurred. + */ +int32_t vision_get_object_count(uint8_t port); + +/** + * Get the white balance parameter of the 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 current RGB white balance setting of the sensor + */ +int32_t vision_get_white_balance(uint8_t port); + +/** + * Prints the contents of the signature as an initializer list to the terminal. + * + * \param sig + * The signature for which the contents will be printed + * + * \return 1 if no errors occured, PROS_ERR otherwise + */ +int32_t vision_print_signature(const vision_signature_s_t sig); + +/** + * Reads up to object_count object descriptors into object_arr. + * + * 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), or + * fewer than object_count number of objects were found. + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * + * \param port + * The V5 port number from 1-21 + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param object_count + * The number of objects to read + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * 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. + */ +int32_t vision_read_by_size(uint8_t port, const uint32_t size_id, const uint32_t object_count, + vision_object_s_t* const object_arr); + +/** + * Reads up to object_count object descriptors into object_arr. + * + * 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), or + * fewer than object_count number of objects were found. + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * + * \param port + * The V5 port number from 1-21 + * \param object_count + * The number of objects to read + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param signature + * The signature ID [1-7] for which objects will be returned. + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * 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. + */ +int32_t vision_read_by_sig(uint8_t port, const uint32_t size_id, const uint32_t sig_id, const uint32_t object_count, + vision_object_s_t* const object_arr); + +/** + * Reads up to object_count object descriptors into object_arr. + * + * 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), or + * fewer than object_count number of objects were found. + * ENODEV - The port cannot be configured as a vision sensor + * + * \param port + * The V5 port number from 1-21 + * \param object_count + * The number of objects to read + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param color_code + * The vision_color_code_t for which objects will be returned + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * 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. + */ +int32_t vision_read_by_code(uint8_t port, const uint32_t size_id, const vision_color_code_t color_code, + const uint32_t object_count, vision_object_s_t* const object_arr); + +/** + * Gets the object detection signature with the given id number. + * + * \param port + * The V5 port number from 1-21 + * \param signature_id + * The signature id to read + * + * \return A vision_signature_s_t containing information about the signature. + */ +vision_signature_s_t vision_get_signature(uint8_t port, const uint8_t signature_id); + +/** + * Stores the supplied object detection signature onto the vision sensor. + * + * NOTE: This saves the signature in volatile memory, and the signature will be + * lost as soon as the sensor is powered down. + * + * \param port + * The V5 port number from 1-21 + * \param signature_id + * The signature id to store into + * \param[in] signature_ptr + * A pointer to the signature to save + * + * \return 1 if no errors occured, PROS_ERR otherwise + */ +int32_t vision_set_signature(uint8_t port, const uint8_t signature_id, vision_signature_s_t* const signature_ptr); + +/** + * Enables/disables auto white-balancing on the 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 + * EINVAL - enable was not 0 or 1 + * + * \param port + * The V5 port number from 1-21 + * \param enabled + * Pass 0 to disable, 1 to enable + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t vision_set_auto_white_balance(uint8_t port, const uint8_t enable); + +/** + * Sets the exposure parameter of the Vision Sensor. See + * https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html#exposure-setting + * for more detials. + * + * 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 percent + * The new exposure setting from [0,150] + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t vision_set_exposure(uint8_t port, const uint8_t exposure); + +/** + * Sets the vision sensor LED color, overriding the automatic behavior. + * + * 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 rgb + * An RGB code to set the LED to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t vision_set_led(uint8_t port, const int32_t rgb); + +/** + * Sets the white balance parameter of the 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 + * \param rgb + * The new RGB white balance setting of the sensor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t vision_set_white_balance(uint8_t port, const int32_t rgb); + +/** + * Sets the (0,0) coordinate for the Field of View. + * + * This will affect the coordinates returned for each request for a + * vision_object_s_t from the sensor, so it is recommended that this function + * only be used to configure the sensor at the beginning of its use. + * + * 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 zero_point + * One of vision_zero_e_t to set the (0,0) coordinate for the FOV + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t vision_set_zero_point(uint8_t port, vision_zero_e_t zero_point); + +/** + * Sets the Wi-Fi mode of the Vision sensor + * + * This functions uses the following values of errno when an error state is + * reached: + * ENXIO - The given port is not within the range of V5 ports (1-21) + * EACCESS - Anothe resources is currently trying to access the port + * + * \param port + * The V5 port number from 1-21 + * \param enable + * Disable Wi-Fi on the Vision sensor if 0, enable otherwise (e.g. 1) + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t vision_set_wifi_mode(uint8_t port, const uint8_t enable); + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_VISION_H_ diff --git a/pros/pros/vision.hpp b/pros/pros/vision.hpp new file mode 100644 index 00000000..eeb00462 --- /dev/null +++ b/pros/pros/vision.hpp @@ -0,0 +1,445 @@ +/** + * \file pros/vision.hpp + * + * Contains prototypes for the VEX Vision Sensor-related functions in C++. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html to learn + * more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_VISION_HPP_ +#define _PROS_VISION_HPP_ + +#include "pros/vision.h" + +#include + +namespace pros { +class Vision { + public: + /** + * Create a 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 a vision sensor + * + * \param port + * 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 + */ + Vision(std::uint8_t port, vision_zero_e_t zero_point = E_VISION_ZERO_TOPLEFT); + + /** + * Clears the vision sensor LED color, reseting it back to its default + * behavior, displaying the most prominent object signature color. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t clear_led(void) const; + + /** + * Creates a signature from the vision sensor utility + * + * \param id + * The signature ID + * \param u_min + * Minimum value on U axis + * \param u_max + * Maximum value on U axis + * \param u_mean + * Mean value on U axis + * \param v_min + * Minimum value on V axis + * \param v_max + * Maximum value on V axis + * \param v_mean + * Mean value on V axis + * \param rgb + * Scale factor + * \param type + * Signature type + * + * \return A vision_signature_s_t that can be set using Vision::set_signature + */ + 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, + const std::int32_t v_min, const std::int32_t v_max, + const std::int32_t v_mean, const float range, + const std::int32_t type); + + /** + * Creates a color code that represents a combination of the given signature + * IDs. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - Fewer than two signatures have been provided or one of the + * signatures is out of its [1-7] range (or 0 when omitted). + * + * \param sig_id1 + * The first signature id [1-7] to add to the color code + * \param sig_id2 + * The second signature id [1-7] to add to the color code + * \param sig_id3 + * The third signature id [1-7] to add to the color code + * \param sig_id4 + * The fourth signature id [1-7] to add to the color code + * \param sig_id5 + * The fifth signature id [1-7] to add to the color code + * + * \return A vision_color_code_t object containing the color code information. + */ + 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 the nth largest object according to size_id. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * + * \return The vision_object_s_t object corresponding to the given size id, or + * PROS_ERR if an error occurred. + */ + vision_object_s_t get_by_size(const std::uint32_t size_id) const; + + /** + * Gets the nth largest object of the given signature according to size_id. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * EINVAL - sig_id is outside the range [1-8] + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param signature + * The vision_signature_s_t signature for which an object will be + * returned. + * + * \return The vision_object_s_t object corresponding to the given signature + * and size_id, or PROS_ERR if an error occurred. + */ + vision_object_s_t get_by_sig(const std::uint32_t size_id, const std::uint32_t sig_id) const; + + /** + * Gets the nth largest object of the given color code according to size_id. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EAGAIN - Reading the Vision Sensor failed for an unknown reason. + * + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param color_code + * The vision_color_code_t for which an object will be returned + * + * \return The vision_object_s_t object corresponding to the given color code + * and size_id, or PROS_ERR if an error occurred. + */ + 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. See + * https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html#exposure-setting + * for more detials. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \return The current exposure parameter from [0,150], + * PROS_ERR if an error occurred + */ + std::int32_t get_exposure(void) const; + + /** + * Gets the number of objects currently detected by the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \return The number of objects detected on the specified vision sensor. + * Returns PROS_ERR if the port was invalid or an error occurred. + */ + std::int32_t get_object_count(void) const; + + /** + * Gets the object detection signature with the given id number. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param signature_id + * The signature id to read + * + * \return A vision_signature_s_t containing information about the signature. + */ + vision_signature_s_t get_signature(const std::uint8_t signature_id) const; + + /** + * Get the white balance parameter of the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \return The current RGB white balance setting of the sensor + */ + std::int32_t get_white_balance(void) const; + + /** + * Gets the port number of the Vision Sensor. + * + * \return The vision sensor's port number. + */ + std::uint8_t get_port(void) const; + + /** + * Reads up to object_count object descriptors into object_arr. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param object_count + * The number of objects to read + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * 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. + */ + 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; + + /** + * Reads up to object_count object descriptors into object_arr. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * EINVAL - sig_id is outside the range [1-8] + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param object_count + * The number of objects to read + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param signature + * The vision_signature_s_t signature for which an object will be + * returned. + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * 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. + */ + std::int32_t read_by_sig(const std::uint32_t size_id, const std::uint32_t sig_id, const std::uint32_t object_count, + vision_object_s_t* const object_arr) const; + + /** + * Reads up to object_count object descriptors into object_arr. + * + * This function uses the following values of errno when an error state is + * reached: + * EDOM - size_id is greater than the number of available objects. + * ENODEV - The port cannot be configured as a vision sensor + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param object_count + * The number of objects to read + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param color_code + * The vision_color_code_t for which objects will be returned + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * 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. + */ + int32_t read_by_code(const std::uint32_t size_id, const vision_color_code_t color_code, + const std::uint32_t object_count, vision_object_s_t* const object_arr) const; + + /** + * Prints the contents of the signature as an initializer list to the terminal. + * + * \param sig + * The signature for which the contents will be printed + * + * \return 1 if no errors occured, PROS_ERR otherwise + */ + static std::int32_t print_signature(const vision_signature_s_t sig); + + /** + * Enables/disables auto white-balancing on the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param enabled + * Pass 0 to disable, 1 to enable + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_auto_white_balance(const std::uint8_t enable) const; + + /** + * Sets the exposure parameter of the Vision Sensor. See + * https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html#exposure-setting + * for more detials. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param percent + * The new exposure setting from [0,150]. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_exposure(const std::uint8_t exposure) const; + + /** + * Sets the vision sensor LED color, overriding the automatic behavior. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param rgb + * An RGB code to set the LED to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_led(const std::int32_t rgb) const; + + /** + * Stores the supplied object detection signature onto the vision sensor. + * + * NOTE: This saves the signature in volatile memory, and the signature will be + * lost as soon as the sensor is powered down. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EINVAL - sig_id is outside the range [1-8] + * + * \param signature_id + * The signature id to store into + * \param[in] signature_ptr + * A pointer to the signature to save + * + * \return 1 if no errors occured, PROS_ERR otherwise + */ + std::int32_t set_signature(const std::uint8_t signature_id, vision_signature_s_t* const signature_ptr) const; + + /** + * Sets the white balance parameter of the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param rgb + * The new RGB white balance setting of the sensor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_white_balance(const std::int32_t rgb) const; + + /** + * Sets the (0,0) coordinate for the Field of View. + * + * This will affect the coordinates returned for each request for a + * vision_object_s_t from the sensor, so it is recommended that this function + * only be used to configure the sensor at the beginning of its use. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param zero_point + * One of vision_zero_e_t to set the (0,0) coordinate for the FOV + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_zero_point(vision_zero_e_t zero_point) const; + + /** + * Sets the Wi-Fi mode of the Vision sensor + * + * This functions uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param enable + * Disable Wi-Fi on the Vision sensor if 0, enable otherwise (e.g. 1) + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t set_wifi_mode(const std::uint8_t enable) const; + + private: + std::uint8_t _port; +}; +} // namespace pros +#endif // _PROS_VISION_HPP_ diff --git a/scripts/actions-entrypoint.sh b/scripts/actions-entrypoint.sh new file mode 100755 index 00000000..102b3367 --- /dev/null +++ b/scripts/actions-entrypoint.sh @@ -0,0 +1,14 @@ +#!/bin/bash +sudo apt-get install -y python3 python3-pip python-is-python3 +sudo apt-get install -y python3-rosdep +sudo apt-get install -y ros-noetic-tf +sudo apt-get install -y libeigen3-dev +sudo apt-get install -y wget + +cd $HOME +wget https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-rm/9-2020q2/gcc-arm-none-eabi-9-2020-q2-update-x86_64-linux.tar.bz2 --no-check-certificate +tar -xjvf gcc-arm-none-eabi-9-2020-q2-update-x86_64-linux.tar.bz2 +echo "$HOME/gcc-arm-none-eabi-9-2020-q2-update/bin/" >> $GITHUB_PATH + +# Install PROS +sudo python -m pip install https://github.com/purduesigbots/pros-cli/releases/download/3.1.4/pros_cli_v5-3.1.4-py3-none-any.whl \ No newline at end of file diff --git a/scripts/compute-startup.sh b/scripts/compute-startup.sh new file mode 100755 index 00000000..74efae7c --- /dev/null +++ b/scripts/compute-startup.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# Run 'crontab -e' and add this script with a @reboot tag to run on startup. Make sure the +# crontab file ends with an empty line +sleep 30 +source /opt/ros/noetic/setup.bash +source /home/ubuntu/ChangeUp/devel/setup.bash +roslaunch /home/ubuntu/ChangeUp/src/change_up_driver_control/launch/15_inch_robot.launch + diff --git a/scripts/devInstallScript.sh b/scripts/devInstallScript.sh new file mode 100755 index 00000000..3b850f9d --- /dev/null +++ b/scripts/devInstallScript.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Installs ROS, PROS and gcc-arm compiler for V5 builds + +# Install ROS +sudo apt-get update +sudo apt-get upgrade -y +sudo apt-get install curl wget apt-transport-https software-properties-common -y +sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list' +curl -sSL 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0xC1CF6E31E6BADE8868B172B4F42ED6FBAB17C654' | sudo apt-key add - +wget -q https://packages.microsoft.com/config/ubuntu/$(lsb_release -sr)/packages-microsoft-prod.deb +DEBIAN_FRONTEND=noninteractive sudo dpkg -i packages-microsoft-prod.deb +rm packages-microsoft-prod.deb +sudo apt-get update +sudo apt-get upgrade -y +sudo apt-get install python3 python-is-python3 python3-pip ros-noetic-desktop-full powershell -y +echo 'source /opt/ros/noetic/setup.bash' >> ~/.bashrc + +# Install gcc-arm compiler +mkdir ~/downloads && sudo mkdir /gcc && cd ~/downloads +wget https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-rm/9-2020q2/gcc-arm-none-eabi-9-2020-q2-update-x86_64-linux.tar.bz2 --no-check-certificate +sudo tar -xjvf gcc-arm-none-eabi-9-2020-q2-update-x86_64-linux.tar.bz2 -C /gcc +echo 'export PATH=$PATH:/gcc/gcc-arm-none-eabi-9-2020-q2-update/bin/' >> ~/.bashrc +source ~/.bashrc +arm-none-eabi-gcc --version + +# Install PROS +sudo python3.8 -m pip install https://github.com/purduesigbots/pros-cli/releases/download/3.1.4/pros_cli_v5-3.1.4-py3-none-any.whl \ No newline at end of file diff --git a/scripts/run_docker.ps1 b/scripts/run_docker.ps1 new file mode 100755 index 00000000..7f9a9ec9 --- /dev/null +++ b/scripts/run_docker.ps1 @@ -0,0 +1,45 @@ +$docker_command = "docker run -it" +$docker_vol_location = -join(" -v ", ($PSScriptRoot -replace "[\\/]scripts", ""), ":/root/ChangeUp raiderrobotics/container-registry:rr-noetic-base") +$docker_container_command = -join(" sh -c 'cd /root/ChangeUp;", $args[0], "'") + +# $IsWindows doesn't work because powershell 5.1 is too old +if ([System.Environment]::OSVersion.Platform -eq "Win32NT") { + $is_not_first + $is_exited + $joined_cmd = -join($docker_command, $docker_vol_location, $docker_container_command) + while(!$is_exited) { + # run docker container + Invoke-Expression -Command $joined_cmd + # check if container has exited to see if it ran successfully (will fail if docker desktop is not running) + $container_status = docker ps -a -q -f ancestor=raiderrobotics/container-registry:rr-noetic-base -f status=exited + if (!$container_status) { + # attempt to launch docker desktop only once + if(!($is_not_first)) { + C:/Program` Files/Docker/Docker/Docker` Desktop.exe -WindowsStyle Minimized + $is_not_first = "True" + } + Write-Host "Docker Desktop Not Running" + Start-Sleep -Seconds 1 + } + else { + # remove container after it exits + docker rm $container_status + $is_exited = "True" + } + } +} +elseif ($IsLinux) { + # rootless podman permission workaround + $is_podman + if (Get-Command podman -erroraction 'silentlycontinue') { + $is_podman = " --privileged --net=host" + } + + # docker command with environment variables that enable X11 programs to work + $joined_cmd = -join($docker_command, " --rm", $is_podman, " --env DISPLAY='", ` + [System.Environment]::GetEnvironmentVariable('DISPLAY'), "' --env='QT_X11_NO_MITSHM=1'", $docker_vol_location, $docker_container_command) + Invoke-Expression -Command $joined_cmd +} +elseif ($IsMacOS) { + Write-Host "macOS not supported" +} diff --git a/src/constant/constants.h b/src/constant/constants.h new file mode 100644 index 00000000..fd824ef9 --- /dev/null +++ b/src/constant/constants.h @@ -0,0 +1,58 @@ +#pragma once + +namespace constant { +const float kMaxVelocity = 50.0f; // Max robot velocity in in/s +const int kProsMaxMotorVoltage = 12000; // Max voltage value for a motor +const int kProsMaxJoystickAnalog = 127; // Max value of a controller stick +} // namespace constant + +/*#ifndef _CONSTANTS_H_ +#define _CONSTANTS_H_ + +#define PUBLISH_DELAY_MS 20 +#define BALL_PRESENT_THRESHOLD 2700 // Threshold for Indexing Sensor to detect +ball #define DELAY_TIME_MILLIS 10 // Standard delay time used in NodeManager + +// Offset to apply to get the gyro into our correct frame of reference +// Forward is M_PI_2, so we rotate the gyro angle to match +#define GYRO_OFFSET (0) +#define MAX_WHEEL_SPEED 1.1526 // Wheel speed for Holonomic Drive in m/s + +// The following was from code that is no longer in current use +#define MAX_ROBOT_SPEED 41.9 // tank drive max robot speed in/s +// Swerve Drive */ + +/* +#define MAX_ROTATIONAL_VELOCITY 0.17 // rad/s ? +#define ROTATION_ANGLE_THRESHOLD (M_PI / 3) +//Keeping this here because it was in the code but never used +#define LEFT_POT_OFFSET 40 +#define RIGHT_POT_OFFSET 1714 +#define REAR_POT_OFFSET 3083 +#define LEFT_MODULE_LOCATION_X -5.25 +#define LEFT_MODULE_LOCATION_Y 5.55 +#define RIGHT_MODULE_LOCATION_X 5.25 +#define RIGHT_MODULE_LOCATION_Y 5.55 +#define REAR_MODULE_LOCATION_X 0.0 +#define REAR_MODULE_LOCATION_Y -5.21 + +#define POSE_PURSUIT_LINEAR_THRESHOLD 5.0 +#define POSE_PURSUIT_THETA_THRESHOLD 0.3 + +#define ODOM_TRACK_WIDTH 0 + +#define DRIVE_TRACK_WIDTH 12.65 - 0.95 + +#define ODOM_PERPENDICULAR_X 0.019 +#define ODOM_PERPENDICULAR_Y -3.862 + +#define ODOM_PARALLEL_X 0.692 +#define ODOM_PARALLEL_Y 0.703 + +#define GYRO_ROLLOVER_ANGLE (M_PI * 3) / 2 + +//Shooter Stuff +#define SHOOTING_VELOCITY 50.0f +#define IDLE_VELOCITY 0.0f + +#endif */ \ No newline at end of file diff --git a/src/constant/drivetrain_constants.h b/src/constant/drivetrain_constants.h new file mode 100644 index 00000000..2a9b2ae0 --- /dev/null +++ b/src/constant/drivetrain_constants.h @@ -0,0 +1,15 @@ +#pragma once + +namespace constant { +const std::vector kLeftDrivetrain = { + {0, false}, + {1, false}, + {2, false} +} + +const std::vector kRightDrivetrain = { + {3, false}, + {4, false}, + {5, false} +} +} diff --git a/src/constant/motor_constants.h b/src/constant/motor_constants.h new file mode 100644 index 00000000..3b53b7c7 --- /dev/null +++ b/src/constant/motor_constants.h @@ -0,0 +1,18 @@ +#pragma once +#include + +#include "hardware/pros_motor.h" + +namespace constant { +const auto kDrivetrainCartridge = hardware::ProsMotorCartridge::kBlueCartridge; +const std::vector kDrivetrainReverse = {false, true}; + +// {top motor, bottom motor} +const std::vector kFrontRightMotorPorts = {1, 2}; +const std::vector kBackRightMotorPorts = {1, 2}; +const std::vector kBackLeftMotorPorts = {1, 2}; +const std::vector kFrontLeftMotorPorts = {1, 2}; + +// shooter - {left, right} +// transfer - {left, right} +} // namespace constant \ No newline at end of file diff --git a/src/drivetrain/holonomic_drive.cpp b/src/drivetrain/holonomic_drive.cpp new file mode 100644 index 00000000..a38250ed --- /dev/null +++ b/src/drivetrain/holonomic_drive.cpp @@ -0,0 +1,12 @@ +#include "drivetrain/holonomic_drive.h" + +namespace drivetrain { +void HolonomicDirectDrivetrain::Drive(const interface::Controller& controller) { + const std::vector voltages = { + controller.GetJoystickVoltage(interface::ControllerJoystick::kLeftX), + controller.GetJoystickVoltage(interface::ControllerJoystick::kLeftY), + controller.GetJoystickVoltage(interface::ControllerJoystick::kRightX), + controller.GetJoystickVoltage(interface::ControllerJoystick::kRightY)}; + holonomic_motors().SetVoltages(voltages); +} +} // namespace drivetrain \ No newline at end of file diff --git a/src/drivetrain/holonomic_drive.h b/src/drivetrain/holonomic_drive.h new file mode 100644 index 00000000..4c3c03c4 --- /dev/null +++ b/src/drivetrain/holonomic_drive.h @@ -0,0 +1,37 @@ +#pragma once +#include + +#include "drivetrain/holonomic_motors.h" +#include "interface/controller.h" +#include "interface/motor.h" + +namespace drivetrain { +class HolonomicDrivetrain { + public: + HolonomicDrivetrain(HolonomicMotors holonomic_motors) + : holonomic_motors_(std::move(holonomic_motors)) {} + + protected: + [[nodiscard]] inline HolonomicMotors& holonomic_motors() { + return holonomic_motors_; + } + + private: + HolonomicMotors holonomic_motors_; +}; + +/** + * Implements a holonomic drive system. + */ +class FieldOrientedHolonomicDrivetrain : public HolonomicDrivetrain { + public: + using HolonomicDrivetrain::HolonomicDrivetrain; +}; + +class HolonomicDirectDrivetrain : virtual public HolonomicDrivetrain { + public: + using HolonomicDrivetrain::HolonomicDrivetrain; // constructor inheritance + + void Drive(const interface::Controller&); +}; +} // namespace drivetrain \ No newline at end of file diff --git a/src/drivetrain/holonomic_motors.h b/src/drivetrain/holonomic_motors.h new file mode 100644 index 00000000..23c1cdef --- /dev/null +++ b/src/drivetrain/holonomic_motors.h @@ -0,0 +1,41 @@ +#pragma once +#include + +#include "constant/motor_constants.h" +#include "hardware/pros_motor_group.h" + +namespace drivetrain { +class HolonomicMotors { + public: + HolonomicMotors(std::vector> motor_ptrs) + : motor_ptrs_(std::move(motor_ptrs)) {} + + // Delete copy constructor and assignment operator to prevent issues with + // wrapped unique_ptrs + HolonomicMotors(const HolonomicMotors&) = delete; + HolonomicMotors& operator=(const HolonomicMotors&) = delete; + + // Add move operators + HolonomicMotors(HolonomicMotors&&) = default; + HolonomicMotors& operator=(HolonomicMotors&&) = default; + ~HolonomicMotors() = default; + + inline void SetVoltages(const std::vector& voltages) const { + for (int i = 0; i < voltages.size(); ++i) { + motor_ptrs()[i]->MoveVoltage(voltages[i]); + } + }; + + private: + [[nodiscard]] inline std::vector>& + motor_ptrs() { + return motor_ptrs_; + } + [[nodiscard]] inline const std::vector>& + motor_ptrs() const { + return motor_ptrs_; + } + + std::vector> motor_ptrs_; +}; +} // namespace drivetrain \ No newline at end of file diff --git a/src/drivetrain/tank_drive.cpp b/src/drivetrain/tank_drive.cpp new file mode 100644 index 00000000..9c9a7b4b --- /dev/null +++ b/src/drivetrain/tank_drive.cpp @@ -0,0 +1,14 @@ +#include "drivetrain/tank_drive.h" + +namespace drivetrain { +void TankDrive::Drive(const interface::Controller& controller) { + const drivetrain::TankMotorVoltages voltages; + + voltages.left_motor_voltage = controller.GetJoystickVoltage( + interface::ControllerJoystick::kLeftY); + voltages.right_motor_voltage = controller.GetJoystickVoltage( + interface::ControllerJoystick::kRightY); + + tank_motors().SetVoltages(voltages); +} +} diff --git a/src/drivetrain/tank_drive.h b/src/drivetrain/tank_drive.h new file mode 100644 index 00000000..e895e4cc --- /dev/null +++ b/src/drivetrain/tank_drive.h @@ -0,0 +1,22 @@ +#pragma once +#include "tank_motors.h" +#include "interface/controller.h" +#include "interface/motor.h" + +namespace drivetrain { +class TankDrive { + public: + TankDrive(TankMotors tank_motors) + : tank_motors_(std::move(tank_motors)) {} + + void Drive(const interface::Controller&); + + protected: + [[nodiscard]] inline TankMotors& tank_motors() { + return tank_motors_; + } + + private: + TankMotors tank_motors_; +} +} diff --git a/src/drivetrain/tank_motors.h b/src/drivetrain/tank_motors.h new file mode 100644 index 00000000..47d45150 --- /dev/null +++ b/src/drivetrain/tank_motors.h @@ -0,0 +1,29 @@ +#pragma once +#include + +#include "constant/motor_constants.h" +#include "hardware/pros_motor_group.h" + +namespace drivetrain { +class TankMotors { + public: + TankMotors(std::unique_ptr left_motor_group_ptr, + std::unique_ptr right_motor_group_ptr) + : left_motor_group_ptr_(std::move(left_motor_group_ptr)), + right_motor_group_ptr_(std::move(right_motor_group_ptr)) {} + + struct TankMotorVoltages { + int8_t left_motor_voltage; + int8_t right_motor_voltage; + }; + + inline void SetVoltages(const TankMotorVoltages& voltages) { + left_motor_group_ptr_->MoveVoltage(voltages.left_motor_voltage); + right_motor_group_ptr_->MoveVoltage(voltages.right_motor_voltage); + } + + private: + std::unique_ptr left_motor_group_ptr_; + std::unique_ptr right_motor_group_ptr_; +}; +} // namespace drivetrain \ No newline at end of file diff --git a/src/factory/motor_factory.cpp b/src/factory/motor_factory.cpp new file mode 100644 index 00000000..25affa95 --- /dev/null +++ b/src/factory/motor_factory.cpp @@ -0,0 +1,42 @@ +#include "motor_factory.h" + +namespace factory { +drivetrain::HolonomicDrivetrain MakeHolonomicDrivetrain( + HolonomicDrivetrainDefinition drivetrainDefinition) { + std::vector> motor_ptrs; + // emplace back constructs the ptr inside the vector instead of copying + motor_ptrs.emplace_back(std::make_unique( + drivetrainDefinition.frontRightMotorDefinitions, + constant::kDrivetrainCartridge)); + motor_ptrs.emplace_back(std::make_unique( + drivetrainDefinition.backRightMotorDefinitions, + constant::kDrivetrainCartridge)); + motor_ptrs.emplace_back(std::make_unique( + drivetrainDefinition.backLeftMotorDefinitions, + constant::kDrivetrainCartridge)); + motor_ptrs.emplace_back(std::make_unique( + drivetrainDefinition.frontLeftMotorDefinitions, + constant::kDrivetrainCartridge)); + + return drivetrain::HolonomicDrivetrain( + drivetrain::HolonomicMotors(std::move(motor_ptrs))); +} + +// TODO: Add checks to ensure that both definitions vectors are the same size. +std::unique_ptr MakeTankDrive( + TankDriveDefinition driveDefinition) { + + std::unique_ptr left_motor_group_ptr; + std::unique_ptr right_motor_group_ptr; + + left_motor_group_ptr = std::make_unique( + driveDefinition.leftMotorDefinitions, + constant::kDrivetrainCartridge); + right_motor_group_ptr = std::make_unique( + driveDefinition.rightMotorDefinitions, + constant::kDrivetrainCartridge); + + return std::make_unique( + drivetrain::TankMotors(left_motor_group_ptr, right_motor_group_ptr)); +} +} // namespace factory \ No newline at end of file diff --git a/src/factory/motor_factory.h b/src/factory/motor_factory.h new file mode 100644 index 00000000..708ed9b3 --- /dev/null +++ b/src/factory/motor_factory.h @@ -0,0 +1,33 @@ +#pragma once +#include + +#include "drivetrain/holonomic_drive.h" +#include "drivetrain/holonomic_motors.h" +#include "hardware/pros_motor.h" +#include "hardware/pros_motor_definition.h" + +namespace factory { +// enum class Robot { kRobotOne, kRobotTwo }; + +struct HolonomicDrivetrainDefinition { + public: + std::vector frontRightMotorDefinitions; + std::vector backRightMotorDefinitions; + std::vector backLeftMotorDefinitions; + std::vector frontLeftMotorDefinitions; +}; + +struct TankDriveDefinition { + public: + std::vector + leftMotorDefinitions, rightMotorDefinitions; +} + +[[nodiscard]] drivetrain::HolonomicDrivetrain MakeHolonomicDrivetrain( + HolonomicDrivetrainDefinition drivetrainDefinition); + +[[nodiscard]] std::unique_ptr MakeTankDrive( + TankDriveDefinition driveDefinition); + +// [[nodiscard]] MakeProsMotor(); +} // namespace factory \ No newline at end of file diff --git a/src/hardware/pros_controller.cpp b/src/hardware/pros_controller.cpp new file mode 100644 index 00000000..ac191e8a --- /dev/null +++ b/src/hardware/pros_controller.cpp @@ -0,0 +1,42 @@ +#include "hardware/pros_controller.h" + +#include "constant/constants.h" + +namespace hardware { +pros::controller_analog_e_t GetProsJoystick( + interface::ControllerJoystick joystick) { + switch (joystick) { + case interface::ControllerJoystick::kLeftX: + return pros::E_CONTROLLER_ANALOG_LEFT_X; + case interface::ControllerJoystick::kLeftY: + return pros::E_CONTROLLER_ANALOG_LEFT_Y; + case interface::ControllerJoystick::kRightX: + return pros::E_CONTROLLER_ANALOG_RIGHT_X; + case interface::ControllerJoystick::kRightY: + return pros::E_CONTROLLER_ANALOG_RIGHT_Y; + default: + throw std::invalid_argument("Expected a convertible joystick."); + } +} + +int ProsController::GetJoystickAnalog( + interface::ControllerJoystick joystick) const { + return controller().get_analog(GetProsJoystick(joystick)); +} + +float ProsController::GetJoystickVoltage( + interface::ControllerJoystick joystick) const { + return controller().get_analog(GetProsJoystick(joystick)) / + // cast to float to prevent integer division + static_cast(constant::kProsMaxJoystickAnalog) * + constant::kProsMaxMotorVoltage; +} + +std::unique_ptr ProsController::MakeDriverController() { + return std::make_unique(pros::E_CONTROLLER_MASTER); +} + +std::unique_ptr ProsController::MakeSecondaryController() { + return std::make_unique(pros::E_CONTROLLER_PARTNER); +} +} // namespace hardware \ No newline at end of file diff --git a/src/hardware/pros_controller.h b/src/hardware/pros_controller.h new file mode 100644 index 00000000..6184b506 --- /dev/null +++ b/src/hardware/pros_controller.h @@ -0,0 +1,38 @@ +#pragma once +#include + +#include "interface/controller.h" +#include "pros.h" + +namespace hardware { +pros::controller_analog_e_t ConvertProsJoystick( + interface::ControllerJoystick joystick); + +class ProsController : public interface::Controller { + public: + ProsController(pros::controller_id_e_t id) : controller_(id) {} + + ProsController(const ProsController&) = delete; + ProsController& operator=(const ProsController&) = delete; + + ProsController(ProsController&&) = default; + ProsController& operator=(ProsController&&) = default; + ~ProsController() = default; + + [[nodiscard]] static std::unique_ptr MakeDriverController(); + [[nodiscard]] static std::unique_ptr + MakeSecondaryController(); + + int GetJoystickAnalog(interface::ControllerJoystick) const override; + float GetJoystickVoltage(interface::ControllerJoystick) const override; + + private: + [[nodiscard]] inline pros::Controller& controller() { return controller_; } + [[nodiscard]] inline pros::Controller& controller() const { + return controller_; + } + + // mutable to enable usage from const methods + mutable pros::Controller controller_; +}; +} // namespace hardware \ No newline at end of file diff --git a/src/hardware/pros_motor.cpp b/src/hardware/pros_motor.cpp new file mode 100644 index 00000000..298bdd5a --- /dev/null +++ b/src/hardware/pros_motor.cpp @@ -0,0 +1,26 @@ +#include "hardware/pros_motor.h" + +namespace hardware { +void ProsMotor::Move(int value) { motor().move(value); } +void ProsMotor::MoveVoltage(int voltage) { motor().move_voltage(voltage); } +void ProsMotor::MoveVelocity(float velocity) { + float rpm = (velocity / constant::kMaxVelocity) * max_rpm(); + motor().move_velocity(rpm); +} +void ProsMotor::MoveAbsolute(double position, int max_velocity) { + motor().move_absolute(position, max_velocity); +} + +void ProsMotor::ResetEncoder() { motor().tare_position(); } + +double ProsMotor::position() const { return motor().get_position(); } +float ProsMotor::velocity() const { + float rpm = motor().get_actual_velocity(); + return (rpm / max_rpm()) * constant::kMaxVelocity; +} + +ProsMotorCartridge ProsMotor::cartridge() const { + return ConvertProsGearset(motor().get_gearing()); +} +int ProsMotor::max_rpm() const { return GetMaxRpm(cartridge()); } +} // namespace hardware \ No newline at end of file diff --git a/src/hardware/pros_motor.h b/src/hardware/pros_motor.h new file mode 100644 index 00000000..682f3f99 --- /dev/null +++ b/src/hardware/pros_motor.h @@ -0,0 +1,45 @@ +#pragma once +#include "constant/constants.h" +#include "hardware/pros_motor_cartridge.h" +#include "hardware/pros_motor_definition.h" +#include "interface/encoder.h" +#include "interface/motor.h" +#include "pros.h" + +namespace hardware { +/** + * A class which wraps a single pros::Motor object. + */ +class ProsMotor : public interface::Motor, public interface::Encoder { + public: + ProsMotor(ProsMotorDefinition definition, ProsMotorCartridge cartridge) + : motor_( + definition.GetProsVirtualPortNumber(), + ConvertProsMotorCartridge(cartridge)) {} + + ProsMotor(const ProsMotor&) = delete; + ProsMotor& operator=(const ProsMotor&) = delete; + + ProsMotor(ProsMotor&&) = default; + ProsMotor& operator=(ProsMotor&&) = default; + ~ProsMotor() = default; + + void Move(int) override; + void MoveVoltage(int) override; + void MoveVelocity(float) override; + void MoveAbsolute(double position, int max_velocity) override; + + void ResetEncoder() override; + [[nodiscard]] double position() const override; + [[nodiscard]] float velocity() const override; + + private: + [[nodiscard]] ProsMotorCartridge cartridge() const; + [[nodiscard]] int max_rpm() const; + + [[nodiscard]] inline pros::Motor& motor() { return motor_; } + [[nodiscard]] inline const pros::Motor& motor() const { return motor_; } + + pros::Motor motor_; +}; +} // namespace hardware \ No newline at end of file diff --git a/src/hardware/pros_motor_cartridge.cpp b/src/hardware/pros_motor_cartridge.cpp new file mode 100644 index 00000000..d5ee01d1 --- /dev/null +++ b/src/hardware/pros_motor_cartridge.cpp @@ -0,0 +1,45 @@ +#include "hardware/pros_motor_cartridge.h" + +namespace hardware { +pros::motor_gearset_e_t ConvertProsMotorCartridge( + ProsMotorCartridge cartridge) { + switch (cartridge) { + case ProsMotorCartridge::kBlueCartridge: + return pros::E_MOTOR_GEARSET_06; + case ProsMotorCartridge::kGreenCartridge: + return pros::E_MOTOR_GEARSET_18; + case ProsMotorCartridge::kRedCartridge: + return pros::E_MOTOR_GEARSET_36; + default: + throw std::invalid_argument( + "Failed to convert cartridge to pros gearset."); + } +} + +ProsMotorCartridge ConvertProsGearset(pros::motor_gearset_e_t gearset) { + switch (gearset) { + case pros::E_MOTOR_GEARSET_06: + return ProsMotorCartridge::kBlueCartridge; + case pros::E_MOTOR_GEARSET_18: + return ProsMotorCartridge::kGreenCartridge; + case pros::E_MOTOR_GEARSET_36: + return ProsMotorCartridge::kRedCartridge; + default: + throw std::invalid_argument( + "Failed to convert pros gearset to cartridge."); + } +} + +int GetMaxRpm(ProsMotorCartridge cartridge) { + switch (cartridge) { + case ProsMotorCartridge::kBlueCartridge: + return 600; + case ProsMotorCartridge::kGreenCartridge: + return 200; + case ProsMotorCartridge::kRedCartridge: + return 100; + default: + throw std::invalid_argument("Failed to convert cartridge to max rpm."); + } +} +} \ No newline at end of file diff --git a/src/hardware/pros_motor_cartridge.h b/src/hardware/pros_motor_cartridge.h new file mode 100644 index 00000000..e6817307 --- /dev/null +++ b/src/hardware/pros_motor_cartridge.h @@ -0,0 +1,25 @@ +#pragma once + +#include "pros.h" + +namespace hardware { +enum class ProsMotorCartridge { + // equal to pros value to enable casting + kBlueCartridge = pros::E_MOTOR_GEAR_BLUE, // 600 rpm + kGreenCartridge = pros::E_MOTOR_GEAR_GREEN, // 200 rpm + kRedCartridge = pros::E_MOTOR_GEAR_RED // 100 rpm +}; + +/** + * Converts a ProsMotorCartridge to a pros gearset. + */ +[[nodiscard]] pros::motor_gearset_e_t ConvertProsMotorCartridge( + ProsMotorCartridge); + +/** + * Converts a pros gearset to a ProsMotorCartridge. + */ +[[nodiscard]] ProsMotorCartridge ConvertProsGearset(pros::motor_gearset_e_t); + +[[nodiscard]] int GetMaxRpm(const ProsMotorCartridge); +} // namespace hardware \ No newline at end of file diff --git a/src/hardware/pros_motor_definition.h b/src/hardware/pros_motor_definition.h new file mode 100644 index 00000000..5040b0d5 --- /dev/null +++ b/src/hardware/pros_motor_definition.h @@ -0,0 +1,21 @@ +#pragma once + +namespace hardware { +struct ProsMotorDefinition { + public: + int port_number; + bool reverse; + + ProsMotorDefinition(int port_number, bool reverse) + : port_number(port_number), reverse(reverse) {} + + /** + * Returns the virtual port number which can be consumed by pros::Motor and + * pros::MotorGroup directly. + * @see https://pros.cs.purdue.edu/v5/api/cpp/motors.html#constructor-s + */ + inline int GetProsVirtualPortNumber() { + return port_number * (reverse ? -1 : 1); + } +}; +} // namespace hardware \ No newline at end of file diff --git a/src/hardware/pros_motor_group.cpp b/src/hardware/pros_motor_group.cpp new file mode 100644 index 00000000..965673f1 --- /dev/null +++ b/src/hardware/pros_motor_group.cpp @@ -0,0 +1,44 @@ +#include "hardware/pros_motor_group.h" + +namespace hardware { +void ProsMotorGroup::Move(int value) { motors().move(value); } +void ProsMotorGroup::MoveVoltage(int voltage) { + motors().move_voltage(voltage); +} +void ProsMotorGroup::MoveVelocity(float velocity) { + float rpm = (velocity / constant::kMaxVelocity) * max_rpm(); + motors().move_velocity(rpm); +} +void ProsMotorGroup::MoveAbsolute(double position, int max_velocity) { + motors().move_absolute(position, max_velocity); +} +void ProsMotorGroup::ResetEncoder() { motors().tare_position(); } + +double ProsMotorGroup::position() const { + // manual member access to avoid automatically calling const motors() + std::vector positions = motors().get_positions(); + return std::reduce(positions.begin(), positions.end()) / positions.size(); +} +float ProsMotorGroup::velocity() const { + std::vector motor_rpms = motors().get_actual_velocities(); + float rpm = + std::reduce(motor_rpms.cbegin(), motor_rpms.cend()) / motor_rpms.size(); + return (rpm / max_rpm()) * constant::kMaxVelocity; +} + +std::vector ProsMotorGroup::ExtractVirtualPortNumbers( + std::vector definitions) { + std::vector result; + std::transform( + definitions.cbegin(), definitions.cend(), std::back_inserter(result), + [](ProsMotorDefinition definition) { + return static_cast(definition.GetProsVirtualPortNumber()); + }); + return result; +} + +ProsMotorCartridge ProsMotorGroup::cartridge() const { + return ConvertProsGearset(motors()[0].get_gearing()); +} +int ProsMotorGroup::max_rpm() const { return GetMaxRpm(cartridge()); } +} // namespace hardware \ No newline at end of file diff --git a/src/hardware/pros_motor_group.h b/src/hardware/pros_motor_group.h new file mode 100644 index 00000000..57aed812 --- /dev/null +++ b/src/hardware/pros_motor_group.h @@ -0,0 +1,61 @@ +#pragma once +#include +#include +#include +#include + +#include "constant/constants.h" +#include "hardware/pros_motor.h" +#include "hardware/pros_motor_cartridge.h" +#include "hardware/pros_motor_definition.h" +#include "interface/encoder.h" +#include "interface/motor.h" +#include "pros.h" + +namespace hardware { +class ProsMotorGroup : public interface::Motor, public interface::Encoder { + public: + ProsMotorGroup( + std::vector definitions, + ProsMotorCartridge cartridge) + : motors_(ExtractVirtualPortNumbers(definitions)) { + motors().set_gearing(static_cast(cartridge)); + } + + ProsMotorGroup(const ProsMotorGroup&) = delete; + ProsMotorGroup& operator=(const ProsMotorGroup&) = delete; + + ProsMotorGroup(ProsMotorGroup&&) = default; + ProsMotorGroup& operator=(ProsMotorGroup&&) = default; + ~ProsMotorGroup() = default; + + void Move(int) override; + void MoveVoltage(int) override; + void MoveVelocity(float) override; + void MoveAbsolute(double position, int max_velocity) override; + + void ResetEncoder() override; + [[nodiscard]] double position() const override; + [[nodiscard]] float velocity() const override; + + private: + [[nodiscard]] ProsMotorCartridge cartridge() const; + [[nodiscard]] int max_rpm() const; + + /** + * Extracts the virtual port numbers of each ProsMotorDefintion in + * definitions. + */ + [[nodiscard]] std::vector ExtractVirtualPortNumbers( + std::vector definitions); + // [[nodiscard]] std::vector FlipPortNumbers( + // std::vector port_numbers, std::vector reverse); + + [[nodiscard]] inline pros::MotorGroup& motors() const { return motors_; } + [[nodiscard]] inline pros::MotorGroup& motors() { return motors_; } + + // mutable to prevent issues with const methods since + // Some pros methods are missing const annotations + mutable pros::MotorGroup motors_; +}; +} // namespace hardware \ No newline at end of file diff --git a/src/interface/controller.h b/src/interface/controller.h new file mode 100644 index 00000000..b90afda2 --- /dev/null +++ b/src/interface/controller.h @@ -0,0 +1,31 @@ +#pragma once +namespace interface { +enum class ControllerJoystick { kLeftX, kLeftY, kRightX, kRightY }; + +enum class ControllerButton { + kA, + kX, + kY, + kB, + kLeftBumper, + kRightBumper, + kUp, + kDown, + kLeft, + kRight +}; // last four variables refer to the d-pad + +enum class ControllerTrigger { kLeft, kRight }; // refers to triggers + +class Controller { + public: + [[nodiscard]] virtual int GetJoystickAnalog( + ControllerJoystick joystick) const = 0; + [[nodiscard]] virtual float GetJoystickVoltage( + ControllerJoystick joystick) const = 0; + [[nodiscard]] virtual bool GetButton(ControllerButton button) const = 0; + [[nodiscard]] virtual float GetTrigger(ControllerTrigger trigger) const = 0; + + virtual ~Controller() = default; +}; +} // namespace interface \ No newline at end of file diff --git a/src/interface/encoder.h b/src/interface/encoder.h new file mode 100644 index 00000000..ab1f4daf --- /dev/null +++ b/src/interface/encoder.h @@ -0,0 +1,12 @@ +#pragma once + +namespace interface { +class Encoder { + public: + virtual void ResetEncoder() = 0; + [[nodiscard]] virtual double position() const = 0; + [[nodiscard]] virtual float velocity() const = 0; + + virtual ~Encoder() = default; +}; +} // namespace interface \ No newline at end of file diff --git a/src/interface/holonomic-drive.h b/src/interface/holonomic-drive.h new file mode 100644 index 00000000..83b128d3 --- /dev/null +++ b/src/interface/holonomic-drive.h @@ -0,0 +1,9 @@ +#pragma once + +namespace interface { + +class HolonomicDrivetrain { + public: +}; + +} // namespace interface \ No newline at end of file diff --git a/src/interface/motor.h b/src/interface/motor.h new file mode 100644 index 00000000..b418f857 --- /dev/null +++ b/src/interface/motor.h @@ -0,0 +1,13 @@ +#pragma once + +namespace interface { +class Motor { + public: + virtual void Move(int) = 0; + virtual void MoveVoltage(int) = 0; + virtual void MoveVelocity(float) = 0; + virtual void MoveAbsolute(double position, int max_velocity) = 0; + + virtual ~Motor() = default; +}; +} // namespace interface \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 00000000..2807121b --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,101 @@ +#include "main.h" + +/** + * When this callback is fired, it will toggle line 2 of the LCD text between + * "I was pressed!" and nothing. + */ +void on_center_button() { + static bool pressed = false; + pressed = !pressed; + if (pressed) { + pros::lcd::set_text(2, "I was pressed!"); + } else { + pros::lcd::clear_line(2); + } +} + +/** + * Runs initialization code. This occurs as soon as the program is started. + * + * All other competition modes are blocked by initialize; it is recommended + * to keep execution time for this mode under a few seconds. + */ +void initialize() { + // pros::lcd::initialize(); + // pros::lcd::set_text(1, "Hello PROS User!"); + + // pros::lcd::register_btn1_cb(on_center_button); +} + +/** + * Runs while the robot is in the disabled state of Field Management System or + * the VEX Competition Switch, following either autonomous or opcontrol. When + * the robot is enabled, this task will exit. + */ +void disabled() {} + +/** + * Runs after initialize(), and before autonomous when connected to the Field + * Management System or the VEX Competition Switch. This is intended for + * competition-specific initialization routines, such as an autonomous selector + * on the LCD. + * + * This task will exit when the robot is enabled and autonomous or opcontrol + * starts. + */ +void competition_initialize() {} + +/** + * Runs the user autonomous code. This function will be started in its own task + * with the default priority and stack size whenever the robot is enabled via + * the Field Management System or the VEX Competition Switch in the autonomous + * mode. Alternatively, this function may be called in initialize or opcontrol + * for non-competition testing purposes. + * + * If the robot is disabled or communications is lost, the autonomous task + * will be stopped. Re-enabling the robot will restart the task, not re-start it + * from where it left off. + */ +void autonomous() {} + +/** + * Runs the operator control code. This function will be started in its own task + * with the default priority and stack size whenever the robot is enabled via + * the Field Management System or the VEX Competition Switch in the operator + * control mode. + * + * If no competition control is connected, this function will run immediately + * following initialize(). + * + * If the robot is disabled or communications is lost, the + * operator control task will be stopped. Re-enabling the robot will restart the + * task, not resume it from where it left off. + */ +void opcontrol() { + std::unique_ptr driver_controller_ptr = hardware::ProsController::MakeDriverController(); + + std::unique_ptr tank_drive_ptr = drivetrain::MakeTankDrive({ + constant::kLeftDrivetrain, + constant::kRightDrivetrain + }) + + // auto drivetrain = drivetrain::HolonomicDirectDrivetrain(); + // while (true) { drivetrain.Drive(*driver_controller_ptr); } + + // pros::Controller master(pros::E_CONTROLLER_MASTER); + // pros::Motor left_mtr(1); + // pros::Motor right_mtr(2); + + // while (true) { + // pros::lcd::print(0, "%d %d %d", (pros::lcd::read_buttons() & + // LCD_BTN_LEFT) >> 2, (pros::lcd::read_buttons() & + // LCD_BTN_CENTER) >> 1, (pros::lcd::read_buttons() & + // LCD_BTN_RIGHT) >> 0); int left = master.get_analog(ANALOG_LEFT_Y); + // int right = master.get_analog(ANALOG_RIGHT_Y); + + // left_mtr = left; + // right_mtr = right; + + // pros::delay(20); + // } +} diff --git a/src/main.h b/src/main.h new file mode 100644 index 00000000..3cfef46c --- /dev/null +++ b/src/main.h @@ -0,0 +1,10 @@ +#pragma once +#include "drivetrain/holonomic_drive.h" +#include "hardware/pros_controller.h" +#include "pros.h" + +void autonomous(void); +void initialize(void); +void disabled(void); +void competition_initialize(void); +void opcontrol(void); \ No newline at end of file diff --git a/startup/start-ros.sh b/startup/start-ros.sh new file mode 100755 index 00000000..b8a3ccb7 --- /dev/null +++ b/startup/start-ros.sh @@ -0,0 +1,5 @@ +#!/bin/bash +echo "Starting ROS..." +cd /home/ubuntu/ChangeUp +source ./devel/setup.bash +roslaunch change_up_driver_control 15_inch_robot.launch