├── .clang-format ├── .github ├── issue_template.md └── workflows │ ├── ccpp.yml │ ├── documentation.yml │ └── examples.yaml ├── .gitignore ├── .vscode ├── settings.json └── tasks.json ├── CMakeLists.txt ├── CMakePresets.json ├── LICENSE ├── README.md ├── cmake └── Warnings.cmake ├── docs └── extra │ └── boards.txt.example ├── doxygen ├── Doxyfile ├── DoxygenLayout.xml ├── custom_stylesheet.css ├── header.html ├── images │ ├── .gitkeep │ ├── Screenshot-Arduino-IDE-Debug.png │ └── increase-bit-depth.svg ├── pages │ └── Debug.md └── scripts │ └── examples.py ├── examples ├── .clang-format ├── Arduino-Helpers │ ├── Debug │ │ └── Debug │ │ │ └── Debug.ino │ ├── Hardware │ │ ├── 1.FilteredAnalog-Advanced │ │ │ └── 1.FilteredAnalog-Advanced.ino │ │ ├── 1.FilteredAnalog │ │ │ └── 1.FilteredAnalog.ino │ │ ├── 2.Button │ │ │ └── 2.Button.ino │ │ ├── 3.MultiPurposeButton │ │ │ └── 3.MultiPurposeButton.ino │ │ ├── Blink-Frequency-Buttons │ │ │ └── Blink-Frequency-Buttons.ino │ │ ├── Extended Input & Output │ │ │ ├── 1. Input │ │ │ │ └── 1. Multiplexers │ │ │ │ │ ├── 1.AnalogReadSerial │ │ │ │ │ └── 1.AnalogReadSerial.ino │ │ │ │ │ ├── 2.DigitalReadSerial │ │ │ │ │ └── 2.DigitalReadSerial.ino │ │ │ │ │ └── 3.FilteredAnalogReadSerial │ │ │ │ │ └── 3.FilteredAnalogReadSerial.ino │ │ │ ├── 2. Output │ │ │ │ ├── 1. Shift Registers │ │ │ │ │ ├── 1.SPI-Blink │ │ │ │ │ │ └── 1.SPI-Blink.ino │ │ │ │ │ ├── 2.BitBang-Blink │ │ │ │ │ │ └── 2.BitBang-Blink.ino │ │ │ │ │ └── 2.RGB-LED-Chaser │ │ │ │ │ │ └── 2.RGB-LED-Chaser.ino │ │ │ │ └── 2. MAX7219 │ │ │ │ │ └── 1.MAX7219-Blink │ │ │ │ │ └── 1.MAX7219-Blink.ino │ │ │ └── 3. In&Out │ │ │ │ ├── MCP23017 │ │ │ │ └── MCP23017.ino │ │ │ │ └── Toggle-LEDs │ │ │ │ └── Toggle-LEDs.ino │ │ ├── MCP23017-Encoders │ │ │ ├── MCP23017-Encoders-Interrupts │ │ │ │ └── MCP23017-Encoders-Interrupts.ino │ │ │ └── MCP23017-Encoders-No-Interrupts │ │ │ │ └── MCP23017-Encoders-No-Interrupts.ino │ │ ├── Pin-Change-Interrupt-Encoders │ │ │ └── Pin-Change-Interrupt-Encoders.ino │ │ └── Timer-Interrupt-Encoders │ │ │ ├── Timer-Interrupt-Encoders.ino │ │ │ └── TimerHelpers.hpp │ ├── Math │ │ └── Quaternion │ │ │ └── Quaternion.ino │ ├── STL │ │ ├── ArraySort │ │ │ └── ArraySort.ino │ │ ├── Complex │ │ │ └── Complex.ino │ │ ├── CountPressedButtons │ │ │ └── CountPressedButtons.ino │ │ └── Numeric │ │ │ └── Numeric.ino │ └── Timing │ │ └── BlinkWithoutDelay-Timer │ │ └── BlinkWithoutDelay-Timer.ino ├── examples.dox └── test │ ├── ExtIO-pin-test │ └── ExtIO-pin-test.ino │ └── STL-test │ ├── STL-test.cpp │ └── STL-test.ino ├── keywords.txt ├── library.properties ├── mock ├── CMakeLists.txt ├── Core-Libraries │ └── SPI.h ├── Core │ ├── Arduino.cpp │ ├── Arduino.h │ ├── ArduinoMock.cpp │ ├── ArduinoMock.hpp │ ├── HardwareSerial.h │ ├── HardwareSerial0.cpp │ ├── Print.cpp │ ├── Print.h │ ├── Printable.h │ ├── Stream.h │ └── binary.h ├── Libraries │ ├── Adafruit_GFX │ │ ├── Adafruit_GFX.h │ │ └── gfxfont.h │ ├── Adafruit_SSD1306 │ │ └── Adafruit_SSD1306.h │ └── Encoder │ │ └── Encoder.h └── README.md ├── scripts ├── addImplementationFiles.py ├── ci │ ├── gen-docs.sh │ ├── install-doxygen.sh │ └── install-lcov.sh ├── coverage-badge.py ├── coverage.sh ├── git-pull-arduino-helpers.sh ├── install-ci.sh ├── install-gtest.sh ├── keywords.py └── listNonEmptyImplementationFiles.py ├── src ├── AH │ ├── Arduino-Wrapper.h │ ├── CMakeLists.txt │ ├── Containers │ │ ├── Array.hpp │ │ ├── ArrayHelpers.hpp │ │ ├── BitArray.hpp │ │ ├── CRTP.hpp │ │ ├── Containers.dox │ │ ├── LinkedList.hpp │ │ ├── Updatable.hpp │ │ └── keywords.yml │ ├── Debug │ │ ├── Debug.cpp │ │ ├── Debug.dox │ │ ├── Debug.hpp │ │ └── DebugVal.hpp │ ├── Error │ │ ├── Error.dox │ │ ├── Error.hpp │ │ └── Exit.cpp │ ├── Filters │ │ ├── EMA.hpp │ │ ├── Filters.dox │ │ ├── Hysteresis.hpp │ │ └── keywords.yml │ ├── Hardware │ │ ├── ADCConfig.hpp │ │ ├── Arduino-Hardware-Types.hpp │ │ ├── Button.cpp │ │ ├── Button.hpp │ │ ├── ButtonMatrix.hpp │ │ ├── ButtonMatrix.ipp │ │ ├── ExtendedInputOutput │ │ │ ├── AnalogMultiplex.hpp │ │ │ ├── ExtIO.dox │ │ │ ├── ExtendedIOElement.cpp │ │ │ ├── ExtendedIOElement.hpp │ │ │ ├── ExtendedInputOutput.cpp │ │ │ ├── ExtendedInputOutput.hpp │ │ │ ├── MAX7219.hpp │ │ │ ├── MCP23017.hpp │ │ │ ├── MCP23017.ipp │ │ │ ├── SPIShiftRegisterOut.hpp │ │ │ ├── SPIShiftRegisterOut.ipp │ │ │ ├── ShiftRegisterOut.hpp │ │ │ ├── ShiftRegisterOut.ipp │ │ │ ├── ShiftRegisterOutBase.hpp │ │ │ ├── ShiftRegisterOutBase.ipp │ │ │ ├── ShiftRegisterOutRGB.cpp │ │ │ ├── ShiftRegisterOutRGB.hpp │ │ │ ├── StaticSizeExtendedIOElement.hpp │ │ │ └── keywords.yml │ │ ├── FilteredAnalog.hpp │ │ ├── Hardware-Types.hpp │ │ ├── Hardware.dox │ │ ├── IncrementButton.cpp │ │ ├── IncrementButton.hpp │ │ ├── IncrementDecrementButtons.cpp │ │ ├── IncrementDecrementButtons.hpp │ │ ├── LEDs │ │ │ ├── DotBarDisplayLEDs.hpp │ │ │ ├── LEDs.hpp │ │ │ ├── MAX7219SevenSegmentDisplay.hpp │ │ │ ├── MAX7219_Base.hpp │ │ │ └── keywords.yml │ │ ├── MCP23017Encoders.hpp │ │ ├── MultiPurposeButton.hpp │ │ ├── RegisterEncoders.hpp │ │ └── keywords.yml │ ├── Math │ │ ├── Degrees.hpp │ │ ├── Divide.hpp │ │ ├── FixArduinoMacros.hpp │ │ ├── IncreaseBitDepth.hpp │ │ ├── Math.dox │ │ ├── MinMaxFix.hpp │ │ ├── Quaternion.cpp │ │ ├── Quaternion.hpp │ │ ├── Vector.cpp │ │ ├── Vector.hpp │ │ └── keywords.yml │ ├── PrintStream │ │ ├── PrintStream.cpp │ │ ├── PrintStream.dox │ │ └── PrintStream.hpp │ ├── STL │ │ ├── Fallback │ │ │ ├── algorithm │ │ │ ├── array │ │ │ ├── backward │ │ │ │ └── binders.h │ │ │ ├── bits │ │ │ │ ├── algorithmfwd.h │ │ │ │ ├── alloc_traits.h │ │ │ │ ├── allocator.h │ │ │ │ ├── boost_concept_check.h │ │ │ │ ├── c++0x_warning.h │ │ │ │ ├── c++allocator.h │ │ │ │ ├── c++config.h │ │ │ │ ├── concept_check.h │ │ │ │ ├── cpp_type_traits.h │ │ │ │ ├── cpu_defines.h │ │ │ │ ├── enable_special_members.h │ │ │ │ ├── exception_defines.h │ │ │ │ ├── functexcept.h │ │ │ │ ├── functional_hash.h │ │ │ │ ├── hash_bytes.h │ │ │ │ ├── invoke.h │ │ │ │ ├── memoryfwd.h │ │ │ │ ├── move.h │ │ │ │ ├── os_defines.h │ │ │ │ ├── predefined_ops.h │ │ │ │ ├── ptr_traits.h │ │ │ │ ├── range_access.h │ │ │ │ ├── std_abs.h │ │ │ │ ├── stl_algo.h │ │ │ │ ├── stl_algobase.h │ │ │ │ ├── stl_bvector.h │ │ │ │ ├── stl_construct.h │ │ │ │ ├── stl_function.h │ │ │ │ ├── stl_heap.h │ │ │ │ ├── stl_iterator.h │ │ │ │ ├── stl_iterator_base_funcs.h │ │ │ │ ├── stl_iterator_base_types.h │ │ │ │ ├── stl_numeric.h │ │ │ │ ├── stl_pair.h │ │ │ │ ├── stl_relops.h │ │ │ │ ├── stl_tempbuf.h │ │ │ │ ├── stl_uninitialized.h │ │ │ │ ├── stl_vector.h │ │ │ │ ├── uniform_int_dist.h │ │ │ │ ├── unique_ptr.h │ │ │ │ ├── uses_allocator.h │ │ │ │ └── vector.tcc │ │ │ ├── bitset │ │ │ ├── climits │ │ │ ├── cmath │ │ │ ├── complex │ │ │ ├── cstddef │ │ │ ├── cstdint │ │ │ ├── cstdlib │ │ │ ├── debug │ │ │ │ ├── assertions.h │ │ │ │ └── debug.h │ │ │ ├── ext │ │ │ │ ├── alloc_traits.h │ │ │ │ ├── new_allocator.h │ │ │ │ ├── numeric_traits.h │ │ │ │ └── type_traits.h │ │ │ ├── initializer_list │ │ │ ├── iterator │ │ │ ├── limits │ │ │ ├── memory │ │ │ ├── new │ │ │ ├── new.cpp │ │ │ ├── numeric │ │ │ ├── optional │ │ │ ├── tuple │ │ │ ├── type_traits │ │ │ ├── utility │ │ │ └── vector │ │ ├── README.md │ │ ├── algorithm │ │ ├── array │ │ ├── bitset │ │ ├── climits │ │ ├── cmath │ │ ├── complex │ │ ├── cstddef │ │ ├── cstdint │ │ ├── cstdlib │ │ ├── initializer_list │ │ ├── iterator │ │ ├── limits │ │ ├── memory │ │ ├── new │ │ ├── numeric │ │ ├── optional │ │ ├── tuple │ │ ├── type_traits │ │ ├── utility │ │ ├── vector │ │ └── vector.cpp │ ├── Settings │ │ ├── NamespaceSettings.hpp │ │ ├── Settings.dox │ │ ├── Settings.hpp │ │ ├── SettingsWrapper.hpp │ │ └── Warnings.hpp │ ├── Teensy │ │ └── TeensyUSBTypes.hpp │ ├── Timing │ │ ├── MillisMicrosTimer.hpp │ │ ├── Timing.dox │ │ └── keywords.yml │ └── Types │ │ ├── Frequency.hpp │ │ ├── FunctionTraits.hpp │ │ └── keywords.yml ├── Arduino_Helpers.dox ├── Arduino_Helpers.h ├── CMakeLists.txt └── keywords.yml ├── test ├── AH │ ├── Containers │ │ ├── test-Array.cpp │ │ ├── test-DoublyLinkedList.cpp │ │ ├── test-Updatable.cpp │ │ └── tests-BitArray.cpp │ ├── Filters │ │ ├── test-EMA.cpp │ │ ├── test-EMA.py │ │ ├── test-EMA_f.py │ │ └── test-Hysteresis.cpp │ ├── Hardware │ │ ├── ExtendedInputOutput │ │ │ ├── test-AnalogMultiplex.cpp │ │ │ └── test-ExtendedInputOutput.cpp │ │ ├── test-Button.cpp │ │ ├── test-FilteredAnalog.cpp │ │ ├── test-IncrementButton.cpp │ │ └── test-IncrementDecrementButtons.cpp │ ├── Math │ │ ├── test-Degrees.cpp │ │ ├── test-IncreaseBitDepth.cpp │ │ ├── test-Quaternion.cpp │ │ └── test-Vector.cpp │ ├── PrintStream │ │ └── test-PrintStream.cpp │ └── Timing │ │ └── test-Timer.cpp ├── CMakeLists.txt ├── examples-board-fqbns.yaml ├── test-main.cpp └── test_example.cpp └── tools ├── arduino-cli.yaml └── arduino-example-builder.py /.github/issue_template.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tttapa/Arduino-Helpers/00f463b534fbea22f0b596e091a60715679e3064/.github/issue_template.md -------------------------------------------------------------------------------- /.github/workflows/ccpp.yml: -------------------------------------------------------------------------------- 1 | name: CI Tests 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v3 12 | - name: Install dependencies 13 | run: sudo ./scripts/install-gtest.sh Debug /usr/local 14 | - name: Configure 15 | run: cmake -S. --preset ci 16 | - name: Build 17 | run: cmake --build --preset ci -j 18 | - name: Test 19 | run: ctest --preset ci 20 | -------------------------------------------------------------------------------- /.github/workflows/documentation.yml: -------------------------------------------------------------------------------- 1 | # This action generates the documentation and then deploys it to the `gh-pages` branch. 2 | 3 | name: Documentation & Coverage 4 | 5 | on: 6 | push: 7 | 8 | jobs: 9 | deploy-docs: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v3 14 | 15 | # Cache the doxygen executable, lcov 16 | - uses: actions/cache@v3 17 | id: cache-tools 18 | with: 19 | path: | 20 | /tmp/doxygen 21 | /tmp/lcov 22 | /tmp/gtest 23 | key: ${{ runner.os }}-doc-${{ hashFiles('scripts/ci/install-doxygen.sh', 'scripts/ci/install-lcov.sh', 'scripts/install-gtest.sh') }} 24 | 25 | - name: Install Graphviz/Dot and LCOV Perl dependencies, as well as TeX Live 26 | run: | 27 | sudo apt-get update 28 | sudo apt-get install \ 29 | graphviz libjson-perl libperlio-gzip-perl perl \ 30 | texlive-binaries 31 | 32 | - name: Install LCOV 33 | run: | 34 | ./scripts/ci/install-lcov.sh /tmp/lcov 35 | echo "/tmp/lcov/bin" >> $GITHUB_PATH 36 | 37 | # Download and build doxygen (if not cached already) 38 | - name: Install Doxygen 39 | run: | 40 | ./scripts/ci/install-doxygen.sh /tmp/doxygen 41 | echo "/tmp/doxygen/bin" >> $GITHUB_PATH 42 | 43 | - name: Install Google Test 44 | if: steps.cache-tools.outputs.cache-hit != 'true' 45 | shell: bash 46 | run: ./scripts/install-gtest.sh Debug /tmp/gtest 47 | 48 | # Install Python 49 | - uses: actions/setup-python@v4 50 | with: 51 | python-version: '3.9' 52 | 53 | # Create the `gh-pages` branch if it doesn't exist already, check it out, 54 | # and copy it to /tmp/staging. 55 | - name: Create staging area 56 | run: | 57 | rm -rf /tmp/staging 58 | git fetch origin gh-pages:gh-pages ||: 59 | git checkout gh-pages || \ 60 | { git checkout --orphan gh-pages && git rm -rf . && git clean -fxd ; } 61 | cp -ar $GITHUB_WORKSPACE/ /tmp/staging 62 | git checkout ${GITHUB_REF##*/} 63 | git submodule update --init --recursive 64 | 65 | # Generate the documentation and save it in /tmp/staging 66 | - name: Generate documentation 67 | run: ./scripts/ci/gen-docs.sh /tmp/staging 68 | env: 69 | CMAKE_PREFIX_PATH: /tmp/gtest 70 | 71 | # Commit the new documentation, squash the commits, and push it to GitHub 72 | - name: Commit and push documention 73 | run: | 74 | git config --global user.name "github-actions" 75 | git config --global user.email "actions@github.com" 76 | commithash=$(git rev-parse HEAD) 77 | cd /tmp/staging 78 | git add . 79 | git commit -m "Documentation for ${commithash}" && \ 80 | git reset $(git commit-tree HEAD^{tree} -m "Documentation for ${commithash}") && \ 81 | git push -f origin gh-pages ||: 82 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # .vscode/ 2 | .vscode/tags 3 | *.pc 4 | .vscode/ipch 5 | .cache 6 | 7 | .~lock* 8 | __pycache__/ 9 | 10 | *.tmp 11 | *.hex 12 | 13 | build 14 | docs/Coverage 15 | docs/Doxygen -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.axbm": "cpp", 4 | "*.ipp": "cpp", 5 | "*.tcc": "cpp", 6 | "*.dox": "cpp" 7 | }, 8 | "editor.minimap.maxColumn": 80, 9 | "editor.minimap.renderCharacters": false, 10 | "editor.rulers": [ 11 | 80 12 | ], 13 | "editor.renderControlCharacters": true, 14 | "editor.renderWhitespace": "boundary", 15 | "files.defaultLanguage": "cpp", 16 | "files.trimFinalNewlines": true, 17 | "files.trimTrailingWhitespace": false, 18 | "search.exclude": { 19 | "**/node_modules": true, 20 | "**/googletest": true, 21 | "**/*.old": true, 22 | "**/docs/Doxygen": true, 23 | "**/docs/Coverage": true 24 | }, 25 | "cmake.useCMakePresets": "always", 26 | "cmake.copyCompileCommands": "${workspaceFolder}/build/compile_commands.json", 27 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "shell", 8 | "label": "Build examples", 9 | "command": "python3 arduino-example-builder.py 'AVR'", 10 | "problemMatcher": "$gcc", 11 | "options": { 12 | "cwd": "${workspaceFolder}/tools", 13 | }, 14 | "group": "build", 15 | }, 16 | ] 17 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | project(Arduino-Helpers CXX) 3 | set(CMAKE_CXX_STANDARD 14) 4 | enable_testing() 5 | 6 | # Add coverage target 7 | option(AH_WITH_COVERAGE 8 | "Generate coverage information." Off) 9 | if (AH_WITH_COVERAGE) 10 | add_custom_target(coverage 11 | ${CMAKE_CURRENT_LIST_DIR}/scripts/coverage.sh 12 | ${CMAKE_CXX_COMPILER_ID} 13 | ${CMAKE_CXX_COMPILER_VERSION} 14 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) 15 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage -fno-inline") 16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -fno-inline") 17 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage") 18 | add_dependencies(coverage Arduino-Helpers::tests) 19 | endif() 20 | 21 | # Add documentation target 22 | find_package(Doxygen) 23 | find_package(Python3 COMPONENTS Interpreter) 24 | if (DOXYGEN_FOUND AND Python3_Interpreter_FOUND) 25 | # Add example documentation target 26 | add_custom_target(examples-doxygen 27 | Python3::Interpreter ${CMAKE_CURRENT_LIST_DIR}/doxygen/scripts/examples.py 28 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/doxygen) 29 | # Add documentation target 30 | add_custom_target(documentation 31 | Doxygen::doxygen 32 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/doxygen 33 | DEPENDS examples-doxygen) 34 | endif() 35 | 36 | # Compiler warnings 37 | option(AH_WARNINGS_AS_ERRORS "Enable -Werror" On) 38 | include(cmake/Warnings.cmake) 39 | 40 | # Build the source files and tests 41 | add_subdirectory(mock) 42 | add_subdirectory(src) 43 | add_subdirectory(test) 44 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 4, 3 | "cmakeMinimumRequired": { 4 | "major": 3, 5 | "minor": 18, 6 | "patch": 0 7 | }, 8 | "configurePresets": [ 9 | { 10 | "name": "dev", 11 | "displayName": "Development", 12 | "description": "", 13 | "generator": "Ninja Multi-Config", 14 | "binaryDir": "${sourceDir}/build/${presetName}", 15 | "cacheVariables": { 16 | "AH_WARNINGS_AS_ERRORS": true, 17 | "AH_WITH_COVERAGE": true, 18 | "CMAKE_CXX_COMPILER_LAUNCHER": "ccache", 19 | "CMAKE_CXX_FLAGS": "-fsanitize=address,leak,undefined,pointer-compare,pointer-subtract", 20 | "CMAKE_EXPORT_COMPILE_COMMANDS": true 21 | } 22 | }, 23 | { 24 | "name": "ci", 25 | "displayName": "CI", 26 | "description": "", 27 | "binaryDir": "${sourceDir}/build/${presetName}", 28 | "cacheVariables": { 29 | "AH_WARNINGS_AS_ERRORS": true, 30 | "AH_WITH_COVERAGE": false, 31 | "CMAKE_CXX_FLAGS": "-fsanitize=address,leak,undefined,pointer-compare,pointer-subtract" 32 | } 33 | }, 34 | { 35 | "name": "ci-cov", 36 | "displayName": "CI + Coverage", 37 | "description": "", 38 | "binaryDir": "${sourceDir}/build/${presetName}", 39 | "cacheVariables": { 40 | "AH_WARNINGS_AS_ERRORS": false, 41 | "AH_WITH_COVERAGE": true, 42 | "CMAKE_CXX_FLAGS": "-fsanitize=address,leak,undefined,pointer-compare,pointer-subtract" 43 | } 44 | } 45 | ], 46 | "buildPresets": [ 47 | { 48 | "name": "dev", 49 | "displayName": "Development", 50 | "configurePreset": "dev" 51 | }, 52 | { 53 | "name": "ci", 54 | "displayName": "CI", 55 | "configurePreset": "ci" 56 | }, 57 | { 58 | "name": "ci-cov", 59 | "displayName": "CI + Coverage", 60 | "configurePreset": "ci-cov" 61 | } 62 | ], 63 | "testPresets": [ 64 | { 65 | "name": "dev", 66 | "displayName": "Development", 67 | "configurePreset": "dev", 68 | "output": { 69 | "outputOnFailure": true 70 | } 71 | }, 72 | { 73 | "name": "ci", 74 | "displayName": "CI", 75 | "configurePreset": "ci", 76 | "output": { 77 | "outputOnFailure": true 78 | } 79 | }, 80 | { 81 | "name": "ci-cov", 82 | "displayName": "CI + Coverage", 83 | "configurePreset": "ci-cov", 84 | "output": { 85 | "outputOnFailure": true 86 | } 87 | } 88 | ] 89 | } -------------------------------------------------------------------------------- /cmake/Warnings.cmake: -------------------------------------------------------------------------------- 1 | set(COMMON_WARNINGS 2 | -fdiagnostics-show-option 3 | -Wall 4 | -Wextra 5 | -pedantic 6 | -Wpedantic 7 | -pedantic-errors 8 | -Wdouble-promotion 9 | -Wswitch-default 10 | -Wswitch-enum 11 | -Wimplicit-fallthrough 12 | -Wuninitialized 13 | -Wno-missing-braces 14 | ) 15 | set(GCC_WARNINGS 16 | -Wno-error=unused-but-set-variable 17 | -Wsuggest-override 18 | -Wno-error=attributes 19 | ) 20 | set(CLANG_WARNINGS 21 | -Wno-error=unknown-warning-option 22 | -Wno-newline-eof 23 | -Wno-error=unused-but-set-variable 24 | -Winconsistent-missing-override 25 | -Wno-gnu-zero-variadic-macro-arguments 26 | ) 27 | set(MSVC_WARNINGS 28 | /W4 29 | /wd4127 # conditional expression is constant 30 | /wd4458 # declaration of 'x' hides class member 31 | /permissive- 32 | ) 33 | set(INTEL_WARNINGS 34 | -Wall 35 | -Wextra 36 | ) 37 | if (AH_WARNINGS_AS_ERRORS) 38 | if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") 39 | list(APPEND MSVC_WARNINGS /WX) 40 | else() 41 | list(APPEND COMMON_WARNINGS -Werror) 42 | endif() 43 | endif() 44 | 45 | add_library(warnings INTERFACE) 46 | 47 | if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") 48 | target_compile_options(warnings INTERFACE 49 | ${COMMON_WARNINGS} ${GCC_WARNINGS}) 50 | elseif (CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") 51 | target_compile_options(warnings INTERFACE 52 | ${COMMON_WARNINGS} ${CLANG_WARNINGS}) 53 | elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") 54 | target_compile_options(warnings INTERFACE 55 | ${MSVC_WARNINGS}) 56 | elseif (CMAKE_CXX_COMPILER_ID MATCHES "Intel") 57 | target_compile_options(warnings INTERFACE 58 | ${INTEL_WARNINGS}) 59 | else() 60 | message(WARNING "No known warnings for this compiler") 61 | endif() 62 | add_library(Arduino-Helpers::warnings ALIAS warnings) 63 | 64 | set(CMAKE_DEBUG_POSTFIX "d") 65 | -------------------------------------------------------------------------------- /doxygen/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | $projectname: $title 10 | $title 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | $treeview 20 | $search 21 | $mathjax 22 | 23 | 24 | $extrastylesheet 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 |
34 | 35 | 36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 49 | 50 | 51 | 52 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 |
45 |
$projectname $projectnumber 46 |
47 |
$projectbrief
48 |
53 |
$projectbrief
54 |
$searchbox
$searchbox
72 |
73 | 74 | 75 | -------------------------------------------------------------------------------- /doxygen/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tttapa/Arduino-Helpers/00f463b534fbea22f0b596e091a60715679e3064/doxygen/images/.gitkeep -------------------------------------------------------------------------------- /doxygen/images/Screenshot-Arduino-IDE-Debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tttapa/Arduino-Helpers/00f463b534fbea22f0b596e091a60715679e3064/doxygen/images/Screenshot-Arduino-IDE-Debug.png -------------------------------------------------------------------------------- /doxygen/pages/Debug.md: -------------------------------------------------------------------------------- 1 | # Debug {#md_pages_Debug} 2 | 3 | @see Module @ref AH_Debug for more information. 4 | @see @ref Debug.ino "examples/Arduino-Helpers/Debug" for example usage. 5 | 6 | ## Adding a 'Debug' menu in the Arduino IDE 7 | 8 | If you are going to be debugging a lot, it might be useful to just add a menu 9 | option in the IDE to disable/enable debugging. 10 | This can be done relatively easily by editing the `boards.txt` file. 11 | 12 | Open the `boards.txt` file of the board you are using. If you're using version 13 | 1.8.x of the Arduino IDE, it'll be located in 14 | `~/.arduino15/packages//hardware///` or 15 | `C:\users\\AppData\Local\Arduino15\packages\\hardware\\\`. 16 | Open it using a text editor (e.g. Gedit on Linux, or Notepad on Windows). 17 | 18 | First, create the menu option by adding the following line at the top of the 19 | file: 20 | 21 | ``` 22 | menu.debug=Debug output 23 | ``` 24 | 25 | Then for your board, just add the different debug options. 26 | For example, if you're using an Arduino UNO: 27 | 28 | ``` 29 | uno.menu.debug.None=None 30 | uno.menu.debug.None.build.debug_output= 31 | uno.menu.debug.Serial=Serial 32 | uno.menu.debug.Serial.build.debug_output=-DDEBUG_OUT=Serial 33 | ``` 34 | 35 | Next, add the debugging flags to the compilation options by adding the line: 36 | 37 | ``` 38 | uno.build.extra_flags={build.debug_output} 39 | ``` 40 | 41 | If your board already has an `extra_flags` entry, just add 42 | ` {build.debug_output}` to the end (separated by a space). For example: 43 | 44 | ``` 45 | leonardo.build.extra_flags={build.usb_flags} {build.debug_output} 46 | ``` 47 | 48 | A complete list of all the AVR boards and their added debug options can be found 49 | [**here**](https://github.com/tttapa/Arduino-Helpers/blob/master/docs/extra/boards.txt.example). 50 | 51 | Finally, restart the IDE. 52 | If you now open your the `Tools` menu in the Arduino IDE, you should see the 53 | debug options: 54 | ![Selecting the Debug output in the Arduino IDE](Screenshot-Arduino-IDE-Debug.png) -------------------------------------------------------------------------------- /doxygen/scripts/examples.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | import os 5 | from os.path import join, realpath, basename, splitext 6 | from pathlib import Path 7 | 8 | dirnm = os.path.dirname(os.path.realpath(__file__)) 9 | doxydir = join(dirnm, '..') 10 | # exclude = re.compile(r'(examples/Arduino-Helpers/)|(examples/test/)') 11 | exclude = re.compile(r'examples/test/') 12 | 13 | template = """\ 14 | /** 15 | * @example "{pathname}" 16 | * 17 | * {title} 18 | * {underline} 19 | *{docstr}*/ 20 | 21 | """ 22 | 23 | 24 | def stripQuotes(string): 25 | string = re.sub(r'^"', '', string) 26 | string = re.sub(r'"$', '', string) 27 | return string 28 | 29 | 30 | with open(join(doxydir, 'Doxyfile')) as doxy: 31 | doxy_content = doxy.read() 32 | m = re.search(r'EXAMPLE_PATH\s*=\s*(.+)', doxy_content) 33 | if m: 34 | exampledir = m.group(1).split('" "')[0] 35 | exampledir = realpath(join(doxydir, stripQuotes(exampledir))) 36 | print("Example directory =", exampledir) 37 | else: 38 | print('Error: couldn\'t find EXAMPLE_PATH in Doxyfile') 39 | exit(1) 40 | m = re.search(r'INPUT\s*=\s*([./a-zA-Z0-9_-]+)', doxy_content) 41 | if m: 42 | lastInclude = m.group(1).split(" ")[-1] 43 | outputfile = realpath(join(doxydir, stripQuotes(lastInclude))) 44 | print("Output file =", outputfile) 45 | else: 46 | print('Error: couldn\'t find INPUT in Doxyfile') 47 | exit(1) 48 | 49 | output = "" 50 | 51 | for root, dirs, files in os.walk(exampledir): 52 | if exclude is not None and re.search(exclude, root) is not None: 53 | print('Excluding', root) 54 | continue 55 | print('Scanning', root) 56 | for file in sorted(files): 57 | if file.endswith('.ino'): 58 | with open(join(root, file)) as example: 59 | example_content = example.read() 60 | s = example_content.split('/**', 1) 61 | if len(s) > 1: 62 | print('\t\033[0;32mFound documentation for', file, 63 | '\033[0m') 64 | docstr = s[1].split('*/', 1)[0] 65 | # Add line break after brief 66 | # docstr = re.sub(r'^\s*\*\s*$', r'\g<0>
', docstr, 1, 67 | # re.MULTILINE) 68 | # pathname = str(Path(root).relative_to(exampledir) / file) 69 | pathname = file 70 | title = splitext(basename(file))[0] 71 | underline = '=' * len(title) 72 | output += template.format(pathname=pathname, 73 | title=title, 74 | underline=underline, 75 | docstr=docstr) 76 | else: 77 | print('\t\033[0;33mWarning: no documentation for', file, 78 | '\033[0m') 79 | print('\t → "' + str(Path(root) / file) + '"') 80 | 81 | with open(outputfile, 'w') as f: 82 | f.write(output) 83 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Debug/Debug/Debug.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This examples shows how use the debug macros for printing different kinds of 3 | * debugging information 4 | * 5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 6 | * 7 | * Behavior 8 | * -------- 9 | * 10 | * - Enable debugging by defining the @ref DEBUG_OUT macro in 11 | * `src/AH/Settings/Settings.hpp` or enable debugging globally as explained 12 | * [here](@ref md_pages_Debug) 13 | * - Upload the sketch to the Arduino, and open the Serial Monitor 14 | * (`CTRL+Shift+M`) 15 | * - Every five seconds, debugging information is printed, for example: 16 | * 17 | * ~~~ 18 | * This is the result of `DEBUG` 19 | * [/home/pieter/GitHub/Arduino-Debugging/Example/Example.ino:12]: This is the result of `DEBUGREF` 20 | * [void loop() @ line 13]: This is the result of `DEBUGFN` 21 | * [0:2:11.085]: This is the result of `DEBUGTIME` 22 | * a = 1, b = 2, c = 3 23 | * log10(1000) - 2 = 1.00 24 | * millis() = 131085 25 | * Serial.read() = -1 26 | * [int someFunction(int) @ line 26]: parameter = 42 27 | * ~~~ 28 | * 29 | * @see @ref md_pages_Debug for instructions on how to add an option in the 30 | * Arduino IDE to easily enable and disable debugging globally without 31 | * editing the settings file. 32 | * 33 | * Written by PieterP, 2018-07-31 34 | * https://github.com/tttapa/Arduino-Helpers 35 | */ 36 | 37 | #include 38 | 39 | #include 40 | 41 | void setup() { 42 | Serial.begin(115200); 43 | while (!Serial) 44 | ; 45 | } 46 | 47 | void loop() { 48 | DEBUG("This is the result of `DEBUG`"); 49 | DEBUGREF("This is the result of `DEBUGREF`"); 50 | DEBUGFN("This is the result of `DEBUGFN`"); 51 | DEBUGTIME("This is the result of `DEBUGTIME`"); 52 | int a = 1, b = 2, c = 3; 53 | DEBUGVAL(a, b, c); 54 | (void)a, (void)b, (void)c; 55 | DEBUGVAL(log10(1000) - 2); 56 | DEBUGVAL(millis()); 57 | DEBUGVAL(Serial.read()); 58 | someFunction(42); 59 | DEBUG(""); 60 | delay(5000); 61 | } 62 | 63 | int someFunction(int parameter) { 64 | DEBUGFN(NAMEDVALUE(parameter)); 65 | return parameter; 66 | } -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Hardware/1.FilteredAnalog/1.FilteredAnalog.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This examples shows how to filter an analog input, so you can get the 3 | * position of a knob or fader without noise. 4 | * 5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 6 | * 7 | * Connections 8 | * ----------- 9 | * 10 | * - A0: wiper of a potentiometer 11 | * 12 | * Connect the left terminal of the potentiometer to ground, and the right one 13 | * to VCC. 14 | * 15 | * Behavior 16 | * -------- 17 | * 18 | * - Upload the sketch to the Arduino, and open the Serial Monitor 19 | * (`CTRL+Shift+M`) 20 | * - When you turn the potentiometer, you should see the position of the 21 | * potentiometer being printed as a number between 0 and 1023. 22 | * - The analog input is filtered, so there shouldn't be any noise on the 23 | * position. If there is, check your wiring, and make sure that the resistance 24 | * of the potentiometer isn't too high (10 kΩ is ideal). 25 | * 26 | * The example @ref 1.FilteredAnalog-Advanced.ino has more information about the 27 | * parameters you can pass to the FilteredAnalog class to tweak the filters, 28 | * increase the resolution, etc. 29 | * 30 | * Written by PieterP, 2019-10-10 31 | * https://github.com/tttapa/Arduino-Helpers 32 | */ 33 | 34 | // Include the library 35 | #include 36 | 37 | #include 38 | #include 39 | 40 | // Create a filtered analog object on pin A0, with the default settings: 41 | FilteredAnalog<> analog = A0; 42 | 43 | void setup() { 44 | Serial.begin(115200); 45 | while (!Serial); 46 | // Select the correct ADC resolution 47 | analog.setupADC(); 48 | // Initialize the filter to whatever the value on the input is right now 49 | // (otherwise, the filter is initialized to zero and you get transients) 50 | analog.resetToCurrentValue(); 51 | } 52 | 53 | void loop() { 54 | // Read the analog input every millisecond, and print if the value has changed 55 | static Timer timer = 1; // ms 56 | if (timer && analog.update()) 57 | Serial.println(analog.getValue()); 58 | } 59 | 60 | // Explanation: 61 | // 62 | // analog.update() reads the analog input, applies the filters, 63 | // saves the value, and returns true if the value has changed. 64 | // You can then retreive the new value using analog.getValue(). 65 | // 66 | // Timer is just a "Blink Without Delay" wrapper, it returns true 67 | // every time the specified amount of time has passed. 68 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Hardware/2.Button/2.Button.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This examples shows how to use the debounced Button class to toggle an LED. 3 | * 4 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 5 | * 6 | * Connections 7 | * ----------- 8 | * 9 | * - 2: Momentary push button (other pin to ground) 10 | * 11 | * The internal pull-up resistor will be enabled. 12 | * 13 | * Behavior 14 | * -------- 15 | * 16 | * - If you press the push button once, the built-in LED is turned on. 17 | * - If you press the button again, the LED is turned off again. 18 | * 19 | * Written by PieterP, 2019-11-22 20 | * https://github.com/tttapa/Arduino-Helpers 21 | */ 22 | 23 | // Include the library 24 | #include 25 | 26 | #include 27 | 28 | // Create a Button object that reads a push button connected to pin 2: 29 | Button pushbutton {2}; 30 | 31 | // The pin with the LED connected: 32 | const pin_t ledPin = LED_BUILTIN; 33 | 34 | void setup() { 35 | pinMode(ledPin, OUTPUT); 36 | pushbutton.begin(); 37 | // You can invert the input, for use with normally closed (NC) switches: 38 | // pushbutton.invert(); 39 | } 40 | 41 | void loop() { 42 | static bool ledState = LOW; 43 | // Read the digital input, debounce the signal, and check the state of 44 | // the button: 45 | if (pushbutton.update() == Button::Falling) { 46 | ledState = !ledState; // Invert the state of the LED 47 | // Update the LED with the new state 48 | digitalWrite(ledPin, ledState ? HIGH : LOW); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Hardware/3.MultiPurposeButton/3.MultiPurposeButton.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This examples shows how to use the MultiPurposeButton class to detect 3 | * different kinds of push button events. 4 | * 5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 6 | * 7 | * Connections 8 | * ----------- 9 | * 10 | * - 2: Momentary push button (other pin to ground) 11 | * 12 | * The internal pull-up resistor will be enabled. 13 | * 14 | * Behavior 15 | * -------- 16 | * 17 | * - Short presses, long presses, multiple presses, etc. are printed to the 18 | * Serial monitor. 19 | * 20 | * Written by PieterP, 2022-05-07 21 | * https://github.com/tttapa/Arduino-Helpers 22 | */ 23 | 24 | #include // https://github.com/tttapa/Arduino-Helpers 25 | 26 | #include 27 | 28 | // Create a Button object that reads a push button connected to pin 2: 29 | MultiPurposeButton btn{2}; 30 | 31 | void setup() { 32 | Serial.begin(115200); 33 | btn.setLongPressDelay(1000); 34 | btn.setMultiPressDelay(400); 35 | btn.begin(); 36 | } 37 | 38 | void loop() { 39 | auto longPressTime = btn.getLongPressedTime(); 40 | switch (btn.update()) { 41 | case btn.None: break; 42 | case btn.PressStart: Serial << "Pressed" << endl; break; 43 | case btn.ShortPressRelease: 44 | Serial << "Released after short press" << endl; 45 | break; 46 | case btn.LongPress: Serial << "Long press" << endl; break; 47 | case btn.LongPressRelease: 48 | Serial << "Released after long press (" << longPressTime << " ms)" 49 | << endl; 50 | break; 51 | case btn.MultiPress: 52 | Serial << "Consecutive presses: " << btn.getCurrentMultiPressCount() + 1 53 | << endl; 54 | break; 55 | case btn.MultiPressDone: 56 | Serial << "Counted " << btn.getMultiPressCount() + 1 57 | << " consecutive presses" << endl; 58 | break; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Hardware/Blink-Frequency-Buttons/Blink-Frequency-Buttons.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This examples shows how to use two push buttons to set the frequency at which 3 | * an LED blinks. 4 | * 5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 6 | * 7 | * Connections 8 | * ----------- 9 | * 10 | * - 2: Momentary push button (other pin to ground) 11 | * - 3: Momentary push button (other pin to ground) 12 | * 13 | * The internal pull-up resistors will be enabled. 14 | * 15 | * Behavior 16 | * -------- 17 | * 18 | * - If you press the first push button, the LED blinks faster. 19 | * - If you press the second push button, the LED blinks slower. 20 | * - You can press and hold one of the push buttons to change the frequency by 21 | * multiple steps. 22 | * - If you press both buttons at the same time, the frequency is reset to the 23 | * initial default frequency. 24 | * 25 | * Written by PieterP, 2019-12-10 26 | * https://github.com/tttapa/Arduino-Helpers 27 | */ 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | const unsigned long maxInterval = 2000; // ms 35 | const unsigned long minInterval = 100; // ms 36 | const unsigned long defaultInterval = 500; // ms 37 | const int intervalDelta = 100; // ms 38 | 39 | IncrementDecrementButtons buttons {2, 3}; 40 | Timer timer = defaultInterval; 41 | 42 | void setup() { 43 | pinMode(LED_BUILTIN, OUTPUT); 44 | buttons.begin(); 45 | Serial.begin(115200); 46 | } 47 | 48 | void loop() { 49 | // toggle the LED when the given number of milliseconds have passed 50 | if (timer) 51 | digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) ? LOW : HIGH); 52 | 53 | // read the buttons, and change interval accordingly 54 | switch (buttons.update()) { 55 | case IncrementDecrementButtons::IncrementShort: 56 | case IncrementDecrementButtons::IncrementLong: 57 | case IncrementDecrementButtons::IncrementHold: 58 | timer.setInterval( 59 | AH::max(timer.getInterval() - intervalDelta, minInterval)); 60 | break; 61 | case IncrementDecrementButtons::DecrementShort: 62 | case IncrementDecrementButtons::DecrementLong: 63 | case IncrementDecrementButtons::DecrementHold: 64 | timer.setInterval( 65 | AH::min(timer.getInterval() + intervalDelta, maxInterval)); 66 | break; 67 | case IncrementDecrementButtons::Reset: 68 | timer.setInterval(defaultInterval); 69 | break; 70 | default: break; 71 | } 72 | 73 | // print the new interval if a button was pushed 74 | if (buttons.getState() != IncrementDecrementButtons::Nothing) 75 | Serial.println(timer.getInterval()); 76 | } -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Hardware/Extended Input & Output/1. Input/1. Multiplexers/1.AnalogReadSerial/1.AnalogReadSerial.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This is an example of the AnalogMultiplex class. It prints the values of all 3 | * 16 inputs of a multiplexers to the serial monitor. 4 | * 5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 6 | * 7 | * Connections 8 | * ----------- 9 | * 10 | * - A0: CD74HC4067 signal pin ("common input/output") 11 | * - 3: CD74HC4067 address pin S0 12 | * - 4: CD74HC4067 address pin S1 13 | * - 5: CD74HC4067 address pin S2 14 | * - 6: CD74HC4067 address pin S3 15 | * 16 | * Optionally you can connect the enable pin as well, this is useful 17 | * if you want to use multiple multiplexers with the same address 18 | * lines and the same analog input. Otherwise, just connect the enable 19 | * pin to ground. 20 | * 21 | * If you are using a 3-bit multiplexer, like the CD74HC4051, you can 22 | * uncomment the code specific to this multiplexer, and use only three 23 | * address pins. 24 | * 25 | * Behavior 26 | * -------- 27 | * 28 | * Connect some potentiometers or other analog sensors to the 16 inputs 29 | * of the multiplexer, and open the serial monitor (CTRL+SHIFT+M) or the 30 | * serial plotter (CTRL+SHIFT+L). You should see all 16 signals printed 31 | * or plotted. 32 | * 33 | * Written by Pieter P, 31-01-2019 34 | * https://github.com/tttapa/Arduino-Helpers 35 | */ 36 | 37 | #include // Include the Arduino Helpers library 38 | #include 39 | 40 | // Instantiate a multiplexer 41 | CD74HC4067 mux { 42 | A0, // analog pin 43 | {3, 4, 5, 6}, // Address pins S0, S1, S2, S3 44 | // 7, // Optionally, specify the enable pin 45 | }; 46 | 47 | // Alternatively, if you have a 3-bit mux: 48 | // CD74HC4051 mux { 49 | // A0, 50 | // {3, 4, 5}, 51 | // // 7, // Optional 52 | // }; 53 | 54 | void setup() { 55 | Serial.begin(115200); 56 | mux.begin(); // Initialize multiplexer 57 | } 58 | 59 | void loop() { 60 | for (pin_t pin = 0; pin < mux.getLength(); ++pin) { 61 | Serial.print(mux.analogRead(pin)); 62 | Serial.print('\t'); 63 | } 64 | Serial.println(); 65 | } 66 | 67 | // A more fancy approach could be to use a range-based for loop 68 | void loop2() { 69 | for (pin_t pin : mux.pins()) { 70 | Serial.print(analogRead(pin)); 71 | Serial.print('\t'); 72 | } 73 | Serial.println(); 74 | } 75 | // Okay, it's a bit slower, because it has to look up what ExtIO device the pin 76 | // belongs to, but hey, it's nice to have it anyway 77 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Hardware/Extended Input & Output/1. Input/1. Multiplexers/2.DigitalReadSerial/2.DigitalReadSerial.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This is an example of the AnalogMultiplex class. It prints the states of all 3 | * 16 switches connected to a multiplexers to the serial monitor. 4 | * 5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 6 | * 7 | * Connections 8 | * ----------- 9 | * 10 | * - 2: CD74HC4067 signal pin ("common input/output") 11 | * - 3: CD74HC4067 address pin S0 12 | * - 4: CD74HC4067 address pin S1 13 | * - 5: CD74HC4067 address pin S2 14 | * - 6: CD74HC4067 address pin S3 15 | * 16 | * Optionally you can connect the enable pin as well, this is useful 17 | * if you want to use multiple multiplexers with the same address 18 | * lines and the same analog input. Otherwise, just connect the enable 19 | * pin to ground. 20 | * 21 | * If you are using a 3-bit multiplexer, like the CD74HC4051, you can 22 | * uncomment the code specific to this multiplexer, and use only three 23 | * address pins. 24 | * 25 | * Connect a switch or push button between each input pin of the multiplexer and 26 | * ground. A pull-up resistor is not necessary, because we'll use the internal 27 | * one. 28 | * 29 | * Behavior 30 | * -------- 31 | * 32 | * Open the serial monitor (CTRL+SHIFT+M) or the serial plotter (CTRL+SHIFT+L), 33 | * and press some buttons, you should see all 16 signals printed or plotted. 34 | * 35 | * Written by Pieter P, 2019-08-08 36 | * https://github.com/tttapa/Arduino-Helpers 37 | */ 38 | 39 | #include // Include the Arduino Helpers library 40 | #include 41 | 42 | // Instantiate a multiplexer 43 | CD74HC4067 mux { 44 | 2, // input pin 45 | {3, 4, 5, 6}, // Address pins S0, S1, S2, S3 46 | // 7, // Optionally, specify the enable pin 47 | }; 48 | 49 | // Alternatively, if you have a 3-bit mux: 50 | // CD74HC4051 mux { 51 | // 2, 52 | // {3, 4, 5}, 53 | // // 7, // Optional 54 | // }; 55 | 56 | void setup() { 57 | Serial.begin(115200); 58 | mux.begin(); // Initialize multiplexer 59 | mux.pinMode(0, INPUT_PULLUP); // Set the pin mode (setting it for one pin of 60 | // the multiplexers sets it for all of them) 61 | } 62 | 63 | void loop() { 64 | for (pin_t pin = 0; pin < mux.getLength(); ++pin) { 65 | Serial.print(mux.digitalRead(pin)); 66 | Serial.print('\t'); 67 | } 68 | Serial.println(); 69 | } 70 | 71 | // A more fancy approach could be to use a range-based for loop 72 | void loop2() { 73 | for (pin_t pin : mux.pins()) { 74 | Serial.print(digitalRead(pin)); 75 | Serial.print('\t'); 76 | } 77 | Serial.println(); 78 | } 79 | // Okay, it's a bit slower, because it has to look up what ExtIO device the pin 80 | // belongs to, but hey, it's nice to have it anyway 81 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Hardware/Extended Input & Output/1. Input/1. Multiplexers/3.FilteredAnalogReadSerial/3.FilteredAnalogReadSerial.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This is an example of the AnalogMultiplex and the FilteredAnalog classes. 3 | * It prints the filtered values of all 16 inputs of a multiplexers to the 4 | * serial monitor. 5 | * 6 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 7 | * 8 | * Connections 9 | * ----------- 10 | * 11 | * - A0: CD74HC4067 signal pin ("common input/output") 12 | * - 3: CD74HC4067 address pin S0 13 | * - 4: CD74HC4067 address pin S1 14 | * - 5: CD74HC4067 address pin S2 15 | * - 6: CD74HC4067 address pin S3 16 | * 17 | * Optionally you can connect the enable pin as well, this is useful 18 | * if you want to use multiple multiplexers with the same address 19 | * lines and the same analog input. Otherwise, just connect the enable 20 | * pin to ground. 21 | * 22 | * If you are using a 3-bit multiplexer, like the CD74HC4051, you can 23 | * uncomment the code specific to this multiplexer, and use only three 24 | * address pins. 25 | * 26 | * Behavior 27 | * -------- 28 | * 29 | * Connect some potentiometers or other analog sensors to the 16 inputs 30 | * of the multiplexer, and open the serial monitor (CTRL+SHIFT+M) or the 31 | * serial plotter (CTRL+SHIFT+L). You should see all 16 signals printed 32 | * or plotted. 33 | * 34 | * Written by Pieter P, 09-04-2019 35 | * https://github.com/tttapa/Arduino-Helpers 36 | */ 37 | 38 | #include // Include the Arduino Helpers library 39 | 40 | #include 41 | #include 42 | #include // copyAs<> 43 | 44 | // Instantiate a multiplexer 45 | CD74HC4067 mux { 46 | A0, // analog pin 47 | {3, 4, 5, 6}, // Address pins S0, S1, S2, S3 48 | // 7, // Optionally, specify the enable pin 49 | }; 50 | 51 | // Alternatively, if you have a 3-bit mux: 52 | // CD74HC4051 mux { 53 | // A0, 54 | // {3, 4, 5}, 55 | // // 7, // Optional 56 | // }; 57 | 58 | // Convert the list of pins of the multiplexer to an array 59 | // of FilteredAnalog objects. 60 | auto filteredAnalogs = copyAs>(mux.pins()); 61 | 62 | void setup() { 63 | Serial.begin(115200); 64 | mux.begin(); // Initialize multiplexer 65 | } 66 | 67 | void loop() { 68 | // Loop over all FilteredAnalog objects in the array 69 | for (auto &analog : filteredAnalogs) { 70 | analog.update(); // actually read the analog value and filter it 71 | Serial.print(analog.getValue()); 72 | Serial.print('\t'); 73 | } 74 | Serial.println(); 75 | } 76 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Hardware/Extended Input & Output/2. Output/1. Shift Registers/1.SPI-Blink/1.SPI-Blink.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This example demonstrates the use of shift registers as if they were just 3 | * normal IO pins. The SPI interface is used because it's easy and fast. 4 | * 5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 6 | * 7 | * Connections 8 | * ----------- 9 | * 10 | * - SS: 74HC595 ST_CP 11 | * - MOSI: 74HC595 DS 12 | * - SCK: 74HC595 SH_CP 13 | * 14 | * Connect an LED (and series resistor) between the first output of the 15 | * shift register and ground. 16 | * 17 | * Remember to connect the enable pin of the shift register to ground and the 18 | * master reset pin to Vcc in order to enable it. 19 | * 20 | * Behavior 21 | * -------- 22 | * 23 | * This sketch will blink the LED once a second. 24 | * 25 | * Written by PieterP, 2018-09-01 26 | * https://github.com/tttapa/Arduino-Helpers 27 | */ 28 | 29 | #include // Include the Arduino Helpers library. 30 | #include 31 | 32 | using namespace ExtIO; // Bring the ExtIO pin functions into your sketch 33 | 34 | // Instantiate a shift register with the SPI slave select pin as latch pin, most 35 | // significant bit first, and a total of 8 outputs. 36 | SPIShiftRegisterOut<8> sreg {SPI, SS, MSBFIRST}; 37 | 38 | const pin_t ledPin = sreg.pin(0); // first pin of the shift register 39 | 40 | void setup() { 41 | sreg.begin(); // Initialize the shift registers 42 | pinMode(ledPin, OUTPUT); // You don't even need this line, since 43 | // shift registers are always outputs 44 | } 45 | 46 | void loop() { 47 | // Toggle the state of the LED every 1/2 second 48 | digitalWrite(ledPin, HIGH); 49 | delay(500); 50 | digitalWrite(ledPin, LOW); 51 | delay(500); 52 | } 53 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Hardware/Extended Input & Output/2. Output/1. Shift Registers/2.BitBang-Blink/2.BitBang-Blink.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This example demonstrates the use of shift registers as if they were just 3 | * normal IO pins. This version uses bit-banging to drive the shift register. 4 | * You should probably be using the SPI version instead. 5 | * 6 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 7 | * 8 | * Connections 9 | * ----------- 10 | * 11 | * - 10: 74HC595 ST_CP 12 | * - 11: 74HC595 DS 13 | * - 13: 74HC595 SH_CP 14 | * 15 | * Connect an LED (and series resistor) between the first output of the 16 | * shift register and ground. 17 | * 18 | * Remember to connect the enable pin the shift register to ground and the 19 | * master reset pin to Vcc in order to enable it. 20 | * 21 | * Behavior 22 | * -------- 23 | * 24 | * This sketch will blink the LED once a second. 25 | * 26 | * Written by PieterP, 2018-09-01 27 | * https://github.com/tttapa/Arduino-Helpers 28 | */ 29 | 30 | #include // Include the Arduino Helpers library. 31 | #include 32 | 33 | using namespace ExtIO; // Bring the ExtIO pin functions into your sketch 34 | 35 | const pin_t latchPin = 10; // Pin connected to ST_CP of 74HC595 36 | const pin_t dataPin = 11; // Pin connected to DS of 74HC595 37 | const pin_t clockPin = 13; // Pin connected to SH_CP of 74HC595 38 | 39 | // Instantiate a shift register on the correct pins, most significant bit first, 40 | // and a total of 8 outputs. 41 | ShiftRegisterOut<8> sreg {dataPin, clockPin, latchPin, MSBFIRST}; 42 | 43 | const pin_t ledPin = sreg.pin(0); // first pin of the shift register 44 | 45 | void setup() { 46 | sreg.begin(); // Initialize the shift registers 47 | pinMode(ledPin, OUTPUT); // You don't even need this line, since 48 | // shift registers are always outputs 49 | } 50 | 51 | void loop() { 52 | // Toggle the state of the LED every 1/2 second 53 | digitalWrite(ledPin, HIGH); 54 | delay(500); 55 | digitalWrite(ledPin, LOW); 56 | delay(500); 57 | } 58 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Hardware/Extended Input & Output/2. Output/2. MAX7219/1.MAX7219-Blink/1.MAX7219-Blink.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This example demonstrates the use of MAX7219 LED outputs as if they were just 3 | * normal IO pins, using `digitalWrite`. 4 | * 5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 6 | * 7 | * Connections 8 | * ----------- 9 | * 10 | * - SS: MAX7219 CS 11 | * - MOSI: MAX7219 DIN 12 | * - SCK: MAX7219 CLK 13 | * 14 | * Behavior 15 | * -------- 16 | * 17 | * This sketch will blink the first and the last LEDs once a second, in an 18 | * alternating pattern. 19 | * 20 | * Written by PieterP, 2020-03-24 21 | * https://github.com/tttapa/Arduino-Helpers 22 | */ 23 | 24 | #include // Include the Arduino Helpers library. 25 | #include 26 | 27 | using namespace ExtIO; // Bring the ExtIO pin functions into your sketch 28 | 29 | // Instantiate a MAX7219 with the SPI slave select pin as latch pin 30 | // There's just 1 MAX7219 in the chain, if you have more of them daisy-chained 31 | // together, you can increase the template argument (between angled brackets) 32 | MAX7219<1> max7219 {SPI, SS}; 33 | 34 | const pin_t ledPin1 = max7219.pin(0); // first LED of the MAX7219 35 | const pin_t ledPin2 = max7219.pin(63); // last LED of the MAX7219 36 | 37 | void setup() { 38 | max7219.begin(); // Initialize the shift registers 39 | pinMode(ledPin1, OUTPUT); // You don't even need this line, since 40 | pinMode(ledPin2, OUTPUT); // since the MAX7219's pins are always outputs 41 | } 42 | 43 | void loop() { 44 | // Toggle the state of the LEDs every 1/2 second 45 | digitalWrite(ledPin1, HIGH); 46 | digitalWrite(ledPin2, LOW); 47 | delay(500); 48 | digitalWrite(ledPin1, LOW); 49 | digitalWrite(ledPin2, HIGH); 50 | delay(500); 51 | } 52 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Hardware/Extended Input & Output/3. In&Out/MCP23017/MCP23017.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This example demonstrates the use of MCP23017 IO expanders as if they were 3 | * just normal IO pins. 4 | * 5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 6 | * 7 | * Connections 8 | * ----------- 9 | * 10 | * - SDA: MCP23017 SDA 11 | * - SCK: MCP23017 SCK 12 | * - 2: MCP23017 INT A or INT B 13 | * 14 | * Connect an LED (and series resistor) between pin GPA0 of the MCP and ground. 15 | * Connect a push button between pin GPB0 of the MCP and ground. The internal 16 | * pull-up resistor will be used. 17 | * 18 | * Tie the three address lines of the MCP to ground. 19 | * 20 | * Behavior 21 | * -------- 22 | * 23 | * When the push button is pressed, the LED turns on. 24 | * 25 | * Written by PieterP, 2020-11-20 26 | * https://github.com/tttapa/Arduino-Helpers 27 | */ 28 | 29 | #include 30 | 31 | #include 32 | 33 | #include 34 | 35 | using namespace ExtIO; // Use the extended input/output functions 36 | 37 | using WireType = decltype(Wire); // The type of the I²C driver to use 38 | MCP23017 mcp { 39 | Wire, // The I²C driver to use 40 | 0x0, // The I²C address offset (depends on the state of the address pins) 41 | 2, // Optional: interrupt pin to detect input changes 42 | }; 43 | 44 | pin_t ledPin = mcp.pinA(0); // GPIOA0 45 | pin_t buttonPin = mcp.pinB(0); // GPIOB0 46 | 47 | void setup() { 48 | Wire.begin(); // Initialize the I²C interface 49 | Wire.setClock(800000); // Faster I²C clock 50 | mcp.begin(); // Initialize the MCP23017 51 | 52 | pinMode(ledPin, OUTPUT); 53 | pinMode(buttonPin, INPUT_PULLUP); 54 | } 55 | 56 | void loop() { 57 | auto buttonState = digitalRead(buttonPin); 58 | digitalWrite(ledPin, buttonState ? LOW : HIGH); 59 | } 60 | 61 | // Note: 62 | // The “interrupt” pin is not used to trigger an actual interrupt on the 63 | // microcontroller. It is just used to check whether any of the inputs of 64 | // the MCP23017 changed without having to do an I²C transaction. Using this 65 | // pin can speed up your code, but it's not necessary, you can leave it out 66 | // in the MCP23017 construction at the top of the sketch. 67 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Hardware/Pin-Change-Interrupt-Encoders/Pin-Change-Interrupt-Encoders.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This example reads multiple encoders using pin change interrupts, on an 3 | * Arduino Uno or Nano. 4 | * 5 | * @boards AVR 6 | * 7 | * The ATmega328P microcontroller only has two interrupt pins (2 and 3), so if 8 | * you want to use more than two interrupt-driven encoders, you'll either have 9 | * to use a timer interrupt to continuously poll the encoders, or use the chip's 10 | * pin change interrupts. This example demonstrates the latter. 11 | * 12 | * @see @ref Timer-Interrupt-Encoders.ino 13 | * 14 | * Familiarity with [direct port manipulation](https://www.arduino.cc/en/Reference/PortManipulation) 15 | * is assumed. 16 | * 17 | * Connections 18 | * ----------- 19 | * 20 | * Connect three encoders to the pins of port C as follows: 21 | * 22 | * - A0: pin A of encoder #0 23 | * - A1: pin B of encoder #0 24 | * - A2: pin A of encoder #1 25 | * - A3: pin B of encoder #1 26 | * - A4: pin A of encoder #2 27 | * - A5: pin B of encoder #2 28 | * 29 | * Connect the common pins to ground, the internal pull-up resistors will be 30 | * enabled. 31 | * 32 | * Behavior 33 | * -------- 34 | * 35 | * When the position of one of the encoders changes, it is printed to the Serial 36 | * monitor. 37 | * 38 | * Written by PieterP, 2021-08-11 39 | * https://github.com/tttapa/Arduino-Helpers 40 | */ 41 | 42 | #include 43 | #include 44 | 45 | // The number of encoders to read: 46 | constexpr uint8_t num_enc = 3; 47 | // Mask the bottom 6 bits of the GPIO registers (2 pins × 3 encoders). 48 | // This determines which pins are used: 49 | const uint8_t pin_mask = 0x3F; 50 | // The actual encoder object that keeps track of the encoder state: 51 | RegisterEncoders encoders; 52 | // AVR uses 8-bit GPIO registers, so the register type is uint8_t. 53 | // Then we specify the number of encoders, the position type, 54 | // and whether the encoders should be interrupt-safe: since we'll 55 | // be calling `encoders.update()` in an interrupt handler, it is 56 | // important that this is set to true. 57 | 58 | // Pin change interrupt handler that reads the pins and updates the state: 59 | ISR (PCINT1_vect) { encoders.update(PINC & pin_mask); } // read port C 60 | 61 | void setup() { 62 | PCMSK1 |= pin_mask; // enable pin change interrupt for given pins in port C 63 | DDRC &= ~pin_mask; // input mode for port C 64 | PORTC |= pin_mask; // enable pull-up resistors for port C 65 | PCICR |= 1 << 1; // enable pin change interrupt for port C 66 | Serial.begin(115200); 67 | } 68 | 69 | void loop() { 70 | // The previous position of each encoder, to detect changes: 71 | static int32_t prevPos[num_enc] {}; 72 | 73 | // Read the encoder positions and print if they changed: 74 | for (uint8_t i = 0; i < num_enc; ++i) { 75 | int32_t newPos = encoders[i].read(); 76 | if (newPos != prevPos[i]) { 77 | Serial << '[' << i << "] " << newPos << endl; 78 | prevPos[i] = newPos; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Hardware/Timer-Interrupt-Encoders/Timer-Interrupt-Encoders.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This example reads multiple encoders using a timer interrupt, on an 3 | * Arduino Uno or Nano. 4 | * 5 | * @boards AVR 6 | * 7 | * The ATmega328P microcontroller only has two interrupt pins (2 and 3), so if 8 | * you want to use more than two interrupt-driven encoders, you'll either have 9 | * to use a timer interrupt to continuously poll the encoders, or use the chip's 10 | * pin change interrupts. This example demonstrates the former. 11 | * 12 | * @see @ref Pin-Change-Interrupt-Encoders.ino 13 | * 14 | * Familiarity with [direct port manipulation](https://www.arduino.cc/en/Reference/PortManipulation) 15 | * is assumed. 16 | * 17 | * Connections 18 | * ----------- 19 | * 20 | * Connect three encoders to the pins of port C as follows: 21 | * 22 | * - A0: pin A of encoder #0 23 | * - A1: pin B of encoder #0 24 | * - A2: pin A of encoder #1 25 | * - A3: pin B of encoder #1 26 | * - A4: pin A of encoder #2 27 | * - A5: pin B of encoder #2 28 | * 29 | * Connect the common pins to ground, the internal pull-up resistors will be 30 | * enabled. 31 | * 32 | * Behavior 33 | * -------- 34 | * 35 | * When the position of one of the encoders changes, it is printed to the Serial 36 | * monitor. 37 | * 38 | * Written by PieterP, 2021-08-11 39 | * https://github.com/tttapa/Arduino-Helpers 40 | */ 41 | 42 | #include 43 | #include 44 | #include "TimerHelpers.hpp" 45 | 46 | // The number of encoders to read: 47 | constexpr uint8_t num_enc = 3; 48 | // Mask the bottom 6 bits of the GPIO registers (2 pins × 3 encoders). 49 | // This determines which pins are used: 50 | const uint8_t pin_mask = 0x3F; 51 | // The actual encoder object that keeps track of the encoder state: 52 | RegisterEncoders encoders; 53 | // AVR uses 8-bit GPIO registers, so the register type is uint8_t. 54 | // Then we specify the number of encoders, the position type, 55 | // and whether the encoders should be interrupt-safe: since we'll 56 | // be calling `encoders.update()` in an interrupt handler, it is 57 | // important that this is set to true. 58 | 59 | // Timer interrupt handler that reads the pins and updates the state: 60 | ISR (TIMER2_COMPA_vect) { encoders.update(PINC & pin_mask); } // read port C 61 | 62 | void setup() { 63 | DDRC &= ~pin_mask; // input mode for port C 64 | PORTC |= pin_mask; // enable pull-up resistors for port C 65 | setTimer2Prescaler(Timer2Prescaler::S8); 66 | setTimer2WGMode(Timer2WGMode::CTC); 67 | OCR2A = 250 - 1; // 8 kHz poll rate (if FCPU = 16'000'000) 68 | bitSet(TIMSK2, OCIE2A); // Timer2 Compare A Match Interrupt Enable 69 | Serial.begin(115200); 70 | } 71 | 72 | void loop() { 73 | // The previous position of each encoder, to detect changes: 74 | static int32_t prevPos[num_enc] {}; 75 | 76 | // Read the encoder positions and print if they changed: 77 | for (uint8_t i = 0; i < num_enc; ++i) { 78 | int32_t newPos = encoders[i].read(); 79 | if (newPos != prevPos[i]) { 80 | Serial << '[' << i << "] " << newPos << endl; 81 | prevPos[i] = newPos; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Hardware/Timer-Interrupt-Encoders/TimerHelpers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /// Timer 2 clock select (Table 17-9). 4 | enum class Timer2Prescaler : uint8_t { 5 | None = 0b000, 6 | S1 = 0b001, 7 | S8 = 0b010, 8 | S32 = 0b011, 9 | S64 = 0b100, 10 | S128 = 0b101, 11 | S256 = 0b110, 12 | S1024 = 0b111, 13 | Invalid = 0xFF, 14 | }; 15 | 16 | /// Convert the prescaler factor to the correct bit pattern to write to the 17 | /// TCCR0B register (Table 17-9). 18 | constexpr inline Timer2Prescaler factorToTimer2Prescaler(uint16_t factor) { 19 | return factor == 1 ? Timer2Prescaler::S1 20 | : factor == 8 ? Timer2Prescaler::S8 21 | : factor == 32 ? Timer2Prescaler::S32 22 | : factor == 64 ? Timer2Prescaler::S64 23 | : factor == 128 ? Timer2Prescaler::S128 24 | : factor == 256 ? Timer2Prescaler::S256 25 | : factor == 1024 ? Timer2Prescaler::S1024 26 | : Timer2Prescaler::Invalid; 27 | } 28 | 29 | /// Timer 2 waveform generation mode (Table 17-8). 30 | enum class Timer2WGMode : uint8_t { 31 | Normal = 0b000, 32 | PWM = 0b001, 33 | CTC = 0b010, 34 | FastPWM = 0b011, 35 | PWM_OCRA = 0b101, 36 | FastPWM_OCRA = 0b111, 37 | }; 38 | 39 | /// Set the clock source/prescaler of Timer2 (Table 17-9). 40 | inline void setTimer2Prescaler(Timer2Prescaler ps) { 41 | if (ps == Timer2Prescaler::Invalid) 42 | return; 43 | bitWrite(TCCR2B, CS22, (static_cast(ps) >> 2) & 1); 44 | bitWrite(TCCR2B, CS21, (static_cast(ps) >> 1) & 1); 45 | bitWrite(TCCR2B, CS20, (static_cast(ps) >> 0) & 1); 46 | } 47 | 48 | /// Set the wavefrom generation mode of Timer2 (Table 17-8). 49 | inline void setTimer2WGMode(Timer2WGMode mode) { 50 | bitWrite(TCCR2B, WGM22, (static_cast(mode) >> 2) & 1); 51 | bitWrite(TCCR2A, WGM21, (static_cast(mode) >> 1) & 1); 52 | bitWrite(TCCR2A, WGM20, (static_cast(mode) >> 0) & 1); 53 | } 54 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Math/Quaternion/Quaternion.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple Quaternion test. 3 | * 4 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 5 | * 6 | * Written by PieterP, 2020-03-24 7 | * https://github.com/tttapa/Arduino-Helpers 8 | */ 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | bool close(float actual, float expected, float atol) { 16 | return std::abs(actual - expected) <= atol; 17 | } 18 | 19 | void setup() { 20 | Serial.begin(115200); 21 | 22 | Vec3f vector {-0.414578098794425, 0.829156197588850, 0.375000000000000}; 23 | Quaternion result = Quaternion::fromDirection(vector); 24 | Quaternion expected {0.829156197588850, -0.5, -0.25, 0.0}; 25 | float atol = 1e-7; 26 | 27 | Serial << setprecision(7) << "Result = " << result << endl; 28 | 29 | Serial << boolalpha; 30 | Serial << close(result.w, expected.w, atol) << endl; 31 | Serial << close(result.x, expected.x, atol) << endl; 32 | Serial << close(result.y, expected.y, atol) << endl; 33 | Serial << close(result.z, expected.z, atol) << endl; 34 | 35 | // Make sure it satisfies the definition of `fromDirection()`. 36 | Vec3f diff = result.rotate({0, 0, 1}) - vector.normalized(); 37 | Serial << close(diff.norm(), 0, atol) << endl; 38 | } 39 | 40 | void loop() {} -------------------------------------------------------------------------------- /examples/Arduino-Helpers/STL/ArraySort/ArraySort.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Example of using the standard library algorithms. 3 | * 4 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 5 | * 6 | * This sketch creates an array with an unordered sequence of 10 numbers. 7 | * It prints the array, and then creates a reverse view on the 6 elements in the 8 | * middle of the array and sorts it. 9 | * The resulting array has the same elements in the 4 outermost places, but the 10 | * 6 elements in the middle have been sorted in reverse order. 11 | * 12 | * **Output** 13 | * ~~~ 14 | * Before sorting: 3, 5, 9, 2, 1, 8, 6, 4, 7, 0 15 | * Sorting ├─────────────────┤ in ascending order 16 | * After sorting: 3, 5, 1, 2, 4, 6, 8, 9, 7, 0 17 | * Sorting ├─────────────────┤ in descending order 18 | * After sorting: 3, 5, 9, 8, 6, 4, 2, 1, 7, 0 19 | * ~~~ 20 | * 21 | * Written by PieterP, 2019-11-12 22 | * https://github.com/tttapa/Arduino-Helpers 23 | */ 24 | 25 | #include 26 | 27 | #include // Array 28 | #include // For printing the array 29 | #include // std::sort 30 | 31 | void setup() { 32 | Serial.begin(115200); 33 | while (!Serial) 34 | ; 35 | 36 | Array array {3, 5, 9, 2, 1, 8, 6, 4, 7, 0}; 37 | 38 | Serial << "Before sorting: " << array << endl; 39 | 40 | Serial << " Sorting ├─────────────────┤ in ascending order" 41 | << endl; 42 | 43 | // select elements 2 through 7 (inclusive) 44 | auto forward_view = array.slice<2, 7>(); 45 | // sort the view in ascending order 46 | std::sort(std::begin(forward_view), std::end(forward_view)); 47 | 48 | Serial << "After sorting: " << array << endl; 49 | Serial << " Sorting ├─────────────────┤ in descending order" 50 | << endl; 51 | 52 | // select elements 2 through 7 (inclusive) in reverse order 53 | auto reverse_view = array.slice<7, 2>(); 54 | // sort the reverse view in ascending order (this means that the original 55 | // array is sorted in descending order) 56 | std::sort(std::begin(reverse_view), std::end(reverse_view)); 57 | 58 | Serial << "After sorting: " << array << endl; 59 | } 60 | 61 | void loop() {} 62 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/STL/Complex/Complex.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Example of using the standard library complex numbers. 3 | * 4 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 5 | * 6 | * **Output** 7 | * ~~~ 8 | * √(2i) = (1.00,1.00) 9 | * ~~~ 10 | * 11 | * Written by PieterP, 2019-11-14 12 | * https://github.com/tttapa/Arduino-Helpers 13 | */ 14 | 15 | #include 16 | 17 | #include 18 | 19 | void setup() { 20 | Serial.begin(115200); 21 | while (!Serial) 22 | ; 23 | 24 | // Create a complex number 25 | std::complex c{0, 2}; 26 | 27 | // Print the square root 28 | Serial << "√(2i) = " << std::sqrt(c) << endl; 29 | } 30 | 31 | void loop() {} 32 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/STL/CountPressedButtons/CountPressedButtons.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Example of using the standard library algorithms and the Button class. 3 | * 4 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 5 | * 6 | * This sketch reads a number of push buttons or switches, and uses the standard 7 | * library algorithms to count how many of them are pressed. 8 | * 9 | * The internal pull-up resistors are enabled and the switches are debounced. 10 | * 11 | * Written by PieterP, 2019-11-24 12 | * https://github.com/tttapa/Arduino-Helpers 13 | */ 14 | #include 15 | 16 | #include // Button 17 | #include // std::accumulate 18 | 19 | // An array of debounced buttons connected to the given pins 20 | Button buttons[] { 21 | 2, 3, 4, 5, 6, 7, 8, 9, 22 | }; 23 | 24 | void setup() { 25 | for (auto &button : buttons) // for all buttons in the array 26 | button.begin(); // initialize (enable internal pull-up resistor) 27 | Serial.begin(115200); 28 | } 29 | 30 | void loop() { 31 | // function that adds one to the counter if the given button is pressed 32 | auto addOneIfPressed = [](unsigned count, const Button &button) { 33 | return button.getState() == Button::Pressed ? count + 1 : count; 34 | }; 35 | 36 | // read all buttons and debounce them 37 | for (auto &button : buttons) 38 | button.update(); 39 | 40 | // apply that function to all buttons and return the count 41 | unsigned pressed = 42 | std::accumulate(std::begin(buttons), // from the first button 43 | std::end(buttons), // to the last 44 | 0u, // initial value of the counter 45 | addOneIfPressed); // counter function to apply 46 | 47 | Serial.println(pressed); 48 | } 49 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/STL/Numeric/Numeric.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Example of using the standard library numeric functions. 3 | * 4 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 5 | * 6 | * This sketch creates an incremental array using the iota function, then 7 | * computes the inner product of the vector with itself, and uses that to 8 | * calculate the norm of the vector. 9 | * 10 | * **Output** 11 | * ~~~ 12 | * v = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 13 | * 〈v, v〉 = 385 14 | * ‖v‖ = 19.6214160 15 | * ~~~ 16 | * 17 | * Written by PieterP, 2019-11-18 18 | * https://github.com/tttapa/Arduino-Helpers 19 | */ 20 | 21 | #include 22 | 23 | #include // Array 24 | #include // For printing the array 25 | #include // std::sqrt 26 | #include // std::iota, std::inner_product 27 | 28 | void setup() { 29 | Serial.begin(115200); 30 | while (!Serial) 31 | ; 32 | 33 | // Create an array with the elements [1, 2 ... 9, 10] 34 | Array vector; 35 | std::iota(std::begin(vector), std::end(vector), 1); 36 | Serial << "v = [" << vector << ']' << endl; 37 | 38 | // Compute the inner product of vector with itself, with an initial sum of 0 39 | int sum_sq = std::inner_product(std::begin(vector), std::end(vector), 40 | std::begin(vector), 0); 41 | Serial << "〈v, v〉 = " << sum_sq << endl; 42 | 43 | // The 2-norm of a vector is the squareroot of the inner product with itself 44 | double norm = std::sqrt(sum_sq); 45 | Serial << "‖v‖ = " << setprecision(7) << norm << endl; 46 | } 47 | 48 | void loop() {} 49 | -------------------------------------------------------------------------------- /examples/Arduino-Helpers/Timing/BlinkWithoutDelay-Timer/BlinkWithoutDelay-Timer.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * This examples shows how use the Timer class to blink an LED every 3 | * second, in a non-blocking fashion (without using delay). 4 | * 5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32 6 | * 7 | * Behavior 8 | * -------- 9 | * 10 | * Blinks the built-in LED every second. 11 | * 12 | * Written by PieterP, 2019-12-06 13 | * https://github.com/tttapa/Arduino-Helpers 14 | */ 15 | 16 | #include 17 | #include 18 | 19 | Timer timer = 500; // milliseconds 20 | 21 | void setup() { 22 | pinMode(LED_BUILTIN, OUTPUT); 23 | } 24 | 25 | void loop() { 26 | if (timer) { 27 | digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) ? LOW : HIGH); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/test/ExtIO-pin-test/ExtIO-pin-test.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * An int literal as argument or constants like LED_BUILTIN should not result 3 | * in ambiguous overload selection. 4 | * 5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Teensy 3.x, ESP8266, ESP32 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | 12 | using namespace ExtIO; 13 | 14 | void setup() { 15 | pinMode(13, OUTPUT); 16 | pinMode(LED_BUILTIN, OUTPUT); 17 | } 18 | 19 | void loop() {} -------------------------------------------------------------------------------- /examples/test/STL-test/STL-test.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Teensy 3.x, ESP8266, ESP32 3 | */ 4 | #include -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Arduino Helpers 2 | version=2.0.0 3 | author=Pieter P 4 | maintainer=Pieter P 5 | sentence=This is a utility library with hardware abstraction, containers, type traits, easy printing, debugging, filters ... Includes a mocking and testing framework. 6 | paragraph=Originally part of the Control Surface library, split off to be used in other libraries as well, or stand-alone. 7 | category=Other 8 | url=https://github.com/tttapa/Arduino-Helpers 9 | architectures=avr,sam,samd,teensy,esp32,esp8266,megaavr,mbed,mbed_nano,mbed_rp2040,renesas_uno 10 | includes=Arduino_Helpers.h 11 | -------------------------------------------------------------------------------- /mock/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(GTest REQUIRED CONFIG) 2 | 3 | add_library(ArduinoMock 4 | "Core/Arduino.cpp" 5 | "Core/ArduinoMock.cpp" 6 | "Core/HardwareSerial0.cpp" 7 | "Core/Print.cpp" 8 | ) 9 | target_include_directories(ArduinoMock PUBLIC 10 | ${CMAKE_CURRENT_SOURCE_DIR}/Core 11 | ${CMAKE_CURRENT_SOURCE_DIR}/Core-Libraries 12 | ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/Adafruit_GFX 13 | ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/Adafruit_SSD1306 14 | ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/Encoder) 15 | target_link_libraries(ArduinoMock 16 | PUBLIC GTest::gtest GTest::gmock 17 | PRIVATE Arduino-Helpers::warnings) -------------------------------------------------------------------------------- /mock/Core-Libraries/SPI.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // TODO 4 | class SPIClass { 5 | } extern SPI; 6 | 7 | enum SPIMode { 8 | SPI_MODE0 = 0, 9 | SPI_MODE1 = 1, 10 | SPI_MODE2 = 2, 11 | SPI_MODE3 = 3, 12 | }; 13 | 14 | class SPISettings { 15 | public: 16 | SPISettings(uint32_t, BitOrder_t, SPIMode) {} 17 | }; -------------------------------------------------------------------------------- /mock/Core/Arduino.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "ArduinoMock.hpp" 3 | 4 | void sei() {} 5 | void cli() {} 6 | 7 | void yield() {} 8 | 9 | void pinMode(uint8_t pin, uint8_t mode) { 10 | ArduinoMock::getInstance().pinMode(pin, mode); 11 | } 12 | 13 | void digitalWrite(uint8_t pin, uint8_t state) { 14 | ArduinoMock::getInstance().digitalWrite(pin, state); 15 | } 16 | 17 | int digitalRead(uint8_t pin) { 18 | return ArduinoMock::getInstance().digitalRead(pin); 19 | } 20 | 21 | int analogRead(uint8_t pin) { 22 | return ArduinoMock::getInstance().analogRead(pin); 23 | } 24 | 25 | void analogReadResolution(uint8_t bits) { 26 | ArduinoMock::getInstance().analogReadResolution(bits); 27 | } 28 | 29 | void analogWrite(uint8_t pin, int value) { 30 | ArduinoMock::getInstance().analogWrite(pin, value); 31 | } 32 | 33 | void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, 34 | uint8_t val) { 35 | ArduinoMock::getInstance().shiftOut(dataPin, clockPin, bitOrder, val); 36 | } 37 | 38 | unsigned long millis() { return ArduinoMock::getInstance().millis(); } 39 | 40 | unsigned long micros() { return ArduinoMock::getInstance().micros(); } -------------------------------------------------------------------------------- /mock/Core/ArduinoMock.cpp: -------------------------------------------------------------------------------- 1 | #include "ArduinoMock.hpp" 2 | 3 | ArduinoMock *ArduinoMock::instance = nullptr; 4 | 5 | ArduinoMock &ArduinoMock::getInstance() { 6 | if (instance == nullptr) 7 | throw std::runtime_error("Error: no active ArduinoMock instance."); 8 | return *instance; 9 | } 10 | void ArduinoMock::begin() { 11 | if (instance != nullptr) 12 | throw std::runtime_error("Error: ArduinoMock instance already active."); 13 | instance = new ArduinoMock; 14 | } 15 | void ArduinoMock::end() { 16 | if (instance == nullptr) 17 | throw new std::runtime_error("Error: no acitve ArduinoMock instance."); 18 | delete instance; 19 | instance = nullptr; 20 | } 21 | 22 | SerialHelper &ArduinoMock::getSerial() { 23 | return getInstance().serial; 24 | } -------------------------------------------------------------------------------- /mock/Core/ArduinoMock.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "HardwareSerial.h" 4 | 5 | class ArduinoMock { 6 | private: 7 | ArduinoMock() {} 8 | SerialHelper serial; 9 | static ArduinoMock *instance; 10 | 11 | public: 12 | static ArduinoMock &getInstance(); 13 | static void begin(); 14 | static void end(); 15 | static SerialHelper &getSerial(); 16 | 17 | MOCK_METHOD(void, pinMode, (uint8_t, uint8_t)); 18 | MOCK_METHOD(void, digitalWrite, (uint8_t, uint8_t)); 19 | MOCK_METHOD(int, digitalRead, (uint8_t)); 20 | MOCK_METHOD(int, analogRead, (uint8_t)); 21 | MOCK_METHOD(void, analogReadResolution, (uint8_t)); 22 | MOCK_METHOD(void, analogWrite, (uint8_t, int)); 23 | MOCK_METHOD(void, shiftOut, (uint8_t, uint8_t, uint8_t, uint8_t)); 24 | 25 | MOCK_METHOD(unsigned long, millis, ()); 26 | MOCK_METHOD(unsigned long, micros, ()); 27 | 28 | virtual ~ArduinoMock() = default; 29 | }; -------------------------------------------------------------------------------- /mock/Core/HardwareSerial.h: -------------------------------------------------------------------------------- 1 | /* 2 | HardwareSerial.h - Hardware serial library for Wiring 3 | Copyright (c) 2006 Nicholas Zambetti. All right reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | Modified 28 September 2010 by Mark Sproul 20 | Modified 14 August 2012 by Alarus 21 | Modified 3 December 2013 by Matthijs Kooijman 22 | */ 23 | 24 | #ifndef HardwareSerial_h 25 | #define HardwareSerial_h 26 | 27 | #include "Stream.h" 28 | #include 29 | 30 | #ifdef F 31 | #undef F 32 | #endif 33 | 34 | #include 35 | 36 | class SerialHelper { 37 | public: 38 | MOCK_METHOD(void, begin, (unsigned long)); 39 | MOCK_METHOD(void, end, ()); 40 | 41 | MOCK_METHOD(int, available, ()); 42 | MOCK_METHOD(int, read, ()); 43 | MOCK_METHOD(int, peek, ()); 44 | 45 | MOCK_METHOD(size_t, write, (uint8_t)); 46 | MOCK_METHOD(size_t, write, (const uint8_t *, size_t)); 47 | 48 | virtual ~SerialHelper() = default; 49 | }; 50 | 51 | class HardwareSerial : public Stream { 52 | public: 53 | void begin(unsigned long baud); 54 | void end(); 55 | 56 | int available() override; 57 | int read() override; 58 | int peek() override; 59 | 60 | size_t write(uint8_t data) override; 61 | size_t write(const uint8_t *data, size_t len) override; 62 | explicit operator bool() const { return true; } 63 | }; 64 | 65 | extern HardwareSerial Serial; 66 | 67 | #ifndef F 68 | #define F(x) (reinterpret_cast(x)) 69 | #endif 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /mock/Core/HardwareSerial0.cpp: -------------------------------------------------------------------------------- 1 | #include "ArduinoMock.hpp" 2 | #include "HardwareSerial.h" 3 | 4 | void HardwareSerial::begin(unsigned long baud) { 5 | ArduinoMock::getSerial().begin(baud); 6 | } 7 | void HardwareSerial::end() { ArduinoMock::getSerial().end(); } 8 | 9 | int HardwareSerial::available() { return ArduinoMock::getSerial().available(); } 10 | int HardwareSerial::read() { return ArduinoMock::getSerial().read(); } 11 | int HardwareSerial::peek() { return ArduinoMock::getSerial().peek(); } 12 | 13 | size_t HardwareSerial::write(uint8_t data) { 14 | return ArduinoMock::getSerial().write(data); 15 | } 16 | size_t HardwareSerial::write(const uint8_t *data, size_t len) { 17 | return ArduinoMock::getSerial().write(data, len); 18 | } 19 | 20 | HardwareSerial Serial; -------------------------------------------------------------------------------- /mock/Core/Printable.h: -------------------------------------------------------------------------------- 1 | #ifndef Printable_h 2 | #define Printable_h 3 | 4 | #include 5 | 6 | class Print; 7 | 8 | class Printable { 9 | public: 10 | virtual size_t printTo(Print &p) const = 0; 11 | }; 12 | 13 | #include 14 | 15 | inline std::ostream &operator<<(std::ostream &os, const Printable &p) { 16 | OstreamPrint op = os; 17 | p.printTo(op); 18 | return os; 19 | } 20 | 21 | #endif -------------------------------------------------------------------------------- /mock/Core/Stream.h: -------------------------------------------------------------------------------- 1 | #ifndef Stream_h 2 | #define Stream_h 3 | 4 | #include "Print.h" 5 | 6 | class Stream : public Print { 7 | public: 8 | virtual int read() = 0; 9 | virtual int peek() = 0; 10 | virtual int available() = 0; 11 | }; 12 | 13 | #endif -------------------------------------------------------------------------------- /mock/Libraries/Adafruit_GFX/gfxfont.h: -------------------------------------------------------------------------------- 1 | // Font structures for newer Adafruit_GFX (1.1 and later). 2 | // Example fonts are included in 'Fonts' directory. 3 | // To use a font in your Arduino sketch, #include the corresponding .h 4 | // file and pass address of GFXfont struct to setFont(). Pass NULL to 5 | // revert to 'classic' fixed-space bitmap font. 6 | 7 | #ifndef _GFXFONT_H_ 8 | #define _GFXFONT_H_ 9 | 10 | /// Font data stored PER GLYPH 11 | typedef struct { 12 | uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap 13 | uint8_t width; ///< Bitmap dimensions in pixels 14 | uint8_t height; ///< Bitmap dimensions in pixels 15 | uint8_t xAdvance; ///< Distance to advance cursor (x axis) 16 | int8_t xOffset; ///< X dist from cursor pos to UL corner 17 | int8_t yOffset; ///< Y dist from cursor pos to UL corner 18 | } GFXglyph; 19 | 20 | /// Data stored for FONT AS A WHOLE 21 | typedef struct { 22 | uint8_t *bitmap; ///< Glyph bitmaps, concatenated 23 | GFXglyph *glyph; ///< Glyph array 24 | uint8_t first; ///< ASCII extents (first char) 25 | uint8_t last; ///< ASCII extents (last char) 26 | uint8_t yAdvance; ///< Newline distance (y axis) 27 | } GFXfont; 28 | 29 | #endif // _GFXFONT_H_ -------------------------------------------------------------------------------- /mock/Libraries/Encoder/Encoder.h: -------------------------------------------------------------------------------- 1 | #ifndef Encoder_h_ 2 | #define Encoder_h_ 3 | 4 | #include 5 | 6 | class EncoderMock { 7 | public: 8 | MOCK_CONST_METHOD0(read, long()); 9 | }; 10 | 11 | class Encoder { 12 | public: 13 | Encoder(int, int) : mock{nullptr} {} 14 | Encoder(const EncoderMock &mock) : mock(&mock) {} 15 | Encoder(const Encoder &) = default; 16 | long read() const { return mock ? mock->read() : 0; } 17 | 18 | private: 19 | const EncoderMock *mock; 20 | }; 21 | 22 | #endif -------------------------------------------------------------------------------- /mock/README.md: -------------------------------------------------------------------------------- 1 | # Arduino Mock 2 | 3 | This folder contains a mock version of the Arduino core. 4 | 5 | It provides the standard Arduino API (`digitalWrite`, `millis`, `Serial` etc.) 6 | with mocks that can be used during testing. -------------------------------------------------------------------------------- /scripts/addImplementationFiles.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import os 4 | import shutil 5 | from os.path import join, getsize, normpath, basename, splitext, relpath 6 | import sys 7 | 8 | script_dir = os.path.dirname(os.path.realpath(__file__)) 9 | src_dir = join(script_dir, "../src") 10 | 11 | template = """\ 12 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 13 | #include "{}" 14 | #endif 15 | """ 16 | 17 | def main(): 18 | for root, dirs, files in os.walk(src_dir): 19 | for f in files: 20 | name, ext = splitext(f) 21 | if ext == '.cpp': 22 | with open(join(root, f), 'r+') as cpp_file: 23 | num_lines = sum(1 for line in cpp_file) 24 | if num_lines > 1 and num_lines < 5: 25 | print(num_lines) 26 | print(normpath(join(root, f))) 27 | 28 | # if ext == '.cpp': 29 | # with open(join(root, f), 'r+') as cpp_file: 30 | # num_lines = sum(1 for line in cpp_file) 31 | # print(num_lines) 32 | # cpp_file.seek(0) 33 | # content = cpp_file.read() 34 | # if num_lines == 1: 35 | # cpp_file.seek(0) 36 | # cpp_file.write( 37 | # '#ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY\n') 38 | # cpp_file.write(content) 39 | # cpp_file.write('\n#endif') 40 | 41 | if (ext == '.hpp' or ext == '.h') \ 42 | and (not (name + '.cpp') in files) \ 43 | and (not (name + '.c') in files) \ 44 | and (basename(root) != 'Doxygen'): 45 | impl_ext = '.cpp' if ext == '.hpp' else '.c' 46 | with open(join(root, name + impl_ext), 'w') as cpp_file: 47 | cpp_file.write(template.format(f)) 48 | 49 | 50 | if __name__ == "__main__": 51 | main() 52 | -------------------------------------------------------------------------------- /scripts/ci/install-doxygen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to download and install Doxygen 4 | 5 | set -ex 6 | 7 | version="Release_1_9_4" # Release tag on GitHub 8 | prefix="${1:-$HOME/.local}" 9 | 10 | [ -e "$prefix/bin/doxygen" ] \ 11 | && exit 0 12 | 13 | mkdir /tmp/doxygen-install 14 | pushd /tmp/doxygen-install 15 | 16 | # Download 17 | [ -d "doxygen" ] \ 18 | || git clone --single-branch --depth=1 --branch "$version" \ 19 | https://github.com/doxygen/doxygen.git 20 | pushd doxygen 21 | # Configure 22 | cmake -Bbuild -S. \ 23 | -DCMAKE_INSTALL_PREFIX="$prefix" \ 24 | -DCMAKE_BUILD_TYPE=Release 25 | # Build 26 | cmake --build build -j1 27 | # Install 28 | cmake --install build 29 | 30 | popd 31 | popd -------------------------------------------------------------------------------- /scripts/ci/install-lcov.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to download and install LCOV 4 | 5 | set -ex 6 | 7 | version="v1.15" # Release tag on GitHub 8 | prefix="${1:-$HOME/.local}" 9 | 10 | [ -e "$prefix/bin/lcov" ] \ 11 | && exit 0 12 | 13 | mkdir /tmp/lcov-install 14 | pushd /tmp/lcov-install 15 | 16 | # Download 17 | [ -d "lcov" ] \ 18 | || git clone --single-branch --depth=1 --branch "$version" \ 19 | https://github.com/linux-test-project/lcov.git 20 | pushd lcov 21 | make install PREFIX="$prefix" 22 | 23 | popd 24 | popd 25 | -------------------------------------------------------------------------------- /scripts/coverage-badge.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Script that extracts the test coverage percentage and saves it as a JSON 4 | shields.io endpoint. 5 | """ 6 | 7 | from os.path import join, normpath, dirname, realpath 8 | import re 9 | 10 | script_dir = dirname(realpath(__file__)) 11 | cov_dir = normpath(join(dirname(script_dir), "docs", "Coverage")) 12 | 13 | json = """\ 14 | {{ 15 | "schemaVersion": 1, 16 | "label": "Test Coverage", 17 | "message": "{linecov}%", 18 | "color": "green" 19 | }} 20 | """ 21 | 22 | def main(): 23 | with open(join(cov_dir, 'index.html'), 'r') as f: 24 | pattern = r'([\d.]+)' 25 | linecov, funccov = map(lambda m: m.group(1), 26 | re.finditer(pattern, f.read())) 27 | print(linecov, funccov) 28 | 29 | with open(join(cov_dir, "shield.io.coverage.json"), 'w') as f: 30 | f.write(json.format(linecov=linecov)) 31 | 32 | 33 | if __name__ == "__main__": 34 | main() 35 | -------------------------------------------------------------------------------- /scripts/coverage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -ex 4 | 5 | dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 6 | 7 | proj_dir=$(dirname "$dir") 8 | build_dir=$(pwd) 9 | 10 | html_dest="$proj_dir/docs/Coverage" 11 | dest="$build_dir/coverage" 12 | mkdir -p "$dest" 13 | mkdir -p "$html_dest" 14 | 15 | rm -f "$dest/*.info" 16 | rm -rf "$html_dest/*" 17 | 18 | # Parse command line arguments 19 | 20 | compiler="${1,,}" 21 | version="${2%%.*}" 22 | 23 | if [ ! -z "$version" ]; then version="-${version}"; fi 24 | 25 | echo "Compiler: ${compiler}${version}" 26 | 27 | # If the compiler is Clang, use a wrapper around llvm-cov that emulates gcov 28 | # and use the right c++filt 29 | if [ "${compiler}" == "clang" ]; then 30 | mkdir -p "/tmp/clang-cxxfilt-gcov" 31 | echo -e "#!/usr/bin/env sh\nexec llvm-cov${version} gcov \"\$@\"" \ 32 | > "/tmp/clang-cxxfilt-gcov/llvm-cov" 33 | chmod +x "/tmp/clang-cxxfilt-gcov/llvm-cov" 34 | # Replace the default c++filt program with LLVM/Clang's version 35 | ln -sfn $(which llvm-cxxfilt${version}) /tmp/clang-cxxfilt-gcov/c++filt 36 | export PATH="/tmp/clang-cxxfilt-gcov:$PATH" 37 | gcov_bin="llvm-cov" 38 | else 39 | gcov_bin="gcov${version}" 40 | fi 41 | 42 | branches=0 43 | 44 | # Reset counters 45 | lcov \ 46 | --zerocounters \ 47 | --directory "$build_dir" 48 | 49 | # Initial capture 50 | lcov \ 51 | --capture --initial \ 52 | --directory "$build_dir" \ 53 | --include "$proj_dir"'/src/AH/**' \ 54 | --output-file "$dest"/coverage_base.info \ 55 | --gcov-tool "$gcov_bin" \ 56 | --rc lcov_branch_coverage=$branches 57 | 58 | # Run tests 59 | ctest 60 | 61 | # Actual capture 62 | lcov \ 63 | --capture \ 64 | --directory "$build_dir" \ 65 | --include "$proj_dir"'/src/AH/**' \ 66 | --output-file "$dest"/coverage_test.info \ 67 | --gcov-tool "$gcov_bin" \ 68 | --rc lcov_branch_coverage=$branches 69 | 70 | # Combine captures 71 | lcov \ 72 | --add-tracefile "$dest"/coverage_base.info \ 73 | --add-tracefile "$dest"/coverage_test.info \ 74 | --output-file "$dest"/coverage_total.info \ 75 | --gcov-tool "$gcov_bin" \ 76 | --rc lcov_branch_coverage=$branches 77 | 78 | # Generate HTML coverage report 79 | genhtml \ 80 | --prefix "$proj_dir" \ 81 | "$dest"/coverage_total.info \ 82 | --output-directory="$html_dest" \ 83 | --legend --title `cd "$proj_dir" && git rev-parse HEAD` \ 84 | --rc lcov_branch_coverage=$branches \ 85 | -s \ 86 | --demangle-cpp 87 | 88 | python3 "$proj_dir/scripts/coverage-badge.py" 89 | -------------------------------------------------------------------------------- /scripts/git-pull-arduino-helpers.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd "$(dirname "$0")" 4 | 5 | read -p "This script will reset and clean 'docs'. Press enter to confirm. " 6 | 7 | git pull arduino-helpers master 8 | git reset ../docs 9 | git reset ../examples/examples.dox 10 | git checkout ../docs 11 | git clean -d ../docs -f 12 | git checkout ../examples/examples.dox 13 | git add ../docs 14 | git add ../examples/examples.dox -------------------------------------------------------------------------------- /scripts/install-ci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | export PATH="$HOME/.local/bin:$PATH" 6 | 7 | if hash arduino-builder; then 8 | echo "Arduino already installed" 9 | else 10 | echo "Installing Arduino" 11 | 12 | cd /tmp 13 | wget https://downloads.arduino.cc/arduino-1.8.9-linux64.tar.xz 14 | mkdir -p ~/opt/ 15 | tar -xf arduino-1.8.9-linux64.tar.xz -C ~/opt/ 16 | 17 | mkdir -p $HOME/.local/share/icons/hicolor 18 | cd $HOME/opt/arduino-1.8.9 19 | ./install.sh 20 | 21 | mkdir -p ~/.local/bin 22 | ln -s ../../opt/arduino-1.8.9/arduino ~/.local/bin/ 23 | ln -s ../../opt/arduino-1.8.9/arduino-builder ~/.local/bin/ 24 | 25 | arduino --pref "boardsmanager.additional.urls=https://dl.espressif.com/dl/package_esp32_index.json,https://arduino.esp8266.com/stable/package_esp8266com_index.json" --save-prefs 26 | arduino --install-boards "esp32:esp32" 27 | arduino --install-boards "esp8266:esp8266" 28 | arduino --install-boards "arduino:avr:1.8.1" 29 | arduino --install-boards "arduino:sam" 30 | arduino --install-boards "arduino:samd" 31 | arduino --install-boards "arduino:megaavr" 32 | arduino --install-boards "arduino:mbed" 33 | 34 | cd /tmp 35 | wget https://www.pjrc.com/teensy/td_148/TeensyduinoInstall.linux64 36 | chmod +x TeensyduinoInstall.linux64 37 | ./TeensyduinoInstall.linux64 --dir="$HOME/opt/arduino-1.8.9" 38 | 39 | mkdir -p ~/Arduino/libraries && cd $_ 40 | git clone https://github.com/adafruit/Adafruit-GFX-Library.git & 41 | git clone https://github.com/tttapa/Adafruit_SSD1306.git & 42 | git clone https://github.com/PaulStoffregen/Encoder.git & 43 | git clone https://github.com/FastLED/FastLED.git & 44 | git clone https://github.com/arduino-libraries/MIDIUSB.git 45 | 46 | wait 47 | fi 48 | 49 | if hash lcov; then 50 | echo "LCOV already installed" 51 | else 52 | echo "Installing LCOV" 53 | cd /tmp 54 | git clone https://github.com/linux-test-project/lcov.git 55 | cd lcov 56 | make install PREFIX=$HOME/.local 57 | fi 58 | 59 | ln -s "${TRAVIS_BUILD_DIR}${GITHUB_WORKSPACE}" \ 60 | "$HOME/Arduino/libraries/Arduino-Helpers" -------------------------------------------------------------------------------- /scripts/install-gtest.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cd "$( dirname "${BASH_SOURCE[0]}" )"/.. 3 | 4 | build_type="${1:-RelWithDebInfo}" 5 | prefix="${2:-/usr/local}" 6 | 7 | set -ex 8 | 9 | pushd /tmp 10 | 11 | # GoogleTest framework 12 | rm -rf googletest 13 | git clone --single-branch --depth=1 --branch main \ 14 | https://github.com/google/googletest.git 15 | pushd googletest 16 | cmake -Bbuild -S. \ 17 | -D CMAKE_INSTALL_PREFIX="${prefix}" \ 18 | -D CMAKE_BUILD_TYPE="${build_type}" 19 | cmake --build build -j 20 | cmake --install build 21 | popd 22 | 23 | popd 24 | -------------------------------------------------------------------------------- /scripts/keywords.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | """ 3 | Script that gathers all keywords from the keywords.yml files in the src 4 | directory into the main keywords.txt file in the root folder. 5 | """ 6 | 7 | import os 8 | import shutil 9 | from os.path import join, normpath, dirname, splitext, relpath, realpath 10 | import sys 11 | import re 12 | 13 | from yaml import safe_load 14 | 15 | script_dir = dirname(realpath(__file__)) 16 | src_dir = normpath(join(script_dir, "../src")) 17 | 18 | 19 | warning = """\ 20 | ################################################################################ 21 | # AUTOMATICALLY GENERATED FILE # 22 | # # 23 | # ! Don't edit this file directly, edit the keywords.yml files in the ! # 24 | # ! appropriate subdirectories instead. ! # 25 | # # 26 | ################################################################################ 27 | 28 | """ 29 | 30 | def keywords_yaml2txt(file): 31 | data = safe_load(file) 32 | txt = "" 33 | for k, v in data.items(): 34 | if isinstance(k, str) and isinstance(v, list): 35 | txt += ''.join(map(lambda name: f'{name}\t{k.upper()}\n', v)) 36 | txt += '\n' 37 | return txt 38 | 39 | 40 | def main(): 41 | txt = warning 42 | for root, dirs, files in os.walk(src_dir): 43 | for f in files: 44 | if re.match(r'keywords.ya?ml', f): 45 | with open(join(root, f), 'r+') as yamlfile: 46 | name = relpath(root, src_dir) 47 | if name == '.': name = 'src' 48 | txt += "# " + name + '\n' 49 | txt += '#' * (len(name) + 2) + '\n' * 2 50 | txt += keywords_yaml2txt(yamlfile) 51 | with open(join(dirname(script_dir), 'keywords.txt'), 'w') as f: 52 | f.write(txt) 53 | 54 | 55 | if __name__ == "__main__": 56 | main() 57 | -------------------------------------------------------------------------------- /scripts/listNonEmptyImplementationFiles.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import os 4 | import shutil 5 | from os.path import join, getsize, normpath, basename, splitext, relpath 6 | import sys 7 | 8 | script_dir = os.path.dirname(os.path.realpath(__file__)) 9 | src_dir = join(script_dir, "../src") 10 | 11 | template = """\ 12 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 13 | #include "{}" 14 | #endif 15 | """ 16 | 17 | 18 | def main(): 19 | for root, dirs, files in os.walk(src_dir): 20 | for f in files: 21 | name, ext = splitext(f) 22 | if ext == '.cpp': 23 | with open(join(root, f), 'r+') as cpp_file: 24 | if not 'TEST_COMPILE_ALL_HEADERS_SEPARATELY' in cpp_file.read( 25 | ): 26 | print( 27 | relpath(normpath(join(root, f)), 28 | normpath(src_dir))) 29 | 30 | 31 | if __name__ == "__main__": 32 | main() 33 | -------------------------------------------------------------------------------- /src/AH/Arduino-Wrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | AH_DIAGNOSTIC_EXTERNAL_HEADER() 7 | #include // min max 8 | AH_DIAGNOSTIC_POP() 9 | 10 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 11 | 12 | #ifdef PSTR 13 | #pragma push_macro("PSTR") 14 | #undef PSTR 15 | #define PSTR(s) (s) 16 | #endif 17 | 18 | using FlashString_t = std::remove_reference::type *; 19 | 20 | #ifdef PSTR 21 | #pragma pop_macro("PSTR") 22 | #endif 23 | 24 | AH_DIAGNOSTIC_POP() 25 | -------------------------------------------------------------------------------- /src/AH/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | option(AH_FAST_COMPILE "Compile only necessary files" On) 2 | 3 | file(GLOB_RECURSE 4 | Arduino_Helpers_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) 5 | add_library(Arduino_Helpers ${Arduino_Helpers_SOURCES}) 6 | target_include_directories(Arduino_Helpers 7 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..) 8 | 9 | target_compile_definitions(Arduino_Helpers PUBLIC 10 | NO_DEBUG_PRINTS 11 | ANALOG_FILTER_SHIFT_FACTOR_OVERRIDE=2) 12 | 13 | target_link_libraries(Arduino_Helpers 14 | PUBLIC ArduinoMock 15 | PRIVATE Arduino-Helpers::warnings) 16 | -------------------------------------------------------------------------------- /src/AH/Containers/CRTP.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /// Helper for the Curiously Recurring Template Pattern. 4 | #define CRTP(Derived) (*static_cast(this)) 5 | #define CRTP_INST(Derived, el) (static_cast(el)) 6 | -------------------------------------------------------------------------------- /src/AH/Containers/Containers.dox: -------------------------------------------------------------------------------- 1 | /// @cond !AH_MAIN_LIBRARY 2 | /// @addtogroup AH_group 3 | /// @{ 4 | /// @endcond 5 | 6 | /** 7 | * @defgroup AH_Containers Containers 8 | * @brief Containers like Array, BitArray, DoublyLinkedList. 9 | */ 10 | 11 | /// @cond !AH_MAIN_LIBRARY 12 | /// @} 13 | /// @endcond -------------------------------------------------------------------------------- /src/AH/Containers/keywords.yml: -------------------------------------------------------------------------------- 1 | keyword1: 2 | # Array.hpp 3 | - Array 4 | - ArraySlice 5 | - iterator 6 | # BitArray.hpp 7 | - BitArray 8 | # LinkedList.hpp 9 | - DoublyLinkedList 10 | - iterator 11 | - const_iterator 12 | - reverse_iterator 13 | - const_reverse_iterator 14 | - DoublyLinkable 15 | # Updatable.hpp 16 | - NormalUpdatable 17 | - Updatable 18 | 19 | keyword2: 20 | # Array.hpp 21 | - length 22 | - begin 23 | - end 24 | - slice 25 | - cslice 26 | - asArray 27 | # ArrayHelpers.hpp 28 | - generate 29 | - generateArray 30 | - copyAs 31 | - fillArray 32 | - cat 33 | - distribute 34 | # BitArray.hpp 35 | - get 36 | - set 37 | - clear 38 | - safeIndex 39 | - getByte 40 | - getBufferLength 41 | # LinkedList.hpp 42 | - append 43 | - insertBefore 44 | - insertSorted 45 | - remove 46 | - moveDown 47 | - couldContain 48 | # Updatable.hpp 49 | - update 50 | - begin 51 | - enable 52 | - disable 53 | - isEnabled 54 | - beginAll 55 | - updateAll 56 | 57 | 58 | literal1: 59 | # Array.hpp 60 | - ElementRefType 61 | - ElementPtrType -------------------------------------------------------------------------------- /src/AH/Debug/Debug.cpp: -------------------------------------------------------------------------------- 1 | #include "Debug.hpp" 2 | 3 | #ifdef DEBUG_OUT 4 | #pragma message("Debugging enabled on output " DEBUG_STR(DEBUG_OUT)) 5 | 6 | #ifndef ARDUINO 7 | BEGIN_AH_NAMESPACE 8 | const decltype(std::chrono::high_resolution_clock::now()) start_time = 9 | std::chrono::high_resolution_clock::now(); 10 | END_AH_NAMESPACE 11 | #endif 12 | 13 | #endif 14 | 15 | #if defined(ESP32) 16 | BEGIN_AH_NAMESPACE 17 | std::mutex debugmutex; 18 | END_AH_NAMESPACE 19 | #elif defined(ARDUINO_ARCH_MBED) 20 | BEGIN_AH_NAMESPACE 21 | rtos::Mutex debugmutex; 22 | END_AH_NAMESPACE 23 | #endif -------------------------------------------------------------------------------- /src/AH/Debug/Debug.dox: -------------------------------------------------------------------------------- 1 | /// @cond !AH_MAIN_LIBRARY 2 | /// @addtogroup AH_group 3 | /// @{ 4 | /// @endcond 5 | 6 | /** 7 | * @defgroup AH_Debug Debug 8 | * @brief Macros for printing debug information that can be easily enabled or 9 | * disabled. 10 | * 11 | * @see @ref md_pages_Debug for instructions on how to add an option in the 12 | * Arduino IDE to easily enable and disable debugging. 13 | */ 14 | 15 | /// @cond !AH_MAIN_LIBRARY 16 | /// @} 17 | /// @endcond -------------------------------------------------------------------------------- /src/AH/Error/Error.dox: -------------------------------------------------------------------------------- 1 | /// @cond !AH_MAIN_LIBRARY 2 | /// @addtogroup AH_group 3 | /// @{ 4 | /// @endcond 5 | 6 | /** 7 | * @defgroup AH_Error Error 8 | * @brief Macros for handling and reporting both fatal and non-fatal errors. 9 | */ 10 | 11 | /// @cond !AH_MAIN_LIBRARY 12 | /// @} 13 | /// @endcond -------------------------------------------------------------------------------- /src/AH/Error/Exit.cpp: -------------------------------------------------------------------------------- 1 | #ifdef ARDUINO 2 | 3 | #include "Error.hpp" 4 | 5 | BEGIN_AH_NAMESPACE 6 | 7 | void fatalErrorExit() { 8 | #if defined(LED_BUILTIN) || (defined(ESP32) && defined(BUILTIN_LED)) 9 | pinMode(LED_BUILTIN, OUTPUT); 10 | while (1) { 11 | digitalWrite(LED_BUILTIN, HIGH); 12 | delay(50); 13 | digitalWrite(LED_BUILTIN, LOW); 14 | delay(50); 15 | digitalWrite(LED_BUILTIN, HIGH); 16 | delay(50); 17 | digitalWrite(LED_BUILTIN, LOW); 18 | delay(850); 19 | } 20 | #else 21 | #warning "LED_BUILTIN is not available, so it cannot blink when an error occurs" 22 | noInterrupts(); 23 | while (1) 24 | yield(); 25 | #endif 26 | } 27 | 28 | END_AH_NAMESPACE 29 | 30 | #endif -------------------------------------------------------------------------------- /src/AH/Filters/Filters.dox: -------------------------------------------------------------------------------- 1 | /// @cond !AH_MAIN_LIBRARY 2 | /// @addtogroup AH_group 3 | /// @{ 4 | /// @endcond 5 | 6 | /** 7 | * @defgroup AH_Filters Filters 8 | * @brief Classes for basic filtering and hysteresis. 9 | */ 10 | 11 | /// @cond !AH_MAIN_LIBRARY 12 | /// @} 13 | /// @endcond -------------------------------------------------------------------------------- /src/AH/Filters/keywords.yml: -------------------------------------------------------------------------------- 1 | keyword1: 2 | # EMA.hpp 3 | - EMA 4 | - EMA_f 5 | # Hysteresis.hpp 6 | - Hysteresis 7 | 8 | keyword2: 9 | # EMA.hpp 10 | - filter 11 | # Hysteresis.hpp 12 | - update 13 | - getValue -------------------------------------------------------------------------------- /src/AH/Hardware/ADCConfig.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /** 4 | * @file 5 | * @brief This file contains the platform-specific ADC resolutions. 6 | * By default, the library automatically selects the maximum supported 7 | * resolution for known boards, otherwise, it falls back to 10 bits. 8 | * @cond AH_MAIN_LIBRARY 9 | * @see @ref ADC_BITS 10 | * @endcond 11 | * @cond !AH_MAIN_LIBRARY 12 | * @see @ref AH::ADC_BITS 13 | * @endcond 14 | */ 15 | 16 | #include 17 | 18 | #if defined(ADC_RESOLUTION) 19 | #define HAS_ANALOG_READ_RESOLUTION 1 20 | 21 | // Teensy 22 | //------------------------------------------------------------------------------ 23 | #elif defined(TEENSYDUINO) && !defined(DOXYGEN) 24 | 25 | #if defined(__AVR__) // Teensy 2.x 26 | #define ADC_RESOLUTION 10 27 | #define HAS_ANALOG_READ_RESOLUTION 0 28 | 29 | #elif defined(__MK20DX128__) // Teensy 3.0 30 | #define ADC_RESOLUTION 13 31 | #define HAS_ANALOG_READ_RESOLUTION 1 32 | 33 | #elif defined(__MK20DX256__) // Teensy 3.1/3.2 34 | #define ADC_RESOLUTION 13 35 | #define HAS_ANALOG_READ_RESOLUTION 1 36 | 37 | #elif defined(__MKL26Z64__) // Teensy LC 38 | #define ADC_RESOLUTION 12 39 | #define HAS_ANALOG_READ_RESOLUTION 1 40 | 41 | #elif defined(__MK64FX512__) // Teensy 3.5 42 | #define ADC_RESOLUTION 13 43 | #define HAS_ANALOG_READ_RESOLUTION 1 44 | 45 | #elif defined(__MK66FX1M0__) // Teensy 3.6 46 | #define ADC_RESOLUTION 13 47 | #define HAS_ANALOG_READ_RESOLUTION 1 48 | 49 | #elif defined(__IMXRT1062__) || defined(__IMXRT1052__) // Teensy 4.0 50 | #define ADC_RESOLUTION 12 51 | #define HAS_ANALOG_READ_RESOLUTION 1 52 | 53 | #else 54 | #warning "Unknown Teensy board, please open an issue on GitHub" \ 55 | "https://github.com/tttapa/Arduino-Helpers" 56 | #endif 57 | 58 | // ESP32 59 | //------------------------------------------------------------------------------ 60 | #elif defined(ESP32) 61 | 62 | #define ADC_RESOLUTION 12 63 | #define HAS_ANALOG_READ_RESOLUTION 1 64 | 65 | // Unit test on PC 66 | // ----------------------------------------------------------------------------- 67 | #elif !defined(ARDUINO) 68 | 69 | #define ADC_RESOLUTION 10 70 | #define HAS_ANALOG_READ_RESOLUTION 1 71 | 72 | // Unknown/Default 73 | //------------------------------------------------------------------------------ 74 | #else 75 | /// The actual maximum resolution of the built-in ADC. 76 | #define ADC_RESOLUTION 10 77 | /// Whether the platform supports the `analogReadResolution` function. 78 | #define HAS_ANALOG_READ_RESOLUTION 0 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /src/AH/Hardware/Arduino-Hardware-Types.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include // pin functions and constants 7 | 8 | #if defined(ARDUINO_API_VERSION) 9 | 10 | using ArduinoPin_t = pin_size_t; 11 | using PinStatus_t = PinStatus; 12 | using PinMode_t = PinMode; 13 | using BitOrder_t = BitOrder; 14 | 15 | #else // ARDUINO_API_VERSION 16 | 17 | using ArduinoPin_t = 18 | AH::function_traits::argument_t<0>; 19 | using PinStatus_t = 20 | AH::function_traits::argument_t<1>; 21 | using PinMode_t = AH::function_traits::argument_t<1>; 22 | 23 | #if defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) 24 | using BitOrder_t = BitOrder; 25 | #else 26 | using BitOrder_t = uint8_t; 27 | #endif 28 | 29 | namespace AH_pin_detail { 30 | constexpr static auto tmp_HIGH = HIGH; 31 | constexpr static auto tmp_LOW = LOW; 32 | constexpr static auto tmp_INPUT = INPUT; 33 | constexpr static auto tmp_OUTPUT = OUTPUT; 34 | constexpr static auto tmp_INPUT_PULLUP = INPUT_PULLUP; 35 | } // namespace AH_pin_detail 36 | #ifdef HIGH 37 | #undef HIGH 38 | #define HIGH HIGH 39 | #endif 40 | #ifdef LOW 41 | #undef LOW 42 | #define LOW LOW 43 | #endif 44 | #ifdef INPUT 45 | #undef INPUT 46 | #define INPUT INPUT 47 | #endif 48 | #ifdef OUTPUT 49 | #undef OUTPUT 50 | #define OUTPUT OUTPUT 51 | #endif 52 | #ifdef INPUT_PULLUP 53 | #undef INPUT_PULLUP 54 | #define INPUT_PULLUP INPUT_PULLUP 55 | #endif 56 | constexpr PinStatus_t HIGH = AH_pin_detail::tmp_HIGH; 57 | constexpr PinStatus_t LOW = AH_pin_detail::tmp_LOW; 58 | constexpr PinMode_t INPUT = AH_pin_detail::tmp_INPUT; 59 | constexpr PinMode_t OUTPUT = AH_pin_detail::tmp_OUTPUT; 60 | constexpr PinMode_t INPUT_PULLUP = AH_pin_detail::tmp_INPUT_PULLUP; 61 | 62 | #endif // ARDUINO_API_VERSION 63 | 64 | BEGIN_AH_NAMESPACE 65 | template 66 | inline ArduinoPin_t arduino_pin_cast(T t) { 67 | return static_cast(t); 68 | } 69 | END_AH_NAMESPACE 70 | -------------------------------------------------------------------------------- /src/AH/Hardware/Button.cpp: -------------------------------------------------------------------------------- 1 | #include "Button.hpp" 2 | 3 | BEGIN_AH_NAMESPACE 4 | 5 | Button::Button(pin_t pin) : pin(pin) {} 6 | 7 | void Button::begin() { ExtIO::pinMode(pin, INPUT_PULLUP); } 8 | 9 | void Button::invert() { state.invert = true; } 10 | 11 | Button::State Button::update() { 12 | // Read pin state and current time 13 | bool input = ExtIO::digitalRead(pin) ^ state.invert; 14 | unsigned long now = millis(); 15 | // Check if enough time has elapsed after last bounce 16 | if (state.bouncing) 17 | state.bouncing = now - state.prevBounceTime <= debounceTime; 18 | // Shift the debounced state one bit to the left, either appending the 19 | // new input state if not bouncing, or repeat the old state if bouncing 20 | bool prevState = state.debounced & 0b01; 21 | bool newState = state.bouncing ? prevState : input; 22 | state.debounced = (prevState << 1) | newState; 23 | // Check if the input changed state (button pressed, released or bouncing) 24 | if (input != state.prevInput) { 25 | state.bouncing = true; 26 | state.prevInput = input; 27 | state.prevBounceTime = now; 28 | } 29 | return getState(); 30 | } 31 | 32 | Button::State Button::getState() const { 33 | return static_cast(state.debounced); 34 | } 35 | 36 | FlashString_t Button::getName(Button::State state) { 37 | switch (state) { 38 | case Button::Pressed: return F("Pressed"); 39 | case Button::Released: return F("Released"); 40 | case Button::Falling: return F("Falling"); 41 | case Button::Rising: return F("Rising"); 42 | default: return F(""); // Keeps the compiler happy 43 | } 44 | } 45 | 46 | unsigned long Button::previousBounceTime() const { 47 | return state.prevBounceTime; 48 | } 49 | 50 | unsigned long Button::stableTime(unsigned long now) const { 51 | return now - previousBounceTime(); 52 | } 53 | 54 | unsigned long Button::stableTime() const { return stableTime(millis()); } 55 | 56 | void Button::setDebounceTime(unsigned long debounceTime) { 57 | Button::debounceTime = debounceTime; 58 | } 59 | 60 | unsigned long Button::getDebounceTime() { return Button::debounceTime; } 61 | 62 | unsigned long Button::debounceTime = BUTTON_DEBOUNCE_TIME; 63 | 64 | END_AH_NAMESPACE 65 | -------------------------------------------------------------------------------- /src/AH/Hardware/ButtonMatrix.hpp: -------------------------------------------------------------------------------- 1 | /* ✔ */ 2 | 3 | #pragma once 4 | 5 | #include 6 | 7 | BEGIN_AH_NAMESPACE 8 | 9 | /** 10 | * @brief A class that reads the states of a button matrix. 11 | * 12 | * @tparam NumRows 13 | * The number of rows in the button matrix. 14 | * @tparam NumCols 15 | * The number of columns in the button matrix. 16 | * 17 | * @ingroup AH_HardwareUtils 18 | */ 19 | template 20 | class ButtonMatrix { 21 | public: 22 | /** 23 | * @brief Construct a new ButtonMatrix object. 24 | * 25 | * @param rowPins 26 | * A list of pin numbers connected to the rows of the button 27 | * matrix. 28 | * **⚠** These pins will be driven LOW as outputs (Lo-Z). 29 | * @param colPins 30 | * A list of pin numbers connected to the columns of the button 31 | * matrix. 32 | * These pins will be used as inputs (Hi-Z), and the internal 33 | * pull-up resistor will be enabled. 34 | */ 35 | ButtonMatrix(const PinList &rowPins, 36 | const PinList &colPins); 37 | 38 | /** 39 | * @brief Initialize (enable internal pull-up resistors on column pins). 40 | */ 41 | void begin(); 42 | 43 | /** 44 | * @brief Scan the matrix, read all button states, and call the 45 | * onButtonChanged callback. 46 | */ 47 | void update(); 48 | 49 | /** 50 | * Get the state of the button in the given column and row. 51 | * 52 | * @note No bounds checking is performed. 53 | */ 54 | bool getPrevState(uint8_t col, uint8_t row); 55 | 56 | /// Configure the debounce time interval. Only one button can change in each 57 | /// debounce interval. Time in milliseconds. 58 | void setDebounceTime(unsigned long debounceTime) { 59 | this->debounceTime = debounceTime; 60 | } 61 | /// Get the debounce time. 62 | unsigned long getDebounceTime() const { return debounceTime; } 63 | 64 | protected: 65 | /** 66 | * @brief The callback function that is called whenever a button changes 67 | * state. Implement this in the derived class. 68 | * 69 | * @param row 70 | * The row of the button that changed state. 71 | * @param col 72 | * The column of the button that changed state. 73 | * @param state 74 | * The new state of the button. 75 | */ 76 | void onButtonChanged(uint8_t row, uint8_t col, bool state) = delete; 77 | 78 | private: 79 | static inline uint8_t positionToBits(uint8_t col, uint8_t row); 80 | static inline uint8_t bitsToIndex(uint8_t bits); 81 | static inline uint8_t bitsToBitmask(uint8_t bits); 82 | void setPrevState(uint8_t col, uint8_t row, bool state); 83 | 84 | unsigned long debounceTime = BUTTON_DEBOUNCE_TIME; 85 | unsigned long prevRefresh = 0; 86 | uint8_t prevStates[(NumCols * NumRows + 7) / 8]; 87 | 88 | const PinList rowPins; 89 | const PinList colPins; 90 | }; 91 | 92 | END_AH_NAMESPACE 93 | 94 | #include "ButtonMatrix.ipp" // Template implementations 95 | -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/ExtIO.dox: -------------------------------------------------------------------------------- 1 | /// @cond !AH_MAIN_LIBRARY 2 | /// @addtogroup AH_group 3 | /// @{ 4 | /// @endcond 5 | 6 | /** 7 | * @defgroup AH_ExtIO Extended Input/Output 8 | * @brief All Elements that extend the number of IO pins of the Arduino: 9 | * Includes shift registers (e.g. 74HC595), multiplexers (e.g. 74HC4067, 10 | * 74HC4051), port expanders (e.g. MCP23017), LED drivers (e.g. 11 | * MAX7219), etc. 12 | */ 13 | 14 | /// @cond !AH_MAIN_LIBRARY 15 | /// @} 16 | /// @endcond -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.cpp: -------------------------------------------------------------------------------- 1 | #include "ExtendedIOElement.hpp" 2 | #include 3 | #include // is_unsigned 4 | 5 | BEGIN_AH_NAMESPACE 6 | 7 | ExtendedIOElement::ExtendedIOElement(pin_t length) 8 | : length(length), start(offset), end(offset + length) { 9 | if (end < start) 10 | FATAL_ERROR(F("ExtIO ran out of pin numbers. " 11 | "Dynamically creating new ExtendedIOElements is not " 12 | "recommended."), 13 | 0x00FF); 14 | offset = end; 15 | } 16 | 17 | void ExtendedIOElement::beginAll() { 18 | ExtendedIOElement::applyToAll(&ExtendedIOElement::begin); 19 | } 20 | 21 | void ExtendedIOElement::updateAllBufferedOutputs() { 22 | ExtendedIOElement::applyToAll(&ExtendedIOElement::updateBufferedOutputs); 23 | } 24 | 25 | void ExtendedIOElement::updateAllBufferedInputs() { 26 | ExtendedIOElement::applyToAll(&ExtendedIOElement::updateBufferedInputs); 27 | } 28 | 29 | pin_t ExtendedIOElement::pin(pin_t p) const { 30 | if (p >= length) { 31 | static_assert(std::is_unsigned::value, 32 | "Error: pin_t should be an unsigned integer type"); 33 | ERROR(F("Error: the pin number (") 34 | << p 35 | << F(") is greater than the number of pins of this " 36 | "ExtendedIOElement (") 37 | << length << ')', 38 | 0x4567); 39 | return end - 1; // LCOV_EXCL_LINE 40 | } 41 | return p + start; 42 | } 43 | 44 | pin_t ExtendedIOElement::operator[](pin_t p) const { return pin(p); } 45 | 46 | pin_t ExtendedIOElement::getLength() const { return length; } 47 | 48 | pin_t ExtendedIOElement::getEnd() const { return end; } 49 | 50 | pin_t ExtendedIOElement::getStart() const { return start; } 51 | 52 | DoublyLinkedList &ExtendedIOElement::getAll() { 53 | return updatables; 54 | } 55 | 56 | pin_t ExtendedIOElement::offset = NUM_DIGITAL_PINS + NUM_ANALOG_INPUTS; 57 | 58 | END_AH_NAMESPACE 59 | -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/SPIShiftRegisterOut.hpp: -------------------------------------------------------------------------------- 1 | /* ✔ */ 2 | 3 | #pragma once 4 | 5 | #include "ShiftRegisterOutBase.hpp" 6 | 7 | #include // MSBFIRST, SS 8 | AH_DIAGNOSTIC_EXTERNAL_HEADER() 9 | #include 10 | AH_DIAGNOSTIC_POP() 11 | 12 | BEGIN_AH_NAMESPACE 13 | 14 | /** 15 | * @brief A class for serial-in/parallel-out shift registers, 16 | * like the 74HC595 that are connected to the SPI bus. 17 | * 18 | * @tparam N 19 | * The number of bits in total. Usually, shift registers (e.g. the 20 | * 74HC595) have eight bits per chip, so `length = 8 * k` where `k` 21 | * is the number of cascaded chips. 22 | * @tparam SPIDriver 23 | * The SPI class to use. Usually, the default is fine. 24 | * 25 | * @ingroup AH_ExtIO 26 | */ 27 | template 28 | class SPIShiftRegisterOut : public ShiftRegisterOutBase { 29 | public: 30 | /** 31 | * @brief Create a new SPIShiftRegisterOut object with a given bit order, 32 | * and a given number of outputs. 33 | * 34 | * Multiple shift registers can be cascaded by connecting the serial output 35 | * of the first one to the input of the second one: 36 | * 37 | * ``` 38 | * SCK >───────────┬──────────────────────┬───────── ⋯ 39 | * ┏━━━━━━━┷━━━━━━━┓ ┏━━━━━━━┷━━━━━━━┓ 40 | * ┃ SH_CP ┃ ┃ SH_CP ┃ 41 | * MOSI >───┨ DS Q7S ┠──────┨ DS Q7S ┠─ ⋯ 42 | * ┃ ST_CP ┃ ┃ ST_CP ┃ 43 | * ┗━━━━━━━┯━━━━━━━┛ ┗━━━━━━━┯━━━━━━━┛ 44 | * CS >───────────┴──────────────────────┴───────── ⋯ 45 | * ``` 46 | * 47 | * @param spi 48 | * The SPI interface to use. 49 | * @param latchPin 50 | * The digital output pin connected to the latch pin (ST_CP or 51 | * RCLK) of the shift register. 52 | * @param bitOrder 53 | * Either `MSBFIRST` (most significant bit first) or `LSBFIRST` 54 | * (least significant bit first). 55 | */ 56 | SPIShiftRegisterOut(SPIDriver spi, pin_t latchPin = SS, 57 | BitOrder_t bitOrder = MSBFIRST); 58 | 59 | /** 60 | * @brief Initialize the shift register. 61 | * Setup the SPI interface, set the CS pin to output mode, 62 | * and set all shift register outputs to `LOW`. 63 | */ 64 | void begin() override; 65 | 66 | /** 67 | * @brief Write the state buffer to the physical outputs. 68 | */ 69 | void updateBufferedOutputs() override; 70 | 71 | private: 72 | SPIDriver spi; 73 | 74 | public: 75 | SPISettings settings{SPI_MAX_SPEED, this->bitOrder, SPI_MODE0}; 76 | }; 77 | 78 | END_AH_NAMESPACE 79 | 80 | #include "SPIShiftRegisterOut.ipp" 81 | -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/SPIShiftRegisterOut.ipp: -------------------------------------------------------------------------------- 1 | #ifdef ARDUINO // TODO: I'm too lazy to mock the SPI library 2 | 3 | #include "ExtendedInputOutput.hpp" 4 | #include "SPIShiftRegisterOut.hpp" 5 | 6 | AH_DIAGNOSTIC_EXTERNAL_HEADER() 7 | #include 8 | AH_DIAGNOSTIC_POP() 9 | 10 | BEGIN_AH_NAMESPACE 11 | 12 | template 13 | SPIShiftRegisterOut::SPIShiftRegisterOut(SPIDriver spi, 14 | pin_t latchPin, 15 | BitOrder_t bitOrder) 16 | : ShiftRegisterOutBase(latchPin, bitOrder), 17 | spi(std::forward(spi)) {} 18 | 19 | template 20 | void SPIShiftRegisterOut::begin() { 21 | ExtIO::pinMode(this->latchPin, OUTPUT); 22 | spi.begin(); 23 | updateBufferedOutputs(); 24 | } 25 | 26 | template 27 | void SPIShiftRegisterOut::updateBufferedOutputs() { 28 | if (!this->dirty) 29 | return; 30 | spi.beginTransaction(settings); 31 | ExtIO::digitalWrite(this->latchPin, LOW); 32 | const uint16_t bufferLength = this->buffer.getBufferLength(); 33 | if (this->bitOrder == LSBFIRST) 34 | for (uint16_t i = 0; i < bufferLength; i++) 35 | spi.transfer(this->buffer.getByte(i)); 36 | else 37 | for (uint16_t i = bufferLength; i-->0;) 38 | spi.transfer(this->buffer.getByte(i)); 39 | ExtIO::digitalWrite(this->latchPin, HIGH); 40 | spi.endTransaction(); 41 | this->dirty = false; 42 | } 43 | 44 | END_AH_NAMESPACE 45 | 46 | #endif -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/ShiftRegisterOut.hpp: -------------------------------------------------------------------------------- 1 | /* ✔ */ 2 | 3 | #pragma once 4 | 5 | #include "ShiftRegisterOutBase.hpp" 6 | 7 | #include // MSBFIRST 8 | 9 | BEGIN_AH_NAMESPACE 10 | 11 | /** 12 | * @brief A class for serial-in/parallel-out shift registers, 13 | * like the 74HC595. 14 | * 15 | * @ingroup AH_ExtIO 16 | */ 17 | template 18 | class ShiftRegisterOut : public ShiftRegisterOutBase { 19 | public: 20 | /** 21 | * @brief Create a new ShiftRegisterOut object with a shift register 22 | * connected to the given pins, with a given bit order, 23 | * and a given number of outputs. 24 | * 25 | * Multiple shift registers can be cascaded by connecting the serial output 26 | * of the first one to the input of the second one: 27 | * ``` 28 | * clockPin >───────────┬──────────────────────┬───────── ⋯ 29 | * ┏━━━━━━━┷━━━━━━━┓ ┏━━━━━━━┷━━━━━━━┓ 30 | * ┃ SH_CP ┃ ┃ SH_CP ┃ 31 | * dataPin >───┨ DS Q7S ┠──────┨ DS Q7S ┠─ ⋯ 32 | * ┃ ST_CP ┃ ┃ ST_CP ┃ 33 | * ┗━━━━━━━┯━━━━━━━┛ ┗━━━━━━━┯━━━━━━━┛ 34 | * latchPin >───────────┴──────────────────────┴───────── ⋯ 35 | * ``` 36 | * 37 | * @param dataPin 38 | * The digital output pin connected to the serial data input (DS or 39 | * SER) of the shift register. 40 | * @param clockPin 41 | * The digital output pin connected to the clock input (SH_CP or 42 | * SRCLK) of the shift register. 43 | * @param latchPin 44 | * The digital output pin connected to the latch pin (ST_CP or 45 | * RCLK) of the shift register. 46 | * @param bitOrder 47 | * Either `MSBFIRST` (most significant bit first) or `LSBFIRST` 48 | * (least significant bit first). 49 | */ 50 | ShiftRegisterOut(pin_t dataPin, pin_t clockPin, pin_t latchPin, 51 | BitOrder_t bitOrder = MSBFIRST); 52 | 53 | /** 54 | * @brief Initialize the shift register. 55 | * Set the data and clock pins to output mode, 56 | * and set all shift register outputs to `LOW`. 57 | */ 58 | void begin() override; 59 | 60 | /** 61 | * @brief Write the state buffer to the physical outputs. 62 | */ 63 | void updateBufferedOutputs() override; 64 | 65 | private: 66 | const pin_t dataPin; 67 | const pin_t clockPin; 68 | }; 69 | 70 | END_AH_NAMESPACE 71 | 72 | #include "ShiftRegisterOut.ipp" 73 | -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/ShiftRegisterOut.ipp: -------------------------------------------------------------------------------- 1 | #include "ExtendedInputOutput.hpp" 2 | #include "ShiftRegisterOut.hpp" 3 | 4 | BEGIN_AH_NAMESPACE 5 | 6 | template 7 | ShiftRegisterOut::ShiftRegisterOut(pin_t dataPin, pin_t clockPin, 8 | pin_t latchPin, BitOrder_t bitOrder) 9 | : ShiftRegisterOutBase(latchPin, bitOrder), dataPin(dataPin), 10 | clockPin(clockPin) {} 11 | 12 | template 13 | void ShiftRegisterOut::begin() { 14 | ExtIO::pinMode(dataPin, OUTPUT); 15 | ExtIO::pinMode(clockPin, OUTPUT); 16 | ExtIO::pinMode(this->latchPin, OUTPUT); 17 | updateBufferedOutputs(); 18 | } 19 | 20 | template 21 | void ShiftRegisterOut::updateBufferedOutputs() { 22 | if (!this->dirty) 23 | return; 24 | ExtIO::digitalWrite(this->latchPin, LOW); 25 | const uint8_t bufferLength = this->buffer.getBufferLength(); 26 | if (this->bitOrder == LSBFIRST) 27 | for (uint8_t i = 0; i < bufferLength; i++) 28 | ExtIO::shiftOut(dataPin, clockPin, LSBFIRST, 29 | this->buffer.getByte(i)); 30 | else 31 | for (int8_t i = bufferLength - 1; i >= 0; i--) 32 | ExtIO::shiftOut(dataPin, clockPin, MSBFIRST, 33 | this->buffer.getByte(i)); 34 | 35 | ExtIO::digitalWrite(this->latchPin, HIGH); 36 | this->dirty = false; 37 | } 38 | 39 | END_AH_NAMESPACE -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/ShiftRegisterOutBase.ipp: -------------------------------------------------------------------------------- 1 | #include "ExtendedInputOutput.hpp" 2 | #include "ShiftRegisterOutBase.hpp" 3 | #include "ShiftRegisterOutRGB.hpp" 4 | 5 | BEGIN_AH_NAMESPACE 6 | 7 | template 8 | ShiftRegisterOutBase::ShiftRegisterOutBase(pin_t latchPin, 9 | BitOrder_t bitOrder) 10 | : latchPin(latchPin), bitOrder(bitOrder) {} 11 | 12 | template 13 | void ShiftRegisterOutBase::digitalWrite(pin_t pin, PinStatus_t val) { 14 | buffer.set(pin, val); 15 | dirty = true; 16 | this->updateBufferedOutputs(); // TODO: should I always update? 17 | } 18 | 19 | template 20 | void ShiftRegisterOutBase::digitalWriteBuffered(pin_t pin, PinStatus_t val) { 21 | buffer.set(pin, val); 22 | dirty = true; 23 | } 24 | 25 | template 26 | PinStatus_t ShiftRegisterOutBase::digitalRead(pin_t pin) { 27 | return buffer.get(pin) ? HIGH : LOW; 28 | } 29 | 30 | template 31 | pin_t ShiftRegisterOutBase::green(pin_t id) { 32 | return this->pin(3 * id + ShiftRegisterOutRGB::greenBit); 33 | } 34 | 35 | template 36 | Array ShiftRegisterOutBase::greenPins() { 37 | return generateIncrementalArray( 38 | this->pin(ShiftRegisterOutRGB::greenBit), 3); 39 | } 40 | 41 | template 42 | pin_t ShiftRegisterOutBase::red(pin_t id) { 43 | return this->pin(3 * id + ShiftRegisterOutRGB::redBit); 44 | } 45 | 46 | template 47 | Array ShiftRegisterOutBase::redPins() { 48 | return generateIncrementalArray( 49 | this->pin(ShiftRegisterOutRGB::redBit), 3); 50 | } 51 | 52 | template 53 | pin_t ShiftRegisterOutBase::blue(pin_t id) { 54 | return this->pin(3 * id + ShiftRegisterOutRGB::blueBit); 55 | } 56 | 57 | template 58 | Array ShiftRegisterOutBase::bluePins() { 59 | return generateIncrementalArray( 60 | this->pin(ShiftRegisterOutRGB::blueBit), 3); 61 | } 62 | 63 | END_AH_NAMESPACE -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/ShiftRegisterOutRGB.cpp: -------------------------------------------------------------------------------- 1 | #include "ShiftRegisterOutRGB.hpp" 2 | 3 | BEGIN_AH_NAMESPACE 4 | 5 | const uint8_t ShiftRegisterOutRGB::redBit __attribute__((weak)) = 0; 6 | const uint8_t ShiftRegisterOutRGB::greenBit __attribute__((weak)) = 1; 7 | const uint8_t ShiftRegisterOutRGB::blueBit __attribute__((weak)) = 2; 8 | 9 | END_AH_NAMESPACE 10 | -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/ShiftRegisterOutRGB.hpp: -------------------------------------------------------------------------------- 1 | /* ✔ */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | 8 | BEGIN_AH_NAMESPACE 9 | 10 | /** 11 | * @brief A struct for setting the RGB mode for RGB shift registers. 12 | */ 13 | struct ShiftRegisterOutRGB { 14 | /** 15 | * @brief The position of the red output pin for 3-color LEDs. 16 | * For the usual RGB configuration, this is 0. 17 | */ 18 | const static uint8_t redBit; // = 0; 19 | /** 20 | * @brief The position of the green output pin for 3-color LEDs. 21 | * For the usual RGB configuration, this is 1. 22 | */ 23 | const static uint8_t greenBit; // = 1; 24 | /** 25 | * @brief The position of the blue output pin for 3-color LEDs. 26 | * For the usual RGB configuration, this is 2. 27 | */ 28 | const static uint8_t blueBit; // = 2; 29 | }; 30 | 31 | END_AH_NAMESPACE 32 | -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/StaticSizeExtendedIOElement.hpp: -------------------------------------------------------------------------------- 1 | /* ✔ */ 2 | 3 | #pragma once 4 | 5 | #include "ExtendedIOElement.hpp" 6 | #include 7 | 8 | BEGIN_AH_NAMESPACE 9 | 10 | /** 11 | * @brief A class for ExtendedIOElement%s with a fixed size. 12 | * 13 | * This class is to make it easier to get an array of all pins of the element. 14 | */ 15 | template 16 | class StaticSizeExtendedIOElement : public ExtendedIOElement { // LCOV_EXCL_LINE 17 | protected: 18 | StaticSizeExtendedIOElement() : ExtendedIOElement{N} {} // LCOV_EXCL_LINE 19 | 20 | public: 21 | /** 22 | * @brief Get an array containing all pins of the element. 23 | */ 24 | Array pins() const { 25 | return generateIncrementalArray(getStart()); 26 | } 27 | 28 | static constexpr uint16_t length() { return N; } 29 | }; 30 | 31 | END_AH_NAMESPACE 32 | -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/keywords.yml: -------------------------------------------------------------------------------- 1 | keyword1: 2 | - AnalogMultiplex 3 | - CD74HC4067 4 | - CD74HC4051 5 | 6 | - ExtIO 7 | 8 | - ExtendedIOElement 9 | 10 | - MAX7219 11 | 12 | - MCP23017 13 | 14 | - ShiftRegisterOut 15 | 16 | - ShiftRegisterOutRGB 17 | 18 | - SPIShiftRegisterOut 19 | 20 | - StaticSizeExtendedIOElement 21 | 22 | keyword2: 23 | - begin 24 | - update 25 | - pinMode 26 | - digitalWrite 27 | - digitalRead 28 | - analogRead 29 | - analogWrite 30 | 31 | - getIOElementOfPin 32 | - shiftOut 33 | 34 | - pin 35 | - getLength 36 | - getEnd 37 | - getStart 38 | - getAll 39 | 40 | - redBit 41 | - greenBit 42 | - blueBit 43 | 44 | - pins 45 | 46 | - pinA 47 | - pinB 48 | 49 | literal1: 50 | -------------------------------------------------------------------------------- /src/AH/Hardware/Hardware-Types.hpp: -------------------------------------------------------------------------------- 1 | /* ✔ */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include // uint8_t 8 | 9 | BEGIN_AH_NAMESPACE 10 | 11 | /// The type returned from analogRead and similar functions. 12 | using analog_t = uint16_t; 13 | /// The type for Arduino pins (and ExtendedIOElement pins). 14 | using pin_t = uint16_t; 15 | 16 | #ifdef NO_PIN // Fix for FastLED: https://github.com/FastLED/FastLED/issues/893 17 | #undef NO_PIN 18 | #endif 19 | 20 | /// A special pin number that indicates an unused or invalid pin. 21 | constexpr pin_t NO_PIN = 1 << (8 * sizeof(pin_t) - 1); 22 | 23 | /// An easy alias for arrays of pins. 24 | template 25 | using PinList = Array; 26 | 27 | END_AH_NAMESPACE 28 | -------------------------------------------------------------------------------- /src/AH/Hardware/Hardware.dox: -------------------------------------------------------------------------------- 1 | /// @cond !AH_MAIN_LIBRARY 2 | /// @addtogroup AH_group 3 | /// @{ 4 | /// @endcond 5 | 6 | /** 7 | * @defgroup AH_HardwareUtils Hardware Utilities 8 | * @brief Classes used for debouncing buttons, incrementing/decrementing 9 | * push buttons, scanning switch matrices, filtering analog input, etc. 10 | */ 11 | 12 | /// @cond !AH_MAIN_LIBRARY 13 | /// @} 14 | /// @endcond -------------------------------------------------------------------------------- /src/AH/Hardware/IncrementButton.cpp: -------------------------------------------------------------------------------- 1 | #include "IncrementButton.hpp" 2 | 3 | BEGIN_AH_NAMESPACE 4 | 5 | IncrementButton::State IncrementButton::updateImplementation() { 6 | Button::State incrState = button.update(); 7 | 8 | if (incrState == Button::Released) { 9 | // Button released, don't do anything 10 | // This one is first to minimize overhead 11 | // because most of the time, the button will 12 | // be released 13 | return Nothing; 14 | } else if (incrState == Button::Rising) { 15 | auto res = longPressState == LongPress ? ReleasedLong : ReleasedShort; 16 | longPressState = Initial; 17 | return res; 18 | } else if (incrState == Button::Falling) { 19 | return IncrementShort; 20 | } else { // if (incrState == Button::Pressed) 21 | auto now = millis(); 22 | if (longPressState == LongPress) { 23 | // still long pressed 24 | if (now - longPressRepeat >= LONG_PRESS_REPEAT_DELAY) { 25 | longPressRepeat += LONG_PRESS_REPEAT_DELAY; 26 | return IncrementHold; 27 | } 28 | } else if (button.stableTime(now) >= LONG_PRESS_DELAY) { 29 | // long press starts 30 | longPressState = LongPress; 31 | longPressRepeat = now; 32 | return IncrementLong; 33 | } 34 | } 35 | return Nothing; 36 | } 37 | 38 | END_AH_NAMESPACE 39 | -------------------------------------------------------------------------------- /src/AH/Hardware/IncrementButton.hpp: -------------------------------------------------------------------------------- 1 | /* ✔ */ 2 | 3 | #pragma once 4 | 5 | #include "Button.hpp" 6 | 7 | BEGIN_AH_NAMESPACE 8 | 9 | /** 10 | * @brief A class for buttons that increment some counter or setting. 11 | * 12 | * It behaves the same way as a computer keyboard: when you press the button, 13 | * it increments the counter once. If you keep on pressing it for longer than 14 | * a certain threshold, it keeps on incrementing at a faster rate, until you 15 | * release it. 16 | * 17 | * @ingroup AH_HardwareUtils 18 | */ 19 | class IncrementButton { 20 | public: 21 | /** 22 | * @brief Create a IncrementButton. 23 | * 24 | * @param button 25 | * The button to read from. 26 | * The button is copied. 27 | */ 28 | IncrementButton(const Button &button) : button(button) {} 29 | 30 | /// @see Button::begin 31 | void begin() { button.begin(); } 32 | 33 | /** 34 | * @brief An enumeration of the different actions to be performed by the 35 | * counter. 36 | * @todo Add states for initial press. 37 | */ 38 | enum State { 39 | Nothing = 0, ///< The counter must not be incremented. 40 | IncrementShort, ///< The counter must be incremented (after short press). 41 | IncrementLong, ///< The counter must be incremented (after long press). 42 | IncrementHold, ///< The counter must be incremented (still pressed). 43 | ReleasedShort, ///< The button was released after a short press. 44 | ReleasedLong, ///< The button was released after a long press. 45 | }; 46 | 47 | /** 48 | * @brief Update and return the state of the increment button. 49 | */ 50 | State update() { return state = updateImplementation(); } 51 | 52 | /** 53 | * @brief Return the state of the increment button without updating it. 54 | * 55 | * Returns the same value as the last @ref update call. 56 | */ 57 | State getState() const { return state; } 58 | 59 | /// @see Button::invert 60 | void invert() { button.invert(); } 61 | 62 | protected: 63 | State updateImplementation(); 64 | 65 | private: 66 | Button button; 67 | 68 | enum { 69 | Initial, 70 | LongPress, 71 | } longPressState = Initial; 72 | unsigned long longPressRepeat; 73 | 74 | State state = Nothing; 75 | }; 76 | 77 | END_AH_NAMESPACE 78 | -------------------------------------------------------------------------------- /src/AH/Hardware/LEDs/DotBarDisplayLEDs.hpp: -------------------------------------------------------------------------------- 1 | /* ✔ */ 2 | 3 | #pragma once 4 | 5 | #include 6 | 7 | BEGIN_AH_NAMESPACE 8 | 9 | /** 10 | * @brief An enumeration type to set an LED display to either bar or dot mode. 11 | */ 12 | enum class DotBarMode : bool { 13 | Bar = false, ///< Turn on a range of LEDs up to the active LED. 14 | Dot = true, ///< Turn on only the active LED 15 | }; 16 | 17 | /** 18 | * @brief A class for LED bars. 19 | * 20 | * @tparam N 21 | * The number of LEDs in the bar. 22 | * 23 | * @ingroup AH_HardwareUtils 24 | */ 25 | template 26 | class DotBarDisplayLEDs : public LEDs { 27 | public: 28 | /// Constructor from list of pins. 29 | DotBarDisplayLEDs(const PinList &ledPins) : LEDs{ledPins} {} 30 | 31 | /** 32 | * @brief Display the given number of LEDs on the LED bar. 33 | * 34 | * @param value 35 | * The number of the LED to activate. 36 | */ 37 | void display(uint16_t value) const { 38 | if (value == 0) 39 | this->clear(); 40 | else if (mode == DotBarMode::Bar) 41 | this->displayRange(0, value); 42 | else 43 | this->displayDot(value - 1); 44 | } 45 | 46 | /** 47 | * @brief Display the given fraction of the LED bar. 48 | * 49 | * @param value 50 | * The fraction of the LED bar to display. 51 | */ 52 | void display(float value) const { display(uint16_t(value * (N + 1))); } 53 | 54 | /// Get the dot/bar mode. 55 | DotBarMode getMode() const { return mode; } 56 | 57 | /** 58 | * @brief Set the mode to either dot or bar mode. 59 | * 60 | * @param mode 61 | * The mode. 62 | */ 63 | void setMode(DotBarMode mode) { this->mode = mode; } 64 | 65 | /// Set the mode to dot mode. 66 | void dotMode() { setMode(DotBarMode::Dot); } 67 | 68 | /// Set the mode to bar mode. 69 | void barMode() { setMode(DotBarMode::Bar); } 70 | 71 | /// Toggle the dot/bar mode. 72 | void toggleMode() { getMode() == DotBarMode::Bar ? dotMode() : barMode(); } 73 | 74 | private: 75 | DotBarMode mode = DotBarMode::Bar; 76 | }; 77 | 78 | END_AH_NAMESPACE 79 | -------------------------------------------------------------------------------- /src/AH/Hardware/LEDs/LEDs.hpp: -------------------------------------------------------------------------------- 1 | /* ✔ */ 2 | 3 | #pragma once 4 | 5 | #include 6 | 7 | BEGIN_AH_NAMESPACE 8 | 9 | /** 10 | * @brief A class for collections of LEDs that can display ranges. 11 | * 12 | * @tparam N 13 | * The number of LEDs in the collection. 14 | * 15 | * @ingroup AH_HardwareUtils 16 | */ 17 | template 18 | class LEDs { 19 | public: 20 | /** 21 | * @brief Create a LEDs object. 22 | * 23 | * @param ledPins 24 | * An array of pins with the LEDs connected. 25 | */ 26 | LEDs(const PinList &ledPins) : ledPins(ledPins) {} 27 | 28 | /** 29 | * @brief Initialize (set LED pins as outputs). 30 | */ 31 | void begin() const { 32 | for (const pin_t &pin : ledPins) 33 | ExtIO::pinMode(pin, OUTPUT); 34 | } 35 | 36 | /** 37 | * @brief Turn on a range of the LEDs. 38 | * 39 | * @param startOn 40 | * The first LED of the range to turn on (the LEDs before this one 41 | * are turned off). 42 | * @param startOff 43 | * The first LED after the range to turn off. 44 | */ 45 | void displayRange(uint16_t startOn, uint16_t startOff) const { 46 | for (uint16_t pin = 0; pin < startOn; pin++) 47 | clear(pin); 48 | for (uint16_t pin = startOn; pin < startOff; pin++) 49 | set(pin); 50 | for (uint16_t pin = startOff; pin < N; pin++) 51 | clear(pin); 52 | } 53 | 54 | /// Turn on the given LED. 55 | void set(uint16_t index) const { 56 | // TODO: bounds check? 57 | ExtIO::digitalWrite(ledPins[index], HIGH); 58 | } 59 | 60 | /// Turn off the given LED. 61 | void clear(uint16_t index) const { 62 | // TODO: bounds check? 63 | ExtIO::digitalWrite(ledPins[index], LOW); 64 | } 65 | 66 | /** 67 | * @brief Turn on a single LED, and turn off all others. 68 | * 69 | * @param led 70 | * The LED to turn on. 71 | */ 72 | void displayDot(uint16_t led) const { displayRange(led, led + 1); } 73 | 74 | /** 75 | * @brief Turn off all LEDs. 76 | */ 77 | void clear() const { 78 | for (pin_t pin : ledPins) 79 | ExtIO::digitalWrite(pin, LOW); 80 | } 81 | 82 | private: 83 | const PinList ledPins; 84 | }; 85 | 86 | END_AH_NAMESPACE 87 | -------------------------------------------------------------------------------- /src/AH/Hardware/LEDs/keywords.yml: -------------------------------------------------------------------------------- 1 | keyword1: 2 | - DotBarDisplayLEDs 3 | 4 | - LEDs 5 | 6 | - MAX7219SevenSegmentDisplay 7 | 8 | keyword2: 9 | - begin 10 | - display 11 | - setMode 12 | - dotMode 13 | - barMode 14 | 15 | - begin 16 | - displayRange 17 | - set 18 | - clear 19 | - displayDot 20 | 21 | - init 22 | - clear 23 | - send 24 | - sendRaw 25 | - setIntensity 26 | 27 | - begin 28 | - display 29 | - printHex 30 | 31 | 32 | literal1: 33 | - DotBarMode 34 | - Dot 35 | - Bar 36 | -------------------------------------------------------------------------------- /src/AH/Hardware/keywords.yml: -------------------------------------------------------------------------------- 1 | keyword1: 2 | # Button.hpp 3 | - Button 4 | # ButtonMatrix.hpp 5 | - ButtonMatrix 6 | # FilteredAnalog.hpp 7 | - FilteredAnalog 8 | # IncrementButton.hpp 9 | - IncrementButton 10 | # IncrementDecrementButtons.hpp 11 | - IncrementDecrementButtons 12 | # MCP23017Encoders.hpp 13 | - MCP23017Encoders 14 | - MCP23017Encoder 15 | 16 | keyword2: 17 | # Button.hpp 18 | - begin 19 | - update 20 | - getState 21 | - getName 22 | - stableTime 23 | # ButtonMatrix.hpp 24 | - onButtonChanged 25 | - begin 26 | - update 27 | # FilteredAnalog.hpp 28 | - reset 29 | - resetToCurrentValue 30 | - getMappingFunction 31 | - map 32 | - invert 33 | - update 34 | - getValue 35 | - getFloatValue 36 | - getRawValue 37 | - getMaxRawValue 38 | - setupADC 39 | # IncrementButton.hpp 40 | - begin 41 | - update 42 | - getState 43 | - invert 44 | # IncrementDecrementButtons.hpp 45 | - begin 46 | - update 47 | - getState 48 | - invert 49 | # MCP23017Encoders.hpp 50 | - begin 51 | - update 52 | - read 53 | - readAndReset 54 | - write 55 | 56 | literal1: 57 | # Button.hpp 58 | - State 59 | - Pressed 60 | - Released 61 | - Falling 62 | - Rising 63 | # FilteredAnalog.hpp 64 | - MappingFunction 65 | # Hardware-Types.hpp 66 | - analog_t 67 | - pin_t 68 | - NO_PIN 69 | - PinList 70 | # IncrementButton.hpp 71 | - State 72 | - Nothing 73 | - IncrementShort 74 | - IncrementLong 75 | - IncrementHold 76 | # IncrementDecrementButtons.hpp 77 | - State 78 | - Nothing 79 | - IncrementShort 80 | - IncrementLong 81 | - IncrementHold 82 | - DecrementShort 83 | - DecrementLong 84 | - DecrementHold 85 | - Reset -------------------------------------------------------------------------------- /src/AH/Math/Degrees.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * @brief Conversions between radians and degrees. 4 | */ 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | BEGIN_AH_NAMESPACE 11 | 12 | namespace detail { 13 | constexpr long double pi_inv_l = 0.318309886183790671537767526745028724L; 14 | constexpr long double pi_l = 3.141592653589793238462643383279502884L; 15 | } // namespace detail 16 | 17 | /// @addtogroup AH_Math 18 | /// @{ 19 | 20 | /// Convert radians to degrees. 21 | template 22 | constexpr inline 23 | typename std::enable_if::value, T>::type 24 | rad2deg(T r) { 25 | return r * static_cast(detail::pi_inv_l) * 180; 26 | } 27 | /// Convert degrees to radians. 28 | template 29 | constexpr inline 30 | typename std::enable_if::value, T>::type 31 | deg2rad(T d) { 32 | return d * static_cast(detail::pi_l) / 180; 33 | } 34 | 35 | /// Convert degrees to radians, e.g. 10_deg. 36 | constexpr long double operator"" _deg(long double deg) { return deg2rad(deg); } 37 | /// Convert degrees to radians, e.g. 10_deg. 38 | constexpr long double operator"" _deg(unsigned long long deg) { 39 | return deg2rad(static_cast(deg)); 40 | } 41 | 42 | /// @} 43 | 44 | END_AH_NAMESPACE 45 | -------------------------------------------------------------------------------- /src/AH/Math/Divide.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | BEGIN_AH_NAMESPACE 9 | 10 | /// Divide by N using the default division operator, without explicit rounding 11 | /// This should be used for floating point types. For integers, prefer using 12 | /// @ref round_div_unsigned_int and @ref round_div_signed_int. 13 | template 14 | struct round_div_default { 15 | static T div(T val) { return val / N; } 16 | }; 17 | 18 | /// Divide an unsigned integer by N, rounding the result. 19 | template 20 | struct round_div_unsigned_int { 21 | static T div(T val) { 22 | return (val + (N / 2)) / N; 23 | static_assert(std::is_unsigned::value && std::is_integral::value, 24 | "This function is only valid for unsigned integers"); 25 | } 26 | }; 27 | 28 | /// Divide a signed integer by N, rounding the result. 29 | template 30 | struct round_div_signed_int { 31 | static T div(T val) { 32 | T offset = val >= 0 ? (N / 2) : (-N / 2); 33 | return (val + offset) / N; 34 | } 35 | }; 36 | 37 | /// Select the right rounding division operator, depending on whether T is a 38 | /// signed or unsigned integer. 39 | template 40 | struct round_div_int 41 | : std::conditional::value, round_div_signed_int, 42 | round_div_unsigned_int>::type {}; 43 | 44 | /// Select the right rounding division operator, depending on whether T is an 45 | /// integer or not. 46 | template 47 | struct round_div_helper 48 | : std::conditional::value, round_div_int, 49 | round_div_default>::type {}; 50 | 51 | /// Divide a number by N and round the result. Uses different specializations 52 | /// for integers to implement efficient rounding. 53 | template 54 | T round_div(T val) { 55 | return round_div_helper::div(val); 56 | } 57 | 58 | END_AH_NAMESPACE 59 | -------------------------------------------------------------------------------- /src/AH/Math/FixArduinoMacros.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | AH_DIAGNOSTIC_EXTERNAL_HEADER() 6 | #include // min max 7 | AH_DIAGNOSTIC_POP() 8 | 9 | #ifdef min 10 | #undef min 11 | #endif 12 | 13 | #ifdef max 14 | #undef max 15 | #endif 16 | 17 | #ifdef abs 18 | #undef abs 19 | #endif 20 | 21 | #ifdef round 22 | #undef round 23 | #endif 24 | -------------------------------------------------------------------------------- /src/AH/Math/Math.dox: -------------------------------------------------------------------------------- 1 | /// @cond !AH_MAIN_LIBRARY 2 | /// @addtogroup AH_group 3 | /// @{ 4 | /// @endcond 5 | 6 | /** 7 | * @defgroup AH_Math Math Utilities 8 | * @brief Mathematics helper functions. Min/max functions, functions to 9 | * uniformly increase the effective bit depth, etc. 10 | */ 11 | /// @{ 12 | 13 | /** 14 | * @defgroup math-types Math Types 15 | * Vector and Quaternion types with the necessary operators and 16 | * functions. 17 | */ 18 | 19 | /// @} 20 | 21 | /// @cond !AH_MAIN_LIBRARY 22 | /// @} 23 | /// @endcond -------------------------------------------------------------------------------- /src/AH/Math/MinMaxFix.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | BEGIN_AH_NAMESPACE 8 | 9 | /// Return the smaller of two numbers/objects. 10 | /// @ingroup AH_Math 11 | template 12 | constexpr auto min(const T &a, const U &b) -> decltype(b < a ? b : a) { 13 | return b < a ? b : a; 14 | } 15 | 16 | /// Return the larger of two numbers/objects. 17 | /// @ingroup AH_Math 18 | template 19 | constexpr auto max(const T &a, const U &b) -> decltype(a < b ? b : a) { 20 | return a < b ? b : a; 21 | } 22 | 23 | END_AH_NAMESPACE 24 | -------------------------------------------------------------------------------- /src/AH/Math/Quaternion.cpp: -------------------------------------------------------------------------------- 1 | #include "Quaternion.hpp" 2 | 3 | #include 4 | #ifndef ARDUINO 5 | #include // std::ostream, << 6 | #endif 7 | 8 | BEGIN_AH_NAMESPACE 9 | 10 | // LCOV_EXCL_START 11 | 12 | #ifndef ARDUINO 13 | 14 | std::ostream &operator<<(std::ostream &os, Quaternion q) { 15 | return os << "(" << q.w << ", " << q.x << ", " << q.y << ", " << q.z << ")"; 16 | } 17 | 18 | std::ostream &operator<<(std::ostream &os, EulerAngles e) { 19 | os << "(" << rad2deg(e.yaw) << "°, " << rad2deg(e.pitch) << "°, " 20 | << rad2deg(e.roll) << "°)"; 21 | return os; 22 | } 23 | 24 | #endif // ARDUINO 25 | 26 | Print &operator<<(Print &os, Quaternion q) { 27 | return os << "(" << q.w << ", " << q.x << ", " << q.y << ", " << q.z << ")"; 28 | } 29 | 30 | Print &operator<<(Print &os, EulerAngles e) { 31 | os << "(" << rad2deg(e.yaw) << "°, " << rad2deg(e.pitch) << "°, " 32 | << rad2deg(e.roll) << "°)"; 33 | return os; 34 | } 35 | 36 | // LCOV_EXCL_STOP 37 | 38 | END_AH_NAMESPACE 39 | -------------------------------------------------------------------------------- /src/AH/Math/Vector.cpp: -------------------------------------------------------------------------------- 1 | #include "Vector.hpp" 2 | 3 | #include 4 | #ifndef ARDUINO 5 | #include // std::ostream, << 6 | #endif 7 | 8 | BEGIN_AH_NAMESPACE 9 | 10 | // LCOV_EXCL_START 11 | 12 | #ifndef ARDUINO 13 | 14 | /// Printing. 15 | /// @related Vec2f 16 | std::ostream &operator<<(std::ostream &os, Vec2f v) { 17 | return os << "(" << v.x << ", " << v.y << ")"; 18 | } 19 | 20 | /// Printing. 21 | /// @related Vec3f 22 | std::ostream &operator<<(std::ostream &os, Vec3f v) { 23 | return os << "(" << v.x << ", " << v.y << ", " << v.z << ")"; 24 | } 25 | 26 | #endif 27 | 28 | /// Printing. 29 | /// @related Vec2f 30 | Print &operator<<(Print &os, Vec2f v) { 31 | return os << "(" << v.x << ", " << v.y << ")"; 32 | } 33 | 34 | /// Printing. 35 | /// @related Vec3f 36 | Print &operator<<(Print &os, Vec3f v) { 37 | return os << "(" << v.x << ", " << v.y << ", " << v.z << ")"; 38 | } 39 | 40 | // LCOV_EXCL_STOP 41 | 42 | END_AH_NAMESPACE 43 | -------------------------------------------------------------------------------- /src/AH/Math/keywords.yml: -------------------------------------------------------------------------------- 1 | keyword1: 2 | - Quaternion 3 | - EulerAngles 4 | - Vec2f 5 | - Vec3f 6 | 7 | keyword2: 8 | - increaseBitDepth 9 | - min 10 | - max 11 | - w 12 | - x 13 | - y 14 | - z 15 | - hamiltonianProduct 16 | - conjugated 17 | - normSquared 18 | - norm 19 | - normalize 20 | - normalized 21 | - rotate 22 | - identity 23 | - fromDirection 24 | - fromXYAngle 25 | - quat2eul 26 | - eul2quat 27 | - rad2deg 28 | - deg2rad 29 | -------------------------------------------------------------------------------- /src/AH/PrintStream/PrintStream.dox: -------------------------------------------------------------------------------- 1 | /// @cond !AH_MAIN_LIBRARY 2 | /// @addtogroup AH_group 3 | /// @{ 4 | /// @endcond 5 | 6 | /** 7 | * @defgroup AH_PrintStream PrintStream 8 | * @brief Functions for printing to Streams using the streaming operator `<<`. 9 | */ 10 | 11 | /// @cond !AH_MAIN_LIBRARY 12 | /// @} 13 | /// @endcond -------------------------------------------------------------------------------- /src/AH/STL/Fallback/algorithm: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | 3 | // Copyright (C) 2001-2017 Free Software Foundation, Inc. 4 | // 5 | // This file is part of the GNU ISO C++ Library. This library is free 6 | // software; you can redistribute it and/or modify it under the 7 | // terms of the GNU General Public License as published by the 8 | // Free Software Foundation; either version 3, or (at your option) 9 | // any later version. 10 | 11 | // This library is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | 16 | // Under Section 7 of GPL version 3, you are granted additional 17 | // permissions described in the GCC Runtime Library Exception, version 18 | // 3.1, as published by the Free Software Foundation. 19 | 20 | // You should have received a copy of the GNU General Public License and 21 | // a copy of the GCC Runtime Library Exception along with this program; 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 | // . 24 | 25 | /* 26 | * 27 | * Copyright (c) 1994 28 | * Hewlett-Packard Company 29 | * 30 | * Permission to use, copy, modify, distribute and sell this software 31 | * and its documentation for any purpose is hereby granted without fee, 32 | * provided that the above copyright notice appear in all copies and 33 | * that both that copyright notice and this permission notice appear 34 | * in supporting documentation. Hewlett-Packard Company makes no 35 | * representations about the suitability of this software for any 36 | * purpose. It is provided "as is" without express or implied warranty. 37 | * 38 | * 39 | * Copyright (c) 1996,1997 40 | * Silicon Graphics Computer Systems, Inc. 41 | * 42 | * Permission to use, copy, modify, distribute and sell this software 43 | * and its documentation for any purpose is hereby granted without fee, 44 | * provided that the above copyright notice appear in all copies and 45 | * that both that copyright notice and this permission notice appear 46 | * in supporting documentation. Silicon Graphics makes no 47 | * representations about the suitability of this software for any 48 | * purpose. It is provided "as is" without express or implied warranty. 49 | */ 50 | 51 | /** @file include/algorithm 52 | * This is a Standard C++ Library header. 53 | */ 54 | 55 | #ifndef _GLIBCXX_ALGORITHM 56 | #define _GLIBCXX_ALGORITHM 1 57 | 58 | #pragma GCC system_header 59 | 60 | #include "utility" // UK-300. 61 | #include "bits/stl_algobase.h" 62 | #include "bits/stl_algo.h" 63 | 64 | #ifdef _GLIBCXX_PARALLEL 65 | # include 66 | #endif 67 | 68 | #endif /* _GLIBCXX_ALGORITHM */ 69 | -------------------------------------------------------------------------------- /src/AH/STL/Fallback/bits/c++0x_warning.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2007-2017 Free Software Foundation, Inc. 2 | // 3 | // This file is part of the GNU ISO C++ Library. This library is free 4 | // software; you can redistribute it and/or modify it under the 5 | // terms of the GNU General Public License as published by the 6 | // Free Software Foundation; either version 3, or (at your option) 7 | // any later version. 8 | 9 | // This library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // Under Section 7 of GPL version 3, you are granted additional 15 | // permissions described in the GCC Runtime Library Exception, version 16 | // 3.1, as published by the Free Software Foundation. 17 | 18 | // You should have received a copy of the GNU General Public License and 19 | // a copy of the GCC Runtime Library Exception along with this program; 20 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 21 | // . 22 | 23 | /** @file bits/c++0x_warning.h 24 | * This is an internal header file, included by other library headers. 25 | * Do not attempt to use it directly. @headername{iosfwd} 26 | */ 27 | 28 | #ifndef _CXX0X_WARNING_H 29 | #define _CXX0X_WARNING_H 1 30 | 31 | #if __cplusplus < 201103L 32 | #error This file requires compiler and library support \ 33 | for the ISO C++ 2011 standard. This support must be enabled \ 34 | with the -std=c++11 or -std=gnu++11 compiler options. 35 | #endif 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/AH/STL/Fallback/bits/c++allocator.h: -------------------------------------------------------------------------------- 1 | // Base to std::allocator -*- C++ -*- 2 | 3 | // Copyright (C) 2004-2017 Free Software Foundation, Inc. 4 | // 5 | // This file is part of the GNU ISO C++ Library. This library is free 6 | // software; you can redistribute it and/or modify it under the 7 | // terms of the GNU General Public License as published by the 8 | // Free Software Foundation; either version 3, or (at your option) 9 | // any later version. 10 | 11 | // This library is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | 16 | // Under Section 7 of GPL version 3, you are granted additional 17 | // permissions described in the GCC Runtime Library Exception, version 18 | // 3.1, as published by the Free Software Foundation. 19 | 20 | // You should have received a copy of the GNU General Public License and 21 | // a copy of the GCC Runtime Library Exception along with this program; 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 | // . 24 | 25 | /** @file bits/c++allocator.h 26 | * This is an internal header file, included by other library headers. 27 | * Do not attempt to use it directly. @headername{memory} 28 | */ 29 | 30 | #ifndef _GLIBCXX_CXX_ALLOCATOR_H 31 | #define _GLIBCXX_CXX_ALLOCATOR_H 1 32 | 33 | #include "../ext/new_allocator.h" 34 | 35 | #if __cplusplus >= 201103L 36 | namespace std 37 | { 38 | /** 39 | * @brief An alias to the base class for std::allocator. 40 | * @ingroup allocators 41 | * 42 | * Used to set the std::allocator base class to 43 | * __gnu_cxx::new_allocator. 44 | * 45 | * @tparam _Tp Type of allocated object. 46 | */ 47 | template 48 | using __allocator_base = __gnu_cxx::new_allocator<_Tp>; 49 | } 50 | #else 51 | // Define new_allocator as the base class to std::allocator. 52 | # define __allocator_base __gnu_cxx::new_allocator 53 | #endif 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/AH/STL/Fallback/bits/cpu_defines.h: -------------------------------------------------------------------------------- 1 | // Specific definitions for generic platforms -*- C++ -*- 2 | 3 | // Copyright (C) 2005-2017 Free Software Foundation, Inc. 4 | // 5 | // This file is part of the GNU ISO C++ Library. This library is free 6 | // software; you can redistribute it and/or modify it under the 7 | // terms of the GNU General Public License as published by the 8 | // Free Software Foundation; either version 3, or (at your option) 9 | // any later version. 10 | 11 | // This library is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | 16 | // Under Section 7 of GPL version 3, you are granted additional 17 | // permissions described in the GCC Runtime Library Exception, version 18 | // 3.1, as published by the Free Software Foundation. 19 | 20 | // You should have received a copy of the GNU General Public License and 21 | // a copy of the GCC Runtime Library Exception along with this program; 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 | // . 24 | 25 | /** @file bits/cpu_defines.h 26 | * This is an internal header file, included by other library headers. 27 | * Do not attempt to use it directly. @headername{iosfwd} 28 | */ 29 | 30 | #ifndef _GLIBCXX_CPU_DEFINES 31 | #define _GLIBCXX_CPU_DEFINES 1 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/AH/STL/Fallback/bits/exception_defines.h: -------------------------------------------------------------------------------- 1 | // -fno-exceptions Support -*- C++ -*- 2 | 3 | // Copyright (C) 2001-2017 Free Software Foundation, Inc. 4 | // 5 | // This file is part of the GNU ISO C++ Library. This library is free 6 | // software; you can redistribute it and/or modify it under the 7 | // terms of the GNU General Public License as published by the 8 | // Free Software Foundation; either version 3, or (at your option) 9 | // any later version. 10 | 11 | // This library is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | 16 | // Under Section 7 of GPL version 3, you are granted additional 17 | // permissions described in the GCC Runtime Library Exception, version 18 | // 3.1, as published by the Free Software Foundation. 19 | 20 | // You should have received a copy of the GNU General Public License and 21 | // a copy of the GCC Runtime Library Exception along with this program; 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 | // . 24 | 25 | /** @file bits/exception_defines.h 26 | * This is an internal header file, included by other library headers. 27 | * Do not attempt to use it directly. @headername{exception} 28 | */ 29 | 30 | #ifndef _EXCEPTION_DEFINES_H 31 | #define _EXCEPTION_DEFINES_H 1 32 | 33 | #if ! __cpp_exceptions 34 | // Iff -fno-exceptions, transform error handling code to work without it. 35 | # define __try if (true) 36 | # define __catch(X) if (false) 37 | # define __throw_exception_again 38 | #else 39 | // Else proceed normally. 40 | # define __try try 41 | # define __catch(X) catch(X) 42 | # define __throw_exception_again throw 43 | #endif 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/AH/STL/Fallback/bits/hash_bytes.h: -------------------------------------------------------------------------------- 1 | // Declarations for hash functions. -*- C++ -*- 2 | 3 | // Copyright (C) 2010-2017 Free Software Foundation, Inc. 4 | // 5 | // This file is part of the GNU ISO C++ Library. This library is free 6 | // software; you can redistribute it and/or modify it under the 7 | // terms of the GNU General Public License as published by the 8 | // Free Software Foundation; either version 3, or (at your option) 9 | // any later version. 10 | 11 | // This library is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | 16 | // Under Section 7 of GPL version 3, you are granted additional 17 | // permissions described in the GCC Runtime Library Exception, version 18 | // 3.1, as published by the Free Software Foundation. 19 | 20 | // You should have received a copy of the GNU General Public License and 21 | // a copy of the GCC Runtime Library Exception along with this program; 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 | // . 24 | 25 | /** @file bits/hash_bytes.h 26 | * This is an internal header file, included by other library headers. 27 | * Do not attempt to use it directly. @headername{functional} 28 | */ 29 | 30 | #ifndef _HASH_BYTES_H 31 | #define _HASH_BYTES_H 1 32 | 33 | #pragma GCC system_header 34 | 35 | #include "../bits/c++config.h" 36 | 37 | namespace std 38 | { 39 | _GLIBCXX_BEGIN_NAMESPACE_VERSION 40 | 41 | // Hash function implementation for the nontrivial specialization. 42 | // All of them are based on a primitive that hashes a pointer to a 43 | // byte array. The actual hash algorithm is not guaranteed to stay 44 | // the same from release to release -- it may be updated or tuned to 45 | // improve hash quality or speed. 46 | size_t 47 | _Hash_bytes(const void* __ptr, size_t __len, size_t __seed); 48 | 49 | // A similar hash primitive, using the FNV hash algorithm. This 50 | // algorithm is guaranteed to stay the same from release to release. 51 | // (although it might not produce the same values on different 52 | // machines.) 53 | size_t 54 | _Fnv_hash_bytes(const void* __ptr, size_t __len, size_t __seed); 55 | 56 | _GLIBCXX_END_NAMESPACE_VERSION 57 | } // namespace 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /src/AH/STL/Fallback/bits/memoryfwd.h: -------------------------------------------------------------------------------- 1 | // Forward declarations -*- C++ -*- 2 | 3 | // Copyright (C) 2001-2017 Free Software Foundation, Inc. 4 | // 5 | // This file is part of the GNU ISO C++ Library. This library is free 6 | // software; you can redistribute it and/or modify it under the 7 | // terms of the GNU General Public License as published by the 8 | // Free Software Foundation; either version 3, or (at your option) 9 | // any later version. 10 | 11 | // This library is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | 16 | // Under Section 7 of GPL version 3, you are granted additional 17 | // permissions described in the GCC Runtime Library Exception, version 18 | // 3.1, as published by the Free Software Foundation. 19 | 20 | // You should have received a copy of the GNU General Public License and 21 | // a copy of the GCC Runtime Library Exception along with this program; 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 | // . 24 | 25 | /* 26 | * Copyright (c) 1996-1997 27 | * Silicon Graphics Computer Systems, Inc. 28 | * 29 | * Permission to use, copy, modify, distribute and sell this software 30 | * and its documentation for any purpose is hereby granted without fee, 31 | * provided that the above copyright notice appear in all copies and 32 | * that both that copyright notice and this permission notice appear 33 | * in supporting documentation. Silicon Graphics makes no 34 | * representations about the suitability of this software for any 35 | * purpose. It is provided "as is" without express or implied warranty. 36 | */ 37 | 38 | /** @file bits/memoryfwd.h 39 | * This is an internal header file, included by other library headers. 40 | * Do not attempt to use it directly. @headername{memory} 41 | */ 42 | 43 | #ifndef _MEMORYFWD_H 44 | #define _MEMORYFWD_H 1 45 | 46 | #pragma GCC system_header 47 | 48 | #include "../bits/c++config.h" 49 | 50 | namespace std _GLIBCXX_VISIBILITY(default) 51 | { 52 | _GLIBCXX_BEGIN_NAMESPACE_VERSION 53 | 54 | /** 55 | * @defgroup allocators Allocators 56 | * @ingroup memory 57 | * 58 | * Classes encapsulating memory operations. 59 | * 60 | * @{ 61 | */ 62 | 63 | template 64 | class allocator; 65 | 66 | template<> 67 | class allocator; 68 | 69 | /// Declare uses_allocator so it can be specialized in \ etc. 70 | template 71 | struct uses_allocator; 72 | 73 | /// @} group memory 74 | 75 | _GLIBCXX_END_NAMESPACE_VERSION 76 | } // namespace std 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /src/AH/STL/Fallback/bits/os_defines.h: -------------------------------------------------------------------------------- 1 | // Specific definitions for GNU/Linux -*- C++ -*- 2 | 3 | // Copyright (C) 2000-2017 Free Software Foundation, Inc. 4 | // 5 | // This file is part of the GNU ISO C++ Library. This library is free 6 | // software; you can redistribute it and/or modify it under the 7 | // terms of the GNU General Public License as published by the 8 | // Free Software Foundation; either version 3, or (at your option) 9 | // any later version. 10 | 11 | // This library is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | 16 | // Under Section 7 of GPL version 3, you are granted additional 17 | // permissions described in the GCC Runtime Library Exception, version 18 | // 3.1, as published by the Free Software Foundation. 19 | 20 | // You should have received a copy of the GNU General Public License and 21 | // a copy of the GCC Runtime Library Exception along with this program; 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 | // . 24 | 25 | /** @file bits/os_defines.h 26 | * This is an internal header file, included by other library headers. 27 | * Do not attempt to use it directly. @headername{iosfwd} 28 | */ 29 | 30 | #ifndef _GLIBCXX_OS_DEFINES 31 | #define _GLIBCXX_OS_DEFINES 1 32 | 33 | // System-specific #define, typedefs, corrections, etc, go here. This 34 | // file will come before all others. 35 | 36 | // This keeps isanum, et al from being propagated as macros. 37 | #define __NO_CTYPE 1 38 | 39 | #if 0 // No GlibC 40 | #include // TODO 41 | 42 | // Provide a declaration for the possibly deprecated gets function, as 43 | // glibc 2.15 and later does not declare gets for ISO C11 when 44 | // __GNU_SOURCE is defined. 45 | #if __GLIBC_PREREQ(2,15) && defined(_GNU_SOURCE) 46 | # undef _GLIBCXX_HAVE_GETS 47 | #endif 48 | 49 | // Glibc 2.23 removed the obsolete isinf and isnan declarations. Check the 50 | // version dynamically in case it has changed since libstdc++ was configured. 51 | #define _GLIBCXX_NO_OBSOLETE_ISINF_ISNAN_DYNAMIC __GLIBC_PREREQ(2,23) 52 | #endif 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/AH/STL/Fallback/climits: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- forwarding header. 2 | 3 | // Copyright (C) 1997-2017 Free Software Foundation, Inc. 4 | // 5 | // This file is part of the GNU ISO C++ Library. This library is free 6 | // software; you can redistribute it and/or modify it under the 7 | // terms of the GNU General Public License as published by the 8 | // Free Software Foundation; either version 3, or (at your option) 9 | // any later version. 10 | 11 | // This library is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | 16 | // Under Section 7 of GPL version 3, you are granted additional 17 | // permissions described in the GCC Runtime Library Exception, version 18 | // 3.1, as published by the Free Software Foundation. 19 | 20 | // You should have received a copy of the GNU General Public License and 21 | // a copy of the GCC Runtime Library Exception along with this program; 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 | // . 24 | 25 | /** @file include/climits 26 | * This is a Standard C++ Library file. You should @c \#include this file 27 | * in your programs, rather than any of the @a *.h implementation files. 28 | * 29 | * This is the C++ version of the Standard C Library header @c limits.h, 30 | * and its contents are (mostly) the same as that header, but are all 31 | * contained in the namespace @c std (except for names which are defined 32 | * as macros in C). 33 | */ 34 | 35 | // 36 | // ISO C++ 14882: 18.2.2 Implementation properties: C library 37 | // 38 | 39 | #pragma GCC system_header 40 | 41 | #include "bits/c++config.h" 42 | #include 43 | 44 | #ifndef _GLIBCXX_CLIMITS 45 | #define _GLIBCXX_CLIMITS 1 46 | 47 | #ifndef LLONG_MIN 48 | #define LLONG_MIN (-__LONG_LONG_MAX__ - 1) 49 | #endif 50 | 51 | #ifndef LLONG_MAX 52 | #define LLONG_MAX __LONG_LONG_MAX__ 53 | #endif 54 | 55 | #ifndef ULLONG_MAX 56 | #define ULLONG_MAX (__LONG_LONG_MAX__ * 2ULL + 1) 57 | #endif 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /src/AH/STL/Fallback/cstdint: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | 3 | // Copyright (C) 2007-2017 Free Software Foundation, Inc. 4 | // 5 | // This file is part of the GNU ISO C++ Library. This library is free 6 | // software; you can redistribute it and/or modify it under the 7 | // terms of the GNU General Public License as published by the 8 | // Free Software Foundation; either version 3, or (at your option) 9 | // any later version. 10 | 11 | // This library is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | 16 | // Under Section 7 of GPL version 3, you are granted additional 17 | // permissions described in the GCC Runtime Library Exception, version 18 | // 3.1, as published by the Free Software Foundation. 19 | 20 | // You should have received a copy of the GNU General Public License and 21 | // a copy of the GCC Runtime Library Exception along with this program; 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 | // . 24 | 25 | /** @file include/cstdint 26 | * This is a Standard C++ Library header. 27 | */ 28 | 29 | #ifndef _GLIBCXX_CSTDINT 30 | #define _GLIBCXX_CSTDINT 1 31 | 32 | #pragma GCC system_header 33 | 34 | #if __cplusplus < 201103L 35 | # include "bits/c++0x_warning.h" 36 | #else 37 | 38 | #include "bits/c++config.h" 39 | 40 | #if _GLIBCXX_HAVE_STDINT_H 41 | # include 42 | #endif 43 | 44 | #ifdef _GLIBCXX_USE_C99_STDINT_TR1 45 | 46 | namespace std 47 | { 48 | using ::int8_t; 49 | using ::int16_t; 50 | using ::int32_t; 51 | using ::int64_t; 52 | 53 | using ::int_fast8_t; 54 | using ::int_fast16_t; 55 | using ::int_fast32_t; 56 | using ::int_fast64_t; 57 | 58 | using ::int_least8_t; 59 | using ::int_least16_t; 60 | using ::int_least32_t; 61 | using ::int_least64_t; 62 | 63 | using ::intmax_t; 64 | using ::intptr_t; 65 | 66 | using ::uint8_t; 67 | using ::uint16_t; 68 | using ::uint32_t; 69 | using ::uint64_t; 70 | 71 | using ::uint_fast8_t; 72 | using ::uint_fast16_t; 73 | using ::uint_fast32_t; 74 | using ::uint_fast64_t; 75 | 76 | using ::uint_least8_t; 77 | using ::uint_least16_t; 78 | using ::uint_least32_t; 79 | using ::uint_least64_t; 80 | 81 | using ::uintmax_t; 82 | using ::uintptr_t; 83 | } // namespace std 84 | 85 | #endif // _GLIBCXX_USE_C99_STDINT_TR1 86 | 87 | #endif // C++11 88 | 89 | #endif // _GLIBCXX_CSTDINT 90 | -------------------------------------------------------------------------------- /src/AH/STL/Fallback/debug/assertions.h: -------------------------------------------------------------------------------- 1 | // Debugging support implementation -*- C++ -*- 2 | 3 | // Copyright (C) 2003-2017 Free Software Foundation, Inc. 4 | // 5 | // This file is part of the GNU ISO C++ Library. This library is free 6 | // software; you can redistribute it and/or modify it under the 7 | // terms of the GNU General Public License as published by the 8 | // Free Software Foundation; either version 3, or (at your option) 9 | // any later version. 10 | 11 | // This library is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | 16 | // Under Section 7 of GPL version 3, you are granted additional 17 | // permissions described in the GCC Runtime Library Exception, version 18 | // 3.1, as published by the Free Software Foundation. 19 | 20 | // You should have received a copy of the GNU General Public License and 21 | // a copy of the GCC Runtime Library Exception along with this program; 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 | // . 24 | 25 | /** @file debug/assertions.h 26 | * This file is a GNU debug extension to the Standard C++ Library. 27 | */ 28 | 29 | #ifndef _GLIBCXX_DEBUG_ASSERTIONS_H 30 | #define _GLIBCXX_DEBUG_ASSERTIONS_H 1 31 | 32 | #ifndef _GLIBCXX_DEBUG 33 | 34 | # define _GLIBCXX_DEBUG_ASSERT(_Condition) 35 | # define _GLIBCXX_DEBUG_PEDASSERT(_Condition) 36 | # define _GLIBCXX_DEBUG_ONLY(_Statement) 37 | 38 | #endif 39 | 40 | #ifndef _GLIBCXX_ASSERTIONS 41 | # define __glibcxx_requires_non_empty_range(_First,_Last) 42 | # define __glibcxx_requires_nonempty() 43 | # define __glibcxx_requires_subscript(_N) 44 | #else 45 | 46 | // Verify that [_First, _Last) forms a non-empty iterator range. 47 | # define __glibcxx_requires_non_empty_range(_First,_Last) \ 48 | __glibcxx_assert(__builtin_expect(_First != _Last, true)) 49 | # define __glibcxx_requires_subscript(_N) \ 50 | __glibcxx_assert(__builtin_expect(_N < this->size(), true)) 51 | // Verify that the container is nonempty 52 | # define __glibcxx_requires_nonempty() \ 53 | __glibcxx_assert(__builtin_expect(!this->empty(), true)) 54 | #endif 55 | 56 | #ifdef _GLIBCXX_DEBUG 57 | # define _GLIBCXX_DEBUG_ASSERT(_Condition) __glibcxx_assert(_Condition) 58 | 59 | # ifdef _GLIBCXX_DEBUG_PEDANTIC 60 | # define _GLIBCXX_DEBUG_PEDASSERT(_Condition) _GLIBCXX_DEBUG_ASSERT(_Condition) 61 | # else 62 | # define _GLIBCXX_DEBUG_PEDASSERT(_Condition) 63 | # endif 64 | 65 | # define _GLIBCXX_DEBUG_ONLY(_Statement) _Statement 66 | #endif 67 | 68 | #endif // _GLIBCXX_DEBUG_ASSERTIONS 69 | -------------------------------------------------------------------------------- /src/AH/STL/Fallback/iterator: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | 3 | // Copyright (C) 2001-2017 Free Software Foundation, Inc. 4 | // 5 | // This file is part of the GNU ISO C++ Library. This library is free 6 | // software; you can redistribute it and/or modify it under the 7 | // terms of the GNU General Public License as published by the 8 | // Free Software Foundation; either version 3, or (at your option) 9 | // any later version. 10 | 11 | // This library is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | 16 | // Under Section 7 of GPL version 3, you are granted additional 17 | // permissions described in the GCC Runtime Library Exception, version 18 | // 3.1, as published by the Free Software Foundation. 19 | 20 | // You should have received a copy of the GNU General Public License and 21 | // a copy of the GCC Runtime Library Exception along with this program; 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 | // . 24 | 25 | /* 26 | * 27 | * Copyright (c) 1994 28 | * Hewlett-Packard Company 29 | * 30 | * Permission to use, copy, modify, distribute and sell this software 31 | * and its documentation for any purpose is hereby granted without fee, 32 | * provided that the above copyright notice appear in all copies and 33 | * that both that copyright notice and this permission notice appear 34 | * in supporting documentation. Hewlett-Packard Company makes no 35 | * representations about the suitability of this software for any 36 | * purpose. It is provided "as is" without express or implied warranty. 37 | * 38 | * 39 | * Copyright (c) 1996,1997 40 | * Silicon Graphics Computer Systems, Inc. 41 | * 42 | * Permission to use, copy, modify, distribute and sell this software 43 | * and its documentation for any purpose is hereby granted without fee, 44 | * provided that the above copyright notice appear in all copies and 45 | * that both that copyright notice and this permission notice appear 46 | * in supporting documentation. Silicon Graphics makes no 47 | * representations about the suitability of this software for any 48 | * purpose. It is provided "as is" without express or implied warranty. 49 | */ 50 | 51 | /** @file include/iterator 52 | * This is a Standard C++ Library header. 53 | */ 54 | 55 | #ifndef _GLIBCXX_ITERATOR 56 | #define _GLIBCXX_ITERATOR 1 57 | 58 | #pragma GCC system_header 59 | 60 | #include "bits/c++config.h" 61 | #include "bits/stl_iterator_base_types.h" 62 | #include "bits/stl_iterator_base_funcs.h" 63 | #include "bits/stl_iterator.h" 64 | // #include 65 | // #include 66 | // #include 67 | // #include 68 | #include "bits/range_access.h" 69 | 70 | #endif /* _GLIBCXX_ITERATOR */ 71 | -------------------------------------------------------------------------------- /src/AH/STL/Fallback/memory: -------------------------------------------------------------------------------- 1 | #ifndef _GLIBCXX_MEMORY 2 | #define _GLIBCXX_MEMORY 1 3 | 4 | #pragma GCC system_header 5 | 6 | #include "bits/unique_ptr.h" 7 | 8 | #endif -------------------------------------------------------------------------------- /src/AH/STL/Fallback/new.cpp: -------------------------------------------------------------------------------- 1 | #ifdef __AVR__ 2 | 3 | #include "new" 4 | 5 | #if __cpp_sized_deallocation 6 | 7 | void operator delete(void* ptr, std::size_t) _GLIBCXX_USE_NOEXCEPT { 8 | delete ptr; 9 | } 10 | 11 | void operator delete[](void* ptr, std::size_t) _GLIBCXX_USE_NOEXCEPT { 12 | delete[] ptr; 13 | } 14 | 15 | #endif 16 | 17 | #endif -------------------------------------------------------------------------------- /src/AH/STL/Fallback/vector: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | 3 | // Copyright (C) 2001-2017 Free Software Foundation, Inc. 4 | // 5 | // This file is part of the GNU ISO C++ Library. This library is free 6 | // software; you can redistribute it and/or modify it under the 7 | // terms of the GNU General Public License as published by the 8 | // Free Software Foundation; either version 3, or (at your option) 9 | // any later version. 10 | 11 | // This library is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | 16 | // Under Section 7 of GPL version 3, you are granted additional 17 | // permissions described in the GCC Runtime Library Exception, version 18 | // 3.1, as published by the Free Software Foundation. 19 | 20 | // You should have received a copy of the GNU General Public License and 21 | // a copy of the GCC Runtime Library Exception along with this program; 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 | // . 24 | 25 | /* 26 | * 27 | * Copyright (c) 1994 28 | * Hewlett-Packard Company 29 | * 30 | * Permission to use, copy, modify, distribute and sell this software 31 | * and its documentation for any purpose is hereby granted without fee, 32 | * provided that the above copyright notice appear in all copies and 33 | * that both that copyright notice and this permission notice appear 34 | * in supporting documentation. Hewlett-Packard Company makes no 35 | * representations about the suitability of this software for any 36 | * purpose. It is provided "as is" without express or implied warranty. 37 | * 38 | * 39 | * Copyright (c) 1996 40 | * Silicon Graphics Computer Systems, Inc. 41 | * 42 | * Permission to use, copy, modify, distribute and sell this software 43 | * and its documentation for any purpose is hereby granted without fee, 44 | * provided that the above copyright notice appear in all copies and 45 | * that both that copyright notice and this permission notice appear 46 | * in supporting documentation. Silicon Graphics makes no 47 | * representations about the suitability of this software for any 48 | * purpose. It is provided "as is" without express or implied warranty. 49 | */ 50 | 51 | /** @file include/vector 52 | * This is a Standard C++ Library header. 53 | */ 54 | 55 | #ifndef _GLIBCXX_VECTOR 56 | #define _GLIBCXX_VECTOR 1 57 | 58 | #pragma GCC system_header 59 | 60 | #include "bits/stl_algobase.h" 61 | #include "bits/allocator.h" 62 | #include "bits/stl_construct.h" 63 | #include "bits/stl_uninitialized.h" 64 | #include "bits/stl_vector.h" 65 | #include "bits/stl_bvector.h" 66 | #include "bits/range_access.h" 67 | 68 | #ifndef _GLIBCXX_EXPORT_TEMPLATE 69 | # include "bits/vector.tcc" 70 | #endif 71 | 72 | #ifdef _GLIBCXX_DEBUG 73 | # include "../debug/vector" 74 | #endif 75 | 76 | #ifdef _GLIBCXX_PROFILE 77 | # include "../profile/vector" 78 | #endif 79 | 80 | #endif /* _GLIBCXX_VECTOR */ 81 | -------------------------------------------------------------------------------- /src/AH/STL/README.md: -------------------------------------------------------------------------------- 1 | The files in the `Fallback` folder are from the GCC 7.4.0 STL implementation, 2 | with minimal modifications to get it to compile with Arduino. -------------------------------------------------------------------------------- /src/AH/STL/algorithm: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #ifdef __AVR__ 8 | #include 9 | 10 | #include "Fallback/algorithm" 11 | #else 12 | #include 13 | #endif 14 | 15 | BEGIN_AH_NAMESPACE 16 | 17 | END_AH_NAMESPACE -------------------------------------------------------------------------------- /src/AH/STL/array: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __AVR__ 4 | #include 5 | 6 | #include "Fallback/array" 7 | #else 8 | #include 9 | #endif 10 | 11 | #include 12 | 13 | BEGIN_AH_NAMESPACE 14 | 15 | END_AH_NAMESPACE -------------------------------------------------------------------------------- /src/AH/STL/bitset: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef __AVR__ 6 | #include 7 | 8 | #include "Fallback/bitset" 9 | #else 10 | #include 11 | #endif 12 | 13 | #include 14 | 15 | template 16 | Print &operator<<(Print &os, const std::bitset &bs) { 17 | for (size_t i = Nb; i-- > 0;) 18 | os << (bs[i] ? '1' : '0'); 19 | return os; 20 | } -------------------------------------------------------------------------------- /src/AH/STL/climits: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef __AVR__ 6 | #include 7 | 8 | #include "Fallback/climits" 9 | #else 10 | #include 11 | #endif -------------------------------------------------------------------------------- /src/AH/STL/cmath: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #ifdef __AVR__ 8 | #include 9 | 10 | #include "Fallback/cmath" 11 | #else 12 | 13 | #include 14 | 15 | #if !defined(__clang__) && !defined(_GLIBCXX_USE_C99_MATH_TR1) 16 | #pragma message("FMA math fix") 17 | namespace std { 18 | constexpr double 19 | fma(double __x, double __y, double __z) 20 | { return __builtin_fma(__x, __y, __z); } 21 | 22 | constexpr float 23 | fma(float __x, float __y, float __z) 24 | { return __builtin_fmaf(__x, __y, __z); } 25 | 26 | constexpr long double 27 | fma(long double __x, long double __y, long double __z) 28 | { return __builtin_fmal(__x, __y, __z); } 29 | 30 | constexpr float 31 | round(float __x) 32 | { return __builtin_roundf(__x); } 33 | 34 | constexpr double 35 | round(double __x) 36 | { return __builtin_round(__x); } 37 | 38 | constexpr long double 39 | round(long double __x) 40 | { return __builtin_roundl(__x); } 41 | 42 | template 43 | constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, 44 | double>::__type 45 | round(_Tp __x) 46 | { return __builtin_round(__x); } 47 | 48 | constexpr float 49 | hypot(float __x, float __y) 50 | { return __builtin_hypotf(__x, __y); } 51 | 52 | constexpr double 53 | hypot(double __x, double __y) 54 | { return __builtin_hypot(__x, __y); } 55 | 56 | constexpr long double 57 | hypot(long double __x, long double __y) 58 | { return __builtin_hypotl(__x, __y); } 59 | } 60 | #endif 61 | 62 | #endif -------------------------------------------------------------------------------- /src/AH/STL/complex: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #ifdef __AVR__ 8 | #include 9 | 10 | #include "Fallback/complex" 11 | #else 12 | #include 13 | #endif 14 | 15 | #include 16 | 17 | template 18 | Print &operator<<(Print &os, const std::complex &x) { 19 | USING_AH_NAMESPACE; 20 | return os << '(' << x.real() << ',' << x.imag() << ')'; 21 | } -------------------------------------------------------------------------------- /src/AH/STL/cstddef: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __AVR__ 4 | #include 5 | 6 | #include "Fallback/cstddef" 7 | #else 8 | #include 9 | #endif 10 | 11 | #include 12 | 13 | BEGIN_AH_NAMESPACE 14 | 15 | END_AH_NAMESPACE -------------------------------------------------------------------------------- /src/AH/STL/cstdint: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __AVR__ 4 | #include 5 | 6 | #include "Fallback/cstdint" 7 | #else 8 | #include 9 | #endif 10 | 11 | #include 12 | 13 | BEGIN_AH_NAMESPACE 14 | 15 | END_AH_NAMESPACE -------------------------------------------------------------------------------- /src/AH/STL/cstdlib: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __AVR__ 4 | #include 5 | 6 | #include "Fallback/cstdlib" 7 | #else 8 | #include 9 | #endif 10 | 11 | #include 12 | 13 | BEGIN_AH_NAMESPACE 14 | 15 | END_AH_NAMESPACE -------------------------------------------------------------------------------- /src/AH/STL/initializer_list: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __AVR__ 4 | #include 5 | 6 | #include "Fallback/initializer_list" 7 | #else 8 | #include 9 | #endif 10 | 11 | #include 12 | 13 | BEGIN_AH_NAMESPACE 14 | 15 | END_AH_NAMESPACE -------------------------------------------------------------------------------- /src/AH/STL/iterator: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #ifdef __AVR__ 8 | #include 9 | 10 | #include "Fallback/iterator" 11 | #else 12 | #include 13 | #endif -------------------------------------------------------------------------------- /src/AH/STL/limits: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __AVR__ 4 | #include 5 | 6 | #include "Fallback/limits" 7 | #else 8 | #include 9 | #endif 10 | 11 | #include 12 | 13 | BEGIN_AH_NAMESPACE 14 | 15 | END_AH_NAMESPACE -------------------------------------------------------------------------------- /src/AH/STL/memory: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef __AVR__ 6 | #include 7 | 8 | #include "Fallback/memory" 9 | #else 10 | #include 11 | #endif 12 | 13 | BEGIN_AH_NAMESPACE 14 | 15 | #if __cplusplus > 201103L 16 | 17 | using std::make_unique; 18 | 19 | #else 20 | 21 | template 22 | struct _MakeUniq 23 | { typedef std::unique_ptr<_Tp> __single_object; }; 24 | 25 | template 26 | struct _MakeUniq<_Tp[]> 27 | { typedef std::unique_ptr<_Tp[]> __array; }; 28 | 29 | template 30 | struct _MakeUniq<_Tp[_Bound]> 31 | { struct __invalid_type { }; }; 32 | 33 | /// std::make_unique for single objects 34 | template 35 | inline typename _MakeUniq<_Tp>::__single_object 36 | make_unique(_Args&&... __args) 37 | { return std::unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); } 38 | 39 | /// std::make_unique for arrays of unknown bound 40 | template 41 | inline typename _MakeUniq<_Tp>::__array 42 | make_unique(size_t __num) 43 | { return std::unique_ptr<_Tp>( 44 | new typename std::remove_extent<_Tp>::type[__num]()); } 45 | 46 | /// Disable std::make_unique for arrays of known bound 47 | template 48 | inline typename _MakeUniq<_Tp>::__invalid_type 49 | make_unique(_Args&&...) = delete; 50 | 51 | #endif 52 | 53 | END_AH_NAMESPACE -------------------------------------------------------------------------------- /src/AH/STL/new: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __AVR__ 4 | #include 5 | 6 | #include "Fallback/new" 7 | #else 8 | #include 9 | #endif 10 | 11 | #include 12 | 13 | BEGIN_AH_NAMESPACE 14 | 15 | END_AH_NAMESPACE -------------------------------------------------------------------------------- /src/AH/STL/numeric: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef __AVR__ 6 | #include 7 | 8 | #include "Fallback/numeric" 9 | #else 10 | #include 11 | #endif -------------------------------------------------------------------------------- /src/AH/STL/optional: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __AVR__ 4 | #include 5 | 6 | #include "Fallback/optional" 7 | #else 8 | #if defined(__cpp_lib_optional) && __cpp_lib_optional >= 201603 9 | #include 10 | #endif 11 | #endif 12 | 13 | #include 14 | 15 | BEGIN_AH_NAMESPACE 16 | 17 | END_AH_NAMESPACE -------------------------------------------------------------------------------- /src/AH/STL/tuple: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef __AVR__ 6 | #include 7 | 8 | #include "Fallback/tuple" 9 | #else 10 | #include 11 | #endif -------------------------------------------------------------------------------- /src/AH/STL/type_traits: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef __AVR__ 6 | #include "Fallback/type_traits" 7 | #else 8 | #include 9 | #endif 10 | 11 | namespace std { 12 | 13 | #if __cplusplus < 201402L 14 | template 15 | using enable_if_t = typename enable_if::type; 16 | 17 | #endif 18 | 19 | } // namespace std -------------------------------------------------------------------------------- /src/AH/STL/utility: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef __AVR__ 6 | #include 7 | 8 | #include "Fallback/utility" 9 | #else 10 | #include 11 | #endif 12 | 13 | namespace std { 14 | 15 | #if __cplusplus < 201402L 16 | 17 | /// https://en.cppreference.com/w/cpp/utility/exchange 18 | template 19 | T exchange(T &obj, U &&new_value) { 20 | T old_value = std::move(obj); 21 | obj = std::forward(new_value); 22 | return old_value; 23 | } 24 | 25 | #endif 26 | 27 | } // namespace std -------------------------------------------------------------------------------- /src/AH/STL/vector: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __AVR__ 4 | #include 5 | 6 | #include "Fallback/vector" 7 | #else 8 | #include 9 | #endif 10 | 11 | #include 12 | 13 | BEGIN_AH_NAMESPACE 14 | 15 | END_AH_NAMESPACE -------------------------------------------------------------------------------- /src/AH/STL/vector.cpp: -------------------------------------------------------------------------------- 1 | #if defined(TEENSYDUINO) && !defined(AVR) && TEENSYDUINO < 153 2 | #include "vector" 3 | #include 4 | 5 | namespace std { 6 | void __throw_bad_alloc() { FATAL_ERROR(F("bad_alloc"), 0x6371); } 7 | 8 | void __throw_length_error(char const *e) { 9 | FATAL_ERROR(F("length_error: ") << e, 0x6372); 10 | } 11 | } // namespace std 12 | #endif -------------------------------------------------------------------------------- /src/AH/Settings/NamespaceSettings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define USE_AH_NAMESPACE 6 | #define AH_NAMESPACE_NAME AH 7 | 8 | // ========================================================================== // 9 | 10 | #ifdef USE_AH_NAMESPACE 11 | #define BEGIN_AH_NAMESPACE \ 12 | AH_DIAGNOSTIC_WERROR() \ 13 | namespace AH_NAMESPACE_NAME { 14 | #define END_AH_NAMESPACE \ 15 | } \ 16 | AH_DIAGNOSTIC_POP() 17 | #define USING_AH_NAMESPACE using namespace AH_NAMESPACE_NAME 18 | #else 19 | #define BEGIN_AH_NAMESPACE 20 | #define END_AH_NAMESPACE 21 | #define USING_AH_NAMESPACE 22 | #endif -------------------------------------------------------------------------------- /src/AH/Settings/Settings.dox: -------------------------------------------------------------------------------- 1 | /// @cond !AH_MAIN_LIBRARY 2 | /// @addtogroup AH_group 3 | /// @{ 4 | /// @endcond 5 | 6 | /** 7 | * @defgroup AH_Settings Settings 8 | * @brief User settings and debugging options. 9 | */ 10 | 11 | /// @cond !AH_MAIN_LIBRARY 12 | /// @} 13 | /// @endcond -------------------------------------------------------------------------------- /src/AH/Settings/SettingsWrapper.hpp: -------------------------------------------------------------------------------- 1 | #ifndef AH_SETTINGSWRAPPER_HPP 2 | #define AH_SETTINGSWRAPPER_HPP 3 | 4 | #include "NamespaceSettings.hpp" 5 | 6 | // ---- User Settings ---- // 7 | // ======================= // 8 | #include "Settings.hpp" 9 | 10 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 11 | 12 | #define AH_IS_EMPTY_HELPER(x) x##1 13 | #define AH_IS_EMPTY(x) AH_IS_EMPTY_HELPER(x) == 1 14 | 15 | #if AH_IS_EMPTY(DEBUG_OUT) 16 | #undef DEBUG_OUT 17 | #endif 18 | 19 | #ifndef ARDUINO 20 | #ifdef DEBUG_OUT 21 | #undef DEBUG_OUT 22 | #ifndef NO_DEBUG_PRINTS 23 | #define DEBUG_OUT std::cout 24 | #endif 25 | #endif 26 | #endif 27 | 28 | #ifdef TEENSYDUINO 29 | #include 30 | #if defined(DEBUG_OUT) && (DEBUG_OUT == Serial) && \ 31 | !defined(TEENSY_SERIALUSB_ENABLED) 32 | #error \ 33 | "Debugging is enabled on the CDC Serial port, but the USB type doesn't support Serial" 34 | #endif 35 | #endif 36 | 37 | BEGIN_AH_NAMESPACE 38 | static_assert( 39 | sizeof(ANALOG_FILTER_TYPE) * CHAR_BIT >= 40 | ADC_BITS + ANALOG_FILTER_SHIFT_FACTOR, 41 | "ANALOG_FILTER_TYPE isn't wide enough to satisfy filter requirements. \n" 42 | "Either decrease the ADC resolution, decrease the filter shift factor, or" 43 | "use a wider type (e.g. uint32_t)"); 44 | END_AH_NAMESPACE 45 | 46 | AH_DIAGNOSTIC_POP() 47 | 48 | // ------- Debug ------- // 49 | // ===================== // 50 | #include 51 | 52 | #endif // AH_SETTINGSWRAPPER_HPP 53 | -------------------------------------------------------------------------------- /src/AH/Settings/Warnings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(__GNUC__) && !defined(__clang__) 4 | 5 | #if __GNUC__ >= 11 6 | 7 | #define AH_DIAGNOSTIC_WERROR() \ 8 | _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic error \"-Wall\"") \ 9 | _Pragma("GCC diagnostic error \"-Wextra\"") \ 10 | _Pragma("GCC diagnostic ignored \"-Wc++0x-compat\"") \ 11 | _Pragma("GCC diagnostic ignored \"-Wc++11-compat\"") 12 | #define AH_DIAGNOSTIC_POP() _Pragma("GCC diagnostic pop") 13 | #define AH_DIAGNOSTIC_EXTERNAL_HEADER() \ 14 | _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wall\"") \ 15 | _Pragma("GCC diagnostic ignored \"-Wextra\"") \ 16 | _Pragma("GCC diagnostic ignored \"-Wsuggest-override\"") _Pragma( \ 17 | "GCC diagnostic ignored \"-Wunused-parameter\"") \ 18 | _Pragma("GCC diagnostic warning \"-Wcast-function-type\"") \ 19 | _Pragma("GCC diagnostic warning \"-Wdeprecated-copy\"") 20 | /* For the last two: see https://github.com/PaulStoffregen/cores/issues/660 */ 21 | 22 | #elif __GNUC__ >= 5 23 | 24 | #define AH_DIAGNOSTIC_WERROR() \ 25 | _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic error \"-Wall\"") \ 26 | _Pragma("GCC diagnostic error \"-Wextra\"") \ 27 | _Pragma("GCC diagnostic ignored \"-Wc++0x-compat\"") 28 | #define AH_DIAGNOSTIC_POP() _Pragma("GCC diagnostic pop") 29 | #define AH_DIAGNOSTIC_EXTERNAL_HEADER() \ 30 | _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wall\"") \ 31 | _Pragma("GCC diagnostic ignored \"-Wextra\"") \ 32 | _Pragma("GCC diagnostic ignored \"-Wsuggest-override\"") \ 33 | _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"") 34 | 35 | #else // __GNUC__ < 5 36 | 37 | #define AH_DIAGNOSTIC_WERROR() \ 38 | _Pragma("GCC diagnostic push") \ 39 | _Pragma("GCC diagnostic ignored \"-Wattributes\"") 40 | #define AH_DIAGNOSTIC_POP() _Pragma("GCC diagnostic pop") 41 | #define AH_DIAGNOSTIC_EXTERNAL_HEADER() \ 42 | _Pragma("GCC diagnostic push") \ 43 | _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"") 44 | 45 | #endif 46 | 47 | #else 48 | 49 | #define AH_DIAGNOSTIC_WERROR() 50 | #define AH_DIAGNOSTIC_POP() 51 | #define AH_DIAGNOSTIC_EXTERNAL_HEADER() 52 | 53 | #endif -------------------------------------------------------------------------------- /src/AH/Teensy/TeensyUSBTypes.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef TEENSYDUINO 4 | 5 | #if defined(USB_MIDI_SERIAL) || defined(USB_MIDI4_SERIAL) || \ 6 | defined(USB_MIDI16_SERIAL) || defined(USB_MIDI_AUDIO_SERIAL) || \ 7 | defined(USB_MIDI16_AUDIO_SERIAL) || defined(USB_MIDI) || \ 8 | defined(USB_MIDI4) || defined(USB_MIDI16) || defined(USB_EVERYTHING) 9 | #define TEENSY_MIDIUSB_ENABLED 10 | #endif 11 | 12 | #if defined(USB_MIDI_SERIAL) || defined(USB_MIDI4_SERIAL) || \ 13 | defined(USB_MIDI16_SERIAL) || defined(USB_MIDI_AUDIO_SERIAL) || \ 14 | defined(USB_MIDI16_AUDIO_SERIAL) || defined(USB_SERIAL_HID) || \ 15 | defined(USB_EVERYTHING) || defined(USB_SERIAL) 16 | #define TEENSY_SERIALUSB_ENABLED 17 | #endif 18 | 19 | #if defined(USB_MIDI_AUDIO_SERIAL) || defined(USB_MIDI16_AUDIO_SERIAL) || \ 20 | defined(USB_AUDIO) || defined(USB_EVERYTHING) 21 | #define TEENSY_AUDIOUSB_ENABLED 22 | #endif 23 | 24 | #endif -------------------------------------------------------------------------------- /src/AH/Timing/MillisMicrosTimer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include // millis, micros 6 | 7 | BEGIN_AH_NAMESPACE 8 | 9 | /// @addtogroup AH_Timing 10 | /// @{ 11 | 12 | /// A function type that returns a time value. 13 | using timefunction = unsigned long (*)(); 14 | 15 | /** 16 | * @brief A class for easily managing timed events. A wrapper for "Blink 17 | * Without Delay". 18 | * 19 | * @tparam time 20 | * The time function to use. 21 | */ 22 | template 23 | class Timer { 24 | public: 25 | /** 26 | * @brief Constructor. 27 | * @param interval 28 | * The interval between two events. 29 | */ 30 | Timer(unsigned long interval) : interval(interval) { 31 | #ifdef ARDUINO 32 | begin(); 33 | #endif 34 | } 35 | /// Initialize or reset the timer. The timer will fire immediately. 36 | void begin() { previous = time() - interval; } 37 | /// Initialize or reset the timer. The timer will fire after one period. 38 | void beginNextPeriod() { previous = time(); } 39 | /// Update the timer and return true if the event should fire. 40 | explicit operator bool() { 41 | auto now = time(); 42 | if (now - previous >= interval) { 43 | previous += interval; 44 | return true; 45 | } 46 | return false; 47 | } 48 | 49 | /// Get the interval of the timer. 50 | unsigned long getInterval() const { return interval; } 51 | /// Set the interval of the timer. 52 | void setInterval(unsigned long interval) { this->interval = interval; } 53 | 54 | private: 55 | unsigned long interval; 56 | unsigned long previous = 0; 57 | }; 58 | 59 | /// @} 60 | 61 | END_AH_NAMESPACE 62 | -------------------------------------------------------------------------------- /src/AH/Timing/Timing.dox: -------------------------------------------------------------------------------- 1 | /// @cond !AH_MAIN_LIBRARY 2 | /// @addtogroup AH_group 3 | /// @{ 4 | /// @endcond 5 | 6 | /** 7 | * @defgroup AH_Timing Timing 8 | * @brief Blink Without Delay-style timers. 9 | */ 10 | 11 | /// @cond !AH_MAIN_LIBRARY 12 | /// @} 13 | /// @endcond -------------------------------------------------------------------------------- /src/AH/Timing/keywords.yml: -------------------------------------------------------------------------------- 1 | keyword1: 2 | - Timer 3 | 4 | keyword2: 5 | - begin 6 | 7 | literal1: 8 | - timefunction -------------------------------------------------------------------------------- /src/AH/Types/Frequency.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | BEGIN_AH_NAMESPACE 6 | 7 | /// Type-safe class for frequency values. 8 | class Frequency { 9 | public: 10 | explicit constexpr Frequency(unsigned long hertz) : hertz(hertz) {} 11 | constexpr operator unsigned long() const { return hertz; } 12 | 13 | private: 14 | unsigned long hertz; 15 | }; 16 | constexpr Frequency operator"" _Hz(unsigned long long hz) { 17 | return Frequency{(unsigned long)hz}; 18 | } 19 | constexpr Frequency operator"" _kHz(long double khz) { 20 | return Frequency{(unsigned long)(khz * 1E3l)}; 21 | } 22 | constexpr Frequency operator"" _kHz(unsigned long long khz) { 23 | return Frequency{(unsigned long)(khz * 1E3)}; 24 | } 25 | constexpr Frequency operator"" _MHz(long double mhz) { 26 | return Frequency{(unsigned long)(mhz * 1E6l)}; 27 | } 28 | constexpr Frequency operator"" _MHz(unsigned long long mhz) { 29 | return Frequency{(unsigned long)(mhz * 1E6)}; 30 | } 31 | 32 | END_AH_NAMESPACE 33 | -------------------------------------------------------------------------------- /src/AH/Types/FunctionTraits.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | BEGIN_AH_NAMESPACE 9 | 10 | template 11 | struct function_traits; 12 | 13 | template 14 | struct function_traits { 15 | static constexpr size_t number_arguments = sizeof...(Args); 16 | 17 | using return_t = Return; 18 | template 19 | struct argument { 20 | using type = 21 | typename std::tuple_element>::type; 22 | }; 23 | 24 | template 25 | using argument_t = typename argument::type; 26 | }; 27 | 28 | END_AH_NAMESPACE 29 | -------------------------------------------------------------------------------- /src/AH/Types/keywords.yml: -------------------------------------------------------------------------------- 1 | keyword1: 2 | - Frequency 3 | 4 | literal1: 5 | - _MHz 6 | - _kHz 7 | - _Hz -------------------------------------------------------------------------------- /src/Arduino_Helpers.dox: -------------------------------------------------------------------------------- 1 | /// @cond !AH_MAIN_LIBRARY 2 | 3 | /** 4 | * @defgroup AH_group Arduino Helpers 5 | * @brief Common utility library: 6 | */ 7 | 8 | /// @endcond -------------------------------------------------------------------------------- /src/Arduino_Helpers.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * @brief Dummy header file for Arduino builder. 4 | * You have to add this file first, so the other headers are in the 5 | * include path. 6 | * 7 | * @author Pieter Pas 8 | * @date 2019-11-07 9 | */ 10 | 11 | #pragma once 12 | 13 | #include 14 | 15 | BEGIN_AH_NAMESPACE 16 | END_AH_NAMESPACE 17 | 18 | #ifndef NO_USING_NAMESPACE_AH 19 | USING_AH_NAMESPACE; 20 | #endif -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(AH) -------------------------------------------------------------------------------- /src/keywords.yml: -------------------------------------------------------------------------------- 1 | keyword1: 2 | - Arduino_Helpers 3 | - AH -------------------------------------------------------------------------------- /test/AH/Containers/test-Updatable.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using std::vector; 9 | using namespace AH; 10 | 11 | struct T {}; 12 | struct TestUpdatable : Updatable { 13 | TestUpdatable *getNext() { return dynamic_cast(next); } 14 | TestUpdatable *getPrevious() { 15 | return dynamic_cast(previous); 16 | } 17 | static auto getList() -> decltype(updatables) & { return updatables; } 18 | 19 | void begin() override {} 20 | void update() override {} 21 | }; 22 | 23 | TEST(Updatable, enableDisable) { 24 | TestUpdatable v[16]; 25 | for (auto &vv : v) 26 | EXPECT_TRUE(vv.isEnabled()); 27 | TestUpdatable::disable(v); 28 | for (auto &vv : v) 29 | EXPECT_FALSE(vv.isEnabled()); 30 | auto &l = TestUpdatable::getList(); 31 | auto len = std::distance(l.begin(), l.end()); 32 | EXPECT_EQ(len, 0); 33 | TestUpdatable::enable(v); 34 | for (auto &vv : v) 35 | EXPECT_TRUE(vv.isEnabled()); 36 | len = std::distance(l.begin(), l.end()); 37 | EXPECT_EQ(len, 16); 38 | } 39 | 40 | TEST(Updatable, alreadyEnabled) { 41 | TestUpdatable v[16]; 42 | try { 43 | v[0].enable(); 44 | FAIL(); 45 | } catch (ErrorException &e) { 46 | EXPECT_EQ(e.getErrorCode(), 0x1212); 47 | } 48 | } 49 | 50 | TEST(Updatable, alreadyDisabled) { 51 | TestUpdatable v[16]; 52 | TestUpdatable::disable(v); 53 | try { 54 | v[0].disable(); 55 | FAIL(); 56 | } catch (ErrorException &e) { 57 | EXPECT_EQ(e.getErrorCode(), 0x1213); 58 | } 59 | } -------------------------------------------------------------------------------- /test/AH/Containers/tests-BitArray.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | USING_AH_NAMESPACE; 5 | 6 | TEST(BitArray, construct) { 7 | BitArray<16> ba; 8 | for (int i = 0; i < 16; i++) 9 | EXPECT_EQ(ba.get(i), false); 10 | } 11 | 12 | TEST(BitArray, setClearGet) { 13 | BitArray<16> ba; 14 | ba.set(12); 15 | ba.set(7); 16 | for (int i = 0; i < 16; i++) 17 | if (i == 12 || i == 7) 18 | EXPECT_TRUE(ba.get(i)); 19 | else 20 | EXPECT_FALSE(ba.get(i)); 21 | ba.clear(12); 22 | for (int i = 0; i < 16; i++) 23 | if (i == 7) 24 | EXPECT_TRUE(ba.get(i)); 25 | else 26 | EXPECT_FALSE(ba.get(i)); 27 | ba.set(7, false); 28 | ba.set(6, true); 29 | for (int i = 0; i < 16; i++) 30 | if (i == 6) 31 | EXPECT_TRUE(ba.get(i)); 32 | else 33 | EXPECT_FALSE(ba.get(i)); 34 | } 35 | 36 | TEST(BitArray, outOfBounds) { 37 | BitArray<16> ba; 38 | EXPECT_THROW(ba.get(17), AH::ErrorException); 39 | } 40 | -------------------------------------------------------------------------------- /test/AH/Filters/test-EMA.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using AH::EMA; 9 | using AH::EMA_f; 10 | 11 | TEST(EMA, EMA) { 12 | using namespace std; 13 | EMA<2, uint16_t> ema; 14 | array signal = { 15 | 100, 100, 25, 25, 50, 123, 465, 75, 56, 50, 23, 41, 16 | }; 17 | array expected = { 18 | 25, 44, 39, 36, 39, 60, 161, 140, 119, 102, 82, 72, 19 | }; 20 | for_each(signal.begin(), signal.end(), [&](uint16_t &s) { s = ema(s); }); 21 | EXPECT_EQ(signal, expected); 22 | 23 | // In general, the results won't be exactly the same, because of rounding 24 | // errors. The expected sequence was generated by SciPy using floats, and 25 | // then the final results were rounded. 26 | // The EMA filter under test here uses integers for intermediate results, 27 | // so the rounding errors will accumulate. 28 | // In this test, however, there seems to be no problem. 29 | } 30 | 31 | TEST(EMA, EMA_overflow) { 32 | // Test that when the input is the maximum allowed value all the time, 33 | // nothing overflows. 34 | using namespace std; 35 | EMA<6, uint16_t> ema; 36 | constexpr size_t N = 2000; 37 | array signal; 38 | constexpr uint16_t maximum = (1 << 10) - 1; 39 | fill(signal.begin(), signal.end(), maximum); 40 | array expected; 41 | generate(expected.begin(), expected.end(), [i = 0]() mutable { 42 | return round(maximum - maximum * pow(1 - 0.015625, ++i)); 43 | }); 44 | for_each(signal.begin(), signal.end(), [&](uint16_t &s) { s = ema(s); }); 45 | for (size_t i = 0; i < signal.size(); ++i) 46 | EXPECT_NEAR(signal[i], expected[i], 1); 47 | } 48 | 49 | TEST(EMA, EMA_f) { 50 | using namespace std; 51 | EMA_f ema = 0.75; 52 | array signal = { 53 | 100.0, 100.0, 25.0, 25.0, 50.0, 123.0, 54 | 465.0, 75.0, 56.0, 50.0, 23.0, 41.0, 55 | }; 56 | array expected = { 57 | 25.0, 43.75, 39.0625, 35.546875, 39.160156, 60.120117, 58 | 161.34009, 139.75507, 118.8163, 101.61223, 81.95917, 71.719376, 59 | }; 60 | for_each(signal.begin(), signal.end(), [&](float &s) { s = ema(s); }); 61 | // ASSERT_EQ(signal, expected); 62 | for (size_t i = 0; i < signal.size(); ++i) 63 | ASSERT_FLOAT_EQ(signal[i], expected[i]); 64 | } 65 | 66 | TEST(EMA, EMA_overflow_init) { 67 | using namespace std; 68 | constexpr uint16_t maximum = (1 << 16) - 1; 69 | EMA<6, uint16_t, uint32_t> ema(maximum); 70 | EXPECT_EQ(ema(maximum), maximum); 71 | EXPECT_EQ(ema(maximum), maximum); 72 | EXPECT_EQ(ema(maximum), maximum); 73 | } 74 | 75 | TEST(EMA, EMA_overflow_reset) { 76 | using namespace std; 77 | constexpr uint16_t maximum = (1 << 16) - 1; 78 | EMA<6, uint16_t, uint32_t> ema; 79 | EXPECT_EQ(ema(0), 0); 80 | EXPECT_EQ(ema(0), 0); 81 | EXPECT_EQ(ema(0), 0); 82 | ema.reset(maximum); 83 | EXPECT_EQ(ema(maximum), maximum); 84 | EXPECT_EQ(ema(maximum), maximum); 85 | EXPECT_EQ(ema(maximum), maximum); 86 | } 87 | -------------------------------------------------------------------------------- /test/AH/Filters/test-EMA.py: -------------------------------------------------------------------------------- 1 | from scipy.signal import lfilter 2 | import numpy as np 3 | 4 | alpha = 0.25 5 | b = np.array((alpha,), dtype=np.float32) 6 | a = np.array((1, alpha-1), dtype=np.float32) 7 | 8 | signal = np.array((100, 100, 25, 25, 50, 123, 465, 75, 56, 50, 23, 41), 9 | dtype=np.float32) 10 | output = lfilter(b, a, signal) 11 | print('array signal = {{'.format(len(signal))) 12 | for i in signal: 13 | print(int(i), end=', ') 14 | print('};') 15 | print('array expected = {{'.format(len(signal))) 16 | for o in output: 17 | print(int(round(o)), end=', ') 18 | print('};') -------------------------------------------------------------------------------- /test/AH/Filters/test-EMA_f.py: -------------------------------------------------------------------------------- 1 | from scipy.signal import lfilter 2 | import numpy as np 3 | 4 | alpha = 0.25 5 | b = np.array((alpha,), dtype=np.float32) 6 | a = np.array((1, alpha-1), dtype=np.float32) 7 | 8 | signal = np.array((100, 100, 25, 25, 50, 123, 465, 75, 56, 50, 23, 41), 9 | dtype=np.float32) 10 | output = lfilter(b, a, signal) 11 | print('array signal = {{'.format(len(signal))) 12 | for i in signal: 13 | print(i, end=', ') 14 | print('};') 15 | print('array expected = {{'.format(len(signal))) 16 | for o in output: 17 | print(o, end=', ') 18 | print('};') -------------------------------------------------------------------------------- /test/AH/Math/test-Degrees.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace AH; 6 | 7 | TEST(Degrees, rad2deg) { 8 | ASSERT_FLOAT_EQ(rad2deg(M_PI), 180); 9 | ASSERT_FLOAT_EQ(rad2deg((float)M_PI), 180); 10 | ASSERT_FLOAT_EQ(rad2deg(2 * M_PI), 360); 11 | ASSERT_FLOAT_EQ(rad2deg(1.), 57.29577951308232); 12 | } 13 | 14 | TEST(Degrees, deg2rad) { 15 | ASSERT_FLOAT_EQ(deg2rad(180.), M_PI); 16 | ASSERT_FLOAT_EQ(deg2rad(360.), 2 * M_PI); 17 | ASSERT_FLOAT_EQ(deg2rad(57.29577951308232), 1); 18 | } 19 | 20 | TEST(Degrees, deg) { 21 | ASSERT_FLOAT_EQ(180_deg, M_PI); 22 | ASSERT_FLOAT_EQ(360_deg, 2 * M_PI); 23 | ASSERT_FLOAT_EQ(57.29577951308232_deg, 1); 24 | } -------------------------------------------------------------------------------- /test/AH/Math/test-IncreaseBitDepth.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | USING_AH_NAMESPACE; 8 | 9 | TEST(IncreaseBitDepth, IncreaseBitDepth) { 10 | std::array in = { 11 | 0b000, 0b001, 0b010, 0b011, 0b100, 0b101, 0b110, 0b111, 12 | }; 13 | std::array out; 14 | std::transform(std::begin(in), std::end(in), std::begin(out), 15 | [](uint8_t in) { 16 | return increaseBitDepth<7, 3, uint8_t, uint8_t>(in); 17 | }); 18 | std::array expected = { 19 | 0b000'0000, 0b001'0010, 0b010'0100, 0b011'0110, 20 | 0b100'1001, 0b101'1011, 0b110'1101, 0b111'1111, 21 | }; 22 | EXPECT_EQ(out, expected); 23 | } 24 | 25 | TEST(IncreaseBitDepth, IncreaseBitDepthMiddle) { 26 | std::array in = { 27 | 0b000, 0b001, 0b010, 0b011, 0b100, 0b101, 0b110, 0b111, 28 | }; 29 | std::array out; 30 | std::transform( 31 | std::begin(in), std::end(in), std::begin(out), [](uint8_t in) { 32 | return increaseBitDepthMiddle<7, 3, uint8_t, uint8_t>(in); 33 | }); 34 | std::array expected = { 35 | 0b000'0000, 0b001'0000, 0b010'0000, 0b011'0000, 36 | 0b100'0000, 0b101'0101, 0b110'1010, 0b111'1111, 37 | }; 38 | EXPECT_EQ(out, expected); 39 | EXPECT_EQ((increaseBitDepthMiddle<2, 2, uint32_t, uint32_t>(3)), 3); 40 | EXPECT_EQ((increaseBitDepthMiddle<3, 2, uint32_t, uint32_t>(3)), 7); 41 | EXPECT_EQ((increaseBitDepthMiddle<4, 2, uint32_t, uint32_t>(3)), 15); 42 | EXPECT_EQ((increaseBitDepthMiddle<5, 2, uint32_t, uint32_t>(3)), 31); 43 | EXPECT_EQ((increaseBitDepthMiddle<32, 2, uint32_t, uint32_t>(3)), 44 | 0xFFFFFFFF); 45 | EXPECT_EQ((increaseBitDepthMiddle<2, 2, uint32_t, uint32_t>(2)), 2); 46 | EXPECT_EQ((increaseBitDepthMiddle<3, 2, uint32_t, uint32_t>(2)), 4); 47 | EXPECT_EQ((increaseBitDepthMiddle<4, 2, uint32_t, uint32_t>(2)), 8); 48 | EXPECT_EQ((increaseBitDepthMiddle<5, 2, uint32_t, uint32_t>(2)), 16); 49 | EXPECT_EQ((increaseBitDepthMiddle<32, 2, uint32_t, uint32_t>(2)), 50 | 0x80000000); 51 | EXPECT_EQ((increaseBitDepthMiddle<32, 10, uint32_t, uint32_t>(512)), 52 | 0x80000000); 53 | EXPECT_EQ((increaseBitDepthMiddle<32, 10, uint32_t, uint32_t>(1023)), 54 | 0xFFFFFFFF); 55 | } 56 | -------------------------------------------------------------------------------- /test/AH/PrintStream/test-PrintStream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace ::testing; 6 | USING_AH_NAMESPACE; 7 | 8 | TEST(Debug, HexDump) { 9 | std::stringstream s; 10 | uint8_t d[] = {0x11, 0x23, 0xF7, 0xFF, 0x00}; 11 | s << HexDump(d, sizeof(d)); 12 | EXPECT_EQ(s.str(), "11 23 F7 FF 00"); 13 | } 14 | -------------------------------------------------------------------------------- /test/AH/Timing/test-Timer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | USING_AH_NAMESPACE; 6 | 7 | using namespace testing; 8 | 9 | TEST(MillisMicrosTimer, TimerMillis) { 10 | Timer timer = 3; 11 | InSequence s; 12 | EXPECT_CALL(ArduinoMock::getInstance(), millis).WillOnce(Return(100)); 13 | timer.begin(); 14 | Mock::VerifyAndClear(&ArduinoMock::getInstance()); 15 | EXPECT_CALL(ArduinoMock::getInstance(), millis) 16 | .WillOnce(Return(100)) 17 | .WillOnce(Return(101)) 18 | .WillOnce(Return(102)) 19 | .WillOnce(Return(103)) 20 | .WillOnce(Return(104)) 21 | .WillOnce(Return(105)) 22 | .WillOnce(Return(106)) 23 | .WillOnce(Return(107)) 24 | .WillOnce(Return(108)) 25 | .WillOnce(Return(109)); 26 | for (unsigned i = 0; i < 10; ++i) 27 | EXPECT_EQ(!!timer, i % 3 == 0) << "i = " << i; 28 | Mock::VerifyAndClear(&ArduinoMock::getInstance()); 29 | } 30 | 31 | TEST(MillisMicrosTimer, TimerMicros) { 32 | Timer timer = 3; 33 | InSequence s; 34 | EXPECT_CALL(ArduinoMock::getInstance(), micros).WillOnce(Return(100)); 35 | timer.begin(); 36 | Mock::VerifyAndClear(&ArduinoMock::getInstance()); 37 | EXPECT_CALL(ArduinoMock::getInstance(), micros) 38 | .WillOnce(Return(100)) 39 | .WillOnce(Return(101)) 40 | .WillOnce(Return(102)) 41 | .WillOnce(Return(103)) 42 | .WillOnce(Return(104)) 43 | .WillOnce(Return(105)) 44 | .WillOnce(Return(106)) 45 | .WillOnce(Return(107)) 46 | .WillOnce(Return(108)) 47 | .WillOnce(Return(109)); 48 | for (unsigned i = 0; i < 10; ++i) 49 | EXPECT_EQ(!!timer, i % 3 == 0) << "i = " << i; 50 | Mock::VerifyAndClear(&ArduinoMock::getInstance()); 51 | } -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(GoogleTest) 2 | 3 | # Test executable compilation and linking 4 | add_executable(tests 5 | "test_example.cpp" 6 | "test-main.cpp" 7 | "AH/PrintStream/test-PrintStream.cpp" 8 | "AH/Timing/test-Timer.cpp" 9 | "AH/Hardware/test-FilteredAnalog.cpp" 10 | "AH/Hardware/ExtendedInputOutput/test-AnalogMultiplex.cpp" 11 | "AH/Hardware/ExtendedInputOutput/test-ExtendedInputOutput.cpp" 12 | "AH/Hardware/test-IncrementDecrementButtons.cpp" 13 | "AH/Hardware/test-IncrementButton.cpp" 14 | "AH/Hardware/test-Button.cpp" 15 | "AH/Containers/test-Updatable.cpp" 16 | "AH/Containers/test-DoublyLinkedList.cpp" 17 | "AH/Containers/test-Array.cpp" 18 | "AH/Containers/tests-BitArray.cpp" 19 | "AH/Math/test-Degrees.cpp" 20 | "AH/Math/test-Quaternion.cpp" 21 | "AH/Math/test-IncreaseBitDepth.cpp" 22 | "AH/Math/test-Vector.cpp" 23 | "AH/Filters/test-Hysteresis.cpp" 24 | "AH/Filters/test-EMA.cpp" 25 | ) 26 | target_include_directories(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 27 | target_link_libraries(tests 28 | PRIVATE Arduino_Helpers 29 | PRIVATE Arduino-Helpers::warnings) 30 | 31 | # Add tests 32 | gtest_discover_tests(tests DISCOVERY_TIMEOUT 60 TIMEOUT 20) 33 | add_executable(Arduino-Helpers::tests ALIAS tests) -------------------------------------------------------------------------------- /test/examples-board-fqbns.yaml: -------------------------------------------------------------------------------- 1 | esp32: esp32:esp32:esp32thing:FlashFreq=80,PartitionScheme=default,UploadSpeed=921600,DebugLevel=none 2 | esp8266: esp8266:esp8266:d1_mini:xtal=80,vt=flash,exception=disabled,stacksmash=disabled,ssl=all,mmu=3232,non32xfer=fast,eesz=4M2M,ip=lm2f,dbg=Disabled,lvl=None____,wipe=none,baud=921600 3 | teensy 3.x: teensy:avr:teensy31:speed=96,usb=serialmidiaudio,opt=o2std,keys=en-us 4 | teensy 3.6: teensy:avr:teensy36:speed=180,usb=serialmidiaudio,opt=o2std,keys=en-us 5 | teensy 4.1: teensy:avr:teensy41:speed=600,usb=serialmidiaudio,opt=o2std,keys=en-us 6 | avr: arduino:avr:uno 7 | avr usb: arduino:avr:leonardo 8 | mega: arduino:avr:mega:cpu=atmega2560 9 | leonardo: arduino:avr:leonardo 10 | due: arduino:sam:arduino_due_x_dbg 11 | nano 33 iot: arduino:samd:nano_33_iot 12 | nano 33 ble: arduino:mbed_nano:nano33ble 13 | nano every: arduino:megaavr:nona4809:mode=off 14 | pi pico: arduino:mbed_rp2040:pico 15 | uno r4: arduino:renesas_uno:minima -------------------------------------------------------------------------------- /test/test-main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class MyEnv : public ::testing::Environment { 5 | public: 6 | void SetUp() override { ArduinoMock::begin(); } 7 | void TearDown() override { ArduinoMock::end(); } 8 | }; 9 | 10 | int main(int argc, char **argv) { 11 | ::testing::InitGoogleTest(&argc, argv); 12 | ::testing::AddGlobalTestEnvironment(new MyEnv); 13 | return RUN_ALL_TESTS(); 14 | } -------------------------------------------------------------------------------- /test/test_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace ::testing; 6 | 7 | TEST(millis, millis) { 8 | EXPECT_CALL(ArduinoMock::getInstance(), millis()) 9 | .Times(2) 10 | .WillOnce(Return(1)) 11 | .WillRepeatedly(Return(2)); 12 | EXPECT_EQ(millis(), 1); 13 | EXPECT_EQ(millis(), 2); 14 | 15 | Mock::VerifyAndClear(&ArduinoMock::getInstance()); 16 | } 17 | 18 | TEST(Serial, write_byte) { 19 | EXPECT_CALL(ArduinoMock::getSerial(), write(0x12)); 20 | Serial.write(0x12); 21 | 22 | Mock::VerifyAndClear(&Serial); 23 | } 24 | 25 | TEST(Serial, write_bytes) { 26 | EXPECT_CALL(ArduinoMock::getSerial(), write(_, _)) 27 | .With(Args<0, 1>(ElementsAre(0x00, 0x01, 0x02))); 28 | const uint8_t buff[] = {0x00, 0x01, 0x02}; 29 | Serial.write(buff, 3); 30 | 31 | Mock::VerifyAndClear(&Serial); 32 | } 33 | 34 | TEST(Serial, print_string) { 35 | EXPECT_CALL(ArduinoMock::getSerial(), write(_, _)) 36 | .With(Args<0, 1>(ElementsAre('T', 'e', 's', 't'))); 37 | const char *str = "Test"; 38 | Serial.print(str); 39 | 40 | Mock::VerifyAndClear(&Serial); 41 | } 42 | 43 | TEST(Serial, println_string) { 44 | EXPECT_CALL(ArduinoMock::getSerial(), write(_, _)) 45 | .With(Args<0, 1>(ElementsAre('T', 'e', 's', 't'))); 46 | EXPECT_CALL(ArduinoMock::getSerial(), write(_, _)) 47 | .With(Args<0, 1>(ElementsAre('\r', '\n'))); 48 | const char *str = "Test"; 49 | Serial.println(str); 50 | 51 | Mock::VerifyAndClear(&Serial); 52 | } 53 | 54 | #include 55 | 56 | TEST(Error, exception) { 57 | USING_AH_NAMESPACE; 58 | EXPECT_THROW(ERROR("An error occured", 12), ErrorException); 59 | } 60 | 61 | bool ends_with(std::string const &value, std::string const &ending) { 62 | if (ending.size() > value.size()) 63 | return false; 64 | return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); 65 | } 66 | 67 | TEST(Error, exceptionWhatErrorCode) { 68 | USING_AH_NAMESPACE; 69 | try { 70 | ERROR("An error occured", 12); 71 | FAIL(); 72 | } catch (ErrorException &e) { 73 | std::string msg = e.what(); 74 | std::cout << msg << endl; 75 | EXPECT_TRUE(ends_with(msg, "An error occured")); 76 | EXPECT_EQ(e.getErrorCode(), 12); 77 | } 78 | } -------------------------------------------------------------------------------- /tools/arduino-cli.yaml: -------------------------------------------------------------------------------- 1 | board_manager: 2 | additional_urls: 3 | - https://arduino.esp8266.com/stable/package_esp8266com_index.json 4 | - https://espressif.github.io/arduino-esp32/package_esp32_index.json 5 | - https://www.pjrc.com/teensy/package_teensy_index.json 6 | --------------------------------------------------------------------------------