├── .clang-format
├── .github
├── issue_template.md
└── workflows
│ ├── ccpp.yml
│ ├── documentation.yml
│ └── examples.yaml
├── .gitignore
├── .vscode
├── settings.json
└── tasks.json
├── CMakeLists.txt
├── CMakePresets.json
├── LICENSE
├── README.md
├── cmake
└── Warnings.cmake
├── docs
└── extra
│ └── boards.txt.example
├── doxygen
├── Doxyfile
├── DoxygenLayout.xml
├── custom_stylesheet.css
├── header.html
├── images
│ ├── .gitkeep
│ ├── Screenshot-Arduino-IDE-Debug.png
│ └── increase-bit-depth.svg
├── pages
│ └── Debug.md
└── scripts
│ └── examples.py
├── examples
├── .clang-format
├── Arduino-Helpers
│ ├── Debug
│ │ └── Debug
│ │ │ └── Debug.ino
│ ├── Hardware
│ │ ├── 1.FilteredAnalog-Advanced
│ │ │ └── 1.FilteredAnalog-Advanced.ino
│ │ ├── 1.FilteredAnalog
│ │ │ └── 1.FilteredAnalog.ino
│ │ ├── 2.Button
│ │ │ └── 2.Button.ino
│ │ ├── 3.MultiPurposeButton
│ │ │ └── 3.MultiPurposeButton.ino
│ │ ├── Blink-Frequency-Buttons
│ │ │ └── Blink-Frequency-Buttons.ino
│ │ ├── Extended Input & Output
│ │ │ ├── 1. Input
│ │ │ │ └── 1. Multiplexers
│ │ │ │ │ ├── 1.AnalogReadSerial
│ │ │ │ │ └── 1.AnalogReadSerial.ino
│ │ │ │ │ ├── 2.DigitalReadSerial
│ │ │ │ │ └── 2.DigitalReadSerial.ino
│ │ │ │ │ └── 3.FilteredAnalogReadSerial
│ │ │ │ │ └── 3.FilteredAnalogReadSerial.ino
│ │ │ ├── 2. Output
│ │ │ │ ├── 1. Shift Registers
│ │ │ │ │ ├── 1.SPI-Blink
│ │ │ │ │ │ └── 1.SPI-Blink.ino
│ │ │ │ │ ├── 2.BitBang-Blink
│ │ │ │ │ │ └── 2.BitBang-Blink.ino
│ │ │ │ │ └── 2.RGB-LED-Chaser
│ │ │ │ │ │ └── 2.RGB-LED-Chaser.ino
│ │ │ │ └── 2. MAX7219
│ │ │ │ │ └── 1.MAX7219-Blink
│ │ │ │ │ └── 1.MAX7219-Blink.ino
│ │ │ └── 3. In&Out
│ │ │ │ ├── MCP23017
│ │ │ │ └── MCP23017.ino
│ │ │ │ └── Toggle-LEDs
│ │ │ │ └── Toggle-LEDs.ino
│ │ ├── MCP23017-Encoders
│ │ │ ├── MCP23017-Encoders-Interrupts
│ │ │ │ └── MCP23017-Encoders-Interrupts.ino
│ │ │ └── MCP23017-Encoders-No-Interrupts
│ │ │ │ └── MCP23017-Encoders-No-Interrupts.ino
│ │ ├── Pin-Change-Interrupt-Encoders
│ │ │ └── Pin-Change-Interrupt-Encoders.ino
│ │ └── Timer-Interrupt-Encoders
│ │ │ ├── Timer-Interrupt-Encoders.ino
│ │ │ └── TimerHelpers.hpp
│ ├── Math
│ │ └── Quaternion
│ │ │ └── Quaternion.ino
│ ├── STL
│ │ ├── ArraySort
│ │ │ └── ArraySort.ino
│ │ ├── Complex
│ │ │ └── Complex.ino
│ │ ├── CountPressedButtons
│ │ │ └── CountPressedButtons.ino
│ │ └── Numeric
│ │ │ └── Numeric.ino
│ └── Timing
│ │ └── BlinkWithoutDelay-Timer
│ │ └── BlinkWithoutDelay-Timer.ino
├── examples.dox
└── test
│ ├── ExtIO-pin-test
│ └── ExtIO-pin-test.ino
│ └── STL-test
│ ├── STL-test.cpp
│ └── STL-test.ino
├── keywords.txt
├── library.properties
├── mock
├── CMakeLists.txt
├── Core-Libraries
│ └── SPI.h
├── Core
│ ├── Arduino.cpp
│ ├── Arduino.h
│ ├── ArduinoMock.cpp
│ ├── ArduinoMock.hpp
│ ├── HardwareSerial.h
│ ├── HardwareSerial0.cpp
│ ├── Print.cpp
│ ├── Print.h
│ ├── Printable.h
│ ├── Stream.h
│ └── binary.h
├── Libraries
│ ├── Adafruit_GFX
│ │ ├── Adafruit_GFX.h
│ │ └── gfxfont.h
│ ├── Adafruit_SSD1306
│ │ └── Adafruit_SSD1306.h
│ └── Encoder
│ │ └── Encoder.h
└── README.md
├── scripts
├── addImplementationFiles.py
├── ci
│ ├── gen-docs.sh
│ ├── install-doxygen.sh
│ └── install-lcov.sh
├── coverage-badge.py
├── coverage.sh
├── git-pull-arduino-helpers.sh
├── install-ci.sh
├── install-gtest.sh
├── keywords.py
└── listNonEmptyImplementationFiles.py
├── src
├── AH
│ ├── Arduino-Wrapper.h
│ ├── CMakeLists.txt
│ ├── Containers
│ │ ├── Array.hpp
│ │ ├── ArrayHelpers.hpp
│ │ ├── BitArray.hpp
│ │ ├── CRTP.hpp
│ │ ├── Containers.dox
│ │ ├── LinkedList.hpp
│ │ ├── Updatable.hpp
│ │ └── keywords.yml
│ ├── Debug
│ │ ├── Debug.cpp
│ │ ├── Debug.dox
│ │ ├── Debug.hpp
│ │ └── DebugVal.hpp
│ ├── Error
│ │ ├── Error.dox
│ │ ├── Error.hpp
│ │ └── Exit.cpp
│ ├── Filters
│ │ ├── EMA.hpp
│ │ ├── Filters.dox
│ │ ├── Hysteresis.hpp
│ │ └── keywords.yml
│ ├── Hardware
│ │ ├── ADCConfig.hpp
│ │ ├── Arduino-Hardware-Types.hpp
│ │ ├── Button.cpp
│ │ ├── Button.hpp
│ │ ├── ButtonMatrix.hpp
│ │ ├── ButtonMatrix.ipp
│ │ ├── ExtendedInputOutput
│ │ │ ├── AnalogMultiplex.hpp
│ │ │ ├── ExtIO.dox
│ │ │ ├── ExtendedIOElement.cpp
│ │ │ ├── ExtendedIOElement.hpp
│ │ │ ├── ExtendedInputOutput.cpp
│ │ │ ├── ExtendedInputOutput.hpp
│ │ │ ├── MAX7219.hpp
│ │ │ ├── MCP23017.hpp
│ │ │ ├── MCP23017.ipp
│ │ │ ├── SPIShiftRegisterOut.hpp
│ │ │ ├── SPIShiftRegisterOut.ipp
│ │ │ ├── ShiftRegisterOut.hpp
│ │ │ ├── ShiftRegisterOut.ipp
│ │ │ ├── ShiftRegisterOutBase.hpp
│ │ │ ├── ShiftRegisterOutBase.ipp
│ │ │ ├── ShiftRegisterOutRGB.cpp
│ │ │ ├── ShiftRegisterOutRGB.hpp
│ │ │ ├── StaticSizeExtendedIOElement.hpp
│ │ │ └── keywords.yml
│ │ ├── FilteredAnalog.hpp
│ │ ├── Hardware-Types.hpp
│ │ ├── Hardware.dox
│ │ ├── IncrementButton.cpp
│ │ ├── IncrementButton.hpp
│ │ ├── IncrementDecrementButtons.cpp
│ │ ├── IncrementDecrementButtons.hpp
│ │ ├── LEDs
│ │ │ ├── DotBarDisplayLEDs.hpp
│ │ │ ├── LEDs.hpp
│ │ │ ├── MAX7219SevenSegmentDisplay.hpp
│ │ │ ├── MAX7219_Base.hpp
│ │ │ └── keywords.yml
│ │ ├── MCP23017Encoders.hpp
│ │ ├── MultiPurposeButton.hpp
│ │ ├── RegisterEncoders.hpp
│ │ └── keywords.yml
│ ├── Math
│ │ ├── Degrees.hpp
│ │ ├── Divide.hpp
│ │ ├── FixArduinoMacros.hpp
│ │ ├── IncreaseBitDepth.hpp
│ │ ├── Math.dox
│ │ ├── MinMaxFix.hpp
│ │ ├── Quaternion.cpp
│ │ ├── Quaternion.hpp
│ │ ├── Vector.cpp
│ │ ├── Vector.hpp
│ │ └── keywords.yml
│ ├── PrintStream
│ │ ├── PrintStream.cpp
│ │ ├── PrintStream.dox
│ │ └── PrintStream.hpp
│ ├── STL
│ │ ├── Fallback
│ │ │ ├── algorithm
│ │ │ ├── array
│ │ │ ├── backward
│ │ │ │ └── binders.h
│ │ │ ├── bits
│ │ │ │ ├── algorithmfwd.h
│ │ │ │ ├── alloc_traits.h
│ │ │ │ ├── allocator.h
│ │ │ │ ├── boost_concept_check.h
│ │ │ │ ├── c++0x_warning.h
│ │ │ │ ├── c++allocator.h
│ │ │ │ ├── c++config.h
│ │ │ │ ├── concept_check.h
│ │ │ │ ├── cpp_type_traits.h
│ │ │ │ ├── cpu_defines.h
│ │ │ │ ├── enable_special_members.h
│ │ │ │ ├── exception_defines.h
│ │ │ │ ├── functexcept.h
│ │ │ │ ├── functional_hash.h
│ │ │ │ ├── hash_bytes.h
│ │ │ │ ├── invoke.h
│ │ │ │ ├── memoryfwd.h
│ │ │ │ ├── move.h
│ │ │ │ ├── os_defines.h
│ │ │ │ ├── predefined_ops.h
│ │ │ │ ├── ptr_traits.h
│ │ │ │ ├── range_access.h
│ │ │ │ ├── std_abs.h
│ │ │ │ ├── stl_algo.h
│ │ │ │ ├── stl_algobase.h
│ │ │ │ ├── stl_bvector.h
│ │ │ │ ├── stl_construct.h
│ │ │ │ ├── stl_function.h
│ │ │ │ ├── stl_heap.h
│ │ │ │ ├── stl_iterator.h
│ │ │ │ ├── stl_iterator_base_funcs.h
│ │ │ │ ├── stl_iterator_base_types.h
│ │ │ │ ├── stl_numeric.h
│ │ │ │ ├── stl_pair.h
│ │ │ │ ├── stl_relops.h
│ │ │ │ ├── stl_tempbuf.h
│ │ │ │ ├── stl_uninitialized.h
│ │ │ │ ├── stl_vector.h
│ │ │ │ ├── uniform_int_dist.h
│ │ │ │ ├── unique_ptr.h
│ │ │ │ ├── uses_allocator.h
│ │ │ │ └── vector.tcc
│ │ │ ├── bitset
│ │ │ ├── climits
│ │ │ ├── cmath
│ │ │ ├── complex
│ │ │ ├── cstddef
│ │ │ ├── cstdint
│ │ │ ├── cstdlib
│ │ │ ├── debug
│ │ │ │ ├── assertions.h
│ │ │ │ └── debug.h
│ │ │ ├── ext
│ │ │ │ ├── alloc_traits.h
│ │ │ │ ├── new_allocator.h
│ │ │ │ ├── numeric_traits.h
│ │ │ │ └── type_traits.h
│ │ │ ├── initializer_list
│ │ │ ├── iterator
│ │ │ ├── limits
│ │ │ ├── memory
│ │ │ ├── new
│ │ │ ├── new.cpp
│ │ │ ├── numeric
│ │ │ ├── optional
│ │ │ ├── tuple
│ │ │ ├── type_traits
│ │ │ ├── utility
│ │ │ └── vector
│ │ ├── README.md
│ │ ├── algorithm
│ │ ├── array
│ │ ├── bitset
│ │ ├── climits
│ │ ├── cmath
│ │ ├── complex
│ │ ├── cstddef
│ │ ├── cstdint
│ │ ├── cstdlib
│ │ ├── initializer_list
│ │ ├── iterator
│ │ ├── limits
│ │ ├── memory
│ │ ├── new
│ │ ├── numeric
│ │ ├── optional
│ │ ├── tuple
│ │ ├── type_traits
│ │ ├── utility
│ │ ├── vector
│ │ └── vector.cpp
│ ├── Settings
│ │ ├── NamespaceSettings.hpp
│ │ ├── Settings.dox
│ │ ├── Settings.hpp
│ │ ├── SettingsWrapper.hpp
│ │ └── Warnings.hpp
│ ├── Teensy
│ │ └── TeensyUSBTypes.hpp
│ ├── Timing
│ │ ├── MillisMicrosTimer.hpp
│ │ ├── Timing.dox
│ │ └── keywords.yml
│ └── Types
│ │ ├── Frequency.hpp
│ │ ├── FunctionTraits.hpp
│ │ └── keywords.yml
├── Arduino_Helpers.dox
├── Arduino_Helpers.h
├── CMakeLists.txt
└── keywords.yml
├── test
├── AH
│ ├── Containers
│ │ ├── test-Array.cpp
│ │ ├── test-DoublyLinkedList.cpp
│ │ ├── test-Updatable.cpp
│ │ └── tests-BitArray.cpp
│ ├── Filters
│ │ ├── test-EMA.cpp
│ │ ├── test-EMA.py
│ │ ├── test-EMA_f.py
│ │ └── test-Hysteresis.cpp
│ ├── Hardware
│ │ ├── ExtendedInputOutput
│ │ │ ├── test-AnalogMultiplex.cpp
│ │ │ └── test-ExtendedInputOutput.cpp
│ │ ├── test-Button.cpp
│ │ ├── test-FilteredAnalog.cpp
│ │ ├── test-IncrementButton.cpp
│ │ └── test-IncrementDecrementButtons.cpp
│ ├── Math
│ │ ├── test-Degrees.cpp
│ │ ├── test-IncreaseBitDepth.cpp
│ │ ├── test-Quaternion.cpp
│ │ └── test-Vector.cpp
│ ├── PrintStream
│ │ └── test-PrintStream.cpp
│ └── Timing
│ │ └── test-Timer.cpp
├── CMakeLists.txt
├── examples-board-fqbns.yaml
├── test-main.cpp
└── test_example.cpp
└── tools
├── arduino-cli.yaml
└── arduino-example-builder.py
/.github/issue_template.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tttapa/Arduino-Helpers/00f463b534fbea22f0b596e091a60715679e3064/.github/issue_template.md
--------------------------------------------------------------------------------
/.github/workflows/ccpp.yml:
--------------------------------------------------------------------------------
1 | name: CI Tests
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v3
12 | - name: Install dependencies
13 | run: sudo ./scripts/install-gtest.sh Debug /usr/local
14 | - name: Configure
15 | run: cmake -S. --preset ci
16 | - name: Build
17 | run: cmake --build --preset ci -j
18 | - name: Test
19 | run: ctest --preset ci
20 |
--------------------------------------------------------------------------------
/.github/workflows/documentation.yml:
--------------------------------------------------------------------------------
1 | # This action generates the documentation and then deploys it to the `gh-pages` branch.
2 |
3 | name: Documentation & Coverage
4 |
5 | on:
6 | push:
7 |
8 | jobs:
9 | deploy-docs:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - uses: actions/checkout@v3
14 |
15 | # Cache the doxygen executable, lcov
16 | - uses: actions/cache@v3
17 | id: cache-tools
18 | with:
19 | path: |
20 | /tmp/doxygen
21 | /tmp/lcov
22 | /tmp/gtest
23 | key: ${{ runner.os }}-doc-${{ hashFiles('scripts/ci/install-doxygen.sh', 'scripts/ci/install-lcov.sh', 'scripts/install-gtest.sh') }}
24 |
25 | - name: Install Graphviz/Dot and LCOV Perl dependencies, as well as TeX Live
26 | run: |
27 | sudo apt-get update
28 | sudo apt-get install \
29 | graphviz libjson-perl libperlio-gzip-perl perl \
30 | texlive-binaries
31 |
32 | - name: Install LCOV
33 | run: |
34 | ./scripts/ci/install-lcov.sh /tmp/lcov
35 | echo "/tmp/lcov/bin" >> $GITHUB_PATH
36 |
37 | # Download and build doxygen (if not cached already)
38 | - name: Install Doxygen
39 | run: |
40 | ./scripts/ci/install-doxygen.sh /tmp/doxygen
41 | echo "/tmp/doxygen/bin" >> $GITHUB_PATH
42 |
43 | - name: Install Google Test
44 | if: steps.cache-tools.outputs.cache-hit != 'true'
45 | shell: bash
46 | run: ./scripts/install-gtest.sh Debug /tmp/gtest
47 |
48 | # Install Python
49 | - uses: actions/setup-python@v4
50 | with:
51 | python-version: '3.9'
52 |
53 | # Create the `gh-pages` branch if it doesn't exist already, check it out,
54 | # and copy it to /tmp/staging.
55 | - name: Create staging area
56 | run: |
57 | rm -rf /tmp/staging
58 | git fetch origin gh-pages:gh-pages ||:
59 | git checkout gh-pages || \
60 | { git checkout --orphan gh-pages && git rm -rf . && git clean -fxd ; }
61 | cp -ar $GITHUB_WORKSPACE/ /tmp/staging
62 | git checkout ${GITHUB_REF##*/}
63 | git submodule update --init --recursive
64 |
65 | # Generate the documentation and save it in /tmp/staging
66 | - name: Generate documentation
67 | run: ./scripts/ci/gen-docs.sh /tmp/staging
68 | env:
69 | CMAKE_PREFIX_PATH: /tmp/gtest
70 |
71 | # Commit the new documentation, squash the commits, and push it to GitHub
72 | - name: Commit and push documention
73 | run: |
74 | git config --global user.name "github-actions"
75 | git config --global user.email "actions@github.com"
76 | commithash=$(git rev-parse HEAD)
77 | cd /tmp/staging
78 | git add .
79 | git commit -m "Documentation for ${commithash}" && \
80 | git reset $(git commit-tree HEAD^{tree} -m "Documentation for ${commithash}") && \
81 | git push -f origin gh-pages ||:
82 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # .vscode/
2 | .vscode/tags
3 | *.pc
4 | .vscode/ipch
5 | .cache
6 |
7 | .~lock*
8 | __pycache__/
9 |
10 | *.tmp
11 | *.hex
12 |
13 | build
14 | docs/Coverage
15 | docs/Doxygen
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.associations": {
3 | "*.axbm": "cpp",
4 | "*.ipp": "cpp",
5 | "*.tcc": "cpp",
6 | "*.dox": "cpp"
7 | },
8 | "editor.minimap.maxColumn": 80,
9 | "editor.minimap.renderCharacters": false,
10 | "editor.rulers": [
11 | 80
12 | ],
13 | "editor.renderControlCharacters": true,
14 | "editor.renderWhitespace": "boundary",
15 | "files.defaultLanguage": "cpp",
16 | "files.trimFinalNewlines": true,
17 | "files.trimTrailingWhitespace": false,
18 | "search.exclude": {
19 | "**/node_modules": true,
20 | "**/googletest": true,
21 | "**/*.old": true,
22 | "**/docs/Doxygen": true,
23 | "**/docs/Coverage": true
24 | },
25 | "cmake.useCMakePresets": "always",
26 | "cmake.copyCompileCommands": "${workspaceFolder}/build/compile_commands.json",
27 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "type": "shell",
8 | "label": "Build examples",
9 | "command": "python3 arduino-example-builder.py 'AVR'",
10 | "problemMatcher": "$gcc",
11 | "options": {
12 | "cwd": "${workspaceFolder}/tools",
13 | },
14 | "group": "build",
15 | },
16 | ]
17 | }
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.18)
2 | project(Arduino-Helpers CXX)
3 | set(CMAKE_CXX_STANDARD 14)
4 | enable_testing()
5 |
6 | # Add coverage target
7 | option(AH_WITH_COVERAGE
8 | "Generate coverage information." Off)
9 | if (AH_WITH_COVERAGE)
10 | add_custom_target(coverage
11 | ${CMAKE_CURRENT_LIST_DIR}/scripts/coverage.sh
12 | ${CMAKE_CXX_COMPILER_ID}
13 | ${CMAKE_CXX_COMPILER_VERSION}
14 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
15 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage -fno-inline")
16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -fno-inline")
17 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
18 | add_dependencies(coverage Arduino-Helpers::tests)
19 | endif()
20 |
21 | # Add documentation target
22 | find_package(Doxygen)
23 | find_package(Python3 COMPONENTS Interpreter)
24 | if (DOXYGEN_FOUND AND Python3_Interpreter_FOUND)
25 | # Add example documentation target
26 | add_custom_target(examples-doxygen
27 | Python3::Interpreter ${CMAKE_CURRENT_LIST_DIR}/doxygen/scripts/examples.py
28 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/doxygen)
29 | # Add documentation target
30 | add_custom_target(documentation
31 | Doxygen::doxygen
32 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/doxygen
33 | DEPENDS examples-doxygen)
34 | endif()
35 |
36 | # Compiler warnings
37 | option(AH_WARNINGS_AS_ERRORS "Enable -Werror" On)
38 | include(cmake/Warnings.cmake)
39 |
40 | # Build the source files and tests
41 | add_subdirectory(mock)
42 | add_subdirectory(src)
43 | add_subdirectory(test)
44 |
--------------------------------------------------------------------------------
/CMakePresets.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 4,
3 | "cmakeMinimumRequired": {
4 | "major": 3,
5 | "minor": 18,
6 | "patch": 0
7 | },
8 | "configurePresets": [
9 | {
10 | "name": "dev",
11 | "displayName": "Development",
12 | "description": "",
13 | "generator": "Ninja Multi-Config",
14 | "binaryDir": "${sourceDir}/build/${presetName}",
15 | "cacheVariables": {
16 | "AH_WARNINGS_AS_ERRORS": true,
17 | "AH_WITH_COVERAGE": true,
18 | "CMAKE_CXX_COMPILER_LAUNCHER": "ccache",
19 | "CMAKE_CXX_FLAGS": "-fsanitize=address,leak,undefined,pointer-compare,pointer-subtract",
20 | "CMAKE_EXPORT_COMPILE_COMMANDS": true
21 | }
22 | },
23 | {
24 | "name": "ci",
25 | "displayName": "CI",
26 | "description": "",
27 | "binaryDir": "${sourceDir}/build/${presetName}",
28 | "cacheVariables": {
29 | "AH_WARNINGS_AS_ERRORS": true,
30 | "AH_WITH_COVERAGE": false,
31 | "CMAKE_CXX_FLAGS": "-fsanitize=address,leak,undefined,pointer-compare,pointer-subtract"
32 | }
33 | },
34 | {
35 | "name": "ci-cov",
36 | "displayName": "CI + Coverage",
37 | "description": "",
38 | "binaryDir": "${sourceDir}/build/${presetName}",
39 | "cacheVariables": {
40 | "AH_WARNINGS_AS_ERRORS": false,
41 | "AH_WITH_COVERAGE": true,
42 | "CMAKE_CXX_FLAGS": "-fsanitize=address,leak,undefined,pointer-compare,pointer-subtract"
43 | }
44 | }
45 | ],
46 | "buildPresets": [
47 | {
48 | "name": "dev",
49 | "displayName": "Development",
50 | "configurePreset": "dev"
51 | },
52 | {
53 | "name": "ci",
54 | "displayName": "CI",
55 | "configurePreset": "ci"
56 | },
57 | {
58 | "name": "ci-cov",
59 | "displayName": "CI + Coverage",
60 | "configurePreset": "ci-cov"
61 | }
62 | ],
63 | "testPresets": [
64 | {
65 | "name": "dev",
66 | "displayName": "Development",
67 | "configurePreset": "dev",
68 | "output": {
69 | "outputOnFailure": true
70 | }
71 | },
72 | {
73 | "name": "ci",
74 | "displayName": "CI",
75 | "configurePreset": "ci",
76 | "output": {
77 | "outputOnFailure": true
78 | }
79 | },
80 | {
81 | "name": "ci-cov",
82 | "displayName": "CI + Coverage",
83 | "configurePreset": "ci-cov",
84 | "output": {
85 | "outputOnFailure": true
86 | }
87 | }
88 | ]
89 | }
--------------------------------------------------------------------------------
/cmake/Warnings.cmake:
--------------------------------------------------------------------------------
1 | set(COMMON_WARNINGS
2 | -fdiagnostics-show-option
3 | -Wall
4 | -Wextra
5 | -pedantic
6 | -Wpedantic
7 | -pedantic-errors
8 | -Wdouble-promotion
9 | -Wswitch-default
10 | -Wswitch-enum
11 | -Wimplicit-fallthrough
12 | -Wuninitialized
13 | -Wno-missing-braces
14 | )
15 | set(GCC_WARNINGS
16 | -Wno-error=unused-but-set-variable
17 | -Wsuggest-override
18 | -Wno-error=attributes
19 | )
20 | set(CLANG_WARNINGS
21 | -Wno-error=unknown-warning-option
22 | -Wno-newline-eof
23 | -Wno-error=unused-but-set-variable
24 | -Winconsistent-missing-override
25 | -Wno-gnu-zero-variadic-macro-arguments
26 | )
27 | set(MSVC_WARNINGS
28 | /W4
29 | /wd4127 # conditional expression is constant
30 | /wd4458 # declaration of 'x' hides class member
31 | /permissive-
32 | )
33 | set(INTEL_WARNINGS
34 | -Wall
35 | -Wextra
36 | )
37 | if (AH_WARNINGS_AS_ERRORS)
38 | if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
39 | list(APPEND MSVC_WARNINGS /WX)
40 | else()
41 | list(APPEND COMMON_WARNINGS -Werror)
42 | endif()
43 | endif()
44 |
45 | add_library(warnings INTERFACE)
46 |
47 | if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
48 | target_compile_options(warnings INTERFACE
49 | ${COMMON_WARNINGS} ${GCC_WARNINGS})
50 | elseif (CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
51 | target_compile_options(warnings INTERFACE
52 | ${COMMON_WARNINGS} ${CLANG_WARNINGS})
53 | elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
54 | target_compile_options(warnings INTERFACE
55 | ${MSVC_WARNINGS})
56 | elseif (CMAKE_CXX_COMPILER_ID MATCHES "Intel")
57 | target_compile_options(warnings INTERFACE
58 | ${INTEL_WARNINGS})
59 | else()
60 | message(WARNING "No known warnings for this compiler")
61 | endif()
62 | add_library(Arduino-Helpers::warnings ALIAS warnings)
63 |
64 | set(CMAKE_DEBUG_POSTFIX "d")
65 |
--------------------------------------------------------------------------------
/doxygen/header.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | $projectname: $title
10 | $title
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | $treeview
20 | $search
21 | $mathjax
22 |
23 |
24 | $extrastylesheet
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |  |
42 |
43 |
44 |
45 |
47 | $projectbrief
48 | |
49 |
50 |
51 |
52 |
53 | $projectbrief
54 | |
55 |
56 |
57 |
58 |
59 |
60 | $searchbox |
61 |
62 |
63 |
64 |
65 |
66 |
67 | $searchbox |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/doxygen/images/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tttapa/Arduino-Helpers/00f463b534fbea22f0b596e091a60715679e3064/doxygen/images/.gitkeep
--------------------------------------------------------------------------------
/doxygen/images/Screenshot-Arduino-IDE-Debug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tttapa/Arduino-Helpers/00f463b534fbea22f0b596e091a60715679e3064/doxygen/images/Screenshot-Arduino-IDE-Debug.png
--------------------------------------------------------------------------------
/doxygen/pages/Debug.md:
--------------------------------------------------------------------------------
1 | # Debug {#md_pages_Debug}
2 |
3 | @see Module @ref AH_Debug for more information.
4 | @see @ref Debug.ino "examples/Arduino-Helpers/Debug" for example usage.
5 |
6 | ## Adding a 'Debug' menu in the Arduino IDE
7 |
8 | If you are going to be debugging a lot, it might be useful to just add a menu
9 | option in the IDE to disable/enable debugging.
10 | This can be done relatively easily by editing the `boards.txt` file.
11 |
12 | Open the `boards.txt` file of the board you are using. If you're using version
13 | 1.8.x of the Arduino IDE, it'll be located in
14 | `~/.arduino15/packages/
/hardware///` or
15 | `C:\users\\AppData\Local\Arduino15\packages\\hardware\\\`.
16 | Open it using a text editor (e.g. Gedit on Linux, or Notepad on Windows).
17 |
18 | First, create the menu option by adding the following line at the top of the
19 | file:
20 |
21 | ```
22 | menu.debug=Debug output
23 | ```
24 |
25 | Then for your board, just add the different debug options.
26 | For example, if you're using an Arduino UNO:
27 |
28 | ```
29 | uno.menu.debug.None=None
30 | uno.menu.debug.None.build.debug_output=
31 | uno.menu.debug.Serial=Serial
32 | uno.menu.debug.Serial.build.debug_output=-DDEBUG_OUT=Serial
33 | ```
34 |
35 | Next, add the debugging flags to the compilation options by adding the line:
36 |
37 | ```
38 | uno.build.extra_flags={build.debug_output}
39 | ```
40 |
41 | If your board already has an `extra_flags` entry, just add
42 | ` {build.debug_output}` to the end (separated by a space). For example:
43 |
44 | ```
45 | leonardo.build.extra_flags={build.usb_flags} {build.debug_output}
46 | ```
47 |
48 | A complete list of all the AVR boards and their added debug options can be found
49 | [**here**](https://github.com/tttapa/Arduino-Helpers/blob/master/docs/extra/boards.txt.example).
50 |
51 | Finally, restart the IDE.
52 | If you now open your the `Tools` menu in the Arduino IDE, you should see the
53 | debug options:
54 | 
--------------------------------------------------------------------------------
/doxygen/scripts/examples.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import re
4 | import os
5 | from os.path import join, realpath, basename, splitext
6 | from pathlib import Path
7 |
8 | dirnm = os.path.dirname(os.path.realpath(__file__))
9 | doxydir = join(dirnm, '..')
10 | # exclude = re.compile(r'(examples/Arduino-Helpers/)|(examples/test/)')
11 | exclude = re.compile(r'examples/test/')
12 |
13 | template = """\
14 | /**
15 | * @example "{pathname}"
16 | *
17 | * {title}
18 | * {underline}
19 | *{docstr}*/
20 |
21 | """
22 |
23 |
24 | def stripQuotes(string):
25 | string = re.sub(r'^"', '', string)
26 | string = re.sub(r'"$', '', string)
27 | return string
28 |
29 |
30 | with open(join(doxydir, 'Doxyfile')) as doxy:
31 | doxy_content = doxy.read()
32 | m = re.search(r'EXAMPLE_PATH\s*=\s*(.+)', doxy_content)
33 | if m:
34 | exampledir = m.group(1).split('" "')[0]
35 | exampledir = realpath(join(doxydir, stripQuotes(exampledir)))
36 | print("Example directory =", exampledir)
37 | else:
38 | print('Error: couldn\'t find EXAMPLE_PATH in Doxyfile')
39 | exit(1)
40 | m = re.search(r'INPUT\s*=\s*([./a-zA-Z0-9_-]+)', doxy_content)
41 | if m:
42 | lastInclude = m.group(1).split(" ")[-1]
43 | outputfile = realpath(join(doxydir, stripQuotes(lastInclude)))
44 | print("Output file =", outputfile)
45 | else:
46 | print('Error: couldn\'t find INPUT in Doxyfile')
47 | exit(1)
48 |
49 | output = ""
50 |
51 | for root, dirs, files in os.walk(exampledir):
52 | if exclude is not None and re.search(exclude, root) is not None:
53 | print('Excluding', root)
54 | continue
55 | print('Scanning', root)
56 | for file in sorted(files):
57 | if file.endswith('.ino'):
58 | with open(join(root, file)) as example:
59 | example_content = example.read()
60 | s = example_content.split('/**', 1)
61 | if len(s) > 1:
62 | print('\t\033[0;32mFound documentation for', file,
63 | '\033[0m')
64 | docstr = s[1].split('*/', 1)[0]
65 | # Add line break after brief
66 | # docstr = re.sub(r'^\s*\*\s*$', r'\g<0>
', docstr, 1,
67 | # re.MULTILINE)
68 | # pathname = str(Path(root).relative_to(exampledir) / file)
69 | pathname = file
70 | title = splitext(basename(file))[0]
71 | underline = '=' * len(title)
72 | output += template.format(pathname=pathname,
73 | title=title,
74 | underline=underline,
75 | docstr=docstr)
76 | else:
77 | print('\t\033[0;33mWarning: no documentation for', file,
78 | '\033[0m')
79 | print('\t → "' + str(Path(root) / file) + '"')
80 |
81 | with open(outputfile, 'w') as f:
82 | f.write(output)
83 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Debug/Debug/Debug.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This examples shows how use the debug macros for printing different kinds of
3 | * debugging information
4 | *
5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
6 | *
7 | * Behavior
8 | * --------
9 | *
10 | * - Enable debugging by defining the @ref DEBUG_OUT macro in
11 | * `src/AH/Settings/Settings.hpp` or enable debugging globally as explained
12 | * [here](@ref md_pages_Debug)
13 | * - Upload the sketch to the Arduino, and open the Serial Monitor
14 | * (`CTRL+Shift+M`)
15 | * - Every five seconds, debugging information is printed, for example:
16 | *
17 | * ~~~
18 | * This is the result of `DEBUG`
19 | * [/home/pieter/GitHub/Arduino-Debugging/Example/Example.ino:12]: This is the result of `DEBUGREF`
20 | * [void loop() @ line 13]: This is the result of `DEBUGFN`
21 | * [0:2:11.085]: This is the result of `DEBUGTIME`
22 | * a = 1, b = 2, c = 3
23 | * log10(1000) - 2 = 1.00
24 | * millis() = 131085
25 | * Serial.read() = -1
26 | * [int someFunction(int) @ line 26]: parameter = 42
27 | * ~~~
28 | *
29 | * @see @ref md_pages_Debug for instructions on how to add an option in the
30 | * Arduino IDE to easily enable and disable debugging globally without
31 | * editing the settings file.
32 | *
33 | * Written by PieterP, 2018-07-31
34 | * https://github.com/tttapa/Arduino-Helpers
35 | */
36 |
37 | #include
38 |
39 | #include
40 |
41 | void setup() {
42 | Serial.begin(115200);
43 | while (!Serial)
44 | ;
45 | }
46 |
47 | void loop() {
48 | DEBUG("This is the result of `DEBUG`");
49 | DEBUGREF("This is the result of `DEBUGREF`");
50 | DEBUGFN("This is the result of `DEBUGFN`");
51 | DEBUGTIME("This is the result of `DEBUGTIME`");
52 | int a = 1, b = 2, c = 3;
53 | DEBUGVAL(a, b, c);
54 | (void)a, (void)b, (void)c;
55 | DEBUGVAL(log10(1000) - 2);
56 | DEBUGVAL(millis());
57 | DEBUGVAL(Serial.read());
58 | someFunction(42);
59 | DEBUG("");
60 | delay(5000);
61 | }
62 |
63 | int someFunction(int parameter) {
64 | DEBUGFN(NAMEDVALUE(parameter));
65 | return parameter;
66 | }
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Hardware/1.FilteredAnalog/1.FilteredAnalog.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This examples shows how to filter an analog input, so you can get the
3 | * position of a knob or fader without noise.
4 | *
5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
6 | *
7 | * Connections
8 | * -----------
9 | *
10 | * - A0: wiper of a potentiometer
11 | *
12 | * Connect the left terminal of the potentiometer to ground, and the right one
13 | * to VCC.
14 | *
15 | * Behavior
16 | * --------
17 | *
18 | * - Upload the sketch to the Arduino, and open the Serial Monitor
19 | * (`CTRL+Shift+M`)
20 | * - When you turn the potentiometer, you should see the position of the
21 | * potentiometer being printed as a number between 0 and 1023.
22 | * - The analog input is filtered, so there shouldn't be any noise on the
23 | * position. If there is, check your wiring, and make sure that the resistance
24 | * of the potentiometer isn't too high (10 kΩ is ideal).
25 | *
26 | * The example @ref 1.FilteredAnalog-Advanced.ino has more information about the
27 | * parameters you can pass to the FilteredAnalog class to tweak the filters,
28 | * increase the resolution, etc.
29 | *
30 | * Written by PieterP, 2019-10-10
31 | * https://github.com/tttapa/Arduino-Helpers
32 | */
33 |
34 | // Include the library
35 | #include
36 |
37 | #include
38 | #include
39 |
40 | // Create a filtered analog object on pin A0, with the default settings:
41 | FilteredAnalog<> analog = A0;
42 |
43 | void setup() {
44 | Serial.begin(115200);
45 | while (!Serial);
46 | // Select the correct ADC resolution
47 | analog.setupADC();
48 | // Initialize the filter to whatever the value on the input is right now
49 | // (otherwise, the filter is initialized to zero and you get transients)
50 | analog.resetToCurrentValue();
51 | }
52 |
53 | void loop() {
54 | // Read the analog input every millisecond, and print if the value has changed
55 | static Timer timer = 1; // ms
56 | if (timer && analog.update())
57 | Serial.println(analog.getValue());
58 | }
59 |
60 | // Explanation:
61 | //
62 | // analog.update() reads the analog input, applies the filters,
63 | // saves the value, and returns true if the value has changed.
64 | // You can then retreive the new value using analog.getValue().
65 | //
66 | // Timer is just a "Blink Without Delay" wrapper, it returns true
67 | // every time the specified amount of time has passed.
68 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Hardware/2.Button/2.Button.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This examples shows how to use the debounced Button class to toggle an LED.
3 | *
4 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
5 | *
6 | * Connections
7 | * -----------
8 | *
9 | * - 2: Momentary push button (other pin to ground)
10 | *
11 | * The internal pull-up resistor will be enabled.
12 | *
13 | * Behavior
14 | * --------
15 | *
16 | * - If you press the push button once, the built-in LED is turned on.
17 | * - If you press the button again, the LED is turned off again.
18 | *
19 | * Written by PieterP, 2019-11-22
20 | * https://github.com/tttapa/Arduino-Helpers
21 | */
22 |
23 | // Include the library
24 | #include
25 |
26 | #include
27 |
28 | // Create a Button object that reads a push button connected to pin 2:
29 | Button pushbutton {2};
30 |
31 | // The pin with the LED connected:
32 | const pin_t ledPin = LED_BUILTIN;
33 |
34 | void setup() {
35 | pinMode(ledPin, OUTPUT);
36 | pushbutton.begin();
37 | // You can invert the input, for use with normally closed (NC) switches:
38 | // pushbutton.invert();
39 | }
40 |
41 | void loop() {
42 | static bool ledState = LOW;
43 | // Read the digital input, debounce the signal, and check the state of
44 | // the button:
45 | if (pushbutton.update() == Button::Falling) {
46 | ledState = !ledState; // Invert the state of the LED
47 | // Update the LED with the new state
48 | digitalWrite(ledPin, ledState ? HIGH : LOW);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Hardware/3.MultiPurposeButton/3.MultiPurposeButton.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This examples shows how to use the MultiPurposeButton class to detect
3 | * different kinds of push button events.
4 | *
5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
6 | *
7 | * Connections
8 | * -----------
9 | *
10 | * - 2: Momentary push button (other pin to ground)
11 | *
12 | * The internal pull-up resistor will be enabled.
13 | *
14 | * Behavior
15 | * --------
16 | *
17 | * - Short presses, long presses, multiple presses, etc. are printed to the
18 | * Serial monitor.
19 | *
20 | * Written by PieterP, 2022-05-07
21 | * https://github.com/tttapa/Arduino-Helpers
22 | */
23 |
24 | #include // https://github.com/tttapa/Arduino-Helpers
25 |
26 | #include
27 |
28 | // Create a Button object that reads a push button connected to pin 2:
29 | MultiPurposeButton btn{2};
30 |
31 | void setup() {
32 | Serial.begin(115200);
33 | btn.setLongPressDelay(1000);
34 | btn.setMultiPressDelay(400);
35 | btn.begin();
36 | }
37 |
38 | void loop() {
39 | auto longPressTime = btn.getLongPressedTime();
40 | switch (btn.update()) {
41 | case btn.None: break;
42 | case btn.PressStart: Serial << "Pressed" << endl; break;
43 | case btn.ShortPressRelease:
44 | Serial << "Released after short press" << endl;
45 | break;
46 | case btn.LongPress: Serial << "Long press" << endl; break;
47 | case btn.LongPressRelease:
48 | Serial << "Released after long press (" << longPressTime << " ms)"
49 | << endl;
50 | break;
51 | case btn.MultiPress:
52 | Serial << "Consecutive presses: " << btn.getCurrentMultiPressCount() + 1
53 | << endl;
54 | break;
55 | case btn.MultiPressDone:
56 | Serial << "Counted " << btn.getMultiPressCount() + 1
57 | << " consecutive presses" << endl;
58 | break;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Hardware/Blink-Frequency-Buttons/Blink-Frequency-Buttons.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This examples shows how to use two push buttons to set the frequency at which
3 | * an LED blinks.
4 | *
5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
6 | *
7 | * Connections
8 | * -----------
9 | *
10 | * - 2: Momentary push button (other pin to ground)
11 | * - 3: Momentary push button (other pin to ground)
12 | *
13 | * The internal pull-up resistors will be enabled.
14 | *
15 | * Behavior
16 | * --------
17 | *
18 | * - If you press the first push button, the LED blinks faster.
19 | * - If you press the second push button, the LED blinks slower.
20 | * - You can press and hold one of the push buttons to change the frequency by
21 | * multiple steps.
22 | * - If you press both buttons at the same time, the frequency is reset to the
23 | * initial default frequency.
24 | *
25 | * Written by PieterP, 2019-12-10
26 | * https://github.com/tttapa/Arduino-Helpers
27 | */
28 |
29 | #include
30 |
31 | #include
32 | #include
33 |
34 | const unsigned long maxInterval = 2000; // ms
35 | const unsigned long minInterval = 100; // ms
36 | const unsigned long defaultInterval = 500; // ms
37 | const int intervalDelta = 100; // ms
38 |
39 | IncrementDecrementButtons buttons {2, 3};
40 | Timer timer = defaultInterval;
41 |
42 | void setup() {
43 | pinMode(LED_BUILTIN, OUTPUT);
44 | buttons.begin();
45 | Serial.begin(115200);
46 | }
47 |
48 | void loop() {
49 | // toggle the LED when the given number of milliseconds have passed
50 | if (timer)
51 | digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) ? LOW : HIGH);
52 |
53 | // read the buttons, and change interval accordingly
54 | switch (buttons.update()) {
55 | case IncrementDecrementButtons::IncrementShort:
56 | case IncrementDecrementButtons::IncrementLong:
57 | case IncrementDecrementButtons::IncrementHold:
58 | timer.setInterval(
59 | AH::max(timer.getInterval() - intervalDelta, minInterval));
60 | break;
61 | case IncrementDecrementButtons::DecrementShort:
62 | case IncrementDecrementButtons::DecrementLong:
63 | case IncrementDecrementButtons::DecrementHold:
64 | timer.setInterval(
65 | AH::min(timer.getInterval() + intervalDelta, maxInterval));
66 | break;
67 | case IncrementDecrementButtons::Reset:
68 | timer.setInterval(defaultInterval);
69 | break;
70 | default: break;
71 | }
72 |
73 | // print the new interval if a button was pushed
74 | if (buttons.getState() != IncrementDecrementButtons::Nothing)
75 | Serial.println(timer.getInterval());
76 | }
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Hardware/Extended Input & Output/1. Input/1. Multiplexers/1.AnalogReadSerial/1.AnalogReadSerial.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This is an example of the AnalogMultiplex class. It prints the values of all
3 | * 16 inputs of a multiplexers to the serial monitor.
4 | *
5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
6 | *
7 | * Connections
8 | * -----------
9 | *
10 | * - A0: CD74HC4067 signal pin ("common input/output")
11 | * - 3: CD74HC4067 address pin S0
12 | * - 4: CD74HC4067 address pin S1
13 | * - 5: CD74HC4067 address pin S2
14 | * - 6: CD74HC4067 address pin S3
15 | *
16 | * Optionally you can connect the enable pin as well, this is useful
17 | * if you want to use multiple multiplexers with the same address
18 | * lines and the same analog input. Otherwise, just connect the enable
19 | * pin to ground.
20 | *
21 | * If you are using a 3-bit multiplexer, like the CD74HC4051, you can
22 | * uncomment the code specific to this multiplexer, and use only three
23 | * address pins.
24 | *
25 | * Behavior
26 | * --------
27 | *
28 | * Connect some potentiometers or other analog sensors to the 16 inputs
29 | * of the multiplexer, and open the serial monitor (CTRL+SHIFT+M) or the
30 | * serial plotter (CTRL+SHIFT+L). You should see all 16 signals printed
31 | * or plotted.
32 | *
33 | * Written by Pieter P, 31-01-2019
34 | * https://github.com/tttapa/Arduino-Helpers
35 | */
36 |
37 | #include // Include the Arduino Helpers library
38 | #include
39 |
40 | // Instantiate a multiplexer
41 | CD74HC4067 mux {
42 | A0, // analog pin
43 | {3, 4, 5, 6}, // Address pins S0, S1, S2, S3
44 | // 7, // Optionally, specify the enable pin
45 | };
46 |
47 | // Alternatively, if you have a 3-bit mux:
48 | // CD74HC4051 mux {
49 | // A0,
50 | // {3, 4, 5},
51 | // // 7, // Optional
52 | // };
53 |
54 | void setup() {
55 | Serial.begin(115200);
56 | mux.begin(); // Initialize multiplexer
57 | }
58 |
59 | void loop() {
60 | for (pin_t pin = 0; pin < mux.getLength(); ++pin) {
61 | Serial.print(mux.analogRead(pin));
62 | Serial.print('\t');
63 | }
64 | Serial.println();
65 | }
66 |
67 | // A more fancy approach could be to use a range-based for loop
68 | void loop2() {
69 | for (pin_t pin : mux.pins()) {
70 | Serial.print(analogRead(pin));
71 | Serial.print('\t');
72 | }
73 | Serial.println();
74 | }
75 | // Okay, it's a bit slower, because it has to look up what ExtIO device the pin
76 | // belongs to, but hey, it's nice to have it anyway
77 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Hardware/Extended Input & Output/1. Input/1. Multiplexers/2.DigitalReadSerial/2.DigitalReadSerial.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This is an example of the AnalogMultiplex class. It prints the states of all
3 | * 16 switches connected to a multiplexers to the serial monitor.
4 | *
5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
6 | *
7 | * Connections
8 | * -----------
9 | *
10 | * - 2: CD74HC4067 signal pin ("common input/output")
11 | * - 3: CD74HC4067 address pin S0
12 | * - 4: CD74HC4067 address pin S1
13 | * - 5: CD74HC4067 address pin S2
14 | * - 6: CD74HC4067 address pin S3
15 | *
16 | * Optionally you can connect the enable pin as well, this is useful
17 | * if you want to use multiple multiplexers with the same address
18 | * lines and the same analog input. Otherwise, just connect the enable
19 | * pin to ground.
20 | *
21 | * If you are using a 3-bit multiplexer, like the CD74HC4051, you can
22 | * uncomment the code specific to this multiplexer, and use only three
23 | * address pins.
24 | *
25 | * Connect a switch or push button between each input pin of the multiplexer and
26 | * ground. A pull-up resistor is not necessary, because we'll use the internal
27 | * one.
28 | *
29 | * Behavior
30 | * --------
31 | *
32 | * Open the serial monitor (CTRL+SHIFT+M) or the serial plotter (CTRL+SHIFT+L),
33 | * and press some buttons, you should see all 16 signals printed or plotted.
34 | *
35 | * Written by Pieter P, 2019-08-08
36 | * https://github.com/tttapa/Arduino-Helpers
37 | */
38 |
39 | #include // Include the Arduino Helpers library
40 | #include
41 |
42 | // Instantiate a multiplexer
43 | CD74HC4067 mux {
44 | 2, // input pin
45 | {3, 4, 5, 6}, // Address pins S0, S1, S2, S3
46 | // 7, // Optionally, specify the enable pin
47 | };
48 |
49 | // Alternatively, if you have a 3-bit mux:
50 | // CD74HC4051 mux {
51 | // 2,
52 | // {3, 4, 5},
53 | // // 7, // Optional
54 | // };
55 |
56 | void setup() {
57 | Serial.begin(115200);
58 | mux.begin(); // Initialize multiplexer
59 | mux.pinMode(0, INPUT_PULLUP); // Set the pin mode (setting it for one pin of
60 | // the multiplexers sets it for all of them)
61 | }
62 |
63 | void loop() {
64 | for (pin_t pin = 0; pin < mux.getLength(); ++pin) {
65 | Serial.print(mux.digitalRead(pin));
66 | Serial.print('\t');
67 | }
68 | Serial.println();
69 | }
70 |
71 | // A more fancy approach could be to use a range-based for loop
72 | void loop2() {
73 | for (pin_t pin : mux.pins()) {
74 | Serial.print(digitalRead(pin));
75 | Serial.print('\t');
76 | }
77 | Serial.println();
78 | }
79 | // Okay, it's a bit slower, because it has to look up what ExtIO device the pin
80 | // belongs to, but hey, it's nice to have it anyway
81 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Hardware/Extended Input & Output/1. Input/1. Multiplexers/3.FilteredAnalogReadSerial/3.FilteredAnalogReadSerial.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This is an example of the AnalogMultiplex and the FilteredAnalog classes.
3 | * It prints the filtered values of all 16 inputs of a multiplexers to the
4 | * serial monitor.
5 | *
6 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
7 | *
8 | * Connections
9 | * -----------
10 | *
11 | * - A0: CD74HC4067 signal pin ("common input/output")
12 | * - 3: CD74HC4067 address pin S0
13 | * - 4: CD74HC4067 address pin S1
14 | * - 5: CD74HC4067 address pin S2
15 | * - 6: CD74HC4067 address pin S3
16 | *
17 | * Optionally you can connect the enable pin as well, this is useful
18 | * if you want to use multiple multiplexers with the same address
19 | * lines and the same analog input. Otherwise, just connect the enable
20 | * pin to ground.
21 | *
22 | * If you are using a 3-bit multiplexer, like the CD74HC4051, you can
23 | * uncomment the code specific to this multiplexer, and use only three
24 | * address pins.
25 | *
26 | * Behavior
27 | * --------
28 | *
29 | * Connect some potentiometers or other analog sensors to the 16 inputs
30 | * of the multiplexer, and open the serial monitor (CTRL+SHIFT+M) or the
31 | * serial plotter (CTRL+SHIFT+L). You should see all 16 signals printed
32 | * or plotted.
33 | *
34 | * Written by Pieter P, 09-04-2019
35 | * https://github.com/tttapa/Arduino-Helpers
36 | */
37 |
38 | #include // Include the Arduino Helpers library
39 |
40 | #include
41 | #include
42 | #include // copyAs<>
43 |
44 | // Instantiate a multiplexer
45 | CD74HC4067 mux {
46 | A0, // analog pin
47 | {3, 4, 5, 6}, // Address pins S0, S1, S2, S3
48 | // 7, // Optionally, specify the enable pin
49 | };
50 |
51 | // Alternatively, if you have a 3-bit mux:
52 | // CD74HC4051 mux {
53 | // A0,
54 | // {3, 4, 5},
55 | // // 7, // Optional
56 | // };
57 |
58 | // Convert the list of pins of the multiplexer to an array
59 | // of FilteredAnalog objects.
60 | auto filteredAnalogs = copyAs>(mux.pins());
61 |
62 | void setup() {
63 | Serial.begin(115200);
64 | mux.begin(); // Initialize multiplexer
65 | }
66 |
67 | void loop() {
68 | // Loop over all FilteredAnalog objects in the array
69 | for (auto &analog : filteredAnalogs) {
70 | analog.update(); // actually read the analog value and filter it
71 | Serial.print(analog.getValue());
72 | Serial.print('\t');
73 | }
74 | Serial.println();
75 | }
76 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Hardware/Extended Input & Output/2. Output/1. Shift Registers/1.SPI-Blink/1.SPI-Blink.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This example demonstrates the use of shift registers as if they were just
3 | * normal IO pins. The SPI interface is used because it's easy and fast.
4 | *
5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
6 | *
7 | * Connections
8 | * -----------
9 | *
10 | * - SS: 74HC595 ST_CP
11 | * - MOSI: 74HC595 DS
12 | * - SCK: 74HC595 SH_CP
13 | *
14 | * Connect an LED (and series resistor) between the first output of the
15 | * shift register and ground.
16 | *
17 | * Remember to connect the enable pin of the shift register to ground and the
18 | * master reset pin to Vcc in order to enable it.
19 | *
20 | * Behavior
21 | * --------
22 | *
23 | * This sketch will blink the LED once a second.
24 | *
25 | * Written by PieterP, 2018-09-01
26 | * https://github.com/tttapa/Arduino-Helpers
27 | */
28 |
29 | #include // Include the Arduino Helpers library.
30 | #include
31 |
32 | using namespace ExtIO; // Bring the ExtIO pin functions into your sketch
33 |
34 | // Instantiate a shift register with the SPI slave select pin as latch pin, most
35 | // significant bit first, and a total of 8 outputs.
36 | SPIShiftRegisterOut<8> sreg {SPI, SS, MSBFIRST};
37 |
38 | const pin_t ledPin = sreg.pin(0); // first pin of the shift register
39 |
40 | void setup() {
41 | sreg.begin(); // Initialize the shift registers
42 | pinMode(ledPin, OUTPUT); // You don't even need this line, since
43 | // shift registers are always outputs
44 | }
45 |
46 | void loop() {
47 | // Toggle the state of the LED every 1/2 second
48 | digitalWrite(ledPin, HIGH);
49 | delay(500);
50 | digitalWrite(ledPin, LOW);
51 | delay(500);
52 | }
53 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Hardware/Extended Input & Output/2. Output/1. Shift Registers/2.BitBang-Blink/2.BitBang-Blink.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This example demonstrates the use of shift registers as if they were just
3 | * normal IO pins. This version uses bit-banging to drive the shift register.
4 | * You should probably be using the SPI version instead.
5 | *
6 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
7 | *
8 | * Connections
9 | * -----------
10 | *
11 | * - 10: 74HC595 ST_CP
12 | * - 11: 74HC595 DS
13 | * - 13: 74HC595 SH_CP
14 | *
15 | * Connect an LED (and series resistor) between the first output of the
16 | * shift register and ground.
17 | *
18 | * Remember to connect the enable pin the shift register to ground and the
19 | * master reset pin to Vcc in order to enable it.
20 | *
21 | * Behavior
22 | * --------
23 | *
24 | * This sketch will blink the LED once a second.
25 | *
26 | * Written by PieterP, 2018-09-01
27 | * https://github.com/tttapa/Arduino-Helpers
28 | */
29 |
30 | #include // Include the Arduino Helpers library.
31 | #include
32 |
33 | using namespace ExtIO; // Bring the ExtIO pin functions into your sketch
34 |
35 | const pin_t latchPin = 10; // Pin connected to ST_CP of 74HC595
36 | const pin_t dataPin = 11; // Pin connected to DS of 74HC595
37 | const pin_t clockPin = 13; // Pin connected to SH_CP of 74HC595
38 |
39 | // Instantiate a shift register on the correct pins, most significant bit first,
40 | // and a total of 8 outputs.
41 | ShiftRegisterOut<8> sreg {dataPin, clockPin, latchPin, MSBFIRST};
42 |
43 | const pin_t ledPin = sreg.pin(0); // first pin of the shift register
44 |
45 | void setup() {
46 | sreg.begin(); // Initialize the shift registers
47 | pinMode(ledPin, OUTPUT); // You don't even need this line, since
48 | // shift registers are always outputs
49 | }
50 |
51 | void loop() {
52 | // Toggle the state of the LED every 1/2 second
53 | digitalWrite(ledPin, HIGH);
54 | delay(500);
55 | digitalWrite(ledPin, LOW);
56 | delay(500);
57 | }
58 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Hardware/Extended Input & Output/2. Output/2. MAX7219/1.MAX7219-Blink/1.MAX7219-Blink.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This example demonstrates the use of MAX7219 LED outputs as if they were just
3 | * normal IO pins, using `digitalWrite`.
4 | *
5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
6 | *
7 | * Connections
8 | * -----------
9 | *
10 | * - SS: MAX7219 CS
11 | * - MOSI: MAX7219 DIN
12 | * - SCK: MAX7219 CLK
13 | *
14 | * Behavior
15 | * --------
16 | *
17 | * This sketch will blink the first and the last LEDs once a second, in an
18 | * alternating pattern.
19 | *
20 | * Written by PieterP, 2020-03-24
21 | * https://github.com/tttapa/Arduino-Helpers
22 | */
23 |
24 | #include // Include the Arduino Helpers library.
25 | #include
26 |
27 | using namespace ExtIO; // Bring the ExtIO pin functions into your sketch
28 |
29 | // Instantiate a MAX7219 with the SPI slave select pin as latch pin
30 | // There's just 1 MAX7219 in the chain, if you have more of them daisy-chained
31 | // together, you can increase the template argument (between angled brackets)
32 | MAX7219<1> max7219 {SPI, SS};
33 |
34 | const pin_t ledPin1 = max7219.pin(0); // first LED of the MAX7219
35 | const pin_t ledPin2 = max7219.pin(63); // last LED of the MAX7219
36 |
37 | void setup() {
38 | max7219.begin(); // Initialize the shift registers
39 | pinMode(ledPin1, OUTPUT); // You don't even need this line, since
40 | pinMode(ledPin2, OUTPUT); // since the MAX7219's pins are always outputs
41 | }
42 |
43 | void loop() {
44 | // Toggle the state of the LEDs every 1/2 second
45 | digitalWrite(ledPin1, HIGH);
46 | digitalWrite(ledPin2, LOW);
47 | delay(500);
48 | digitalWrite(ledPin1, LOW);
49 | digitalWrite(ledPin2, HIGH);
50 | delay(500);
51 | }
52 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Hardware/Extended Input & Output/3. In&Out/MCP23017/MCP23017.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This example demonstrates the use of MCP23017 IO expanders as if they were
3 | * just normal IO pins.
4 | *
5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
6 | *
7 | * Connections
8 | * -----------
9 | *
10 | * - SDA: MCP23017 SDA
11 | * - SCK: MCP23017 SCK
12 | * - 2: MCP23017 INT A or INT B
13 | *
14 | * Connect an LED (and series resistor) between pin GPA0 of the MCP and ground.
15 | * Connect a push button between pin GPB0 of the MCP and ground. The internal
16 | * pull-up resistor will be used.
17 | *
18 | * Tie the three address lines of the MCP to ground.
19 | *
20 | * Behavior
21 | * --------
22 | *
23 | * When the push button is pressed, the LED turns on.
24 | *
25 | * Written by PieterP, 2020-11-20
26 | * https://github.com/tttapa/Arduino-Helpers
27 | */
28 |
29 | #include
30 |
31 | #include
32 |
33 | #include
34 |
35 | using namespace ExtIO; // Use the extended input/output functions
36 |
37 | using WireType = decltype(Wire); // The type of the I²C driver to use
38 | MCP23017 mcp {
39 | Wire, // The I²C driver to use
40 | 0x0, // The I²C address offset (depends on the state of the address pins)
41 | 2, // Optional: interrupt pin to detect input changes
42 | };
43 |
44 | pin_t ledPin = mcp.pinA(0); // GPIOA0
45 | pin_t buttonPin = mcp.pinB(0); // GPIOB0
46 |
47 | void setup() {
48 | Wire.begin(); // Initialize the I²C interface
49 | Wire.setClock(800000); // Faster I²C clock
50 | mcp.begin(); // Initialize the MCP23017
51 |
52 | pinMode(ledPin, OUTPUT);
53 | pinMode(buttonPin, INPUT_PULLUP);
54 | }
55 |
56 | void loop() {
57 | auto buttonState = digitalRead(buttonPin);
58 | digitalWrite(ledPin, buttonState ? LOW : HIGH);
59 | }
60 |
61 | // Note:
62 | // The “interrupt” pin is not used to trigger an actual interrupt on the
63 | // microcontroller. It is just used to check whether any of the inputs of
64 | // the MCP23017 changed without having to do an I²C transaction. Using this
65 | // pin can speed up your code, but it's not necessary, you can leave it out
66 | // in the MCP23017 construction at the top of the sketch.
67 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Hardware/Pin-Change-Interrupt-Encoders/Pin-Change-Interrupt-Encoders.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This example reads multiple encoders using pin change interrupts, on an
3 | * Arduino Uno or Nano.
4 | *
5 | * @boards AVR
6 | *
7 | * The ATmega328P microcontroller only has two interrupt pins (2 and 3), so if
8 | * you want to use more than two interrupt-driven encoders, you'll either have
9 | * to use a timer interrupt to continuously poll the encoders, or use the chip's
10 | * pin change interrupts. This example demonstrates the latter.
11 | *
12 | * @see @ref Timer-Interrupt-Encoders.ino
13 | *
14 | * Familiarity with [direct port manipulation](https://www.arduino.cc/en/Reference/PortManipulation)
15 | * is assumed.
16 | *
17 | * Connections
18 | * -----------
19 | *
20 | * Connect three encoders to the pins of port C as follows:
21 | *
22 | * - A0: pin A of encoder #0
23 | * - A1: pin B of encoder #0
24 | * - A2: pin A of encoder #1
25 | * - A3: pin B of encoder #1
26 | * - A4: pin A of encoder #2
27 | * - A5: pin B of encoder #2
28 | *
29 | * Connect the common pins to ground, the internal pull-up resistors will be
30 | * enabled.
31 | *
32 | * Behavior
33 | * --------
34 | *
35 | * When the position of one of the encoders changes, it is printed to the Serial
36 | * monitor.
37 | *
38 | * Written by PieterP, 2021-08-11
39 | * https://github.com/tttapa/Arduino-Helpers
40 | */
41 |
42 | #include
43 | #include
44 |
45 | // The number of encoders to read:
46 | constexpr uint8_t num_enc = 3;
47 | // Mask the bottom 6 bits of the GPIO registers (2 pins × 3 encoders).
48 | // This determines which pins are used:
49 | const uint8_t pin_mask = 0x3F;
50 | // The actual encoder object that keeps track of the encoder state:
51 | RegisterEncoders encoders;
52 | // AVR uses 8-bit GPIO registers, so the register type is uint8_t.
53 | // Then we specify the number of encoders, the position type,
54 | // and whether the encoders should be interrupt-safe: since we'll
55 | // be calling `encoders.update()` in an interrupt handler, it is
56 | // important that this is set to true.
57 |
58 | // Pin change interrupt handler that reads the pins and updates the state:
59 | ISR (PCINT1_vect) { encoders.update(PINC & pin_mask); } // read port C
60 |
61 | void setup() {
62 | PCMSK1 |= pin_mask; // enable pin change interrupt for given pins in port C
63 | DDRC &= ~pin_mask; // input mode for port C
64 | PORTC |= pin_mask; // enable pull-up resistors for port C
65 | PCICR |= 1 << 1; // enable pin change interrupt for port C
66 | Serial.begin(115200);
67 | }
68 |
69 | void loop() {
70 | // The previous position of each encoder, to detect changes:
71 | static int32_t prevPos[num_enc] {};
72 |
73 | // Read the encoder positions and print if they changed:
74 | for (uint8_t i = 0; i < num_enc; ++i) {
75 | int32_t newPos = encoders[i].read();
76 | if (newPos != prevPos[i]) {
77 | Serial << '[' << i << "] " << newPos << endl;
78 | prevPos[i] = newPos;
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Hardware/Timer-Interrupt-Encoders/Timer-Interrupt-Encoders.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This example reads multiple encoders using a timer interrupt, on an
3 | * Arduino Uno or Nano.
4 | *
5 | * @boards AVR
6 | *
7 | * The ATmega328P microcontroller only has two interrupt pins (2 and 3), so if
8 | * you want to use more than two interrupt-driven encoders, you'll either have
9 | * to use a timer interrupt to continuously poll the encoders, or use the chip's
10 | * pin change interrupts. This example demonstrates the former.
11 | *
12 | * @see @ref Pin-Change-Interrupt-Encoders.ino
13 | *
14 | * Familiarity with [direct port manipulation](https://www.arduino.cc/en/Reference/PortManipulation)
15 | * is assumed.
16 | *
17 | * Connections
18 | * -----------
19 | *
20 | * Connect three encoders to the pins of port C as follows:
21 | *
22 | * - A0: pin A of encoder #0
23 | * - A1: pin B of encoder #0
24 | * - A2: pin A of encoder #1
25 | * - A3: pin B of encoder #1
26 | * - A4: pin A of encoder #2
27 | * - A5: pin B of encoder #2
28 | *
29 | * Connect the common pins to ground, the internal pull-up resistors will be
30 | * enabled.
31 | *
32 | * Behavior
33 | * --------
34 | *
35 | * When the position of one of the encoders changes, it is printed to the Serial
36 | * monitor.
37 | *
38 | * Written by PieterP, 2021-08-11
39 | * https://github.com/tttapa/Arduino-Helpers
40 | */
41 |
42 | #include
43 | #include
44 | #include "TimerHelpers.hpp"
45 |
46 | // The number of encoders to read:
47 | constexpr uint8_t num_enc = 3;
48 | // Mask the bottom 6 bits of the GPIO registers (2 pins × 3 encoders).
49 | // This determines which pins are used:
50 | const uint8_t pin_mask = 0x3F;
51 | // The actual encoder object that keeps track of the encoder state:
52 | RegisterEncoders encoders;
53 | // AVR uses 8-bit GPIO registers, so the register type is uint8_t.
54 | // Then we specify the number of encoders, the position type,
55 | // and whether the encoders should be interrupt-safe: since we'll
56 | // be calling `encoders.update()` in an interrupt handler, it is
57 | // important that this is set to true.
58 |
59 | // Timer interrupt handler that reads the pins and updates the state:
60 | ISR (TIMER2_COMPA_vect) { encoders.update(PINC & pin_mask); } // read port C
61 |
62 | void setup() {
63 | DDRC &= ~pin_mask; // input mode for port C
64 | PORTC |= pin_mask; // enable pull-up resistors for port C
65 | setTimer2Prescaler(Timer2Prescaler::S8);
66 | setTimer2WGMode(Timer2WGMode::CTC);
67 | OCR2A = 250 - 1; // 8 kHz poll rate (if FCPU = 16'000'000)
68 | bitSet(TIMSK2, OCIE2A); // Timer2 Compare A Match Interrupt Enable
69 | Serial.begin(115200);
70 | }
71 |
72 | void loop() {
73 | // The previous position of each encoder, to detect changes:
74 | static int32_t prevPos[num_enc] {};
75 |
76 | // Read the encoder positions and print if they changed:
77 | for (uint8_t i = 0; i < num_enc; ++i) {
78 | int32_t newPos = encoders[i].read();
79 | if (newPos != prevPos[i]) {
80 | Serial << '[' << i << "] " << newPos << endl;
81 | prevPos[i] = newPos;
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Hardware/Timer-Interrupt-Encoders/TimerHelpers.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | /// Timer 2 clock select (Table 17-9).
4 | enum class Timer2Prescaler : uint8_t {
5 | None = 0b000,
6 | S1 = 0b001,
7 | S8 = 0b010,
8 | S32 = 0b011,
9 | S64 = 0b100,
10 | S128 = 0b101,
11 | S256 = 0b110,
12 | S1024 = 0b111,
13 | Invalid = 0xFF,
14 | };
15 |
16 | /// Convert the prescaler factor to the correct bit pattern to write to the
17 | /// TCCR0B register (Table 17-9).
18 | constexpr inline Timer2Prescaler factorToTimer2Prescaler(uint16_t factor) {
19 | return factor == 1 ? Timer2Prescaler::S1
20 | : factor == 8 ? Timer2Prescaler::S8
21 | : factor == 32 ? Timer2Prescaler::S32
22 | : factor == 64 ? Timer2Prescaler::S64
23 | : factor == 128 ? Timer2Prescaler::S128
24 | : factor == 256 ? Timer2Prescaler::S256
25 | : factor == 1024 ? Timer2Prescaler::S1024
26 | : Timer2Prescaler::Invalid;
27 | }
28 |
29 | /// Timer 2 waveform generation mode (Table 17-8).
30 | enum class Timer2WGMode : uint8_t {
31 | Normal = 0b000,
32 | PWM = 0b001,
33 | CTC = 0b010,
34 | FastPWM = 0b011,
35 | PWM_OCRA = 0b101,
36 | FastPWM_OCRA = 0b111,
37 | };
38 |
39 | /// Set the clock source/prescaler of Timer2 (Table 17-9).
40 | inline void setTimer2Prescaler(Timer2Prescaler ps) {
41 | if (ps == Timer2Prescaler::Invalid)
42 | return;
43 | bitWrite(TCCR2B, CS22, (static_cast(ps) >> 2) & 1);
44 | bitWrite(TCCR2B, CS21, (static_cast(ps) >> 1) & 1);
45 | bitWrite(TCCR2B, CS20, (static_cast(ps) >> 0) & 1);
46 | }
47 |
48 | /// Set the wavefrom generation mode of Timer2 (Table 17-8).
49 | inline void setTimer2WGMode(Timer2WGMode mode) {
50 | bitWrite(TCCR2B, WGM22, (static_cast(mode) >> 2) & 1);
51 | bitWrite(TCCR2A, WGM21, (static_cast(mode) >> 1) & 1);
52 | bitWrite(TCCR2A, WGM20, (static_cast(mode) >> 0) & 1);
53 | }
54 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Math/Quaternion/Quaternion.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * Simple Quaternion test.
3 | *
4 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
5 | *
6 | * Written by PieterP, 2020-03-24
7 | * https://github.com/tttapa/Arduino-Helpers
8 | */
9 |
10 | #include
11 |
12 | #include
13 | #include
14 |
15 | bool close(float actual, float expected, float atol) {
16 | return std::abs(actual - expected) <= atol;
17 | }
18 |
19 | void setup() {
20 | Serial.begin(115200);
21 |
22 | Vec3f vector {-0.414578098794425, 0.829156197588850, 0.375000000000000};
23 | Quaternion result = Quaternion::fromDirection(vector);
24 | Quaternion expected {0.829156197588850, -0.5, -0.25, 0.0};
25 | float atol = 1e-7;
26 |
27 | Serial << setprecision(7) << "Result = " << result << endl;
28 |
29 | Serial << boolalpha;
30 | Serial << close(result.w, expected.w, atol) << endl;
31 | Serial << close(result.x, expected.x, atol) << endl;
32 | Serial << close(result.y, expected.y, atol) << endl;
33 | Serial << close(result.z, expected.z, atol) << endl;
34 |
35 | // Make sure it satisfies the definition of `fromDirection()`.
36 | Vec3f diff = result.rotate({0, 0, 1}) - vector.normalized();
37 | Serial << close(diff.norm(), 0, atol) << endl;
38 | }
39 |
40 | void loop() {}
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/STL/ArraySort/ArraySort.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * Example of using the standard library algorithms.
3 | *
4 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
5 | *
6 | * This sketch creates an array with an unordered sequence of 10 numbers.
7 | * It prints the array, and then creates a reverse view on the 6 elements in the
8 | * middle of the array and sorts it.
9 | * The resulting array has the same elements in the 4 outermost places, but the
10 | * 6 elements in the middle have been sorted in reverse order.
11 | *
12 | * **Output**
13 | * ~~~
14 | * Before sorting: 3, 5, 9, 2, 1, 8, 6, 4, 7, 0
15 | * Sorting ├─────────────────┤ in ascending order
16 | * After sorting: 3, 5, 1, 2, 4, 6, 8, 9, 7, 0
17 | * Sorting ├─────────────────┤ in descending order
18 | * After sorting: 3, 5, 9, 8, 6, 4, 2, 1, 7, 0
19 | * ~~~
20 | *
21 | * Written by PieterP, 2019-11-12
22 | * https://github.com/tttapa/Arduino-Helpers
23 | */
24 |
25 | #include
26 |
27 | #include // Array
28 | #include // For printing the array
29 | #include // std::sort
30 |
31 | void setup() {
32 | Serial.begin(115200);
33 | while (!Serial)
34 | ;
35 |
36 | Array array {3, 5, 9, 2, 1, 8, 6, 4, 7, 0};
37 |
38 | Serial << "Before sorting: " << array << endl;
39 |
40 | Serial << " Sorting ├─────────────────┤ in ascending order"
41 | << endl;
42 |
43 | // select elements 2 through 7 (inclusive)
44 | auto forward_view = array.slice<2, 7>();
45 | // sort the view in ascending order
46 | std::sort(std::begin(forward_view), std::end(forward_view));
47 |
48 | Serial << "After sorting: " << array << endl;
49 | Serial << " Sorting ├─────────────────┤ in descending order"
50 | << endl;
51 |
52 | // select elements 2 through 7 (inclusive) in reverse order
53 | auto reverse_view = array.slice<7, 2>();
54 | // sort the reverse view in ascending order (this means that the original
55 | // array is sorted in descending order)
56 | std::sort(std::begin(reverse_view), std::end(reverse_view));
57 |
58 | Serial << "After sorting: " << array << endl;
59 | }
60 |
61 | void loop() {}
62 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/STL/Complex/Complex.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * Example of using the standard library complex numbers.
3 | *
4 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
5 | *
6 | * **Output**
7 | * ~~~
8 | * √(2i) = (1.00,1.00)
9 | * ~~~
10 | *
11 | * Written by PieterP, 2019-11-14
12 | * https://github.com/tttapa/Arduino-Helpers
13 | */
14 |
15 | #include
16 |
17 | #include
18 |
19 | void setup() {
20 | Serial.begin(115200);
21 | while (!Serial)
22 | ;
23 |
24 | // Create a complex number
25 | std::complex c{0, 2};
26 |
27 | // Print the square root
28 | Serial << "√(2i) = " << std::sqrt(c) << endl;
29 | }
30 |
31 | void loop() {}
32 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/STL/CountPressedButtons/CountPressedButtons.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * Example of using the standard library algorithms and the Button class.
3 | *
4 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
5 | *
6 | * This sketch reads a number of push buttons or switches, and uses the standard
7 | * library algorithms to count how many of them are pressed.
8 | *
9 | * The internal pull-up resistors are enabled and the switches are debounced.
10 | *
11 | * Written by PieterP, 2019-11-24
12 | * https://github.com/tttapa/Arduino-Helpers
13 | */
14 | #include
15 |
16 | #include // Button
17 | #include // std::accumulate
18 |
19 | // An array of debounced buttons connected to the given pins
20 | Button buttons[] {
21 | 2, 3, 4, 5, 6, 7, 8, 9,
22 | };
23 |
24 | void setup() {
25 | for (auto &button : buttons) // for all buttons in the array
26 | button.begin(); // initialize (enable internal pull-up resistor)
27 | Serial.begin(115200);
28 | }
29 |
30 | void loop() {
31 | // function that adds one to the counter if the given button is pressed
32 | auto addOneIfPressed = [](unsigned count, const Button &button) {
33 | return button.getState() == Button::Pressed ? count + 1 : count;
34 | };
35 |
36 | // read all buttons and debounce them
37 | for (auto &button : buttons)
38 | button.update();
39 |
40 | // apply that function to all buttons and return the count
41 | unsigned pressed =
42 | std::accumulate(std::begin(buttons), // from the first button
43 | std::end(buttons), // to the last
44 | 0u, // initial value of the counter
45 | addOneIfPressed); // counter function to apply
46 |
47 | Serial.println(pressed);
48 | }
49 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/STL/Numeric/Numeric.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * Example of using the standard library numeric functions.
3 | *
4 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
5 | *
6 | * This sketch creates an incremental array using the iota function, then
7 | * computes the inner product of the vector with itself, and uses that to
8 | * calculate the norm of the vector.
9 | *
10 | * **Output**
11 | * ~~~
12 | * v = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
13 | * 〈v, v〉 = 385
14 | * ‖v‖ = 19.6214160
15 | * ~~~
16 | *
17 | * Written by PieterP, 2019-11-18
18 | * https://github.com/tttapa/Arduino-Helpers
19 | */
20 |
21 | #include
22 |
23 | #include // Array
24 | #include // For printing the array
25 | #include // std::sqrt
26 | #include // std::iota, std::inner_product
27 |
28 | void setup() {
29 | Serial.begin(115200);
30 | while (!Serial)
31 | ;
32 |
33 | // Create an array with the elements [1, 2 ... 9, 10]
34 | Array vector;
35 | std::iota(std::begin(vector), std::end(vector), 1);
36 | Serial << "v = [" << vector << ']' << endl;
37 |
38 | // Compute the inner product of vector with itself, with an initial sum of 0
39 | int sum_sq = std::inner_product(std::begin(vector), std::end(vector),
40 | std::begin(vector), 0);
41 | Serial << "〈v, v〉 = " << sum_sq << endl;
42 |
43 | // The 2-norm of a vector is the squareroot of the inner product with itself
44 | double norm = std::sqrt(sum_sq);
45 | Serial << "‖v‖ = " << setprecision(7) << norm << endl;
46 | }
47 |
48 | void loop() {}
49 |
--------------------------------------------------------------------------------
/examples/Arduino-Helpers/Timing/BlinkWithoutDelay-Timer/BlinkWithoutDelay-Timer.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This examples shows how use the Timer class to blink an LED every
3 | * second, in a non-blocking fashion (without using delay).
4 | *
5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Due, Teensy 3.x, ESP8266, ESP32
6 | *
7 | * Behavior
8 | * --------
9 | *
10 | * Blinks the built-in LED every second.
11 | *
12 | * Written by PieterP, 2019-12-06
13 | * https://github.com/tttapa/Arduino-Helpers
14 | */
15 |
16 | #include
17 | #include
18 |
19 | Timer timer = 500; // milliseconds
20 |
21 | void setup() {
22 | pinMode(LED_BUILTIN, OUTPUT);
23 | }
24 |
25 | void loop() {
26 | if (timer) {
27 | digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) ? LOW : HIGH);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/examples/test/ExtIO-pin-test/ExtIO-pin-test.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * An int literal as argument or constants like LED_BUILTIN should not result
3 | * in ambiguous overload selection.
4 | *
5 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Teensy 3.x, ESP8266, ESP32
6 | */
7 |
8 | #include
9 |
10 | #include
11 |
12 | using namespace ExtIO;
13 |
14 | void setup() {
15 | pinMode(13, OUTPUT);
16 | pinMode(LED_BUILTIN, OUTPUT);
17 | }
18 |
19 | void loop() {}
--------------------------------------------------------------------------------
/examples/test/STL-test/STL-test.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, UNO R4, Pi Pico, Teensy 3.x, ESP8266, ESP32
3 | */
4 | #include
--------------------------------------------------------------------------------
/library.properties:
--------------------------------------------------------------------------------
1 | name=Arduino Helpers
2 | version=2.0.0
3 | author=Pieter P
4 | maintainer=Pieter P
5 | sentence=This is a utility library with hardware abstraction, containers, type traits, easy printing, debugging, filters ... Includes a mocking and testing framework.
6 | paragraph=Originally part of the Control Surface library, split off to be used in other libraries as well, or stand-alone.
7 | category=Other
8 | url=https://github.com/tttapa/Arduino-Helpers
9 | architectures=avr,sam,samd,teensy,esp32,esp8266,megaavr,mbed,mbed_nano,mbed_rp2040,renesas_uno
10 | includes=Arduino_Helpers.h
11 |
--------------------------------------------------------------------------------
/mock/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | find_package(GTest REQUIRED CONFIG)
2 |
3 | add_library(ArduinoMock
4 | "Core/Arduino.cpp"
5 | "Core/ArduinoMock.cpp"
6 | "Core/HardwareSerial0.cpp"
7 | "Core/Print.cpp"
8 | )
9 | target_include_directories(ArduinoMock PUBLIC
10 | ${CMAKE_CURRENT_SOURCE_DIR}/Core
11 | ${CMAKE_CURRENT_SOURCE_DIR}/Core-Libraries
12 | ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/Adafruit_GFX
13 | ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/Adafruit_SSD1306
14 | ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/Encoder)
15 | target_link_libraries(ArduinoMock
16 | PUBLIC GTest::gtest GTest::gmock
17 | PRIVATE Arduino-Helpers::warnings)
--------------------------------------------------------------------------------
/mock/Core-Libraries/SPI.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | // TODO
4 | class SPIClass {
5 | } extern SPI;
6 |
7 | enum SPIMode {
8 | SPI_MODE0 = 0,
9 | SPI_MODE1 = 1,
10 | SPI_MODE2 = 2,
11 | SPI_MODE3 = 3,
12 | };
13 |
14 | class SPISettings {
15 | public:
16 | SPISettings(uint32_t, BitOrder_t, SPIMode) {}
17 | };
--------------------------------------------------------------------------------
/mock/Core/Arduino.cpp:
--------------------------------------------------------------------------------
1 | #include "Arduino.h"
2 | #include "ArduinoMock.hpp"
3 |
4 | void sei() {}
5 | void cli() {}
6 |
7 | void yield() {}
8 |
9 | void pinMode(uint8_t pin, uint8_t mode) {
10 | ArduinoMock::getInstance().pinMode(pin, mode);
11 | }
12 |
13 | void digitalWrite(uint8_t pin, uint8_t state) {
14 | ArduinoMock::getInstance().digitalWrite(pin, state);
15 | }
16 |
17 | int digitalRead(uint8_t pin) {
18 | return ArduinoMock::getInstance().digitalRead(pin);
19 | }
20 |
21 | int analogRead(uint8_t pin) {
22 | return ArduinoMock::getInstance().analogRead(pin);
23 | }
24 |
25 | void analogReadResolution(uint8_t bits) {
26 | ArduinoMock::getInstance().analogReadResolution(bits);
27 | }
28 |
29 | void analogWrite(uint8_t pin, int value) {
30 | ArduinoMock::getInstance().analogWrite(pin, value);
31 | }
32 |
33 | void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder,
34 | uint8_t val) {
35 | ArduinoMock::getInstance().shiftOut(dataPin, clockPin, bitOrder, val);
36 | }
37 |
38 | unsigned long millis() { return ArduinoMock::getInstance().millis(); }
39 |
40 | unsigned long micros() { return ArduinoMock::getInstance().micros(); }
--------------------------------------------------------------------------------
/mock/Core/ArduinoMock.cpp:
--------------------------------------------------------------------------------
1 | #include "ArduinoMock.hpp"
2 |
3 | ArduinoMock *ArduinoMock::instance = nullptr;
4 |
5 | ArduinoMock &ArduinoMock::getInstance() {
6 | if (instance == nullptr)
7 | throw std::runtime_error("Error: no active ArduinoMock instance.");
8 | return *instance;
9 | }
10 | void ArduinoMock::begin() {
11 | if (instance != nullptr)
12 | throw std::runtime_error("Error: ArduinoMock instance already active.");
13 | instance = new ArduinoMock;
14 | }
15 | void ArduinoMock::end() {
16 | if (instance == nullptr)
17 | throw new std::runtime_error("Error: no acitve ArduinoMock instance.");
18 | delete instance;
19 | instance = nullptr;
20 | }
21 |
22 | SerialHelper &ArduinoMock::getSerial() {
23 | return getInstance().serial;
24 | }
--------------------------------------------------------------------------------
/mock/Core/ArduinoMock.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "HardwareSerial.h"
4 |
5 | class ArduinoMock {
6 | private:
7 | ArduinoMock() {}
8 | SerialHelper serial;
9 | static ArduinoMock *instance;
10 |
11 | public:
12 | static ArduinoMock &getInstance();
13 | static void begin();
14 | static void end();
15 | static SerialHelper &getSerial();
16 |
17 | MOCK_METHOD(void, pinMode, (uint8_t, uint8_t));
18 | MOCK_METHOD(void, digitalWrite, (uint8_t, uint8_t));
19 | MOCK_METHOD(int, digitalRead, (uint8_t));
20 | MOCK_METHOD(int, analogRead, (uint8_t));
21 | MOCK_METHOD(void, analogReadResolution, (uint8_t));
22 | MOCK_METHOD(void, analogWrite, (uint8_t, int));
23 | MOCK_METHOD(void, shiftOut, (uint8_t, uint8_t, uint8_t, uint8_t));
24 |
25 | MOCK_METHOD(unsigned long, millis, ());
26 | MOCK_METHOD(unsigned long, micros, ());
27 |
28 | virtual ~ArduinoMock() = default;
29 | };
--------------------------------------------------------------------------------
/mock/Core/HardwareSerial.h:
--------------------------------------------------------------------------------
1 | /*
2 | HardwareSerial.h - Hardware serial library for Wiring
3 | Copyright (c) 2006 Nicholas Zambetti. All right reserved.
4 |
5 | This library is free software; you can redistribute it and/or
6 | modify it under the terms of the GNU Lesser General Public
7 | License as published by the Free Software Foundation; either
8 | version 2.1 of the License, or (at your option) any later version.
9 |
10 | This library is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | Lesser General Public License for more details.
14 |
15 | You should have received a copy of the GNU Lesser General Public
16 | License along with this library; if not, write to the Free Software
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 |
19 | Modified 28 September 2010 by Mark Sproul
20 | Modified 14 August 2012 by Alarus
21 | Modified 3 December 2013 by Matthijs Kooijman
22 | */
23 |
24 | #ifndef HardwareSerial_h
25 | #define HardwareSerial_h
26 |
27 | #include "Stream.h"
28 | #include
29 |
30 | #ifdef F
31 | #undef F
32 | #endif
33 |
34 | #include
35 |
36 | class SerialHelper {
37 | public:
38 | MOCK_METHOD(void, begin, (unsigned long));
39 | MOCK_METHOD(void, end, ());
40 |
41 | MOCK_METHOD(int, available, ());
42 | MOCK_METHOD(int, read, ());
43 | MOCK_METHOD(int, peek, ());
44 |
45 | MOCK_METHOD(size_t, write, (uint8_t));
46 | MOCK_METHOD(size_t, write, (const uint8_t *, size_t));
47 |
48 | virtual ~SerialHelper() = default;
49 | };
50 |
51 | class HardwareSerial : public Stream {
52 | public:
53 | void begin(unsigned long baud);
54 | void end();
55 |
56 | int available() override;
57 | int read() override;
58 | int peek() override;
59 |
60 | size_t write(uint8_t data) override;
61 | size_t write(const uint8_t *data, size_t len) override;
62 | explicit operator bool() const { return true; }
63 | };
64 |
65 | extern HardwareSerial Serial;
66 |
67 | #ifndef F
68 | #define F(x) (reinterpret_cast(x))
69 | #endif
70 |
71 | #endif
72 |
--------------------------------------------------------------------------------
/mock/Core/HardwareSerial0.cpp:
--------------------------------------------------------------------------------
1 | #include "ArduinoMock.hpp"
2 | #include "HardwareSerial.h"
3 |
4 | void HardwareSerial::begin(unsigned long baud) {
5 | ArduinoMock::getSerial().begin(baud);
6 | }
7 | void HardwareSerial::end() { ArduinoMock::getSerial().end(); }
8 |
9 | int HardwareSerial::available() { return ArduinoMock::getSerial().available(); }
10 | int HardwareSerial::read() { return ArduinoMock::getSerial().read(); }
11 | int HardwareSerial::peek() { return ArduinoMock::getSerial().peek(); }
12 |
13 | size_t HardwareSerial::write(uint8_t data) {
14 | return ArduinoMock::getSerial().write(data);
15 | }
16 | size_t HardwareSerial::write(const uint8_t *data, size_t len) {
17 | return ArduinoMock::getSerial().write(data, len);
18 | }
19 |
20 | HardwareSerial Serial;
--------------------------------------------------------------------------------
/mock/Core/Printable.h:
--------------------------------------------------------------------------------
1 | #ifndef Printable_h
2 | #define Printable_h
3 |
4 | #include
5 |
6 | class Print;
7 |
8 | class Printable {
9 | public:
10 | virtual size_t printTo(Print &p) const = 0;
11 | };
12 |
13 | #include
14 |
15 | inline std::ostream &operator<<(std::ostream &os, const Printable &p) {
16 | OstreamPrint op = os;
17 | p.printTo(op);
18 | return os;
19 | }
20 |
21 | #endif
--------------------------------------------------------------------------------
/mock/Core/Stream.h:
--------------------------------------------------------------------------------
1 | #ifndef Stream_h
2 | #define Stream_h
3 |
4 | #include "Print.h"
5 |
6 | class Stream : public Print {
7 | public:
8 | virtual int read() = 0;
9 | virtual int peek() = 0;
10 | virtual int available() = 0;
11 | };
12 |
13 | #endif
--------------------------------------------------------------------------------
/mock/Libraries/Adafruit_GFX/gfxfont.h:
--------------------------------------------------------------------------------
1 | // Font structures for newer Adafruit_GFX (1.1 and later).
2 | // Example fonts are included in 'Fonts' directory.
3 | // To use a font in your Arduino sketch, #include the corresponding .h
4 | // file and pass address of GFXfont struct to setFont(). Pass NULL to
5 | // revert to 'classic' fixed-space bitmap font.
6 |
7 | #ifndef _GFXFONT_H_
8 | #define _GFXFONT_H_
9 |
10 | /// Font data stored PER GLYPH
11 | typedef struct {
12 | uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap
13 | uint8_t width; ///< Bitmap dimensions in pixels
14 | uint8_t height; ///< Bitmap dimensions in pixels
15 | uint8_t xAdvance; ///< Distance to advance cursor (x axis)
16 | int8_t xOffset; ///< X dist from cursor pos to UL corner
17 | int8_t yOffset; ///< Y dist from cursor pos to UL corner
18 | } GFXglyph;
19 |
20 | /// Data stored for FONT AS A WHOLE
21 | typedef struct {
22 | uint8_t *bitmap; ///< Glyph bitmaps, concatenated
23 | GFXglyph *glyph; ///< Glyph array
24 | uint8_t first; ///< ASCII extents (first char)
25 | uint8_t last; ///< ASCII extents (last char)
26 | uint8_t yAdvance; ///< Newline distance (y axis)
27 | } GFXfont;
28 |
29 | #endif // _GFXFONT_H_
--------------------------------------------------------------------------------
/mock/Libraries/Encoder/Encoder.h:
--------------------------------------------------------------------------------
1 | #ifndef Encoder_h_
2 | #define Encoder_h_
3 |
4 | #include
5 |
6 | class EncoderMock {
7 | public:
8 | MOCK_CONST_METHOD0(read, long());
9 | };
10 |
11 | class Encoder {
12 | public:
13 | Encoder(int, int) : mock{nullptr} {}
14 | Encoder(const EncoderMock &mock) : mock(&mock) {}
15 | Encoder(const Encoder &) = default;
16 | long read() const { return mock ? mock->read() : 0; }
17 |
18 | private:
19 | const EncoderMock *mock;
20 | };
21 |
22 | #endif
--------------------------------------------------------------------------------
/mock/README.md:
--------------------------------------------------------------------------------
1 | # Arduino Mock
2 |
3 | This folder contains a mock version of the Arduino core.
4 |
5 | It provides the standard Arduino API (`digitalWrite`, `millis`, `Serial` etc.)
6 | with mocks that can be used during testing.
--------------------------------------------------------------------------------
/scripts/addImplementationFiles.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | import os
4 | import shutil
5 | from os.path import join, getsize, normpath, basename, splitext, relpath
6 | import sys
7 |
8 | script_dir = os.path.dirname(os.path.realpath(__file__))
9 | src_dir = join(script_dir, "../src")
10 |
11 | template = """\
12 | #ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY
13 | #include "{}"
14 | #endif
15 | """
16 |
17 | def main():
18 | for root, dirs, files in os.walk(src_dir):
19 | for f in files:
20 | name, ext = splitext(f)
21 | if ext == '.cpp':
22 | with open(join(root, f), 'r+') as cpp_file:
23 | num_lines = sum(1 for line in cpp_file)
24 | if num_lines > 1 and num_lines < 5:
25 | print(num_lines)
26 | print(normpath(join(root, f)))
27 |
28 | # if ext == '.cpp':
29 | # with open(join(root, f), 'r+') as cpp_file:
30 | # num_lines = sum(1 for line in cpp_file)
31 | # print(num_lines)
32 | # cpp_file.seek(0)
33 | # content = cpp_file.read()
34 | # if num_lines == 1:
35 | # cpp_file.seek(0)
36 | # cpp_file.write(
37 | # '#ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY\n')
38 | # cpp_file.write(content)
39 | # cpp_file.write('\n#endif')
40 |
41 | if (ext == '.hpp' or ext == '.h') \
42 | and (not (name + '.cpp') in files) \
43 | and (not (name + '.c') in files) \
44 | and (basename(root) != 'Doxygen'):
45 | impl_ext = '.cpp' if ext == '.hpp' else '.c'
46 | with open(join(root, name + impl_ext), 'w') as cpp_file:
47 | cpp_file.write(template.format(f))
48 |
49 |
50 | if __name__ == "__main__":
51 | main()
52 |
--------------------------------------------------------------------------------
/scripts/ci/install-doxygen.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Script to download and install Doxygen
4 |
5 | set -ex
6 |
7 | version="Release_1_9_4" # Release tag on GitHub
8 | prefix="${1:-$HOME/.local}"
9 |
10 | [ -e "$prefix/bin/doxygen" ] \
11 | && exit 0
12 |
13 | mkdir /tmp/doxygen-install
14 | pushd /tmp/doxygen-install
15 |
16 | # Download
17 | [ -d "doxygen" ] \
18 | || git clone --single-branch --depth=1 --branch "$version" \
19 | https://github.com/doxygen/doxygen.git
20 | pushd doxygen
21 | # Configure
22 | cmake -Bbuild -S. \
23 | -DCMAKE_INSTALL_PREFIX="$prefix" \
24 | -DCMAKE_BUILD_TYPE=Release
25 | # Build
26 | cmake --build build -j1
27 | # Install
28 | cmake --install build
29 |
30 | popd
31 | popd
--------------------------------------------------------------------------------
/scripts/ci/install-lcov.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Script to download and install LCOV
4 |
5 | set -ex
6 |
7 | version="v1.15" # Release tag on GitHub
8 | prefix="${1:-$HOME/.local}"
9 |
10 | [ -e "$prefix/bin/lcov" ] \
11 | && exit 0
12 |
13 | mkdir /tmp/lcov-install
14 | pushd /tmp/lcov-install
15 |
16 | # Download
17 | [ -d "lcov" ] \
18 | || git clone --single-branch --depth=1 --branch "$version" \
19 | https://github.com/linux-test-project/lcov.git
20 | pushd lcov
21 | make install PREFIX="$prefix"
22 |
23 | popd
24 | popd
25 |
--------------------------------------------------------------------------------
/scripts/coverage-badge.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | Script that extracts the test coverage percentage and saves it as a JSON
4 | shields.io endpoint.
5 | """
6 |
7 | from os.path import join, normpath, dirname, realpath
8 | import re
9 |
10 | script_dir = dirname(realpath(__file__))
11 | cov_dir = normpath(join(dirname(script_dir), "docs", "Coverage"))
12 |
13 | json = """\
14 | {{
15 | "schemaVersion": 1,
16 | "label": "Test Coverage",
17 | "message": "{linecov}%",
18 | "color": "green"
19 | }}
20 | """
21 |
22 | def main():
23 | with open(join(cov_dir, 'index.html'), 'r') as f:
24 | pattern = r'