├── .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 ├── README.md └── extra │ └── boards.txt.example ├── doxygen ├── Doxyfile ├── DoxygenLayout.xml ├── custom_stylesheet.css ├── header.html ├── images │ ├── .gitkeep │ ├── 50Hz-notch.png │ └── Screenshot-Arduino-IDE-Debug.png ├── 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 ├── Filters │ ├── Butterworth │ │ └── Butterworth.ino │ ├── FIRNotch │ │ └── FIRNotch.ino │ ├── MedianFilter │ │ └── MedianFilter.ino │ └── SimpleMovingAverage │ │ └── SimpleMovingAverage.ino ├── examples.dox └── test │ ├── ExtIO-pin-test │ └── ExtIO-pin-test.ino │ ├── Filter-Performance-Test │ └── Filter-Performance-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 ├── python ├── butterworth.svg ├── firnotch.svg ├── visualization │ ├── __init__.py │ └── bode.py ├── visualize-butterworth.py └── visualize-firnotch.py ├── 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.cpp │ │ ├── Array.hpp │ │ ├── ArrayHelpers.cpp │ │ ├── ArrayHelpers.hpp │ │ ├── BitArray.cpp │ │ ├── BitArray.hpp │ │ ├── CRTP.hpp │ │ ├── Containers.dox │ │ ├── LinkedList.cpp │ │ ├── LinkedList.hpp │ │ ├── Updatable.cpp │ │ ├── Updatable.hpp │ │ └── keywords.yml │ ├── Debug │ │ ├── Debug.cpp │ │ ├── Debug.dox │ │ ├── Debug.hpp │ │ └── DebugVal.hpp │ ├── Error │ │ ├── Error.cpp │ │ ├── Error.dox │ │ ├── Error.hpp │ │ └── Exit.cpp │ ├── Filters │ │ ├── EMA.cpp │ │ ├── EMA.hpp │ │ ├── Filters.dox │ │ ├── Hysteresis.cpp │ │ ├── Hysteresis.hpp │ │ └── keywords.yml │ ├── Hardware │ │ ├── ADCConfig.cpp │ │ ├── ADCConfig.hpp │ │ ├── Arduino-Hardware-Types.hpp │ │ ├── Button.cpp │ │ ├── Button.hpp │ │ ├── ButtonMatrix.cpp │ │ ├── ButtonMatrix.hpp │ │ ├── ButtonMatrix.ipp │ │ ├── ExtendedInputOutput │ │ │ ├── AnalogMultiplex.cpp │ │ │ ├── AnalogMultiplex.hpp │ │ │ ├── ExtIO.dox │ │ │ ├── ExtendedIOElement.cpp │ │ │ ├── ExtendedIOElement.hpp │ │ │ ├── ExtendedInputOutput.cpp │ │ │ ├── ExtendedInputOutput.hpp │ │ │ ├── MAX7219.cpp │ │ │ ├── MAX7219.hpp │ │ │ ├── MCP23017.hpp │ │ │ ├── MCP23017.ipp │ │ │ ├── SPIShiftRegisterOut.cpp │ │ │ ├── SPIShiftRegisterOut.hpp │ │ │ ├── SPIShiftRegisterOut.ipp │ │ │ ├── ShiftRegisterOut.cpp │ │ │ ├── ShiftRegisterOut.hpp │ │ │ ├── ShiftRegisterOut.ipp │ │ │ ├── ShiftRegisterOutBase.cpp │ │ │ ├── ShiftRegisterOutBase.hpp │ │ │ ├── ShiftRegisterOutBase.ipp │ │ │ ├── ShiftRegisterOutRGB.cpp │ │ │ ├── ShiftRegisterOutRGB.hpp │ │ │ ├── StaticSizeExtendedIOElement.cpp │ │ │ ├── StaticSizeExtendedIOElement.hpp │ │ │ └── keywords.yml │ │ ├── FilteredAnalog.cpp │ │ ├── FilteredAnalog.hpp │ │ ├── Hardware-Types.hpp │ │ ├── Hardware.dox │ │ ├── IncrementButton.cpp │ │ ├── IncrementButton.hpp │ │ ├── IncrementDecrementButtons.cpp │ │ ├── IncrementDecrementButtons.hpp │ │ ├── LEDs │ │ │ ├── DotBarDisplayLEDs.cpp │ │ │ ├── DotBarDisplayLEDs.hpp │ │ │ ├── LEDs.cpp │ │ │ ├── LEDs.hpp │ │ │ ├── MAX7219SevenSegmentDisplay.cpp │ │ │ ├── MAX7219SevenSegmentDisplay.hpp │ │ │ ├── MAX7219_Base.cpp │ │ │ ├── MAX7219_Base.hpp │ │ │ └── keywords.yml │ │ ├── MCP23017Encoders.hpp │ │ ├── MultiPurposeButton.hpp │ │ ├── RegisterEncoders.hpp │ │ └── keywords.yml │ ├── Math │ │ ├── Degrees.hpp │ │ ├── Divide.hpp │ │ ├── FixArduinoMacros.hpp │ │ ├── IncreaseBitDepth.cpp │ │ ├── IncreaseBitDepth.hpp │ │ ├── Math.dox │ │ ├── MinMaxFix.cpp │ │ ├── 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.cpp │ │ ├── NamespaceSettings.hpp │ │ ├── Settings.cpp │ │ ├── Settings.dox │ │ ├── Settings.hpp │ │ ├── SettingsWrapper.cpp │ │ ├── SettingsWrapper.hpp │ │ └── Warnings.hpp │ ├── Teensy │ │ └── TeensyUSBTypes.hpp │ ├── Timing │ │ ├── MillisMicrosTimer.cpp │ │ ├── MillisMicrosTimer.hpp │ │ ├── Timing.dox │ │ └── keywords.yml │ └── Types │ │ ├── Frequency.hpp │ │ ├── FunctionTraits.hpp │ │ └── keywords.yml ├── Arduino_Helpers.dox ├── Arduino_Helpers.h ├── CMakeLists.txt ├── Filters.h ├── Filters │ ├── BiQuad.hpp │ ├── Butterworth.hpp │ ├── FIRFilter.hpp │ ├── Filters.dox │ ├── FixedPoint.hpp │ ├── IIRFilter.hpp │ ├── MedianFilter.hpp │ ├── Notch.hpp │ ├── SMA.hpp │ ├── SOSFilter.hpp │ ├── TransferFunction.hpp │ └── keywords.yml └── 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 ├── Filters │ ├── test-BiQuad.cpp │ ├── test-Butterworth.cpp │ ├── test-Butterworth.py │ ├── test-FIRFilter.cpp │ ├── test-FIRFilter.py │ ├── test-FixedPoint.cpp │ ├── test-IIRFilter.cpp │ ├── test-IIRFilter.py │ ├── test-MedianFilter.cpp │ ├── test-MedianFilter.py │ ├── test-SMA.cpp │ ├── test-SMA.py │ └── test-SOSFilter.cpp ├── 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-Filters/a11a239a890b6a41006679c4a235ba6b91b3e883/.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@v1 12 | - name: Install dependencies 13 | run: sudo ./scripts/install-gtest.sh Debug /usr/local 14 | - name: Configure 15 | run: cmake -S. --preset ci 16 | env: 17 | CC: gcc-9 18 | CXX: g++-9 19 | - name: Build 20 | run: cmake --build --preset ci -j 21 | - name: Test 22 | run: ctest --preset ci 23 | -------------------------------------------------------------------------------- /.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-Filters 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_program(AH_DOXYGEN doxygen) 23 | if (AH_DOXYGEN) 24 | add_custom_target(documentation 25 | doxygen 26 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/doxygen) 27 | endif() 28 | 29 | # Compiler warnings 30 | option(AH_WARNINGS_AS_ERRORS "Enable -Werror" On) 31 | include(cmake/Warnings.cmake) 32 | 33 | # Build the source files and tests 34 | add_subdirectory(mock) 35 | add_subdirectory(src) 36 | add_subdirectory(test) 37 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | Documentation for the [**Arduino Filters**](https://github.com/tttapa/Arduino-Filters) library. 2 | 3 | - [master](https://tttapa.github.io/Arduino-Filters/Doxygen/index.html) 4 | - [1.0.0](https://tttapa.github.io/Arduino-Filters/1.0.0/Doxygen/index.html) -------------------------------------------------------------------------------- /doxygen/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tttapa/Arduino-Filters/a11a239a890b6a41006679c4a235ba6b91b3e883/doxygen/images/.gitkeep -------------------------------------------------------------------------------- /doxygen/images/50Hz-notch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tttapa/Arduino-Filters/a11a239a890b6a41006679c4a235ba6b91b3e883/doxygen/images/50Hz-notch.png -------------------------------------------------------------------------------- /doxygen/images/Screenshot-Arduino-IDE-Debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tttapa/Arduino-Filters/a11a239a890b6a41006679c4a235ba6b91b3e883/doxygen/images/Screenshot-Arduino-IDE-Debug.png -------------------------------------------------------------------------------- /doxygen/pages/Debug.md: -------------------------------------------------------------------------------- 1 | # 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) -------------------------------------------------------------------------------- /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, 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 | DEBUGVAL(log10(1000) - 2); 55 | DEBUGVAL(millis()); 56 | DEBUGVAL(Serial.read()); 57 | someFunction(42); 58 | DEBUG(""); 59 | delay(5000); 60 | } 61 | 62 | int someFunction(int parameter) { 63 | DEBUGFN(NAMEDVALUE(parameter)); 64 | return parameter; 65 | } -------------------------------------------------------------------------------- /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, 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-Filters 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, 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, 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/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, 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/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, 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, 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, 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, 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, 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 | #include 31 | #include 32 | 33 | using namespace ExtIO; // Use the extended input/output functions 34 | 35 | using WireType = decltype(Wire); // The type of the I²C driver to use 36 | MCP23017 mcp { 37 | Wire, // The I²C driver to use 38 | 0x0, // The I²C address offset (depends on the state of the address pins) 39 | 2, // Optional: interrupt pin to detect input changes 40 | }; 41 | 42 | pin_t ledPin = mcp.pinA(0); // GPIOA0 43 | pin_t buttonPin = mcp.pinB(0); // GPIOB0 44 | 45 | void setup() { 46 | Wire.begin(); // Initialize the I²C interface 47 | Wire.setClock(800000); // Faster I²C clock 48 | mcp.begin(); // Initialize the MCP23017 49 | 50 | pinMode(ledPin, OUTPUT); 51 | pinMode(buttonPin, INPUT_PULLUP); 52 | } 53 | 54 | void loop() { 55 | auto buttonState = digitalRead(buttonPin); 56 | digitalWrite(ledPin, buttonState ? LOW : HIGH); 57 | } 58 | 59 | // Note: 60 | // The “interrupt” pin is not used to trigger an actual interrupt on the 61 | // microcontroller. It is just used to check whether any of the inputs of 62 | // the MCP23017 changed without having to do an I²C transaction. Using this 63 | // pin can speed up your code, but it's not necessary, you can leave it out 64 | // in the MCP23017 construction at the top of the sketch. 65 | -------------------------------------------------------------------------------- /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, 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, 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, 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, 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, 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, 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/Filters/Butterworth/Butterworth.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Example of Butterworth filter. 3 | * 4 | * @boards AVR, AVR USB, Nano 33 IoT, Nano 33 BLE, Due, Teensy 3.x, ESP8266, ESP32 5 | * 6 | * @see 7 | * 8 | * Written by PieterP, 2019-11-12 9 | * https://github.com/tttapa/Arduino-Filters 10 | */ 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | void setup() { 18 | Serial.begin(115200); 19 | } 20 | 21 | // Sampling frequency 22 | const double f_s = 100; // Hz 23 | // Cut-off frequency (-3 dB) 24 | const double f_c = 25; // Hz 25 | // Normalized cut-off frequency 26 | const double f_n = 2 * f_c / f_s; 27 | 28 | // Sample timer 29 | Timer timer = std::round(1e6 / f_s); 30 | 31 | // Sixth-order Butterworth filter 32 | auto filter = butter<6>(f_n); 33 | 34 | void loop() { 35 | if (timer) 36 | Serial.println(filter(analogRead(A0))); 37 | } -------------------------------------------------------------------------------- /examples/Filters/FIRNotch/FIRNotch.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Example of 50 Hz (+harmonics) notch filter. 3 | * 4 | * @boards AVR, AVR USB, Nano 33 IoT, Nano 33 BLE, Due, Teensy 3.x, ESP8266, ESP32 5 | * 6 | * @see 7 | * 8 | * Be careful when selecting a sampling frequency that's a multiple of 50 Hz, as 9 | * this will alias 50 Hz harmonics to 0 Hz (DC), and this might introduce a more 10 | * or less constant error to your measurements. 11 | * It's best to add an analog anti-aliasing filter as well. 12 | * 13 | * ![Filtered mains power noise signal (blue is unfilterd, red is filtered)](50Hz-notch.png) 14 | * 15 | * Written by PieterP, 2019-11-22 16 | * https://github.com/tttapa/Arduino-Filters 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | void setup() { 25 | Serial.begin(1e6); 26 | } 27 | 28 | // Sampling frequency 29 | const double f_s = 250; // Hz 30 | // Notch frequency (-∞ dB) 31 | const double f_c = 50; // Hz 32 | // Normalized notch frequency 33 | const double f_n = 2 * f_c / f_s; 34 | 35 | // Sample timer 36 | Timer timer = std::round(1e6 / f_s); 37 | 38 | // Very simple Finite Impulse Response notch filter 39 | auto filter1 = simpleNotchFIR(f_n); // fundamental 40 | auto filter2 = simpleNotchFIR(2 * f_n); // second harmonic 41 | 42 | void loop() { 43 | if (timer) { 44 | auto raw = analogRead(A0); 45 | Serial.print(raw); 46 | Serial.print('\t'); 47 | Serial.println(filter2(filter1(raw))); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /examples/Filters/MedianFilter/MedianFilter.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Example of median filter. 3 | * 4 | * @boards AVR, AVR USB, Nano 33 IoT, Nano 33 BLE, Due, Teensy 3.x, ESP8266, ESP32 5 | * 6 | * Written by PieterP, 2019-11-16 7 | * https://github.com/tttapa/Arduino-Filters 8 | */ 9 | 10 | #include 11 | 12 | #include // std::round 13 | #include // Timer 14 | #include // MedianFilter 15 | 16 | void setup() { 17 | Serial.begin(115200); 18 | } 19 | 20 | // Sampling frequency 21 | const double f_s = 100; // Hz 22 | 23 | // Sample timer 24 | Timer timer = std::round(1e6 / f_s); 25 | // Median filter of length 10, initialized with a value of 512. 26 | MedianFilter<10, uint16_t> medfilt = {512}; 27 | 28 | void loop() { 29 | if (timer) // returns true once every 10 ms, determines sampling frequency 30 | Serial.println(medfilt(analogRead(A0))); 31 | } -------------------------------------------------------------------------------- /examples/Filters/SimpleMovingAverage/SimpleMovingAverage.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Example of a Simple Moving Average (SMA, also known as Running Average) 3 | * filter. 4 | * 5 | * @boards AVR, AVR USB, Nano 33 IoT, Nano 33 BLE, Due, Teensy 3.x, ESP8266, ESP32 6 | * 7 | * Written by PieterP, 2020-01-07 8 | * https://github.com/tttapa/Arduino-Filters 9 | */ 10 | 11 | #include 12 | 13 | #include // std::round 14 | #include // Timer 15 | #include // SMA (Simple Moving Average) 16 | 17 | void setup() { 18 | Serial.begin(115200); 19 | } 20 | 21 | // Sampling frequency 22 | const double f_s = 100; // Hz 23 | 24 | // Sample timer 25 | Timer timer = std::round(1e6 / f_s); 26 | // Simple Moving Average filter of length 10, initialized with a value of 512. 27 | SMA<10> average = {512}; 28 | 29 | void loop() { 30 | if (timer) // returns true once every 10 ms, determines sampling frequency 31 | Serial.println(average(analogRead(A0))); 32 | } 33 | 34 | // By default, SMA uses `uint16_t` as the type for the input and output values, 35 | // and `uint32_t` for the accumulator (the sum of previous inputs). 36 | // This works fine for most use cases, but you can specifically set the types 37 | // as well. The first type is the type of the in- and outputs, and the second 38 | // type is the type of the accumulator. 39 | // 40 | // For example: 41 | // 42 | // SMA<10, uint32_t, uint64_t> // for very large inputs (larger than 65,535) 43 | // SMA<10, int16_t, int32_t> // for inputs that can go negative 44 | // SMA<10, float, float> // for decimal (floating point) values 45 | // SMA<10, uint16_t, uint16_t> // for small input values and short averages 46 | // 47 | // Some important things to note: 48 | // - Unsigned integer types are slightly faster than signed integer types 49 | // - Integer types are significantly faster than floating point types. 50 | // Since most sensors and ADCs return an integer, it's often a good idea to 51 | // filter the raw integer measurement, before converting it to a floating 52 | // point number (e.g. voltage or temperature). 53 | // - The accumulator has to be large enough to fit N times the maximum input 54 | // value. If your maximum input value is 1023 (e.g. from analogRead), and if 55 | // the accumulator type is `uint16_t`, as in the last example above, the 56 | // maximum length N of the SMA will be ⌊(2¹⁶ - 1) / 1023⌋ = 64. 57 | // Alternatively, analogRead returns a 10-bit number, so the maximum length 58 | // is 2¹⁶⁻¹⁰ = 2⁶ = 64, which is the same result as before. -------------------------------------------------------------------------------- /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 33 IoT, Nano 33 BLE, 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 33 IoT, Nano 33 BLE, Teensy 3.x, ESP8266, ESP32 3 | */ 4 | #include -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Arduino Filters 2 | version=1.0.0 3 | author=Pieter P 4 | maintainer=Pieter P 5 | sentence=Filter library for Arduino. 6 | paragraph= Supports IIR and FIR filters with many different implementations, Direct Form 1 & 2, BiQuad, Second Order Sections ... Supports Butterworth filters etc. 7 | category=Data Processing 8 | url=https://github.com/tttapa/Arduino-Filters 9 | architectures=avr,sam,samd,teensy,esp32,esp8266,megaavr,mbed,mbed_nano 10 | includes=Filters.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. -------------------------------------------------------------------------------- /python/visualization/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tttapa/Arduino-Filters/a11a239a890b6a41006679c4a235ba6b91b3e883/python/visualization/__init__.py -------------------------------------------------------------------------------- /python/visualization/bode.py: -------------------------------------------------------------------------------- 1 | from scipy.signal import freqz 2 | import matplotlib.pyplot as plt 3 | from math import pi 4 | import numpy as np 5 | 6 | def bode(b, a, f_s, magnitude_limits = None, phase_limits = None): 7 | w, H = freqz(b, a, 4096) # Calculate the frequency response 8 | w *= f_s / (2 * pi) # Convert from rad/sample to Hz 9 | 10 | # Plot the amplitude response 11 | plt.subplot(2, 1, 1) 12 | plt.suptitle('Bode Plot') 13 | H_dB = 20 * np.log10(abs(H)) # Convert modulus of H to dB 14 | plt.plot(w, H_dB) 15 | plt.ylabel('Magnitude [dB]') 16 | plt.xlim(0, f_s / 2) 17 | if (magnitude_limits is not None): 18 | plt.ylim(*magnitude_limits) 19 | plt.axhline(0, linewidth=0.8, color='black', linestyle=':') 20 | 21 | # Plot the phase response 22 | plt.subplot(2, 1, 2) 23 | phi = np.angle(H) # Argument of H 24 | phi = np.unwrap(phi) # Remove discontinuities 25 | phi *= 180 / pi # and convert to degrees 26 | plt.plot(w, phi) 27 | plt.xlabel('Frequency [Hz]') 28 | plt.ylabel('Phase [°]') 29 | plt.xlim(0, f_s / 2) 30 | if (phase_limits is not None): 31 | plt.ylim(*phase_limits) 32 | plt.axhline(0, linewidth=0.8, color='black', linestyle=':') 33 | 34 | plt.show() -------------------------------------------------------------------------------- /python/visualize-butterworth.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | Visualization of the filter from the Butterworth.ino example. 5 | """ 6 | 7 | from visualization.bode import bode 8 | from scipy.signal import butter 9 | 10 | f_s = 100 # Sample frequency Hz 11 | f_c = 25 # Cut-off frequency in Hz 12 | f_n = 2 * f_c / f_s # Normalized cut-off frequency 13 | order = 6 # Order of the butterworth filter 14 | 15 | # Design the digital Butterworth filter 16 | b, a = butter(order, f_n) 17 | 18 | # Display the bode plot of the filter 19 | bode(b, a, f_s, magnitude_limits=[-100, 10], phase_limits=[-540, 45]) 20 | -------------------------------------------------------------------------------- /python/visualize-firnotch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | Visualization of the filter from the FIRNotch.ino example. 5 | """ 6 | 7 | from visualization.bode import bode 8 | from math import pi, cos 9 | 10 | f_s = 250 # Sample frequency in Hz 11 | f_c = 50 # Notch frequency in Hz 12 | 13 | omega_c = 2 * pi * f_c # Notch angular frequency 14 | omega_c_d = omega_c / f_s # Normalized notch frequency (digital) 15 | 16 | h0 = 2 - 2 * cos(omega_c_d) # DC gain 17 | 18 | b = [1 / h0, -2 * cos(omega_c_d) / h0, 1 / h0] # Calculate coefficients 19 | a = [1] 20 | 21 | # Display the bode plot of the filter 22 | bode(b, a, f_s, magnitude_limits=[-60, 20], phase_limits=[-90, 135]) 23 | -------------------------------------------------------------------------------- /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/Filters/**' \ 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/Filters/**' \ 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-Filters" -------------------------------------------------------------------------------- /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 | if (AH_FAST_COMPILE) 4 | set(Arduino_Helpers_SOURCES 5 | "PrintStream/PrintStream.cpp" 6 | "Debug/Debug.cpp" 7 | "Hardware/IncrementDecrementButtons.cpp" 8 | "Hardware/Button.cpp" 9 | "Hardware/IncrementButton.cpp" 10 | "Hardware/ExtendedInputOutput/ShiftRegisterOutRGB.cpp" 11 | "Hardware/ExtendedInputOutput/ExtendedIOElement.cpp" 12 | "Hardware/ExtendedInputOutput/ExtendedInputOutput.cpp" 13 | "Error/Exit.cpp" 14 | "Math/Vector.cpp" 15 | "Math/Quaternion.cpp" 16 | ) 17 | else () 18 | file(GLOB_RECURSE 19 | Arduino_Helpers_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) 20 | endif () 21 | 22 | add_library(Arduino_Helpers ${Arduino_Helpers_SOURCES}) 23 | target_include_directories(Arduino_Helpers 24 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..) 25 | 26 | if (AH_FAST_COMPILE) 27 | target_compile_definitions(Arduino_Helpers 28 | PUBLIC 29 | -DNO_DEBUG_PRINTS 30 | -DANALOG_FILTER_SHIFT_FACTOR_OVERRIDE=2) 31 | else () 32 | target_compile_definitions(Arduino_Helpers 33 | PUBLIC 34 | #-DNO_DEBUG_PRINTS 35 | -DTEST_COMPILE_ALL_HEADERS_SEPARATELY 36 | -DANALOG_FILTER_SHIFT_FACTOR_OVERRIDE=2) 37 | endif () 38 | 39 | target_link_libraries(Arduino_Helpers 40 | PUBLIC ArduinoMock 41 | PRIVATE Arduino-Helpers::warnings) -------------------------------------------------------------------------------- /src/AH/Containers/Array.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "Array.hpp" 3 | #endif -------------------------------------------------------------------------------- /src/AH/Containers/ArrayHelpers.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "ArrayHelpers.hpp" 3 | #endif -------------------------------------------------------------------------------- /src/AH/Containers/BitArray.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "BitArray.hpp" 3 | #endif -------------------------------------------------------------------------------- /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/LinkedList.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "LinkedList.hpp" 3 | #endif -------------------------------------------------------------------------------- /src/AH/Containers/Updatable.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "Updatable.hpp" 3 | #endif 4 | -------------------------------------------------------------------------------- /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.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "Error.hpp" 3 | #endif -------------------------------------------------------------------------------- /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 4 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 5 | 6 | #include "Error.hpp" 7 | 8 | BEGIN_AH_NAMESPACE 9 | 10 | void fatalErrorExit() { 11 | #if defined(LED_BUILTIN) || (defined(ESP32) && defined(BUILTIN_LED)) 12 | pinMode(LED_BUILTIN, OUTPUT); 13 | while (1) { 14 | digitalWrite(LED_BUILTIN, HIGH); 15 | delay(50); 16 | digitalWrite(LED_BUILTIN, LOW); 17 | delay(50); 18 | digitalWrite(LED_BUILTIN, HIGH); 19 | delay(50); 20 | digitalWrite(LED_BUILTIN, LOW); 21 | delay(850); 22 | } 23 | #else 24 | #warning "LED_BUILTIN is not available, so it cannot blink when an error occurs" 25 | noInterrupts(); 26 | while (1) 27 | yield(); 28 | #endif 29 | } 30 | 31 | END_AH_NAMESPACE 32 | 33 | AH_DIAGNOSTIC_POP() 34 | 35 | #endif -------------------------------------------------------------------------------- /src/AH/Filters/EMA.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "EMA.hpp" 3 | #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/Hysteresis.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "Hysteresis.hpp" 3 | #endif -------------------------------------------------------------------------------- /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.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "ADCConfig.hpp" 3 | #endif 4 | -------------------------------------------------------------------------------- /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 | * @see @ref AH::ADC_BITS 9 | */ 10 | 11 | #include 12 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 13 | 14 | AH_DIAGNOSTIC_EXTERNAL_HEADER() 15 | #include 16 | AH_DIAGNOSTIC_POP() 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 | 82 | AH_DIAGNOSTIC_POP() -------------------------------------------------------------------------------- /src/AH/Hardware/Arduino-Hardware-Types.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 5 | 6 | #include 7 | #include 8 | 9 | AH_DIAGNOSTIC_EXTERNAL_HEADER() 10 | #include // pin functions and constants 11 | AH_DIAGNOSTIC_POP() 12 | 13 | 14 | #if defined(ARDUINO_API_VERSION) 15 | 16 | using ArduinoPin_t = pin_size_t; 17 | using PinStatus_t = PinStatus; 18 | using PinMode_t = PinMode; 19 | using BitOrder_t = BitOrder; 20 | 21 | #else // ARDUINO_API_VERSION 22 | 23 | using ArduinoPin_t = 24 | AH::function_traits::argument_t<0>; 25 | using PinStatus_t = 26 | AH::function_traits::argument_t<1>; 27 | using PinMode_t = AH::function_traits::argument_t<1>; 28 | 29 | #if defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) 30 | using BitOrder_t = BitOrder; 31 | #else 32 | using BitOrder_t = uint8_t; 33 | #endif 34 | 35 | namespace AH_pin_detail { 36 | constexpr static auto tmp_HIGH = HIGH; 37 | constexpr static auto tmp_LOW = LOW; 38 | constexpr static auto tmp_INPUT = INPUT; 39 | constexpr static auto tmp_OUTPUT = OUTPUT; 40 | constexpr static auto tmp_INPUT_PULLUP = INPUT_PULLUP; 41 | } // namespace AH_pin_detail 42 | #ifdef HIGH 43 | #undef HIGH 44 | #define HIGH HIGH 45 | #endif 46 | #ifdef LOW 47 | #undef LOW 48 | #define LOW LOW 49 | #endif 50 | #ifdef INPUT 51 | #undef INPUT 52 | #define INPUT INPUT 53 | #endif 54 | #ifdef OUTPUT 55 | #undef OUTPUT 56 | #define OUTPUT OUTPUT 57 | #endif 58 | #ifdef INPUT_PULLUP 59 | #undef INPUT_PULLUP 60 | #define INPUT_PULLUP INPUT_PULLUP 61 | #endif 62 | constexpr PinStatus_t HIGH = AH_pin_detail::tmp_HIGH; 63 | constexpr PinStatus_t LOW = AH_pin_detail::tmp_LOW; 64 | constexpr PinMode_t INPUT = AH_pin_detail::tmp_INPUT; 65 | constexpr PinMode_t OUTPUT = AH_pin_detail::tmp_OUTPUT; 66 | constexpr PinMode_t INPUT_PULLUP = AH_pin_detail::tmp_INPUT_PULLUP; 67 | 68 | #endif // ARDUINO_API_VERSION 69 | 70 | BEGIN_AH_NAMESPACE 71 | template 72 | inline ArduinoPin_t arduino_pin_cast(T t) { 73 | return static_cast(t); 74 | } 75 | END_AH_NAMESPACE 76 | 77 | AH_DIAGNOSTIC_POP() -------------------------------------------------------------------------------- /src/AH/Hardware/Button.cpp: -------------------------------------------------------------------------------- 1 | #include "Button.hpp" 2 | 3 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 4 | 5 | BEGIN_AH_NAMESPACE 6 | 7 | Button::Button(pin_t pin) : pin(pin) {} 8 | 9 | void Button::begin() { ExtIO::pinMode(pin, INPUT_PULLUP); } 10 | 11 | void Button::invert() { state.invert = true; } 12 | 13 | Button::State Button::update() { 14 | // Read pin state and current time 15 | bool input = ExtIO::digitalRead(pin) ^ state.invert; 16 | unsigned long now = millis(); 17 | // Check if enough time has elapsed after last bounce 18 | if (state.bouncing) 19 | state.bouncing = now - state.prevBounceTime <= debounceTime; 20 | // Shift the debounced state one bit to the left, either appending the 21 | // new input state if not bouncing, or repeat the old state if bouncing 22 | bool prevState = state.debounced & 0b01; 23 | bool newState = state.bouncing ? prevState : input; 24 | state.debounced = (prevState << 1) | newState; 25 | // Check if the input changed state (button pressed, released or bouncing) 26 | if (input != state.prevInput) { 27 | state.bouncing = true; 28 | state.prevInput = input; 29 | state.prevBounceTime = now; 30 | } 31 | return getState(); 32 | } 33 | 34 | Button::State Button::getState() const { 35 | return static_cast(state.debounced); 36 | } 37 | 38 | FlashString_t Button::getName(Button::State state) { 39 | switch (state) { 40 | case Button::Pressed: return F("Pressed"); 41 | case Button::Released: return F("Released"); 42 | case Button::Falling: return F("Falling"); 43 | case Button::Rising: return F("Rising"); 44 | default: return F(""); // Keeps the compiler happy 45 | } 46 | } 47 | 48 | unsigned long Button::previousBounceTime() const { 49 | return state.prevBounceTime; 50 | } 51 | 52 | unsigned long Button::stableTime(unsigned long now) const { 53 | return now - previousBounceTime(); 54 | } 55 | 56 | unsigned long Button::stableTime() const { return stableTime(millis()); } 57 | 58 | void Button::setDebounceTime(unsigned long debounceTime) { 59 | Button::debounceTime = debounceTime; 60 | } 61 | 62 | unsigned long Button::getDebounceTime() { return Button::debounceTime; } 63 | 64 | unsigned long Button::debounceTime = BUTTON_DEBOUNCE_TIME; 65 | 66 | END_AH_NAMESPACE 67 | 68 | AH_DIAGNOSTIC_POP() -------------------------------------------------------------------------------- /src/AH/Hardware/ButtonMatrix.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "ButtonMatrix.hpp" 3 | #endif -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/AnalogMultiplex.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "AnalogMultiplex.hpp" 3 | #endif -------------------------------------------------------------------------------- /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 | * Currently only shift registers and multiplexers. 10 | */ 11 | 12 | /// @cond !AH_MAIN_LIBRARY 13 | /// @} 14 | /// @endcond -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 3 | 4 | #include "ExtendedIOElement.hpp" 5 | #include 6 | #include // is_unsigned 7 | 8 | BEGIN_AH_NAMESPACE 9 | 10 | ExtendedIOElement::ExtendedIOElement(pin_t length) 11 | : length(length), start(offset), end(offset + length) { 12 | if (end < start) 13 | FATAL_ERROR(F("ExtIO ran out of pin numbers. " 14 | "Dynamically creating new ExtendedIOElements is not " 15 | "recommended."), 16 | 0x00FF); 17 | offset = end; 18 | } 19 | 20 | void ExtendedIOElement::beginAll() { 21 | ExtendedIOElement::applyToAll(&ExtendedIOElement::begin); 22 | } 23 | 24 | void ExtendedIOElement::updateAllBufferedOutputs() { 25 | ExtendedIOElement::applyToAll(&ExtendedIOElement::updateBufferedOutputs); 26 | } 27 | 28 | void ExtendedIOElement::updateAllBufferedInputs() { 29 | ExtendedIOElement::applyToAll(&ExtendedIOElement::updateBufferedInputs); 30 | } 31 | 32 | pin_t ExtendedIOElement::pin(pin_t p) const { 33 | if (p >= length) { 34 | static_assert(std::is_unsigned::value, 35 | "Error: pin_t should be an unsigned integer type"); 36 | ERROR(F("Error: the pin number (") 37 | << p 38 | << F(") is greater than the number of pins of this " 39 | "ExtendedIOElement (") 40 | << length << ')', 41 | 0x4567); 42 | return end - 1; // LCOV_EXCL_LINE 43 | } 44 | return p + start; 45 | } 46 | 47 | pin_t ExtendedIOElement::operator[](pin_t p) const { return pin(p); } 48 | 49 | pin_t ExtendedIOElement::getLength() const { return length; } 50 | 51 | pin_t ExtendedIOElement::getEnd() const { return end; } 52 | 53 | pin_t ExtendedIOElement::getStart() const { return start; } 54 | 55 | DoublyLinkedList &ExtendedIOElement::getAll() { 56 | return updatables; 57 | } 58 | 59 | pin_t ExtendedIOElement::offset = NUM_DIGITAL_PINS + NUM_ANALOG_INPUTS; 60 | 61 | END_AH_NAMESPACE 62 | 63 | AH_DIAGNOSTIC_POP() -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/MAX7219.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | // #include "MAX7219.hpp" // TODO 3 | #endif -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/SPIShiftRegisterOut.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "SPIShiftRegisterOut.hpp" 3 | #endif -------------------------------------------------------------------------------- /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.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "ShiftRegisterOut.hpp" 3 | #endif -------------------------------------------------------------------------------- /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.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "ShiftRegisterOutBase.hpp" 3 | #endif -------------------------------------------------------------------------------- /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 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 3 | 4 | BEGIN_AH_NAMESPACE 5 | 6 | const uint8_t ShiftRegisterOutRGB::redBit __attribute__((weak)) = 0; 7 | const uint8_t ShiftRegisterOutRGB::greenBit __attribute__((weak)) = 1; 8 | const uint8_t ShiftRegisterOutRGB::blueBit __attribute__((weak)) = 2; 9 | 10 | END_AH_NAMESPACE 11 | 12 | AH_DIAGNOSTIC_POP() 13 | -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/ShiftRegisterOutRGB.hpp: -------------------------------------------------------------------------------- 1 | /* ✔ */ 2 | 3 | #pragma once 4 | 5 | #include 6 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 7 | 8 | #include 9 | #include 10 | 11 | BEGIN_AH_NAMESPACE 12 | 13 | /** 14 | * @brief A struct for setting the RGB mode for RGB shift registers. 15 | */ 16 | struct ShiftRegisterOutRGB { 17 | /** 18 | * @brief The position of the red output pin for 3-color LEDs. 19 | * For the usual RGB configuration, this is 0. 20 | */ 21 | const static uint8_t redBit; // = 0; 22 | /** 23 | * @brief The position of the green output pin for 3-color LEDs. 24 | * For the usual RGB configuration, this is 1. 25 | */ 26 | const static uint8_t greenBit; // = 1; 27 | /** 28 | * @brief The position of the blue output pin for 3-color LEDs. 29 | * For the usual RGB configuration, this is 2. 30 | */ 31 | const static uint8_t blueBit; // = 2; 32 | }; 33 | 34 | END_AH_NAMESPACE 35 | 36 | AH_DIAGNOSTIC_POP() 37 | -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/StaticSizeExtendedIOElement.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "StaticSizeExtendedIOElement.hpp" 3 | #endif 4 | -------------------------------------------------------------------------------- /src/AH/Hardware/ExtendedInputOutput/StaticSizeExtendedIOElement.hpp: -------------------------------------------------------------------------------- 1 | /* ✔ */ 2 | 3 | #pragma once 4 | 5 | #include 6 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 7 | 8 | #include "ExtendedIOElement.hpp" 9 | #include 10 | 11 | BEGIN_AH_NAMESPACE 12 | 13 | /** 14 | * @brief A class for ExtendedIOElement%s with a fixed size. 15 | * 16 | * This class is to make it easier to get an array of all pins of the element. 17 | */ 18 | template 19 | class StaticSizeExtendedIOElement : public ExtendedIOElement { // LCOV_EXCL_LINE 20 | protected: 21 | StaticSizeExtendedIOElement() : ExtendedIOElement{N} {} // LCOV_EXCL_LINE 22 | 23 | public: 24 | /** 25 | * @brief Get an array containing all pins of the element. 26 | */ 27 | Array pins() const { 28 | return generateIncrementalArray(getStart()); 29 | } 30 | 31 | static constexpr uint16_t length() { return N; } 32 | }; 33 | 34 | END_AH_NAMESPACE 35 | 36 | AH_DIAGNOSTIC_POP() 37 | -------------------------------------------------------------------------------- /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/FilteredAnalog.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "FilteredAnalog.hpp" 3 | #endif -------------------------------------------------------------------------------- /src/AH/Hardware/Hardware-Types.hpp: -------------------------------------------------------------------------------- 1 | /* ✔ */ 2 | 3 | #pragma once 4 | 5 | #include 6 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 7 | 8 | #include 9 | #include 10 | #include // uint8_t 11 | 12 | BEGIN_AH_NAMESPACE 13 | 14 | /// The type returned from analogRead and similar functions. 15 | using analog_t = uint16_t; 16 | /// The type for Arduino pins (and ExtendedIOElement pins). 17 | using pin_t = uint16_t; 18 | 19 | #ifdef NO_PIN // Fix for FastLED: https://github.com/FastLED/FastLED/issues/893 20 | #undef NO_PIN 21 | #endif 22 | 23 | /// A special pin number that indicates an unused or invalid pin. 24 | constexpr pin_t NO_PIN = 1 << (8 * sizeof(pin_t) - 1); 25 | 26 | /// An easy alias for arrays of pins. 27 | template 28 | using PinList = Array; 29 | 30 | END_AH_NAMESPACE 31 | 32 | AH_DIAGNOSTIC_POP() 33 | -------------------------------------------------------------------------------- /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 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 4 | 5 | BEGIN_AH_NAMESPACE 6 | 7 | IncrementButton::State IncrementButton::updateImplementation() { 8 | Button::State incrState = button.update(); 9 | 10 | if (incrState == Button::Released) { 11 | // Button released, don't do anything 12 | // This one is first to minimize overhead 13 | // because most of the time, the button will 14 | // be released 15 | return Nothing; 16 | } else if (incrState == Button::Rising) { 17 | auto res = longPressState == LongPress ? ReleasedLong : ReleasedShort; 18 | longPressState = Initial; 19 | return res; 20 | } else if (incrState == Button::Falling) { 21 | return IncrementShort; 22 | } else { // if (incrState == Button::Pressed) 23 | auto now = millis(); 24 | if (longPressState == LongPress) { 25 | // still long pressed 26 | if (now - longPressRepeat >= LONG_PRESS_REPEAT_DELAY) { 27 | longPressRepeat += LONG_PRESS_REPEAT_DELAY; 28 | return IncrementHold; 29 | } 30 | } else if (button.stableTime(now) >= LONG_PRESS_DELAY) { 31 | // long press starts 32 | longPressState = LongPress; 33 | longPressRepeat = now; 34 | return IncrementLong; 35 | } 36 | } 37 | return Nothing; 38 | } 39 | 40 | END_AH_NAMESPACE 41 | 42 | AH_DIAGNOSTIC_POP() 43 | -------------------------------------------------------------------------------- /src/AH/Hardware/IncrementButton.hpp: -------------------------------------------------------------------------------- 1 | /* ✔ */ 2 | 3 | #pragma once 4 | 5 | #include 6 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 7 | 8 | #include "Button.hpp" 9 | 10 | BEGIN_AH_NAMESPACE 11 | 12 | /** 13 | * @brief A class for buttons that increment some counter or setting. 14 | * 15 | * It behaves the same way as a computer keyboard: when you press the button, 16 | * it increments the counter once. If you keep on pressing it for longer than 17 | * a certain threshold, it keeps on incrementing at a faster rate, until you 18 | * release it. 19 | * 20 | * @ingroup AH_HardwareUtils 21 | */ 22 | class IncrementButton { 23 | public: 24 | /** 25 | * @brief Create a IncrementButton. 26 | * 27 | * @param button 28 | * The button to read from. 29 | * The button is copied. 30 | */ 31 | IncrementButton(const Button &button) : button(button) {} 32 | 33 | /// @see Button::begin 34 | void begin() { button.begin(); } 35 | 36 | /** 37 | * @brief An enumeration of the different actions to be performed by the 38 | * counter. 39 | * @todo Add states for initial press. 40 | */ 41 | enum State { 42 | Nothing = 0, ///< The counter must not be incremented. 43 | IncrementShort, ///< The counter must be incremented (after short press). 44 | IncrementLong, ///< The counter must be incremented (after long press). 45 | IncrementHold, ///< The counter must be incremented (still pressed). 46 | ReleasedShort, ///< The button was released after a short press. 47 | ReleasedLong, ///< The button was released after a long press. 48 | }; 49 | 50 | /** 51 | * @brief Update and return the state of the increment button. 52 | */ 53 | State update() { return state = updateImplementation(); } 54 | 55 | /** 56 | * @brief Return the state of the increment button without updating it. 57 | * 58 | * Returns the same value as the last @ref update call. 59 | */ 60 | State getState() const { return state; } 61 | 62 | /// @see Button::invert 63 | void invert() { button.invert(); } 64 | 65 | protected: 66 | State updateImplementation(); 67 | 68 | private: 69 | Button button; 70 | 71 | enum { 72 | Initial, 73 | LongPress, 74 | } longPressState = Initial; 75 | unsigned long longPressRepeat; 76 | 77 | State state = Nothing; 78 | }; 79 | 80 | END_AH_NAMESPACE 81 | 82 | AH_DIAGNOSTIC_POP() 83 | -------------------------------------------------------------------------------- /src/AH/Hardware/LEDs/DotBarDisplayLEDs.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "DotBarDisplayLEDs.hpp" 3 | #endif -------------------------------------------------------------------------------- /src/AH/Hardware/LEDs/DotBarDisplayLEDs.hpp: -------------------------------------------------------------------------------- 1 | /* ✔ */ 2 | 3 | #pragma once 4 | 5 | #include 6 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 7 | 8 | #include 9 | 10 | BEGIN_AH_NAMESPACE 11 | 12 | /** 13 | * @brief An enumeration type to set an LED display to either bar or dot mode. 14 | */ 15 | enum class DotBarMode : bool { 16 | Bar = false, ///< Turn on a range of LEDs up to the active LED. 17 | Dot = true, ///< Turn on only the active LED 18 | }; 19 | 20 | /** 21 | * @brief A class for LED bars. 22 | * 23 | * @tparam N 24 | * The number of LEDs in the bar. 25 | * 26 | * @ingroup AH_HardwareUtils 27 | */ 28 | template 29 | class DotBarDisplayLEDs : public LEDs { 30 | public: 31 | /// Constructor from list of pins. 32 | DotBarDisplayLEDs(const PinList &ledPins) : LEDs{ledPins} {} 33 | 34 | /** 35 | * @brief Display the given number of LEDs on the LED bar. 36 | * 37 | * @param value 38 | * The number of the LED to activate. 39 | */ 40 | void display(uint16_t value) const { 41 | if (value == 0) 42 | this->clear(); 43 | else if (mode == DotBarMode::Bar) 44 | this->displayRange(0, value); 45 | else 46 | this->displayDot(value - 1); 47 | } 48 | 49 | /** 50 | * @brief Display the given fraction of the LED bar. 51 | * 52 | * @param value 53 | * The fraction of the LED bar to display. 54 | */ 55 | void display(float value) const { display(uint16_t(value * (N + 1))); } 56 | 57 | /// Get the dot/bar mode. 58 | DotBarMode getMode() const { return mode; } 59 | 60 | /** 61 | * @brief Set the mode to either dot or bar mode. 62 | * 63 | * @param mode 64 | * The mode. 65 | */ 66 | void setMode(DotBarMode mode) { this->mode = mode; } 67 | 68 | /// Set the mode to dot mode. 69 | void dotMode() { setMode(DotBarMode::Dot); } 70 | 71 | /// Set the mode to bar mode. 72 | void barMode() { setMode(DotBarMode::Bar); } 73 | 74 | /// Toggle the dot/bar mode. 75 | void toggleMode() { getMode() == DotBarMode::Bar ? dotMode() : barMode(); } 76 | 77 | private: 78 | DotBarMode mode = DotBarMode::Bar; 79 | }; 80 | 81 | END_AH_NAMESPACE 82 | 83 | AH_DIAGNOSTIC_POP() 84 | -------------------------------------------------------------------------------- /src/AH/Hardware/LEDs/LEDs.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "LEDs.hpp" 3 | #endif -------------------------------------------------------------------------------- /src/AH/Hardware/LEDs/LEDs.hpp: -------------------------------------------------------------------------------- 1 | /* ✔ */ 2 | 3 | #pragma once 4 | 5 | #include 6 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 7 | 8 | #include 9 | 10 | BEGIN_AH_NAMESPACE 11 | 12 | /** 13 | * @brief A class for collections of LEDs that can display ranges. 14 | * 15 | * @tparam N 16 | * The number of LEDs in the collection. 17 | * 18 | * @ingroup AH_HardwareUtils 19 | */ 20 | template 21 | class LEDs { 22 | public: 23 | /** 24 | * @brief Create a LEDs object. 25 | * 26 | * @param ledPins 27 | * An array of pins with the LEDs connected. 28 | */ 29 | LEDs(const PinList &ledPins) : ledPins(ledPins) {} 30 | 31 | /** 32 | * @brief Initialize (set LED pins as outputs). 33 | */ 34 | void begin() const { 35 | for (const pin_t &pin : ledPins) 36 | ExtIO::pinMode(pin, OUTPUT); 37 | } 38 | 39 | /** 40 | * @brief Turn on a range of the LEDs. 41 | * 42 | * @param startOn 43 | * The first LED of the range to turn on (the LEDs before this one 44 | * are turned off). 45 | * @param startOff 46 | * The first LED after the range to turn off. 47 | */ 48 | void displayRange(uint16_t startOn, uint16_t startOff) const { 49 | for (uint16_t pin = 0; pin < startOn; pin++) 50 | clear(pin); 51 | for (uint16_t pin = startOn; pin < startOff; pin++) 52 | set(pin); 53 | for (uint16_t pin = startOff; pin < N; pin++) 54 | clear(pin); 55 | } 56 | 57 | /// Turn on the given LED. 58 | void set(uint16_t index) const { 59 | // TODO: bounds check? 60 | ExtIO::digitalWrite(ledPins[index], HIGH); 61 | } 62 | 63 | /// Turn off the given LED. 64 | void clear(uint16_t index) const { 65 | // TODO: bounds check? 66 | ExtIO::digitalWrite(ledPins[index], LOW); 67 | } 68 | 69 | /** 70 | * @brief Turn on a single LED, and turn off all others. 71 | * 72 | * @param led 73 | * The LED to turn on. 74 | */ 75 | void displayDot(uint16_t led) const { displayRange(led, led + 1); } 76 | 77 | /** 78 | * @brief Turn off all LEDs. 79 | */ 80 | void clear() const { 81 | for (pin_t pin : ledPins) 82 | ExtIO::digitalWrite(pin, LOW); 83 | } 84 | 85 | private: 86 | const PinList ledPins; 87 | }; 88 | 89 | END_AH_NAMESPACE 90 | 91 | AH_DIAGNOSTIC_POP() 92 | -------------------------------------------------------------------------------- /src/AH/Hardware/LEDs/MAX7219SevenSegmentDisplay.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | // #include "MAX7219SevenSegmentDisplay.hpp" // TODO 3 | #endif -------------------------------------------------------------------------------- /src/AH/Hardware/LEDs/MAX7219_Base.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | // #include "MAX7219_Base.hpp" // TODO 3 | #endif -------------------------------------------------------------------------------- /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 | #include 10 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 11 | 12 | BEGIN_AH_NAMESPACE 13 | 14 | namespace detail { 15 | constexpr long double pi_inv_l = 0.318309886183790671537767526745028724L; 16 | constexpr long double pi_l = 3.141592653589793238462643383279502884L; 17 | } // namespace detail 18 | 19 | /// @addtogroup AH_Math 20 | /// @{ 21 | 22 | /// Convert radians to degrees. 23 | template 24 | constexpr inline 25 | typename std::enable_if::value, T>::type 26 | rad2deg(T r) { 27 | return r * static_cast(detail::pi_inv_l) * 180; 28 | } 29 | /// Convert degrees to radians. 30 | template 31 | constexpr inline 32 | typename std::enable_if::value, T>::type 33 | deg2rad(T d) { 34 | return d * static_cast(detail::pi_l) / 180; 35 | } 36 | 37 | /// Convert degrees to radians, e.g. 10_deg. 38 | constexpr long double operator"" _deg(long double deg) { return deg2rad(deg); } 39 | /// Convert degrees to radians, e.g. 10_deg. 40 | constexpr long double operator"" _deg(unsigned long long deg) { 41 | return deg2rad(static_cast(deg)); 42 | } 43 | 44 | /// @} 45 | 46 | END_AH_NAMESPACE 47 | 48 | AH_DIAGNOSTIC_POP() 49 | -------------------------------------------------------------------------------- /src/AH/Math/Divide.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | AH_DIAGNOSTIC_WERROR() 10 | 11 | BEGIN_AH_NAMESPACE 12 | 13 | /// Divide by N using the default division operator, without explicit rounding 14 | /// This should be used for floating point types. For integers, prefer using 15 | /// @ref round_div_unsigned_int and @ref round_div_signed_int. 16 | template 17 | struct round_div_default { 18 | static T div(T val) { return val / N; } 19 | }; 20 | 21 | /// Divide an unsigned integer by N, rounding the result. 22 | template 23 | struct round_div_unsigned_int { 24 | static T div(T val) { 25 | return (val + (N / 2)) / N; 26 | static_assert(std::is_unsigned::value && std::is_integral::value, 27 | "This function is only valid for unsigned integers"); 28 | } 29 | }; 30 | 31 | /// Divide a signed integer by N, rounding the result. 32 | template 33 | struct round_div_signed_int { 34 | static T div(T val) { 35 | T offset = val >= 0 ? (N / 2) : (-N / 2); 36 | return (val + offset) / N; 37 | } 38 | }; 39 | 40 | /// Select the right rounding division operator, depending on whether T is a 41 | /// signed or unsigned integer. 42 | template 43 | struct round_div_int 44 | : std::conditional::value, round_div_signed_int, 45 | round_div_unsigned_int>::type {}; 46 | 47 | /// Select the right rounding division operator, depending on whether T is an 48 | /// integer or not. 49 | template 50 | struct round_div_helper 51 | : std::conditional::value, round_div_int, 52 | round_div_default>::type {}; 53 | 54 | /// Divide a number by N and round the result. Uses different specializations 55 | /// for integers to implement efficient rounding. 56 | template 57 | T round_div(T val) { 58 | return round_div_helper::div(val); 59 | } 60 | 61 | END_AH_NAMESPACE 62 | 63 | AH_DIAGNOSTIC_POP() -------------------------------------------------------------------------------- /src/AH/Math/FixArduinoMacros.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 5 | 6 | AH_DIAGNOSTIC_EXTERNAL_HEADER() 7 | #include // min max 8 | AH_DIAGNOSTIC_POP() 9 | 10 | #ifdef min 11 | #undef min 12 | #endif 13 | 14 | #ifdef max 15 | #undef max 16 | #endif 17 | 18 | #ifdef abs 19 | #undef abs 20 | #endif 21 | 22 | #ifdef round 23 | #undef round 24 | #endif 25 | 26 | AH_DIAGNOSTIC_POP() 27 | -------------------------------------------------------------------------------- /src/AH/Math/IncreaseBitDepth.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "IncreaseBitDepth.hpp" 3 | #endif 4 | -------------------------------------------------------------------------------- /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.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "MinMaxFix.hpp" 3 | #endif 4 | -------------------------------------------------------------------------------- /src/AH/Math/MinMaxFix.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 5 | 6 | #include 7 | 8 | #include 9 | 10 | BEGIN_AH_NAMESPACE 11 | 12 | /// Return the smaller of two numbers/objects. 13 | /// @ingroup AH_Math 14 | template 15 | constexpr auto min(const T &a, const U &b) -> decltype(b < a ? b : a) { 16 | return b < a ? b : a; 17 | } 18 | 19 | /// Return the larger of two numbers/objects. 20 | /// @ingroup AH_Math 21 | template 22 | constexpr auto max(const T &a, const U &b) -> decltype(a < b ? b : a) { 23 | return a < b ? b : a; 24 | } 25 | 26 | END_AH_NAMESPACE 27 | 28 | AH_DIAGNOSTIC_POP() 29 | -------------------------------------------------------------------------------- /src/AH/Math/Quaternion.cpp: -------------------------------------------------------------------------------- 1 | #include "Quaternion.hpp" 2 | 3 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 4 | 5 | #include 6 | #ifndef ARDUINO 7 | #include // std::ostream, << 8 | #endif 9 | 10 | BEGIN_AH_NAMESPACE 11 | 12 | // LCOV_EXCL_START 13 | 14 | #ifndef ARDUINO 15 | 16 | std::ostream &operator<<(std::ostream &os, Quaternion q) { 17 | return os << "(" << q.w << ", " << q.x << ", " << q.y << ", " << q.z << ")"; 18 | } 19 | 20 | std::ostream &operator<<(std::ostream &os, EulerAngles e) { 21 | os << "(" << rad2deg(e.yaw) << "°, " << rad2deg(e.pitch) << "°, " 22 | << rad2deg(e.roll) << "°)"; 23 | return os; 24 | } 25 | 26 | #endif // ARDUINO 27 | 28 | Print &operator<<(Print &os, Quaternion q) { 29 | return os << "(" << q.w << ", " << q.x << ", " << q.y << ", " << q.z << ")"; 30 | } 31 | 32 | Print &operator<<(Print &os, EulerAngles e) { 33 | os << "(" << rad2deg(e.yaw) << "°, " << rad2deg(e.pitch) << "°, " 34 | << rad2deg(e.roll) << "°)"; 35 | return os; 36 | } 37 | 38 | // LCOV_EXCL_STOP 39 | 40 | END_AH_NAMESPACE 41 | 42 | AH_DIAGNOSTIC_POP() 43 | -------------------------------------------------------------------------------- /src/AH/Math/Vector.cpp: -------------------------------------------------------------------------------- 1 | #include "Vector.hpp" 2 | 3 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 4 | 5 | #include 6 | #ifndef ARDUINO 7 | #include // std::ostream, << 8 | #endif 9 | 10 | BEGIN_AH_NAMESPACE 11 | 12 | // LCOV_EXCL_START 13 | 14 | #ifndef ARDUINO 15 | 16 | /// Printing. 17 | /// @related Vec2f 18 | std::ostream &operator<<(std::ostream &os, Vec2f v) { 19 | return os << "(" << v.x << ", " << v.y << ")"; 20 | } 21 | 22 | /// Printing. 23 | /// @related Vec3f 24 | std::ostream &operator<<(std::ostream &os, Vec3f v) { 25 | return os << "(" << v.x << ", " << v.y << ", " << v.z << ")"; 26 | } 27 | 28 | #endif 29 | 30 | /// Printing. 31 | /// @related Vec2f 32 | Print &operator<<(Print &os, Vec2f v) { 33 | return os << "(" << v.x << ", " << v.y << ")"; 34 | } 35 | 36 | /// Printing. 37 | /// @related Vec3f 38 | Print &operator<<(Print &os, Vec3f v) { 39 | return os << "(" << v.x << ", " << v.y << ", " << v.z << ")"; 40 | } 41 | 42 | // LCOV_EXCL_STOP 43 | 44 | END_AH_NAMESPACE 45 | 46 | AH_DIAGNOSTIC_POP() 47 | -------------------------------------------------------------------------------- /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/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/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/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 -------------------------------------------------------------------------------- /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) 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.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "NamespaceSettings.hpp" 3 | #endif 4 | -------------------------------------------------------------------------------- /src/AH/Settings/NamespaceSettings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define USE_AH_NAMESPACE 4 | #define AH_NAMESPACE_NAME AH 5 | 6 | // ========================================================================== // 7 | 8 | #ifdef USE_AH_NAMESPACE 9 | #define BEGIN_AH_NAMESPACE namespace AH_NAMESPACE_NAME { 10 | #define END_AH_NAMESPACE } 11 | #define USING_AH_NAMESPACE using namespace AH_NAMESPACE_NAME 12 | #else 13 | #define BEGIN_AH_NAMESPACE 14 | #define END_AH_NAMESPACE 15 | #define USING_AH_NAMESPACE 16 | #endif -------------------------------------------------------------------------------- /src/AH/Settings/Settings.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | // #include "Settings.hpp" 3 | #endif 4 | -------------------------------------------------------------------------------- /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.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "SettingsWrapper.hpp" 3 | #endif 4 | -------------------------------------------------------------------------------- /src/AH/Settings/SettingsWrapper.hpp: -------------------------------------------------------------------------------- 1 | #ifndef AH_SETTINGSWRAPPER_HPP 2 | #define AH_SETTINGSWRAPPER_HPP 3 | 4 | #include 5 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 6 | 7 | // ---- User Settings ---- // 8 | // ======================= // 9 | #include "NamespaceSettings.hpp" 10 | #include "Settings.hpp" 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 | // ------- Debug ------- // 47 | // ===================== // 48 | #include 49 | 50 | AH_DIAGNOSTIC_POP() 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__ >= 5 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 | #define AH_DIAGNOSTIC_POP() _Pragma("GCC diagnostic pop") 12 | #define AH_DIAGNOSTIC_EXTERNAL_HEADER() \ 13 | _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wall\"") \ 14 | _Pragma("GCC diagnostic ignored \"-Wextra\"") \ 15 | _Pragma("GCC diagnostic ignored \"-Wsuggest-override\"") \ 16 | _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"") 17 | 18 | #else // __GNUC__ < 5 19 | 20 | #define AH_DIAGNOSTIC_WERROR() \ 21 | _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic error \"-Wall\"") \ 22 | _Pragma("GCC diagnostic error \"-Wextra\"") \ 23 | _Pragma("GCC diagnostic ignored \"-Wc++0x-compat\"") \ 24 | _Pragma("GCC diagnostic ignored \"-Wattributes\"") 25 | #define AH_DIAGNOSTIC_POP() _Pragma("GCC diagnostic pop") 26 | #define AH_DIAGNOSTIC_EXTERNAL_HEADER() \ 27 | _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wall\"") \ 28 | _Pragma("GCC diagnostic ignored \"-Wextra\"") \ 29 | _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"") 30 | 31 | #endif 32 | 33 | #else 34 | 35 | #define AH_DIAGNOSTIC_WERROR() 36 | #define AH_DIAGNOSTIC_POP() 37 | #define AH_DIAGNOSTIC_EXTERNAL_HEADER() 38 | 39 | #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.cpp: -------------------------------------------------------------------------------- 1 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY 2 | #include "MillisMicrosTimer.hpp" 3 | #endif -------------------------------------------------------------------------------- /src/AH/Timing/MillisMicrosTimer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 5 | 6 | AH_DIAGNOSTIC_EXTERNAL_HEADER() 7 | #include // millis, micros 8 | AH_DIAGNOSTIC_POP() 9 | 10 | #include 11 | 12 | BEGIN_AH_NAMESPACE 13 | 14 | /// @addtogroup AH_Timing 15 | /// @{ 16 | 17 | /// A function type that returns a time value. 18 | using timefunction = unsigned long (*)(); 19 | 20 | /** 21 | * @brief A class for easily managing timed events. A wrapper for "Blink 22 | * Without Delay". 23 | * 24 | * @tparam time 25 | * The time function to use. 26 | */ 27 | template 28 | class Timer { 29 | public: 30 | /** 31 | * @brief Constructor. 32 | * @param interval 33 | * The interval between two events. 34 | */ 35 | Timer(unsigned long interval) : interval(interval) { 36 | #ifdef ARDUINO 37 | begin(); 38 | #endif 39 | } 40 | /// Initialize or reset the timer. The timer will fire immediately. 41 | void begin() { previous = time() - interval; } 42 | /// Initialize or reset the timer. The timer will fire after one period. 43 | void beginNextPeriod() { previous = time(); } 44 | /// Update the timer and return true if the event should fire. 45 | explicit operator bool() { 46 | auto now = time(); 47 | if (now - previous >= interval) { 48 | previous += interval; 49 | return true; 50 | } 51 | return false; 52 | } 53 | 54 | /// Get the interval of the timer. 55 | unsigned long getInterval() const { return interval; } 56 | /// Set the interval of the timer. 57 | void setInterval(unsigned long interval) { this->interval = interval; } 58 | 59 | private: 60 | unsigned long interval; 61 | unsigned long previous = 0; 62 | }; 63 | 64 | /// @} 65 | 66 | END_AH_NAMESPACE 67 | 68 | AH_DIAGNOSTIC_POP() 69 | -------------------------------------------------------------------------------- /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 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 5 | 6 | #include 7 | 8 | BEGIN_AH_NAMESPACE 9 | 10 | /// Type-safe class for frequency values. 11 | class Frequency { 12 | public: 13 | explicit constexpr Frequency(unsigned long hertz) : hertz(hertz) {} 14 | constexpr operator unsigned long() const { return hertz; } 15 | 16 | private: 17 | unsigned long hertz; 18 | }; 19 | constexpr Frequency operator"" _Hz(unsigned long long hz) { 20 | return Frequency{(unsigned long)hz}; 21 | } 22 | constexpr Frequency operator"" _kHz(long double khz) { 23 | return Frequency{(unsigned long)(khz * 1E3l)}; 24 | } 25 | constexpr Frequency operator"" _kHz(unsigned long long khz) { 26 | return Frequency{(unsigned long)(khz * 1E3)}; 27 | } 28 | constexpr Frequency operator"" _MHz(long double mhz) { 29 | return Frequency{(unsigned long)(mhz * 1E6l)}; 30 | } 31 | constexpr Frequency operator"" _MHz(unsigned long long mhz) { 32 | return Frequency{(unsigned long)(mhz * 1E6)}; 33 | } 34 | 35 | END_AH_NAMESPACE 36 | 37 | AH_DIAGNOSTIC_POP() 38 | -------------------------------------------------------------------------------- /src/AH/Types/FunctionTraits.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | AH_DIAGNOSTIC_WERROR() // Enable errors on warnings 8 | 9 | #include 10 | 11 | BEGIN_AH_NAMESPACE 12 | 13 | template 14 | struct function_traits; 15 | 16 | template 17 | struct function_traits { 18 | static constexpr size_t number_arguments = sizeof...(Args); 19 | 20 | using return_t = Return; 21 | template 22 | struct argument { 23 | using type = 24 | typename std::tuple_element>::type; 25 | }; 26 | 27 | template 28 | using argument_t = typename argument::type; 29 | }; 30 | 31 | END_AH_NAMESPACE 32 | 33 | AH_DIAGNOSTIC_POP() 34 | -------------------------------------------------------------------------------- /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 | /** 3 | * @file 4 | * @brief Dummy header file for Arduino builder. 5 | * You have to add this file first, so the other headers are in the 6 | * include path. 7 | * 8 | * @author Pieter Pas 9 | * @date 2019-11-07 10 | */ 11 | 12 | #pragma once 13 | 14 | #include 15 | 16 | BEGIN_AH_NAMESPACE 17 | END_AH_NAMESPACE 18 | 19 | #ifndef NO_USING_NAMESPACE_AH 20 | USING_AH_NAMESPACE; 21 | #endif -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(AH) -------------------------------------------------------------------------------- /src/Filters.h: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @file 4 | * @brief Dummy header file for Arduino builder. 5 | * You have to add this file first, so the other headers are in the 6 | * include path. 7 | * 8 | * @author Pieter Pas 9 | * @date 2019-11-07 10 | */ 11 | 12 | #pragma once 13 | 14 | #include // For VSCode errors in examples 15 | #include 16 | 17 | BEGIN_AH_NAMESPACE 18 | END_AH_NAMESPACE 19 | 20 | #ifndef NO_USING_NAMESPACE_AH 21 | USING_AH_NAMESPACE; 22 | #endif -------------------------------------------------------------------------------- /src/Filters/FIRFilter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | /// @addtogroup Filters 6 | /// @{ 7 | 8 | /** 9 | * @brief Finite Impulse Response filter implementation. 10 | * 11 | * Implements the following difference equation: 12 | * 13 | * @f[ 14 | * y[n] = \sum_{i=0}^{N-1} b_i \cdot x[n-i] 15 | * @f] 16 | */ 17 | template 18 | class FIRFilter { 19 | public: 20 | /** 21 | * @brief Construct a new FIR Filter object. 22 | * 23 | * The coefficients @f$ b @f$ can be derived from the transfer function: 24 | * 25 | * @f[ 26 | * H(z) = b_0 + b_1 z^{-1} + \ldots + b_{N_b} z ^{-N_b} 27 | * @f] 28 | * 29 | * @param coefficients 30 | * The coefficients of the transfer function numerator. 31 | */ 32 | FIRFilter(const AH::Array &coefficients) { 33 | for (uint8_t i = 0; i < 2 * N - 1; ++i) 34 | this->coefficients[i] = coefficients[(2 * N - 1 - i) % N]; 35 | } 36 | 37 | /** 38 | * @brief Update the internal state with the new input @f$ x[n] @f$ and 39 | * return the new output @f$ y[n] @f$. 40 | * 41 | * @param input 42 | * The new input @f$ x[n] @f$. 43 | * @return The new output @f$ y[n] @f$. 44 | */ 45 | T operator()(T input) { 46 | // Save the new value to the ring buffer. 47 | x[index_b] = input; 48 | 49 | // Calculate the offset to the shifted coefficients. 50 | T *coeff_shift = coefficients.end() - N - index_b; 51 | 52 | // Multiply and accumulate the inputs and their respective coefficients. 53 | T acc = {}; 54 | for (uint8_t i = 0; i < N; i++) 55 | acc += x[i] * coeff_shift[i]; 56 | 57 | // Increment and wrap around the index of the ring buffer. 58 | index_b++; 59 | if (index_b == N) 60 | index_b = 0; 61 | 62 | return acc; 63 | } 64 | 65 | private: 66 | uint8_t index_b = 0; 67 | AH::Array x = {}; 68 | AH::Array coefficients; 69 | }; 70 | 71 | /// @} 72 | -------------------------------------------------------------------------------- /src/Filters/Filters.dox: -------------------------------------------------------------------------------- 1 | /** 2 | * @defgroup Filters Arduino Filters 3 | * @brief Main module containing all filters and filter utilities. 4 | */ 5 | 6 | /** 7 | * @defgroup FilterImplementations Filter Implementations 8 | * @brief Different implementations. 9 | * @ingroup Filters 10 | */ 11 | 12 | /** 13 | * @defgroup FilterDesign Filter Design 14 | * @brief Filter design tools. 15 | * @ingroup Filters 16 | */ 17 | -------------------------------------------------------------------------------- /src/Filters/Notch.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /// @addtogroup FilterDesign 7 | /// @{ 8 | 9 | /** 10 | * @brief Create a very simple second-order FIR notch filter. 11 | * 12 | * @f[ 13 | * H(z) = \frac{z^2 - 2\cos\left(\omega_{c,d}\right)z + 1} 14 | * {2 - 2\cos\left(\omega_{c,d}\right)} 15 | * @f] 16 | * where @f$ \omega_{c,d} = \pi f_n = 2\pi \frac{f_c}{f_n} @f$ 17 | * 18 | * @see 19 | * 20 | * @param f_n 21 | * Normalized notch frequency in half-cycles per sample. 22 | * @f$ f_n = \frac{2 f_c}{f_s} \in \left[0, 1\right] @f$, where 23 | * @f$ f_s @f$ is the sample frequency in @f$ \text{Hz} @f$, and 24 | * @f$ f_c @f$ is the analog notch frequency in @f$ \text{Hz} @f$. 25 | */ 26 | template 27 | FIRFilter<3, T> simpleNotchFIR(double f_n) { 28 | double cos_omega = std::cos(M_PI * f_n); 29 | double normalize = 2 - 2 * cos_omega; 30 | return {{ 31 | T(1. / normalize), 32 | T(-2 * cos_omega / normalize), 33 | T(1. / normalize), 34 | }}; 35 | } 36 | 37 | /// @} -------------------------------------------------------------------------------- /src/Filters/SMA.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /// @addtogroup Filters 10 | /// @{ 11 | 12 | /** 13 | * @brief Simple Moving Average filter. 14 | * 15 | * Returns the average of the N most recent input values. 16 | * 17 | * @f[ 18 | * y[n] = \frac{1}{N} \sum_{i=0}^{N-1}x[n-i] 19 | * @f] 20 | * 21 | * @see https://tttapa.github.io/Pages/Mathematics/Systems-and-Control-Theory/Digital-filters/Simple%20Moving%20Average/Simple-Moving-Average.html 22 | * 23 | * @tparam N 24 | * The number of samples to average. 25 | * @tparam input_t 26 | * The type of the input (and output) of the filter. 27 | * @tparam sum_t 28 | * The type to use for the accumulator, must be large enough to fit 29 | * N times the maximum input value. 30 | */ 31 | template 32 | class SMA { 33 | public: 34 | /** 35 | * @brief Default constructor (initial state is initialized to all zeros). 36 | */ 37 | SMA() = default; 38 | 39 | /** 40 | * @brief Constructor (initial state is initialized to given value). 41 | * 42 | * @param initialValue 43 | * Determines the initial state of the filter: 44 | * @f$ x[-N] =\ \ldots\ = x[-2] = x[-1] = \text{initialValue} @f$ 45 | */ 46 | SMA(input_t initialValue) : sum(N * (sum_t)initialValue) { 47 | std::fill(std::begin(previousInputs), std::end(previousInputs), 48 | initialValue); 49 | } 50 | 51 | /** 52 | * @brief Update the internal state with the new input @f$ x[n] @f$ and 53 | * return the new output @f$ y[n] @f$. 54 | * 55 | * @param input 56 | * The new input @f$ x[n] @f$. 57 | * @return The new output @f$ y[n] @f$. 58 | */ 59 | input_t operator()(input_t input) { 60 | sum -= previousInputs[index]; 61 | sum += input; 62 | previousInputs[index] = input; 63 | if (++index == N) 64 | index = 0; 65 | return AH::round_div(sum); 66 | } 67 | 68 | private: 69 | uint8_t index = 0; 70 | input_t previousInputs[N] = {}; 71 | sum_t sum = 0; 72 | }; 73 | 74 | /// @} 75 | -------------------------------------------------------------------------------- /src/Filters/SOSFilter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /// @addtogroup Filters 7 | /// @{ 8 | 9 | template 10 | using SOSCoefficients = AH::Array, N>; 11 | 12 | /** 13 | * @brief Second Order Sections filter. Higher cost than direct 14 | * implementation, but better numerical stability. 15 | * 16 | * @tparam T 17 | * The type of the signals and filter coefficients. 18 | * @tparam N 19 | * The number of sections. 20 | */ 21 | template > 22 | class SOSFilter { 23 | public: 24 | /// Constructor. 25 | SOSFilter(const SOSCoefficients §ionCoefficients) 26 | : sections(AH::copyAs(sectionCoefficients)) {} 27 | 28 | /** 29 | * @brief Update the internal state with the new input @f$ x[n] @f$ and 30 | * return the new output @f$ y[n] @f$. 31 | * 32 | * @param input 33 | * The new input @f$ x[n] @f$. 34 | * @return The new output @f$ y[n] @f$. 35 | */ 36 | T operator()(T input) { 37 | for (auto §ion : sections) 38 | input = section(input); 39 | return input; 40 | } 41 | 42 | private: 43 | AH::Array sections; 44 | }; 45 | 46 | /// @} 47 | 48 | template 49 | TransferFunction 50 | sos2tf_helper(const TransferFunction &tf, 51 | AH::ArraySlice, N, false, true> sos) { 52 | auto sub_tf = sos2tf_helper(tf, sos.template slice<0, N - 2>()); 53 | return TransferFunction{ 54 | AH::distribute(sub_tf.b, sos[N - 1].b), 55 | AH::distribute(sub_tf.a, sos[N - 1].a), 56 | }; 57 | } 58 | 59 | template 60 | TransferFunction 61 | sos2tf_helper(const TransferFunction &tf, 62 | AH::ArraySlice, 1, false, true> sos) { 63 | return TransferFunction{ 64 | AH::distribute(tf.b, sos[0].b), 65 | AH::distribute(tf.a, sos[0].a), 66 | }; 67 | } 68 | 69 | /** 70 | * @brief Convert Second Order Section (SOS) coefficients to an equivalent 71 | * tranfer function representation. 72 | * @ingroup FilterDesign 73 | */ 74 | template 75 | TransferFunction 76 | sos2tf(const SOSCoefficients &sos) { 77 | return sos2tf_helper(sos[N - 1], sos.template slice<0, N - 2>()); 78 | } 79 | 80 | template 81 | TransferFunction<3, 3, T> sos2tf(const SOSCoefficients &sos) { 82 | return sos[0]; 83 | } 84 | -------------------------------------------------------------------------------- /src/Filters/TransferFunction.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /// @addtogroup Filters 4 | /// @{ 5 | 6 | #include 7 | 8 | /** 9 | * @brief Class for transfer function coefficients. 10 | * 11 | * @f[ 12 | * H(z) = \frac{b_0 + b_1 z^{-1} + \ldots + b_{N_b} z ^{-N_b}} 13 | * {a_0 + a_1 z^{-1} + \ldots + a_{N_b} z ^{-N_a}} 14 | * @f] 15 | */ 16 | template 17 | struct TransferFunction { 18 | TransferFunction() = default; 19 | 20 | /// Construct a new Transfer Function object. 21 | TransferFunction(const AH::Array &b, const AH::Array &a) 22 | : b(b), a(a) {} 23 | 24 | AH::Array b = {{}}; 25 | AH::Array a = {{}}; 26 | }; 27 | 28 | /// @} -------------------------------------------------------------------------------- /src/Filters/keywords.yml: -------------------------------------------------------------------------------- 1 | keyword1: 2 | - MedianFilter 3 | 4 | keyword2: 5 | - butter 6 | 7 | literal1: -------------------------------------------------------------------------------- /src/keywords.yml: -------------------------------------------------------------------------------- 1 | keyword1: 2 | - Arduino_Helpers 3 | - AH 4 | - Filters -------------------------------------------------------------------------------- /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.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 | -------------------------------------------------------------------------------- /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 | "Filters/test-SOSFilter.cpp" 26 | "Filters/test-MedianFilter.cpp" 27 | "Filters/test-IIRFilter.cpp" 28 | "Filters/test-BiQuad.cpp" 29 | "Filters/test-Butterworth.cpp" 30 | "Filters/test-FIRFilter.cpp" 31 | "Filters/test-SMA.cpp" 32 | "Filters/test-FixedPoint.cpp" 33 | ) 34 | target_include_directories(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 35 | target_link_libraries(tests 36 | PRIVATE Arduino_Helpers 37 | PRIVATE Arduino-Helpers::warnings) 38 | 39 | # Add tests 40 | gtest_discover_tests(tests DISCOVERY_TIMEOUT 60 TIMEOUT 20) 41 | add_executable(Arduino-Helpers::tests ALIAS tests) -------------------------------------------------------------------------------- /test/Filters/test-BiQuad.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | TEST(BiQuad, BiQuadDF1RandomInt) { 7 | using namespace std; 8 | IIRFilter<3, 3, int> reference = {{1, 10, -2}, {-1, 2, -3}}; 9 | BiQuadFilterDF1 biquad = {{1, 10, -2}, {-1, 2, -3}}; 10 | array signal = {100, 10, 102, 23, 51, 1, -10, -53, 100, -100, 11 | 100, -10, 10, 11, 20, 30, 123, 12, 90, 10}; 12 | array expected = signal; 13 | transform(signal.begin(), signal.end(), signal.begin(), biquad); 14 | transform(expected.begin(), expected.end(), expected.begin(), reference); 15 | EXPECT_EQ(signal, expected); 16 | } 17 | 18 | TEST(BiQuad, BiQuadDF1RandomFloat) { 19 | using namespace std; 20 | IIRFilter<3, 3, float> reference = {{1, 10, -2}, {-1, 2, -3}}; 21 | BiQuadFilterDF1 biquad = {{1, 10, -2}, {-1, 2, -3}}; 22 | array signal = {100, 10, 102, 23, 51, 1, -10, -53, 100, -100, 23 | 100, -10, 10, 11, 20, 30, 123, 12, 90, 10}; 24 | array expected = signal; 25 | transform(signal.begin(), signal.end(), signal.begin(), biquad); 26 | transform(expected.begin(), expected.end(), expected.begin(), reference); 27 | EXPECT_EQ(signal, expected); 28 | } 29 | 30 | TEST(BiQuad, BiQuadDF2RandomInt) { 31 | using namespace std; 32 | IIRFilter<3, 3, int> reference = {{1, 10, -2}, {-1, 2, -3}}; 33 | BiQuadFilterDF2 biquad = {{1, 10, -2}, {-1, 2, -3}}; 34 | array signal = {100, 10, 102, 23, 51, 1, -10, -53, 100, -100, 35 | 100, -10, 10, 11, 20, 30, 123, 12, 90, 10}; 36 | array expected = signal; 37 | transform(signal.begin(), signal.end(), signal.begin(), biquad); 38 | transform(expected.begin(), expected.end(), expected.begin(), reference); 39 | EXPECT_EQ(signal, expected); 40 | } 41 | 42 | TEST(BiQuad, BiQuadDF2RandomFloat) { 43 | using namespace std; 44 | IIRFilter<3, 3, float> reference = {{1, 10, -2}, {-1, 2, -3}}; 45 | BiQuadFilterDF2 biquad = {{1, 10, -2}, {-1, 2, -3}}; 46 | array signal = {100, 10, 102, 23, 51, 1, -10, -53, 100, -100, 47 | 100, -10, 10, 11, 20, 30, 123, 12, 90, 10}; 48 | array expected = signal; 49 | transform(signal.begin(), signal.end(), signal.begin(), biquad); 50 | transform(expected.begin(), expected.end(), expected.begin(), reference); 51 | EXPECT_EQ(signal, expected); 52 | } -------------------------------------------------------------------------------- /test/Filters/test-Butterworth.py: -------------------------------------------------------------------------------- 1 | from scipy.signal import lfilter, butter 2 | import numpy as np 3 | 4 | type = 'double' 5 | 6 | b, a = butter(7, 0.4) 7 | 8 | signal = np.array((100, 10, 102, 23, 51, 1, -10, -53, 100, -100, 100, -10, 10, 9 | 11, 20, 30, 123, 12, 90, 10), 10 | dtype=np.float64) 11 | output = lfilter(b, a, signal) 12 | print(f'array<{type}, {len(signal)}> signal = {{') 13 | print(' ', ', '.join(map(lambda x: str(x), signal))) 14 | print('};') 15 | print(f'array<{type}, {len(signal)}> expected = {{') 16 | print(' ', ', '.join(map(lambda x: str(x), output))) 17 | print('};') 18 | print(f'transform(signal.begin(), signal.end(), signal.begin(), butterworth);') 19 | print('EXPECT_EQ(signal, expected);') -------------------------------------------------------------------------------- /test/Filters/test-FIRFilter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | TEST(FIRFilter, FIRFilter1) { 6 | using namespace std; 7 | 8 | FIRFilter<1, int> filter = {{1}}; 9 | array signal = {100, 10, 102, 23, 51, 1, -10, -53, 100, -100, 10 | 100, -10, 10, 11, 20, 30, 123, 12, 90, 10}; 11 | array expected = {100, 10, 102, 23, 51, 1, -10, -53, 100, -100, 12 | 100, -10, 10, 11, 20, 30, 123, 12, 90, 10}; 13 | for_each(signal.begin(), signal.end(), [&](int &s) { s = filter(s); }); 14 | EXPECT_EQ(signal, expected); 15 | } 16 | 17 | TEST(FIRFilter, FIRFilter1000) { 18 | using namespace std; 19 | 20 | FIRFilter<4, int> filter = {{1, 0, 0, 0}}; 21 | array signal = {100, 10, 102, 23, 51, 1, -10, -53, 100, -100, 22 | 100, -10, 10, 11, 20, 30, 123, 12, 90, 10}; 23 | array expected = {100, 10, 102, 23, 51, 1, -10, -53, 100, -100, 24 | 100, -10, 10, 11, 20, 30, 123, 12, 90, 10}; 25 | for_each(signal.begin(), signal.end(), [&](int &s) { s = filter(s); }); 26 | EXPECT_EQ(signal, expected); 27 | } 28 | 29 | TEST(FIRFilter, FIRFilterRandom) { 30 | using namespace std; 31 | FIRFilter<11, int> filter = {{1, 2, 3, -4, -4, 5, 6, 1, 2, 1, -2}}; 32 | array signal = {100, 10, 102, 23, 51, 1, -10, -53, 100, -100, 33 | 100, -10, 10, 11, 20, 30, 123, 12, 90, 10}; 34 | array expected = {100, 210, 422, -143, -37, 224, 295, 35 | 304, 693, 592, 800, -163, -113, 180, 36 | -362, -15, 776, 320, 288, 70}; 37 | for_each(signal.begin(), signal.end(), [&](int &s) { s = filter(s); }); 38 | EXPECT_EQ(signal, expected); 39 | } -------------------------------------------------------------------------------- /test/Filters/test-FIRFilter.py: -------------------------------------------------------------------------------- 1 | from scipy.signal import lfilter 2 | import numpy as np 3 | 4 | b = np.array((1, 0, 0, 0), dtype=np.float64) 5 | a = np.array((1, ), dtype=np.float64) 6 | 7 | signal = np.array((100, 10, 102, 23, 51, 1, -10, -53, 100, -100, 100, -10, 10, 8 | 11, 20, 30, 123, 12, 90, 10), 9 | dtype=np.float64) 10 | output = lfilter(b, a, signal) 11 | print(f'FIRFilter<{len(b)}, int> filter = {{{{') 12 | print(' ', ', '.join(map(lambda x: str(x), np.round(b).astype(np.int)))) 13 | print('}};') 14 | print(f'array signal = {{') 15 | print(' ', ', '.join(map(lambda x: str(x), np.round(signal).astype(np.int)))) 16 | print('};') 17 | print(f'array expected = {{') 18 | print(' ', ', '.join(map(lambda x: str(x), np.round(signal).astype(np.int)))) 19 | print('};') 20 | print( 21 | 'for_each(signal.begin(), signal.end(), [&](int &s) { s = filter(s); });') 22 | print('EXPECT_EQ(signal, expected);') -------------------------------------------------------------------------------- /test/Filters/test-IIRFilter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | TEST(IIRFilter, IIRFilterRandomInt) { 6 | using namespace std; 7 | IIRFilter<5, 3, int> filter = {{1, 10, 2, -3, -1}, {-1, 2, -3}}; 8 | array signal = {100, 10, 102, 23, 51, 1, -10, -53, 100, -100, 9 | 100, -10, 10, 11, 20, 30, 123, 12, 90, 10}; 10 | array expected = {-100, -1210, -2522, -2177, 2857, 11 | 12004, 15506, -4673, -55360, -97524, 12 | -28437, 235155, 555311, 405266, -855481, 13 | -2926992, -3287961, 2203823, 14271183, 21930362}; 14 | for_each(signal.begin(), signal.end(), [&](int &s) { s = filter(s); }); 15 | EXPECT_EQ(signal, expected); 16 | } 17 | 18 | TEST(IIRFilter, IIRFilterRandomDouble) { 19 | using namespace std; 20 | IIRFilter<5, 3, double> filter = {{1, 10, 2, -3, -1}, {-1, 2, -3}}; 21 | array signal = { 22 | 100, 10, 102, 23, 51, 1, -10, -53, 100, -100, 23 | 100, -10, 10, 11, 20, 30, 123, 12, 90, 10, 24 | }; 25 | array expected = { 26 | -100, -1210, -2522, -2177, 2857, 12004, 15506, 27 | -4673, -55360, -97524, -28437, 235155, 555311, 405266, 28 | -855481, -2926992, -3287961, 2203823, 14271183, 21930362, 29 | }; 30 | for_each(signal.begin(), signal.end(), [&](double &s) { s = filter(s); }); 31 | EXPECT_EQ(signal, expected); 32 | } -------------------------------------------------------------------------------- /test/Filters/test-IIRFilter.py: -------------------------------------------------------------------------------- 1 | from scipy.signal import lfilter 2 | import numpy as np 3 | 4 | type = 'int' 5 | b = np.array((1, 10, 2, -3, -1), dtype=np.float64) 6 | a = np.array((-1, 2, -3), dtype=np.float64) 7 | 8 | signal = np.array((100, 10, 102, 23, 51, 1, -10, -53, 100, -100, 100, -10, 10, 9 | 11, 20, 30, 123, 12, 90, 10), 10 | dtype=np.float64) 11 | output = lfilter(b, a, signal) 12 | print(f'IIRFilter<{len(b)}, {len(a)}, {type}> filter = {{{{') 13 | print(' ', ', '.join(map(lambda x: str(x), np.round(b).astype(np.int)))) 14 | print('},') 15 | print('{') 16 | print(' ', ', '.join(map(lambda x: str(x), np.round(a).astype(np.int)))) 17 | print('}};') 18 | print(f'array<{type}, {len(signal)}> signal = {{') 19 | print(' ', ', '.join(map(lambda x: str(x), np.round(signal).astype(np.int)))) 20 | print('};') 21 | print(f'array<{type}, {len(signal)}> expected = {{') 22 | print(' ', ', '.join(map(lambda x: str(x), np.round(output).astype(np.int)))) 23 | print('};') 24 | print( 25 | f'for_each(signal.begin(), signal.end(), [&]({type} &s) {{ s = filter(s); }});' 26 | ) 27 | print('EXPECT_EQ(signal, expected);') -------------------------------------------------------------------------------- /test/Filters/test-MedianFilter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | TEST(MedianFilter, odd) { 8 | MedianFilter<5> med = 3.14; 9 | std::array signal = { 10 | 100.0, 100.0, 25.0, 25.0, 50.0, 123.0, 11 | 465.0, 75.0, 56.0, 50.0, 23.0, 41.0, 12 | }; 13 | std::array expected = { 14 | 3.140000104904175, 15 | 3.140000104904175, 16 | 25.0, 17 | 25.0, 18 | 50.0, 19 | 50.0, 20 | 50.0, 21 | 75.0, 22 | 75.0, 23 | 75.0, 24 | 56.0, 25 | 50.0, 26 | }; 27 | std::transform(signal.begin(), signal.end(), signal.begin(), med); 28 | // ASSERT_EQ(signal, expected); 29 | for (size_t i = 0; i < signal.size(); ++i) 30 | EXPECT_FLOAT_EQ(signal[i], expected[i]) << i; 31 | } 32 | 33 | TEST(MedianFilter, even) { 34 | MedianFilter<6> med = 3.14; 35 | std::array signal = { 36 | 100.0, 100.0, 25.0, 25.0, 50.0, 123.0, 37 | 465.0, 75.0, 56.0, 50.0, 23.0, 41.0, 38 | }; 39 | std::array expected = { 40 | 3.140000104904175, 41 | 3.140000104904175, 42 | 14.069999694824219, 43 | 25.0, 44 | 37.5, 45 | 75.0, 46 | 75.0, 47 | 62.5, 48 | 65.5, 49 | 65.5, 50 | 65.5, 51 | 53.0, 52 | }; 53 | std::transform(signal.begin(), signal.end(), signal.begin(), med); 54 | // ASSERT_EQ(signal, expected); 55 | for (size_t i = 0; i < signal.size(); ++i) 56 | EXPECT_FLOAT_EQ(signal[i], expected[i]) << i; 57 | } -------------------------------------------------------------------------------- /test/Filters/test-MedianFilter.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def medfilt(signal, N): 4 | result = np.empty((len(signal)- N + 1,)) 5 | for i in range(len(result)): 6 | result[i] = np.median(signal[i:i+N]) 7 | return result 8 | 9 | N = 6 10 | signal = np.array((100, 100, 25, 25, 50, 123, 465, 75, 56, 50, 23, 41), 11 | dtype=np.float32) 12 | prepend = np.ones((N-1,), dtype=np.float32) * 3.14 13 | extended = np.concatenate((prepend, signal)) 14 | output = medfilt(extended, N) 15 | print('std::array signal = {{'.format(len(signal))) 16 | for i in signal: 17 | print(i, end=', ') 18 | print('};') 19 | print('std::array expected = {{'.format(len(signal))) 20 | for o in output: 21 | print(o, end=', ') 22 | print('};') 23 | 24 | N = 5 25 | signal = np.array((100, 100, 25, 25, 50, 123, 465, 75, 56, 50, 23, 41), 26 | dtype=np.float32) 27 | prepend = np.ones((N-1,), dtype=np.float32) * 3.14 28 | extended = np.concatenate((prepend, signal)) 29 | output = medfilt(extended, N) 30 | print('std::array signal = {{'.format(len(signal))) 31 | for i in signal: 32 | print(i, end=', ') 33 | print('};') 34 | print('std::array expected = {{'.format(len(signal))) 35 | for o in output: 36 | print(o, end=', ') 37 | print('};') -------------------------------------------------------------------------------- /test/Filters/test-SMA.py: -------------------------------------------------------------------------------- 1 | from scipy.signal import lfilter 2 | import numpy as np 3 | 4 | N = 10 5 | b = np.ones((N,), dtype=np.float32) 6 | a = np.array((N,), 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('std::array signal = {{'.format(len(signal))) 12 | for i in signal: 13 | print(i, end=', ') 14 | print('};') 15 | print('std::array expected = {{'.format(len(signal))) 16 | for o in output: 17 | print(o, end=', ') 18 | print('};') 19 | 20 | signal = np.concatenate((np.array((100,) * N, dtype=np.float32), signal)) 21 | output = lfilter(b, a, signal)[N:] 22 | print('std::array expected = {{'.format(len(output))) 23 | for o in output: 24 | print(o, end=', ') 25 | print('};') -------------------------------------------------------------------------------- /test/Filters/test-SOSFilter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | /* 7 | * (1 + 2 s⁻¹ + 3 s⁻²) (4 + 5 s⁻1 + 6 s⁻²) 8 | * ---------------------------------------- = 9 | * (-1 - 2 s⁻¹ + 3 s⁻²) (1 - 3 s⁻¹ + 2 s⁻²) 10 | * 11 | * (4 + 13 s⁻¹ + 28 s⁻² + 27 s⁻³ + 28 s⁻⁴) 12 | * --------------------------------------- 13 | * (-1 + 1 s⁻¹ + 7 s⁻² - 13 s⁻³ + 6 s⁻⁴) 14 | * 15 | */ 16 | TEST(SOSFilter, SOSFilter) { 17 | using namespace std; 18 | IIRFilter<5, 5, int> reference = {{4, 13, 28, 27, 18}, {-1, 1, 7, -13, 6}}; 19 | SOSFilter sos = {{{ 20 | {{1, 2, 3}, {-1, -2, 3}}, 21 | {{4, 5, 6}, {1, -3, 2}}, 22 | }}}; 23 | array signal = {100, 10, 102, 23, 51, 1, -10, -53, 100, -100, 24 | 100, -10, 10, 11, 20, 30, 123, 12, 90, 10}; 25 | array expected = signal; 26 | transform(signal.begin(), signal.end(), signal.begin(), sos); 27 | transform(expected.begin(), expected.end(), expected.begin(), reference); 28 | EXPECT_EQ(signal, expected); 29 | } -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /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://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json 5 | - https://www.pjrc.com/teensy/td_156/package_teensy_index.json 6 | --------------------------------------------------------------------------------