diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 00000000..d234b37a --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,5 @@ +paths: + - firmware + - include +paths-ignore: + - .pio/libdeps diff --git a/.github/workflows/build-bhaptics.yml b/.github/workflows/build-bhaptics.yml deleted file mode 100644 index f31fcc3c..00000000 --- a/.github/workflows/build-bhaptics.yml +++ /dev/null @@ -1,222 +0,0 @@ -name: Check bHaptics builds - -on: - pull_request: - branches: - - master - - develop - paths-ignore: - - '**/*.md' - push: - branches: - - master - paths-ignore: - - '**/*.md' - -jobs: - check-build-os: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: - - windows-latest - - ubuntu-latest - - macos-latest - target: - - bhaptics_tactsuit_x40 - - # Enabling all flags to test build for every feature - battery_flag: - - BATTERY_ENABLED=true - serial_plotter_flag: - - SERIAL_PLOTTER=true - - # C'mon, GitHub, give us YAML anchors, it's a basic feature! cc actions/runner#1182 - steps: - - uses: actions/checkout@v3 - - - name: Cache pip - uses: actions/cache@v3 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - - name: Cache PlatformIO - uses: actions/cache@v3 - with: - path: ~/.platformio - key: ${{ runner.os }}-pio-${{ hashFiles('**/lockfiles') }} - restore-keys: | - ${{ runner.os }}-pio- - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.9' - - - name: Update build flags (non-macOS) - if: runner.os != 'macOS' - run: | - sed -i '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.battery_flag }}/' platformio.ini - sed -i '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.serial_plotter_flag }}/' platformio.ini - - - name: Update build flags (macOS) - if: runner.os == 'macOS' - run: | - sed -i '' '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.battery_flag }}/' platformio.ini - sed -i '' '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.serial_plotter_flag }}/' platformio.ini - - - name: Install PlatformIO - run: | - python -m pip install --upgrade pip - pip install --upgrade platformio - pio upgrade --dev - pio pkg update --global - - - name: Build - run: | - echo "::group::platformio.ini" - cat platformio.ini - echo "::endgroup::" - pio run --environment ${{matrix.target}} - - build-flags: - needs: check-build-os - runs-on: ubuntu-latest - strategy: - fail-fast: true - matrix: - target: - # Using x40 as it is uses both ledc and pca9685 outputs - - bhaptics_tactsuit_x40 - battery_flag: - - BATTERY_ENABLED=true - - BATTERY_ENABLED=false - serial_plotter_flag: - - SERIAL_PLOTTER=false - - SERIAL_PLOTTER=true - - steps: - - uses: actions/checkout@v3 - - - name: Cache pip - uses: actions/cache@v3 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - - name: Cache PlatformIO - uses: actions/cache@v3 - with: - path: ~/.platformio - key: ${{ runner.os }}-pio-${{ hashFiles('**/lockfiles') }} - restore-keys: | - ${{ runner.os }}-pio- - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.9' - - - name: Update build flags (non-macOS) - if: runner.os != 'macOS' - run: | - sed -i '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.battery_flag }}/' platformio.ini - sed -i '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.serial_plotter_flag }}/' platformio.ini - - - name: Update build flags (macOS) - if: runner.os == 'macOS' - run: | - sed -i '' '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.battery_flag }}/' platformio.ini - sed -i '' '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.serial_plotter_flag }}/' platformio.ini - - - name: Install PlatformIO - run: | - python -m pip install --upgrade pip - pip install --upgrade platformio - pio upgrade --dev - pio pkg update --global - - - name: Build - run: | - echo "::group::platformio.ini" - cat platformio.ini - echo "::endgroup::" - pio run --environment ${{matrix.target}} - - build-targets: - needs: build-flags - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - target: - - bhaptics_tactsuit_x16 - - bhaptics_tactsuit_x16_pca9685 - - bhaptics_tactsuit_x40 - - bhaptics_tactosy2_forearm_right - - bhaptics_tactosyh_hand_right - - bhaptics_tactosyf_foot_right - - bhaptics_tactal - - bhaptics_tactglove_right - - # Enabling all flags to test build for every feature - battery_flag: - - BATTERY_ENABLED=true - serial_plotter_flag: - - SERIAL_PLOTTER=true - - steps: - - uses: actions/checkout@v3 - - - name: Cache pip - uses: actions/cache@v3 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - - name: Cache PlatformIO - uses: actions/cache@v3 - with: - path: ~/.platformio - key: ${{ runner.os }}-pio-${{ hashFiles('**/lockfiles') }} - restore-keys: | - ${{ runner.os }}-pio- - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.9' - - - name: Update build flags (non-macOS) - if: runner.os != 'macOS' - run: | - sed -i '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.battery_flag }}/' platformio.ini - sed -i '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.serial_plotter_flag }}/' platformio.ini - - - name: Update build flags (macOS) - if: runner.os == 'macOS' - run: | - sed -i '' '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.battery_flag }}/' platformio.ini - sed -i '' '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.serial_plotter_flag }}/' platformio.ini - - - name: Install PlatformIO - run: | - python -m pip install --upgrade pip - pip install --upgrade platformio - pio upgrade --dev - pio pkg update --global - - - name: Build - run: | - echo "::group::platformio.ini" - cat platformio.ini - echo "::endgroup::" - pio run --environment ${{matrix.target}} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..0298c543 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,251 @@ +name: PlatformIO CI + +on: + pull_request: + branches: + - master + - develop + paths-ignore: + - '**/*.md' + push: + branches: + - master + - develop + paths-ignore: + - '**/*.md' + +jobs: + build: + name: Build ${{ matrix.target }} on ${{ matrix.os }} ${{ matrix.coverage && 'with coverage' || 'without coverage' }}, -D ${{ matrix.battery_flag }} -D ${{ matrix.serial_plotter_flag }} -D ${{ matrix.nimble_flag }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest ] + target: + - bhaptics_tactsuit_x16 + - bhaptics_tactsuit_x16_pca9685 + - bhaptics_tactsuit_x40 + - bhaptics_tactosy2_forearm_right + - bhaptics_tactosyh_hand_right + - bhaptics_tactosyf_foot_right + - bhaptics_tactal + - bhaptics_tactglove_right + battery_flag: [ BATTERY_ENABLED=true ] + serial_plotter_flag: [ SERIAL_PLOTTER=false ] + nimble_flag: [ BLUETOOTH_USE_NIMBLE=false ] + coverage: [ false ] + + include: + # Extra tests for x40, as it uses the most features + - target: bhaptics_tactsuit_x40 + os: ubuntu-latest + coverage: true + battery_flag: BATTERY_ENABLED=true + serial_plotter_flag: SERIAL_PLOTTER=true + nimble_flag: BLUETOOTH_USE_NIMBLE=true + # - target: bhaptics_tactsuit_x40 + # os: ubuntu-latest + # coverage: true + # battery_flag: BATTERY_ENABLED=true + # serial_plotter_flag: SERIAL_PLOTTER=true + # nimble_flag: BLUETOOTH_USE_NIMBLE=false + - target: bhaptics_tactsuit_x40 + os: ubuntu-latest + coverage: false + battery_flag: BATTERY_ENABLED=true + serial_plotter_flag: SERIAL_PLOTTER=false + nimble_flag: BLUETOOTH_USE_NIMBLE=true + + steps: + - uses: actions/checkout@v3 + + - name: Speedup package installation + if: matrix.coverage + uses: abbbi/github-actions-tune@v1 + + - name: Setup LCOV + if: matrix.coverage + uses: hrishikesh-kadam/setup-lcov@v1 + + - name: Cache pip + uses: actions/cache@v3 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - uses: actions/cache@v3 + with: + path: ~/.platformio/.cache + key: ${{ runner.os }}-pio-${{ matrix.target }} + restore-keys: | + ${{ runner.os }}-pio- + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.9' + + - name: Enable coverage (non-macOS) + if: runner.os != 'macOS' && matrix.coverage + run: | + sed -i '/__OH_FIRMWARE__/p; s/-D __OH_FIRMWARE__/-lgcov --coverage/' platformio.ini + - name: Enable coverage (macOS) + if: runner.os == 'macOS' && matrix.coverage + run: | + sed -i '' '/__OH_FIRMWARE__/p; s/-D __OH_FIRMWARE__/-lgcov --coverage/' platformio.ini + + - name: Update build flags (non-macOS) + if: runner.os != 'macOS' + run: | + sed -i '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.battery_flag }}/' platformio.ini + sed -i '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.serial_plotter_flag }}/' platformio.ini + sed -i '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.nimble_flag }}/' platformio.ini + - name: Update build flags (macOS) + if: runner.os == 'macOS' + run: | + sed -i '' '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.battery_flag }}/' platformio.ini + sed -i '' '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.serial_plotter_flag }}/' platformio.ini + sed -i '' '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.nimble_flag }}/' platformio.ini + + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + pio upgrade --dev + pio pkg update --global + + - name: Install libs + run: pio lib -e ${{matrix.target}} install + + - name: Change memory segments + if: matrix.coverage + run: | + sed -i "s/len\s=\s0x2c200\s-\s0xdb5c/len = 289888/" ~/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/ld/memory.ld + + - name: Build + run: | + echo "::group::platformio.ini" + cat platformio.ini + echo "::endgroup::" + pio run --environment ${{matrix.target}} + + - name: Collect initial coverage + if: matrix.coverage + run: | + mkdir -p ./build/lcov + lcov -i -d ./.pio/build/${{matrix.target}}/ -c -o ./build/lcov/lcov.info.${{matrix.target}} -gcov-tool ~/.platformio/packages/toolchain-xtensa-esp32/bin/xtensa-esp32-elf-gcov + + - name: Upload coverage Artifact + uses: actions/upload-artifact@v3 + if: matrix.coverage + with: + name: lcov.info.${{matrix.target}} + path: ./build/lcov/lcov.info.${{matrix.target}} + retention-days: 5 + + test: + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + target: + - native + + steps: + - uses: actions/checkout@v3 + + - name: Speedup package installation + uses: abbbi/github-actions-tune@v1 + + - name: Setup LCOV + uses: hrishikesh-kadam/setup-lcov@v1 + + - name: Cache pip + uses: actions/cache@v3 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Cache PlatformIO + uses: actions/cache@v3 + with: + path: ~/.platformio + key: ${{ runner.os }}-pio-${{ hashFiles('**/lockfiles') }} + restore-keys: | + ${{ runner.os }}-pio- + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.9' + + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + pio upgrade --dev + pio pkg update --global + + - name: Run Unit Tests + run: pio test -e ${{matrix.target}} + + - name: Collect coverage report + run: | + mkdir -p ./build/lcov + lcov -d ./.pio/build/${{matrix.target}}/ -c -o ./build/lcov/lcov.info.${{matrix.target}}.test + + - name: Upload coverage Artifact + uses: actions/upload-artifact@v3 + with: + name: lcov.info.${{matrix.target}}.test + path: ./build/lcov/lcov.info.${{matrix.target}}.test + retention-days: 5 + + coverage-report: + needs: [build, test] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Speedup package installation + uses: abbbi/github-actions-tune@v1 + + - name: Setup LCOV + uses: hrishikesh-kadam/setup-lcov@v1 + + - name: Download all workflow run artifacts + id: download + uses: actions/download-artifact@v3 + with: + path: build/artifacts + + - name: Merge lcov files + run: | + mkdir ./build/lcov/ + find ./build/artifacts -mindepth 2 -type f -exec mv '{}' ./build/lcov/ \; + ls -lahR ./build/lcov/ + + find ./build/lcov -name 'lcov.info.*' -exec echo -a {} \; | xargs lcov -o ./build/lcov/lcov.info + lcov --remove ./build/lcov/lcov.info '/usr/include/*' '*.platformio/*' '*/.pio/*' '*/tool-unity/*' '*/test/*' '*/MockArduino/*' -o ./build/lcov/lcov.info.cleaned + + - name: Generate HTML report + run: genhtml -p $PWD -o ./build/coverage/ --demangle-cpp ./build/lcov/lcov.info.cleaned + + - name: Upload coverage Artifact + uses: actions/upload-artifact@v3 + with: + name: coverage-report + path: | + ./build/lcov/ + ./build/coverage/ + retention-days: 5 + + - uses: manarbenkraouda/lcov-reporter-action@v0.3.5.3 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + lcov-file: ./build/lcov/lcov.info.cleaned diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c13a50f0..7e624290 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,14 +1,3 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# name: "CodeQL" on: @@ -40,6 +29,12 @@ jobs: # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + # Enabling all flags to test build for every feature + battery_flag: + - BATTERY_ENABLED=true + serial_plotter_flag: + - SERIAL_PLOTTER=true + steps: - name: Checkout repository uses: actions/checkout@v3 @@ -58,6 +53,7 @@ jobs: uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} + config-file: ./.github/codeql/codeql-config.yml # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. @@ -100,6 +96,12 @@ jobs: with: python-version: '3.9' + - name: Update build flags (non-macOS) + if: runner.os != 'macOS' + run: | + sed -i '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.battery_flag }}/' platformio.ini + sed -i '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.serial_plotter_flag }}/' platformio.ini + - name: Install PlatformIO run: | python -m pip install --upgrade pip diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c4d1f32c..3cae90cd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,6 +27,10 @@ jobs: - bhaptics_tactal - bhaptics_tactglove_left - bhaptics_tactglove_right + battery_flag: + - BATTERY_ENABLED=true + nimble_flag: + - BLUETOOTH_USE_NIMBLE=true steps: - uses: actions/checkout@v3 @@ -64,6 +68,11 @@ jobs: sed -i '/\[env\]/p; s/\[env\]/upload_protocol = custom/' platformio.ini sed -i '/\[env\]/p; s/\[env\]/upload_command = \$PYTHONEXE .\/scripts\/ci\/create-archive.py \$FLASH_EXTRA_IMAGES \$ESP32_APP_OFFSET \$SOURCE/' platformio.ini + - name: Update build flags (non-macOS) + run: | + sed -i '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.battery_flag }}/' platformio.ini + sed -i '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.nimble_flag }}/' platformio.ini + - name: Build run: | mkdir build diff --git a/.gitignore b/.gitignore index 38011f71..ef82776d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +# IDE files/dirs .vscode .vscode/.browse.c_cpp.db* .vscode/c_cpp_properties.json @@ -8,6 +9,9 @@ *.bak *.code-workspace +.idea +cmake-build-debug + # PlatformIO files/dirs .pio* .pioenvs @@ -15,5 +19,10 @@ .clang_complete .gcc-flags.json +# Test files/dirs +lcov.info +lcov.info.* +lcov-report/ + # CI /build/ diff --git a/.vscode/settings.json b/.vscode/settings.json index 5a32a597..ae85168d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -50,6 +50,9 @@ "map": "cpp", "memory_resource": "cpp", "string_view": "cpp", + "bit": "cpp", + "set": "cpp", + "iostream": "cpp", "*.hpp": "cpp" }, "files.eol": "\n", diff --git a/devices.json b/devices.json deleted file mode 100644 index ff7016ae..00000000 --- a/devices.json +++ /dev/null @@ -1,203 +0,0 @@ -[ - { - "Name": "Tactosy", - "NameContains": "tactosy_", - "FirmwareService": "tactosy-v2", - "RawValue": 508, - "HasBattery": true, - "CandidatePositions": [ - "ForearmL", - "ForearmL" - ], - "WriteSize": 20 - }, - { - "Name": "Tactosy2", - "NameContains": "tactosy2_", - "FirmwareService": "v2-tactosy2", - "RawValue": 508, - "HasBattery": true, - "CandidatePositions": [ - "ForearmL", - "ForearmR" - ], - "WriteSize": 20 - }, - { - "Name": "Tactot", - "NameContains": "tactot_", - "FirmwareService": "tactot", - "RawValue": 508, - "HasBattery": false, - "CandidatePositions": [ - "Vest" - ], - "WriteSize": 20 - }, - { - "Name": "Tactot2", - "NameContains": "tactot2_", - "FirmwareService": "tactot2", - "RawValue": 508, - "HasBattery": true, - "CandidatePositions": [ - "Vest" - ], - "WriteSize": 20 - }, - { - "Name": "Tactot3", - "NameContains": "tactot3_", - "FirmwareService": "v2-tactot3", - "RawValue": 508, - "HasBattery": true, - "CandidatePositions": [ - "Vest" - ], - "WriteSize": 20 - }, - { - "Name": "Tactot3", - "NameContains": "tactot_", - "FirmwareService": "tactot3", - "RawValue": 508, - "HasBattery": true, - "CandidatePositions": [ - "Vest" - ], - "WriteSize": 20 - }, - { - "Name": "TactSuitX40", - "NameContains": "tactsuit", - "FirmwareService": "tactsuit_x40", - "RawValue": 509, - "HasBattery": true, - "CandidatePositions": [ - "Vest" - ], - "WriteSize": 20 - }, - { - "Name": "TactSuitX16", - "NameContains": "tactsuit", - "FirmwareService": "tactsuit_x16", - "RawValue": 510, - "HasBattery": true, - "CandidatePositions": [ - "Vest" - ], - "WriteSize": 20 - }, - { - "Name": "Tactal", - "NameContains": "tactal_", - "FirmwareService": "v2-tactal", - "HasBattery": true, - "CandidatePositions": [ - "Head" - ], - "WriteSize": 20 - }, - { - "Name": "TactGloveL", - "NameContains": "tactglove (l", - "FirmwareService": "tactglove-v1", - "RawValue": 508, - "HasBattery": true, - "CandidatePositions": [ - "GloveL" - ], - "WriteSize": 20 - }, - { - "Name": "TactGloveR", - "NameContains": "tactglove (r", - "FirmwareService": "tactglove-v1", - "RawValue": 508, - "HasBattery": true, - "CandidatePositions": [ - "GloveR" - ], - "WriteSize": 20 - }, - { - "Name": "TactFacial", - "NameContains": "tactfacial_", - "FirmwareService": "tactfacial", - "RawValue": 508, - "HasBattery": true, - "CandidatePositions": [ - "Head" - ], - "WriteSize": 20 - }, - { - "Name": "TactosyH", - "NameContains": "tactosyh_", - "FirmwareService": "v2-tactosyh", - "RawValue": 508, - "HasBattery": true, - "CandidatePositions": [ - "HandL", - "HandR" - ], - "WriteSize": 20 - }, - { - "Name": "TactosyF", - "NameContains": "tactosyf_", - "FirmwareService": "v2-tactosyf", - "RawValue": 508, - "HasBattery": true, - "CandidatePositions": [ - "FootL", - "FootR" - ], - "WriteSize": 20 - }, - { - "Name": "TactThermoHL", - "NameContains": "tactthermohl", - "FirmwareService": "", - "RawValue": 508, - "HasBattery": true, - "CandidatePositions": [ - "HandL" - ], - "WriteSize": 20 - }, - { - "Name": "TactThermoHR", - "NameContains": "tactthermohr", - "FirmwareService": "", - "RawValue": 508, - "HasBattery": true, - "CandidatePositions": [ - "HandR" - ], - "WriteSize": 20 - }, - { - "Name": "TactThermoFL", - "NameContains": "tactthermofl", - "FirmwareService": "", - "RawValue": 508, - "HasBattery": true, - "CandidatePositions": [ - "FootL" - ], - "WriteSize": 20 - }, - { - "Name": "TactThermoFR", - "NameContains": "tactthermofr", - "FirmwareService": "", - "RawValue": 508, - "HasBattery": true, - "CandidatePositions": [ - "FootR" - ], - "WriteSize": 20 - } -] \ No newline at end of file diff --git a/examples/bhaptics-ble-bt-serial.cpp b/examples/bhaptics-ble-bt-serial.cpp new file mode 100644 index 00000000..82fe2729 --- /dev/null +++ b/examples/bhaptics-ble-bt-serial.cpp @@ -0,0 +1,70 @@ +// Override you configs in this file (Ctrl+Click) +#include "config/all.h" + +#include +#include + +#include "senseshift.h" + +#include +#include +#include + +#include +#include + +using namespace OH; +using namespace BH; + +extern SenseShift App; +SenseShift* app = &App; + +BluetoothSerial SerialBT; +BluetoothSerial* btSerial = &SerialBT; + +static const size_t bhLayoutSize = BH_LAYOUT_TACTAL_SIZE; +static const oh_output_point_t* bhLayout[bhLayoutSize] = BH_LAYOUT_TACTAL; + +class BLECallbacks : public BHBLEConnectionCallbacks { + public: + void postInit() { + btSerial->begin("SenseShift Serial"); + } +}; + +void setupMode() { + // Configure PWM pins to their positions on the face + auto faceOutputs = PlaneMapper_Margin::mapMatrixCoordinates({ + // clang-format off + {new PWMOutputWriter(32), new PWMOutputWriter(33), new PWMOutputWriter(25), new PWMOutputWriter(26), new PWMOutputWriter(27), new PWMOutputWriter(14)}, + // clang-format on + }); + + auto* face = new HapticPlane_Closest(faceOutputs); + app->getHapticBody()->addComponent(OUTPUT_PATH_ACCESSORY, face); + + app->getHapticBody()->setup(); + + uint8_t serialNumber[BH_SERIAL_NUMBER_LENGTH] = BH_SERIAL_NUMBER; + ConnectionBHBLE_Config config = { + .deviceName = BLUETOOTH_NAME, + .appearance = BH_BLE_APPEARANCE, + .serialNumber = serialNumber, + }; + auto* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { + plainOutputTransformer(app->getHapticBody(), value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); + }, app); + bhBleConnection->setCallbacks(new BLECallbacks()); + bhBleConnection->begin(); +} + +void loopMode() { + // This way is suboptimal, but hardware interrupts for Serial are not supported by the Arduino framework + if (btSerial->available()) { + Serial.print(btSerial->read()); + } + if (Serial.available()) { + btSerial->write(Serial.read()); + } + sleep(20); +} diff --git a/firmware/firmware.cpp b/firmware/firmware.cpp index 43a84b53..943d46b2 100644 --- a/firmware/firmware.cpp +++ b/firmware/firmware.cpp @@ -1,4 +1,4 @@ -#include "openhaptics.h" +#include "senseshift.h" #if defined(ARDUINO) #include @@ -8,31 +8,30 @@ #include #endif // SERIAL_PLOTTER +#ifndef SERIAL_PLOTTER_PORT +#define SERIAL_PLOTTER_PORT Serial +#endif // SERIAL_PLOTTER_PORT + #ifndef PIO_UNIT_TESTING extern void setupMode(); +extern void loopMode(); #if defined(ARDUINO) -OpenHaptics App; +SenseShift App; void setup() { - Serial.begin(115200); - setupMode(); #if defined(SERIAL_PLOTTER) && SERIAL_PLOTTER == true - auto* serialOutputState = new OH::SerialPlotter_OutputStates(Serial, App.getOutput()); + auto* serialOutputState = new OH::SerialPlotter_OutputStates(SERIAL_PLOTTER_PORT, App.getHapticBody()); serialOutputState->begin(); #endif // SERIAL_PLOTTER - - // Free up the Arduino loop task - vTaskDelete(NULL); } void loop() { - // Arduino loop task is deleted in setup() - // Delete the `vTaskDelete(NULL);` line in setup() to enable this function + loopMode(); } #endif // ARDUINO diff --git a/firmware/mode_configs/bhaptics/tactal.cpp b/firmware/mode_configs/bhaptics/tactal.cpp index 719694d9..7f0561e8 100644 --- a/firmware/mode_configs/bhaptics/tactal.cpp +++ b/firmware/mode_configs/bhaptics/tactal.cpp @@ -4,7 +4,7 @@ #include #include -#include "openhaptics.h" +#include "senseshift.h" #include #include @@ -17,33 +17,24 @@ using namespace OH; using namespace BH; -extern OpenHaptics App; -OpenHaptics* app = &App; +extern SenseShift App; +SenseShift* app = &App; -// ========= Output ========= - -const size_t bhLayoutSize = BH_LAYOUT_TACTAL_SIZE; -const oh_output_point_t* bhLayout[bhLayoutSize] = BH_LAYOUT_TACTAL; - -// ========= Connection ========= - -// ========= Battery ========= - -#if defined(BATTERY_ENABLED) && BATTERY_ENABLED == true -#endif +static const size_t bhLayoutSize = BH_LAYOUT_TACTAL_SIZE; +static const oh_output_point_t* bhLayout[bhLayoutSize] = BH_LAYOUT_TACTAL; void setupMode() { // Configure PWM pins to their positions on the face - auto faceOutputs = mapMatrixCoordinates({ + auto faceOutputs = PlaneMapper_Margin::mapMatrixCoordinates({ // clang-format off {new PWMOutputWriter(32), new PWMOutputWriter(33), new PWMOutputWriter(25), new PWMOutputWriter(26), new PWMOutputWriter(27), new PWMOutputWriter(14)}, // clang-format on }); - ClosestOutputComponent* face = new ClosestOutputComponent(OUTPUT_PATH_ACCESSORY, faceOutputs); - app->getOutput()->addComponent(face); + auto* face = new HapticPlane_Closest(faceOutputs); + app->getHapticBody()->addComponent(OUTPUT_PATH_ACCESSORY, face); - app->getOutput()->setup(); + app->getHapticBody()->setup(); uint8_t serialNumber[BH_SERIAL_NUMBER_LENGTH] = BH_SERIAL_NUMBER; ConnectionBHBLE_Config config = { @@ -51,13 +42,18 @@ void setupMode() { .appearance = BH_BLE_APPEARANCE, .serialNumber = serialNumber, }; - AbstractConnection* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { - plainOutputTransformer(app->getOutput(), value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); + auto* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { + plainOutputTransformer(app->getHapticBody(), value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); }, app); bhBleConnection->begin(); #if defined(BATTERY_ENABLED) && BATTERY_ENABLED == true - AbstractBattery* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, &App, tskNO_AFFINITY); + auto* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, &App, tskNO_AFFINITY); battery->begin(); #endif } + +void loopMode() { + // Free up the Arduino loop task + vTaskDelete(NULL); +} diff --git a/firmware/mode_configs/bhaptics/tactglove.cpp b/firmware/mode_configs/bhaptics/tactglove.cpp index 4c629df3..e365ddc5 100644 --- a/firmware/mode_configs/bhaptics/tactglove.cpp +++ b/firmware/mode_configs/bhaptics/tactglove.cpp @@ -6,7 +6,7 @@ #include -#include "openhaptics.h" +#include "senseshift.h" #include #include @@ -19,8 +19,8 @@ using namespace OH; using namespace BH; -extern OpenHaptics App; -OpenHaptics* app = &App; +extern SenseShift App; +SenseShift* app = &App; #pragma region bHaptics_trash @@ -30,7 +30,7 @@ static const uint16_t _bh_size_x = 6; static const uint16_t _bh_size_y = 1; inline oh_output_point_t* make_point(oh_output_coord_t x, oh_output_coord_t y) { - return mapPoint(x, y, (oh_output_coord_t) (_bh_size_x - 1), (oh_output_coord_t) (_bh_size_y - 1)); + return PlaneMapper_Margin::mapPoint(x, y, (oh_output_coord_t) (_bh_size_x - 1), (oh_output_coord_t) (_bh_size_y - 1)); } static const uint16_t bhLayoutSize = _bh_size_x * _bh_size_y; @@ -39,7 +39,7 @@ static const oh_output_point_t* bhLayout[bhLayoutSize] = { // Thumb, Index, Middle, Ring, Pinky make_point(0, 0), make_point(1, 0), make_point(2, 0), make_point(3, 0), make_point(4, 0), - // Palm + // Wrist make_point(5, 0) // clang-format on @@ -49,19 +49,21 @@ static const oh_output_point_t* bhLayout[bhLayoutSize] = { void setupMode() { // Configure PWM pins to their positions on the glove - auto gloveOutputs = mapMatrixCoordinates({ + auto gloveOutputs = PlaneMapper_Margin::mapMatrixCoordinates({ // clang-format off { + // Thumb, Index, Middle, Ring, Pinky new PWMOutputWriter(32), new PWMOutputWriter(33), new PWMOutputWriter(25), new PWMOutputWriter(26), new PWMOutputWriter(27), + // Wrist new PWMOutputWriter(14) }, // clang-format on }); - OutputComponent* glove = new ClosestOutputComponent(OUTPUT_PATH_ACCESSORY, gloveOutputs); - app->getOutput()->addComponent(glove); + auto* glove = new HapticPlane_Closest(gloveOutputs); + app->getHapticBody()->addComponent(OUTPUT_PATH_ACCESSORY, glove); - app->getOutput()->setup(); + app->getHapticBody()->setup(); uint8_t serialNumber[BH_SERIAL_NUMBER_LENGTH] = BH_SERIAL_NUMBER; ConnectionBHBLE_Config config = { @@ -69,13 +71,18 @@ void setupMode() { .appearance = BH_BLE_APPEARANCE, .serialNumber = serialNumber, }; - AbstractConnection* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { - plainOutputTransformer(app->getOutput(), value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); + auto* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { + plainOutputTransformer(app->getHapticBody(), value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); }, app); bhBleConnection->begin(); #if defined(BATTERY_ENABLED) && BATTERY_ENABLED == true - AbstractBattery* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, app, tskNO_AFFINITY); + auto* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, app, tskNO_AFFINITY); battery->begin(); #endif } + +void loopMode() { + // Free up the Arduino loop task + vTaskDelete(NULL); +} diff --git a/firmware/mode_configs/bhaptics/tactosy2.cpp b/firmware/mode_configs/bhaptics/tactosy2.cpp index 36129d18..5846b08f 100644 --- a/firmware/mode_configs/bhaptics/tactosy2.cpp +++ b/firmware/mode_configs/bhaptics/tactosy2.cpp @@ -4,7 +4,7 @@ #include #include -#include "openhaptics.h" +#include "senseshift.h" #include #include @@ -17,25 +17,25 @@ using namespace OH; using namespace BH; -extern OpenHaptics App; -OpenHaptics* app = &App; +extern SenseShift App; +SenseShift* app = &App; static const size_t bhLayoutSize = BH_LAYOUT_TACTOSY2_SIZE; static const oh_output_point_t* bhLayout[bhLayoutSize] = BH_LAYOUT_TACTOSY2; void setupMode() { // Configure PWM pins to their positions on the forearm - auto forearmOutputs = mapMatrixCoordinates({ + auto forearmOutputs = PlaneMapper_Margin::mapMatrixCoordinates({ // clang-format off {new PWMOutputWriter(32), new PWMOutputWriter(33), new PWMOutputWriter(25)}, {new PWMOutputWriter(26), new PWMOutputWriter(27), new PWMOutputWriter(14)}, // clang-format on }); - OutputComponent* forearm = new ClosestOutputComponent(OUTPUT_PATH_ACCESSORY, forearmOutputs); - app->getOutput()->addComponent(forearm); + auto* forearm = new HapticPlane_Closest(forearmOutputs); + app->getHapticBody()->addComponent(OUTPUT_PATH_ACCESSORY, forearm); - app->getOutput()->setup(); + app->getHapticBody()->setup(); uint8_t serialNumber[BH_SERIAL_NUMBER_LENGTH] = BH_SERIAL_NUMBER; ConnectionBHBLE_Config config = { @@ -43,13 +43,18 @@ void setupMode() { .appearance = BH_BLE_APPEARANCE, .serialNumber = serialNumber, }; - AbstractConnection* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { - plainOutputTransformer(app->getOutput(), value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); + auto* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { + plainOutputTransformer(app->getHapticBody(), value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); }, app); bhBleConnection->begin(); #if defined(BATTERY_ENABLED) && BATTERY_ENABLED == true - AbstractBattery* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, app, tskNO_AFFINITY); + auto* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, app, tskNO_AFFINITY); battery->begin(); #endif } + +void loopMode() { + // Free up the Arduino loop task + vTaskDelete(NULL); +} diff --git a/firmware/mode_configs/bhaptics/tactosyf.cpp b/firmware/mode_configs/bhaptics/tactosyf.cpp index 29fb0ded..94b68a8c 100644 --- a/firmware/mode_configs/bhaptics/tactosyf.cpp +++ b/firmware/mode_configs/bhaptics/tactosyf.cpp @@ -4,7 +4,7 @@ #include #include -#include "openhaptics.h" +#include "senseshift.h" #include #include @@ -17,15 +17,15 @@ using namespace OH; using namespace BH; -extern OpenHaptics App; -OpenHaptics* app = &App; +extern SenseShift App; +SenseShift* app = &App; -void setupMode() { - static const size_t bhLayoutSize = BH_LAYOUT_TACTOSYF_SIZE; - static const oh_output_point_t* bhLayout[bhLayoutSize] = BH_LAYOUT_TACTOSYF; +static const size_t bhLayoutSize = BH_LAYOUT_TACTOSYF_SIZE; +static const oh_output_point_t* bhLayout[bhLayoutSize] = BH_LAYOUT_TACTOSYF; +void setupMode() { // Configure PWM pins to their positions on the feet - auto footOutputs = mapMatrixCoordinates({ + auto footOutputs = PlaneMapper_Margin::mapMatrixCoordinates({ // clang-format off { new PWMOutputWriter(32) }, { new PWMOutputWriter(33) }, @@ -33,10 +33,10 @@ void setupMode() { // clang-format on }); - OutputComponent* foot = new ClosestOutputComponent(OUTPUT_PATH_ACCESSORY, footOutputs); - app->getOutput()->addComponent(foot); + auto* foot = new HapticPlane_Closest(footOutputs); + app->getHapticBody()->addComponent(OUTPUT_PATH_ACCESSORY, foot); - app->getOutput()->setup(); + app->getHapticBody()->setup(); uint8_t serialNumber[BH_SERIAL_NUMBER_LENGTH] = BH_SERIAL_NUMBER; ConnectionBHBLE_Config config = { @@ -44,13 +44,18 @@ void setupMode() { .appearance = BH_BLE_APPEARANCE, .serialNumber = serialNumber, }; - AbstractConnection* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { - plainOutputTransformer(app->getOutput(), value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); + auto* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { + plainOutputTransformer(app->getHapticBody(), value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); }, app); bhBleConnection->begin(); #if defined(BATTERY_ENABLED) && BATTERY_ENABLED == true - AbstractBattery* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, app, tskNO_AFFINITY); + auto* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, app, tskNO_AFFINITY); battery->begin(); #endif } + +void loopMode() { + // Free up the Arduino loop task + vTaskDelete(NULL); +} diff --git a/firmware/mode_configs/bhaptics/tactosyh.cpp b/firmware/mode_configs/bhaptics/tactosyh.cpp index 2f6c9a1e..95a31b4c 100644 --- a/firmware/mode_configs/bhaptics/tactosyh.cpp +++ b/firmware/mode_configs/bhaptics/tactosyh.cpp @@ -4,7 +4,7 @@ #include #include -#include "openhaptics.h" +#include "senseshift.h" #include #include @@ -17,15 +17,15 @@ using namespace OH; using namespace BH; -extern OpenHaptics App; -OpenHaptics* app = &App; +extern SenseShift App; +SenseShift* app = &App; static const size_t bhLayoutSize = BH_LAYOUT_TACTOSYH_SIZE; static const oh_output_point_t* bhLayout[bhLayoutSize] = BH_LAYOUT_TACTOSYH; void setupMode() { // Configure PWM pins to their positions on the hands - auto handOutputs = mapMatrixCoordinates({ + auto handOutputs = PlaneMapper_Margin::mapMatrixCoordinates({ // clang-format off {new PWMOutputWriter(32)}, {new PWMOutputWriter(33)}, @@ -33,10 +33,10 @@ void setupMode() { // clang-format on }); - OutputComponent* hand = new ClosestOutputComponent(OUTPUT_PATH_ACCESSORY, handOutputs); - app->getOutput()->addComponent(hand); + auto* hand = new HapticPlane_Closest(handOutputs); + app->getHapticBody()->addComponent(OUTPUT_PATH_ACCESSORY, hand); - app->getOutput()->setup(); + app->getHapticBody()->setup(); uint8_t serialNumber[BH_SERIAL_NUMBER_LENGTH] = BH_SERIAL_NUMBER; ConnectionBHBLE_Config config = { @@ -44,13 +44,18 @@ void setupMode() { .appearance = BH_BLE_APPEARANCE, .serialNumber = serialNumber, }; - AbstractConnection* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { - plainOutputTransformer(app->getOutput(), value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); + auto* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { + plainOutputTransformer(app->getHapticBody(), value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); }, app); bhBleConnection->begin(); #if defined(BATTERY_ENABLED) && BATTERY_ENABLED == true - AbstractBattery* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, app, tskNO_AFFINITY); + auto* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, app, tskNO_AFFINITY); battery->begin(); #endif } + +void loopMode() { + // Free up the Arduino loop task + vTaskDelete(NULL); +} diff --git a/firmware/mode_configs/bhaptics/tactsuit_x16.cpp b/firmware/mode_configs/bhaptics/tactsuit_x16.cpp index 13e79cc2..3b60dc0b 100644 --- a/firmware/mode_configs/bhaptics/tactsuit_x16.cpp +++ b/firmware/mode_configs/bhaptics/tactsuit_x16.cpp @@ -4,7 +4,7 @@ #include #include -#include "openhaptics.h" +#include "senseshift.h" #include #include @@ -17,8 +17,8 @@ using namespace OH; using namespace BH; -extern OpenHaptics App; -OpenHaptics* app = &App; +extern SenseShift App; +SenseShift* app = &App; static const oh_output_point_t* bhLayout[] = BH_LAYOUT_TACTSUITX16; static const size_t bhLayoutSize = BH_LAYOUT_TACTSUITX16_SIZE; @@ -29,26 +29,26 @@ static const uint8_t layoutGroups[layoutGroupsSize] = BH_LAYOUT_TACTSUITX16_GROU void setupMode() { // Configure PWM pins to their positions on the vest - auto frontOutputs = mapMatrixCoordinates({ + auto frontOutputs = PlaneMapper_Margin::mapMatrixCoordinates({ // clang-format off {new PWMOutputWriter(32), new PWMOutputWriter(33), new PWMOutputWriter(25), new PWMOutputWriter(26)}, {new PWMOutputWriter(27), new PWMOutputWriter(14), new PWMOutputWriter(12), new PWMOutputWriter(13)}, // clang-format on }); - auto backOutputs = mapMatrixCoordinates({ + auto backOutputs = PlaneMapper_Margin::mapMatrixCoordinates({ // clang-format off {new PWMOutputWriter(19), new PWMOutputWriter(18), new PWMOutputWriter(5), new PWMOutputWriter(17)}, {new PWMOutputWriter(16), new PWMOutputWriter(4), new PWMOutputWriter(2), new PWMOutputWriter(15)}, // clang-format on }); - OutputComponent* chestFront = new ClosestOutputComponent(OUTPUT_PATH_CHEST_FRONT, frontOutputs); - OutputComponent* chestBack = new ClosestOutputComponent(OUTPUT_PATH_CHEST_BACK, backOutputs); + auto* chestFront = new HapticPlane_Closest(frontOutputs); + auto* chestBack = new HapticPlane_Closest(backOutputs); - app->getOutput()->addComponent(chestFront); - app->getOutput()->addComponent(chestBack); + app->getHapticBody()->addComponent(OUTPUT_PATH_CHEST_FRONT, chestFront); + app->getHapticBody()->addComponent(OUTPUT_PATH_CHEST_BACK, chestBack); - app->getOutput()->setup(); + app->getHapticBody()->setup(); uint8_t serialNumber[BH_SERIAL_NUMBER_LENGTH] = BH_SERIAL_NUMBER; ConnectionBHBLE_Config config = { @@ -56,13 +56,18 @@ void setupMode() { .appearance = BH_BLE_APPEARANCE, .serialNumber = serialNumber, }; - AbstractConnection* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { - vestX16OutputTransformer(app->getOutput(), value, bhLayout, bhLayoutSize, layoutGroups, layoutGroupsSize); + auto* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { + vestX16OutputTransformer(app->getHapticBody(), value, bhLayout, bhLayoutSize, layoutGroups, layoutGroupsSize); }, app); bhBleConnection->begin(); #if defined(BATTERY_ENABLED) && BATTERY_ENABLED == true - AbstractBattery* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, app, tskNO_AFFINITY); + auto* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, app, tskNO_AFFINITY); battery->begin(); #endif } + +void loopMode() { + // Free up the Arduino loop task + vTaskDelete(NULL); +} diff --git a/firmware/mode_configs/bhaptics/tactsuit_x16_pca9685.cpp b/firmware/mode_configs/bhaptics/tactsuit_x16_pca9685.cpp index 381ea9ec..34163680 100644 --- a/firmware/mode_configs/bhaptics/tactsuit_x16_pca9685.cpp +++ b/firmware/mode_configs/bhaptics/tactsuit_x16_pca9685.cpp @@ -4,7 +4,7 @@ #include #include -#include "openhaptics.h" +#include "senseshift.h" #include #include @@ -17,8 +17,8 @@ using namespace OH; using namespace BH; -extern OpenHaptics App; -OpenHaptics* app = &App; +extern SenseShift App; +SenseShift* app = &App; static const oh_output_point_t* bhLayout[] = BH_LAYOUT_TACTSUITX16; static const size_t bhLayoutSize = BH_LAYOUT_TACTSUITX16_SIZE; @@ -34,26 +34,26 @@ void setupMode() { pwm->setPWMFreq(PWM_FREQUENCY); // Assign the pins on the configured PCA9685 to positions on the vest - auto frontOutputs = mapMatrixCoordinates({ + auto frontOutputs = PlaneMapper_Margin::mapMatrixCoordinates({ // clang-format off {new PCA9685OutputWriter(pwm, 0), new PCA9685OutputWriter(pwm, 1), new PCA9685OutputWriter(pwm, 2), new PCA9685OutputWriter(pwm, 3)}, {new PCA9685OutputWriter(pwm, 4), new PCA9685OutputWriter(pwm, 5), new PCA9685OutputWriter(pwm, 6), new PCA9685OutputWriter(pwm, 7)}, // clang-format on }); - auto backOutputs = mapMatrixCoordinates({ + auto backOutputs = PlaneMapper_Margin::mapMatrixCoordinates({ // clang-format off {new PCA9685OutputWriter(pwm, 8), new PCA9685OutputWriter(pwm, 9), new PCA9685OutputWriter(pwm, 10), new PCA9685OutputWriter(pwm, 11)}, {new PCA9685OutputWriter(pwm, 12), new PCA9685OutputWriter(pwm, 13), new PCA9685OutputWriter(pwm, 14), new PCA9685OutputWriter(pwm, 15)}, // clang-format on }); - OutputComponent* chestFront = new ClosestOutputComponent(OUTPUT_PATH_CHEST_FRONT, frontOutputs); - OutputComponent* chestBack = new ClosestOutputComponent(OUTPUT_PATH_CHEST_BACK, backOutputs); + auto* chestFront = new HapticPlane_Closest(frontOutputs); + auto* chestBack = new HapticPlane_Closest(backOutputs); - app->getOutput()->addComponent(chestFront); - app->getOutput()->addComponent(chestBack); + app->getHapticBody()->addComponent(OUTPUT_PATH_CHEST_FRONT, chestFront); + app->getHapticBody()->addComponent(OUTPUT_PATH_CHEST_BACK, chestBack); - app->getOutput()->setup(); + app->getHapticBody()->setup(); uint8_t serialNumber[BH_SERIAL_NUMBER_LENGTH] = BH_SERIAL_NUMBER; ConnectionBHBLE_Config config = { @@ -61,13 +61,18 @@ void setupMode() { .appearance = BH_BLE_APPEARANCE, .serialNumber = serialNumber, }; - AbstractConnection* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { - vestX16OutputTransformer(app->getOutput(), value, bhLayout, bhLayoutSize, layoutGroups, layoutGroupsSize); + auto* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { + vestX16OutputTransformer(app->getHapticBody(), value, bhLayout, bhLayoutSize, layoutGroups, layoutGroupsSize); }, app); bhBleConnection->begin(); #if defined(BATTERY_ENABLED) && BATTERY_ENABLED == true - AbstractBattery* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, app, tskNO_AFFINITY); + auto* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, app, tskNO_AFFINITY); battery->begin(); #endif } + +void loopMode() { + // Free up the Arduino loop task + vTaskDelete(NULL); +} diff --git a/firmware/mode_configs/bhaptics/tactsuit_x40.cpp b/firmware/mode_configs/bhaptics/tactsuit_x40.cpp index a2275dc5..b8a52446 100644 --- a/firmware/mode_configs/bhaptics/tactsuit_x40.cpp +++ b/firmware/mode_configs/bhaptics/tactsuit_x40.cpp @@ -4,7 +4,7 @@ #include #include -#include "openhaptics.h" +#include "senseshift.h" #include #include @@ -18,25 +18,25 @@ using namespace OH; using namespace BH; -extern OpenHaptics App; -OpenHaptics* app = &App; +extern SenseShift App; +SenseShift* app = &App; static const size_t bhLayoutSize = BH_LAYOUT_TACTSUITX40_SIZE; static const oh_output_point_t* bhLayout[bhLayoutSize] = BH_LAYOUT_TACTSUITX40; void setupMode() { // Configure the PCA9685s - Adafruit_PWMServoDriver* pwm0 = new Adafruit_PWMServoDriver(0x40); + auto* pwm0 = new Adafruit_PWMServoDriver(0x40); pwm0->begin(); pwm0->setPWMFreq(PWM_FREQUENCY); - Adafruit_PWMServoDriver* pwm1 = new Adafruit_PWMServoDriver(0x41); + auto* pwm1 = new Adafruit_PWMServoDriver(0x41); pwm1->begin(); pwm1->setPWMFreq(PWM_FREQUENCY); // Assign the pins on the configured PCA9685s and PWM pins to locations on the // vest - auto frontOutputs = mapMatrixCoordinates({ + auto frontOutputs = PlaneMapper_Margin::mapMatrixCoordinates({ // clang-format off {new PCA9685OutputWriter(pwm0, 0), new PCA9685OutputWriter(pwm0, 1), new PCA9685OutputWriter(pwm0, 2), new PCA9685OutputWriter(pwm0, 3)}, {new PCA9685OutputWriter(pwm0, 4), new PCA9685OutputWriter(pwm0, 5), new PCA9685OutputWriter(pwm0, 6), new PCA9685OutputWriter(pwm0, 7)}, @@ -45,7 +45,7 @@ void setupMode() { {new PWMOutputWriter(32), new PWMOutputWriter(33), new PWMOutputWriter(25), new PWMOutputWriter(26)}, // clang-format on }); - auto backOutputs = mapMatrixCoordinates({ + auto backOutputs = PlaneMapper_Margin::mapMatrixCoordinates({ // clang-format off {new PCA9685OutputWriter(pwm1, 0), new PCA9685OutputWriter(pwm1, 1), new PCA9685OutputWriter(pwm1, 2), new PCA9685OutputWriter(pwm1, 3)}, {new PCA9685OutputWriter(pwm1, 4), new PCA9685OutputWriter(pwm1, 5), new PCA9685OutputWriter(pwm1, 6), new PCA9685OutputWriter(pwm1, 7)}, @@ -55,13 +55,13 @@ void setupMode() { // clang-format on }); - OutputComponent* chestFront = new ClosestOutputComponent(OUTPUT_PATH_CHEST_FRONT, frontOutputs); - OutputComponent* chestBack = new ClosestOutputComponent(OUTPUT_PATH_CHEST_BACK, backOutputs); + auto* chestFront = new HapticPlane_Closest(frontOutputs); + auto* chestBack = new HapticPlane_Closest(backOutputs); - app->getOutput()->addComponent(chestFront); - app->getOutput()->addComponent(chestBack); + app->getHapticBody()->addComponent(OUTPUT_PATH_CHEST_FRONT, chestFront); + app->getHapticBody()->addComponent(OUTPUT_PATH_CHEST_BACK, chestBack); - app->getOutput()->setup(); + app->getHapticBody()->setup(); uint8_t serialNumber[BH_SERIAL_NUMBER_LENGTH] = BH_SERIAL_NUMBER; ConnectionBHBLE_Config config = { @@ -69,14 +69,18 @@ void setupMode() { .appearance = BH_BLE_APPEARANCE, .serialNumber = serialNumber, }; - AbstractConnection* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { - Serial.println(value.c_str()); - vestOutputTransformer(app->getOutput(), value, bhLayout, bhLayoutSize); + auto* bhBleConnection = new ConnectionBHBLE(config, [](std::string& value)->void { + vestOutputTransformer(app->getHapticBody(), value, bhLayout, bhLayoutSize); }, app); bhBleConnection->begin(); #if defined(BATTERY_ENABLED) && BATTERY_ENABLED == true - AbstractBattery* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, app, tskNO_AFFINITY); + auto* battery = new ADCNaiveBattery(36, { .sampleRate = BATTERY_SAMPLE_RATE }, app, tskNO_AFFINITY); battery->begin(); #endif } + +void loopMode() { + // Free up the Arduino loop task + vTaskDelete(NULL); +} diff --git a/firmware/mode_configs/test.cpp b/firmware/mode_configs/test.cpp index e1e04c8d..a34397df 100644 --- a/firmware/mode_configs/test.cpp +++ b/firmware/mode_configs/test.cpp @@ -1,52 +1,42 @@ // Override you configs in this file (Ctrl+Click) #include "config/all.h" -#include -#include +#ifdef UNIT_TEST + #include "ArduinoFake.h" +#else + #include "Arduino.h" +#endif -#include "openhaptics.h" +#include "senseshift.h" -#include "connections/bhaptics.h" +#include -#if defined(BATTERY_ENABLED) && BATTERY_ENABLED == true -#include "battery/adc_battery.h" -#endif +using namespace OH; + +extern SenseShift App; +SenseShift* app = &App; -class TestOutput : public OH::AbstractOutputWriter { +class TestOutput : public OH::AbstractActuator { private: uint8_t channel; public: TestOutput(uint8_t channel) : channel(channel){}; uint8_t getChannel() { return channel; }; - void writeOutput(oh_output_intensity_t intensity) { - Serial.printf("\t> Channel %2u: %3u\n", channel, intensity); - }; + void writeOutput(oh_output_intensity_t intensity) {}; }; void setupMode() { - auto testOutputs = mapMatrixCoordinates({ + auto testOutputs = PlaneMapper_Margin::mapMatrixCoordinates({ {new TestOutput(0), new TestOutput(1)}, {new TestOutput(2), new TestOutput(3)}, {new TestOutput(4), new TestOutput(5)}, {new TestOutput(6), new TestOutput(7)}, }); - for (const auto& kv : testOutputs) { - Serial.printf("> Channel %2u: (%5u, %5u)\n", - ((TestOutput*)kv.second)->getChannel(), kv.first.x, - kv.first.y); - } - - auto test = new ClosestOutputComponent(testOutputs); - - App.getOutput()->addComponent(OUTPUT_PATH_ACCESSORY, test); + auto test = new HapticPlane_Closest(testOutputs); + App.getHapticBody()->addComponent(OUTPUT_PATH_ACCESSORY, test); +} - for (auto i = 0; i < testOutputs.size(); i++) { - oh_output_data_t outData{ - oh_output_point_t(0, 0), - (uint8_t)map(i, 0, testOutputs.size() - 1, 0, 255), - }; - App.getOutput()->writeOutput(OUTPUT_PATH_ACCESSORY, outData); - } +void loopMode() { } diff --git a/firmware/openhaptics.cpp b/firmware/openhaptics.cpp deleted file mode 100644 index 2f48d44f..00000000 --- a/firmware/openhaptics.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "config/all.h" - -#include "openhaptics.h" - -#ifdef ARDUINO -#include -#endif - -#include - -OpenHaptics::OpenHaptics() { - this->output = new OH::Output(); -} - -void OpenHaptics::registerComponent(OH::IComponent* component) { - if (component == nullptr) { - return; - } - - for (auto* c : this->components) { - if (c == component) { - return; - } - } - - this->components.insert(component); -} - -void OpenHaptics::postEvent(const OH::IEvent* event) { - log_i("Event dispatched at %u: %s (%p)", millis(), event->eventName.c_str(), event); - - for (auto* listener : this->eventListeners) { - listener->handleEvent(event); - } - - delete event; -} - -void OpenHaptics::addEventListener(const OH::IEventListener* listener) { - this->eventListeners.push_back(listener); -} diff --git a/firmware/senseshift.cpp b/firmware/senseshift.cpp new file mode 100644 index 00000000..38a95f46 --- /dev/null +++ b/firmware/senseshift.cpp @@ -0,0 +1,27 @@ +#include "config/all.h" + +#include "senseshift.h" + +#ifdef ARDUINO +#include +#endif + +#include + +SenseShift::SenseShift() { + this->pHapticBody = new OH::HapticBody(); +} + +void SenseShift::postEvent(const OH::IEvent* event) { + log_i("Event dispatched at %u: %s (%p)", millis(), event->eventName.c_str(), event); + + for (auto* listener : this->eventListeners) { + listener->handleEvent(event); + } + + delete event; +} + +void SenseShift::addEventListener(const OH::IEventListener* listener) { + this->eventListeners.push_back(listener); +} diff --git a/include/config/battery.h b/include/config/battery.h index b77cea1c..9c34c5e8 100644 --- a/include/config/battery.h +++ b/include/config/battery.h @@ -5,7 +5,7 @@ #endif #ifndef BATTERY_SAMPLE_RATE -#define BATTERY_SAMPLE_RATE 60000 +#define BATTERY_SAMPLE_RATE 10000 #endif #ifndef BATTERY_THRESHOLD_PERCENTAGE diff --git a/include/config/bluetooth.h b/include/config/bluetooth.h index a9bca958..737344d5 100644 --- a/include/config/bluetooth.h +++ b/include/config/bluetooth.h @@ -1,10 +1,14 @@ #pragma once #ifndef BLUETOOTH_NAME -#define BLUETOOTH_NAME "OpenHaptics" +#define BLUETOOTH_NAME "SenseShift" #endif #ifndef BLUETOOTH_ADDRESS #define BLUETOOTH_ADDRESS \ { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB } #endif + +#ifndef BLUETOOTH_USE_NIMBLE +#define BLUETOOTH_USE_NIMBLE false +#endif diff --git a/include/openhaptics.h b/include/senseshift.h similarity index 56% rename from include/openhaptics.h rename to include/senseshift.h index 8f1bba47..12b0bf9d 100644 --- a/include/openhaptics.h +++ b/include/senseshift.h @@ -2,9 +2,8 @@ #include "config/all.h" -#include #include -#include +#include #include #if defined(BATTERY_ENABLED) && BATTERY_ENABLED == true @@ -13,25 +12,22 @@ #include -class OpenHaptics final : public OH::IComponentRegistry, public OH::IEventDispatcher +class SenseShift final : public OH::IEventDispatcher { private: - std::set components{}; std::vector eventListeners{}; - OH::Output* output; + OH::HapticBody* pHapticBody; #if defined(BATTERY_ENABLED) && BATTERY_ENABLED == true OH::AbstractBattery* battery; #endif public: - OpenHaptics(); - std::set getComponents() { - return this->components; - }; - void registerComponent(OH::IComponent*); + SenseShift(); - OH::Output* getOutput() { return this->output; }; + OH::HapticBody* getHapticBody() { + return this->pHapticBody; + }; void postEvent(const OH::IEvent* event) override; void addEventListener(const OH::IEventListener* listener) override; diff --git a/ini/bhaptics.ini b/ini/bhaptics.ini index 06d22bb1..7b94115c 100644 --- a/ini/bhaptics.ini +++ b/ini/bhaptics.ini @@ -1,140 +1,230 @@ [bhaptics] -build_flags = ${common.build_flags} +platform = platformio/espressif32@^6.1.0 +platform_packages = + platformio/framework-arduinoespressif32@^3.20007.0 +framework = arduino +board = esp32doit-devkit-v1 +upload_speed = 921600 +monitor_speed = 115200 + +build_flags = ${common.build_flags} -D BHAPTICS -build_unflags = ${common.build_unflags} -build_src_filter = ${common.build_src_filter} - + - + -lib_deps = ${common.lib_deps} +build_unflags = ${common.build_unflags} +build_src_filter = ${common.build_src_filter} +lib_deps = ${common.lib_deps} [env:bhaptics_tactsuit_x16] -build_flags = ${bhaptics.build_flags} +platform = ${bhaptics.platform} +platform_packages = ${bhaptics.platform_packages} +framework = ${bhaptics.framework} +board = ${bhaptics.board} +upload_speed = ${bhaptics.upload_speed} +monitor_speed = ${bhaptics.monitor_speed} + +build_flags = ${bhaptics.build_flags} -D BH_DEVICE_TACTSUITX16 -D BH_BLE_APPEARANCE=510 '-D BLUETOOTH_NAME="TactSuitX16"' '-D BH_SERIAL_NUMBER={ 0x0d, 0x3a, 0xeb, 0x77, 0xbe, 0xf8, 0x7a, 0x1e, 0x3b, 0x2a }' -build_unflags = ${bhaptics.build_unflags} -build_src_filter = ${bhaptics.build_src_filter} +build_unflags = ${bhaptics.build_unflags} +build_src_filter = ${bhaptics.build_src_filter} + -lib_deps = ${bhaptics.lib_deps} +lib_deps = ${bhaptics.lib_deps} [env:bhaptics_tactsuit_x16_pca9685] -build_flags = ${bhaptics.build_flags} +platform = ${bhaptics.platform} +platform_packages = ${bhaptics.platform_packages} +framework = ${bhaptics.framework} +board = ${bhaptics.board} +upload_speed = ${bhaptics.upload_speed} +monitor_speed = ${bhaptics.monitor_speed} + +build_flags = ${bhaptics.build_flags} -D BH_DEVICE_TACTSUITX16 -D BH_BLE_APPEARANCE=510 '-D BLUETOOTH_NAME="TactSuitX16"' '-D BH_SERIAL_NUMBER={ 0x0d, 0x3a, 0xeb, 0x77, 0xbe, 0xf8, 0x7a, 0x1e, 0x3b, 0x2a }' -build_unflags = ${bhaptics.build_unflags} -build_src_filter = ${bhaptics.build_src_filter} +build_unflags = ${bhaptics.build_unflags} +build_src_filter = ${bhaptics.build_src_filter} + -lib_deps = ${bhaptics.lib_deps} +lib_deps = ${bhaptics.lib_deps} [env:bhaptics_tactsuit_x40] -build_flags = ${bhaptics.build_flags} +platform = ${bhaptics.platform} +platform_packages = ${bhaptics.platform_packages} +framework = ${bhaptics.framework} +board = ${bhaptics.board} +upload_speed = ${bhaptics.upload_speed} +monitor_speed = ${bhaptics.monitor_speed} + +build_flags = ${bhaptics.build_flags} -D BH_DEVICE_TACTSUITX40 -D BH_BLE_APPEARANCE=509 '-D BLUETOOTH_NAME="TactSuitX40"' '-D BH_SERIAL_NUMBER={ 0xcf, 0xcb, 0x0d, 0x95, 0x5f, 0xf6, 0xee, 0x2c, 0xbd, 0x73 }' -build_unflags = ${bhaptics.build_unflags} -build_src_filter = ${bhaptics.build_src_filter} +build_unflags = ${bhaptics.build_unflags} +build_src_filter = ${bhaptics.build_src_filter} + -lib_deps = ${bhaptics.lib_deps} +lib_deps = ${bhaptics.lib_deps} [env:bhaptics_tactosy2_forearm_left] -build_flags = ${bhaptics.build_flags} +platform = ${bhaptics.platform} +platform_packages = ${bhaptics.platform_packages} +framework = ${bhaptics.framework} +board = ${bhaptics.board} +upload_speed = ${bhaptics.upload_speed} +monitor_speed = ${bhaptics.monitor_speed} + +build_flags = ${bhaptics.build_flags} -D BH_DEVICE_TACTOSY2 -D BH_BLE_APPEARANCE=508 '-D BLUETOOTH_NAME="Tactosy2_L"' '-D BH_SERIAL_NUMBER={ 0xa0, 0xba, 0x0a, 0xd1, 0xbf, 0x36, 0x11, 0x30, 0xa4, 0xff }' -build_unflags = ${bhaptics.build_unflags} -build_src_filter = ${bhaptics.build_src_filter} +build_unflags = ${bhaptics.build_unflags} +build_src_filter = ${bhaptics.build_src_filter} + -lib_deps = ${bhaptics.lib_deps} +lib_deps = ${bhaptics.lib_deps} [env:bhaptics_tactosy2_forearm_right] -build_flags = ${bhaptics.build_flags} +platform = ${bhaptics.platform} +platform_packages = ${bhaptics.platform_packages} +framework = ${bhaptics.framework} +board = ${bhaptics.board} +upload_speed = ${bhaptics.upload_speed} +monitor_speed = ${bhaptics.monitor_speed} + +build_flags = ${bhaptics.build_flags} -D BH_DEVICE_TACTOSY2 -D BH_BLE_APPEARANCE=508 '-D BLUETOOTH_NAME="Tactosy2_R"' '-D BH_SERIAL_NUMBER={ 0xb0, 0x1c, 0xc1, 0xf8, 0xec, 0x12, 0x18, 0x4e, 0x09, 0x77 }' -build_unflags = ${bhaptics.build_unflags} -build_src_filter = ${bhaptics.build_src_filter} +build_unflags = ${bhaptics.build_unflags} +build_src_filter = ${bhaptics.build_src_filter} + -lib_deps = ${bhaptics.lib_deps} +lib_deps = ${bhaptics.lib_deps} [env:bhaptics_tactosyh_hand_left] -build_flags = ${bhaptics.build_flags} +platform = ${bhaptics.platform} +platform_packages = ${bhaptics.platform_packages} +framework = ${bhaptics.framework} +board = ${bhaptics.board} +upload_speed = ${bhaptics.upload_speed} +monitor_speed = ${bhaptics.monitor_speed} + +build_flags = ${bhaptics.build_flags} -D BH_DEVICE_TACTOSYH -D BH_BLE_APPEARANCE=508 '-D BLUETOOTH_NAME="TactosyH_L"' '-D BH_SERIAL_NUMBER={ 0xc1, 0x36, 0xdc, 0x21, 0xc9, 0xd4, 0x17, 0x85, 0xbb, 0x90 }' -build_unflags = ${bhaptics.build_unflags} -build_src_filter = ${bhaptics.build_src_filter} +build_unflags = ${bhaptics.build_unflags} +build_src_filter = ${bhaptics.build_src_filter} + -lib_deps = ${bhaptics.lib_deps} +lib_deps = ${bhaptics.lib_deps} [env:bhaptics_tactosyh_hand_right] -build_flags = ${bhaptics.build_flags} +platform = ${bhaptics.platform} +platform_packages = ${bhaptics.platform_packages} +framework = ${bhaptics.framework} +board = ${bhaptics.board} +upload_speed = ${bhaptics.upload_speed} +monitor_speed = ${bhaptics.monitor_speed} + +build_flags = ${bhaptics.build_flags} -D BH_DEVICE_TACTOSYH -D BH_BLE_APPEARANCE=508 '-D BLUETOOTH_NAME="TactosyH_R"' '-D BH_SERIAL_NUMBER={ 0xc7, 0x5f, 0x3b, 0x06, 0x38, 0xba, 0x34, 0xfa, 0x36, 0xc1 }' -build_unflags = ${bhaptics.build_unflags} -build_src_filter = ${bhaptics.build_src_filter} +build_unflags = ${bhaptics.build_unflags} +build_src_filter = ${bhaptics.build_src_filter} + -lib_deps = ${bhaptics.lib_deps} +lib_deps = ${bhaptics.lib_deps} [env:bhaptics_tactosyf_foot_left] -build_flags = ${bhaptics.build_flags} +platform = ${bhaptics.platform} +platform_packages = ${bhaptics.platform_packages} +framework = ${bhaptics.framework} +board = ${bhaptics.board} +upload_speed = ${bhaptics.upload_speed} +monitor_speed = ${bhaptics.monitor_speed} + +build_flags = ${bhaptics.build_flags} -D BH_DEVICE_TACTOSYF -D BH_BLE_APPEARANCE=508 '-D BLUETOOTH_NAME="TactosyF_L"' '-D BH_SERIAL_NUMBER={ 0x1a, 0x45, 0x83, 0x44, 0x03, 0xc5, 0xf3, 0xc3, 0xf3, 0xb8 }' -build_unflags = ${bhaptics.build_unflags} -build_src_filter = ${bhaptics.build_src_filter} +build_unflags = ${bhaptics.build_unflags} +build_src_filter = ${bhaptics.build_src_filter} + -lib_deps = ${bhaptics.lib_deps} +lib_deps = ${bhaptics.lib_deps} [env:bhaptics_tactosyf_foot_right] -build_flags = ${bhaptics.build_flags} +platform = ${bhaptics.platform} +platform_packages = ${bhaptics.platform_packages} +framework = ${bhaptics.framework} +board = ${bhaptics.board} +upload_speed = ${bhaptics.upload_speed} +monitor_speed = ${bhaptics.monitor_speed} + +build_flags = ${bhaptics.build_flags} -D BH_DEVICE_TACTOSYF -D BH_BLE_APPEARANCE=508 '-D BLUETOOTH_NAME="TactosyF_R"' '-D BH_SERIAL_NUMBER={ 0x14, 0xb9, 0x02, 0x62, 0x41, 0xe4, 0x04, 0xb2, 0xc5, 0x11 }' -build_unflags = ${bhaptics.build_unflags} -build_src_filter = ${bhaptics.build_src_filter} +build_unflags = ${bhaptics.build_unflags} +build_src_filter = ${bhaptics.build_src_filter} + -lib_deps = ${bhaptics.lib_deps} +lib_deps = ${bhaptics.lib_deps} [env:bhaptics_tactal] -build_flags = ${bhaptics.build_flags} +platform = ${bhaptics.platform} +platform_packages = ${bhaptics.platform_packages} +framework = ${bhaptics.framework} +board = ${bhaptics.board} +upload_speed = ${bhaptics.upload_speed} +monitor_speed = ${bhaptics.monitor_speed} + +build_flags = ${bhaptics.build_flags} -D BH_DEVICE_TACTAL -D BH_BLE_APPEARANCE=508 '-D BLUETOOTH_NAME="Tactal"' '-D BH_SERIAL_NUMBER={ 0xed, 0xcb, 0x55, 0x7c, 0xd7, 0xb9, 0x16, 0xc5, 0x18, 0x2a }' -build_unflags = ${bhaptics.build_unflags} -build_src_filter = ${bhaptics.build_src_filter} +build_unflags = ${bhaptics.build_unflags} +build_src_filter = ${bhaptics.build_src_filter} + -lib_deps = ${bhaptics.lib_deps} +lib_deps = ${bhaptics.lib_deps} [env:bhaptics_tactglove_left] -build_flags = ${bhaptics.build_flags} +platform = ${bhaptics.platform} +platform_packages = ${bhaptics.platform_packages} +framework = ${bhaptics.framework} +board = ${bhaptics.board} +upload_speed = ${bhaptics.upload_speed} +monitor_speed = ${bhaptics.monitor_speed} + +build_flags = ${bhaptics.build_flags} -D BH_DEVICE_TACTGLOVE -D BH_BLE_APPEARANCE=508 '-D BLUETOOTH_NAME="TactGlove (L"' '-D BH_SERIAL_NUMBER={ 0xcd, 0x0b, 0x81, 0x45, 0x85, 0xf9, 0x2b, 0x6c, 0xed, 0x5b }' -build_unflags = ${bhaptics.build_unflags} -build_src_filter = ${bhaptics.build_src_filter} +build_unflags = ${bhaptics.build_unflags} +build_src_filter = ${bhaptics.build_src_filter} + -lib_deps = ${bhaptics.lib_deps} +lib_deps = ${bhaptics.lib_deps} [env:bhaptics_tactglove_right] -build_flags = ${bhaptics.build_flags} +platform = ${bhaptics.platform} +platform_packages = ${bhaptics.platform_packages} +framework = ${bhaptics.framework} +board = ${bhaptics.board} +upload_speed = ${bhaptics.upload_speed} +monitor_speed = ${bhaptics.monitor_speed} + +build_flags = ${bhaptics.build_flags} -D BH_DEVICE_TACTGLOVE -D BH_BLE_APPEARANCE=508 '-D BLUETOOTH_NAME="TactGlove (R"' '-D BH_SERIAL_NUMBER={ 0x12, 0x0b, 0xae, 0xbf, 0xbc, 0x90, 0x3b, 0x0d, 0x84, 0xdd }' -build_unflags = ${bhaptics.build_unflags} -build_src_filter = ${bhaptics.build_src_filter} +build_unflags = ${bhaptics.build_unflags} +build_src_filter = ${bhaptics.build_src_filter} + -lib_deps = ${bhaptics.lib_deps} +lib_deps = ${bhaptics.lib_deps} diff --git a/lib/arduino/battery/adc_naive.cpp b/lib/arduino/battery/adc_naive.cpp index d16dcddc..7d396997 100644 --- a/lib/arduino/battery/adc_naive.cpp +++ b/lib/arduino/battery/adc_naive.cpp @@ -6,6 +6,6 @@ void OH::ADCNaiveBattery::setup() { pinMode(this->pin, INPUT); } -uint8_t OH::ADCNaiveBattery::updateLevel() { +uint8_t OH::ADCNaiveBattery::updateValue() { return map(analogRead(this->pin), 0.0f, 4095.0f, 0, 255); } diff --git a/lib/arduino/battery/adc_naive.hpp b/lib/arduino/battery/adc_naive.hpp index c877caa6..886292ed 100644 --- a/lib/arduino/battery/adc_naive.hpp +++ b/lib/arduino/battery/adc_naive.hpp @@ -8,13 +8,13 @@ namespace OH { uint8_t pin; protected: - uint8_t updateLevel() override; + uint8_t updateValue() override; public: - ADCNaiveBattery(const uint8_t pin, OH::BatteryConfig config, OH::IEventDispatcher* eventDispatcher, TaskConfig taskConfig = { "ADC Battery", 2048, BATTERY_TASK_PRIORITY, tskNO_AFFINITY }) + ADCNaiveBattery(const uint8_t pin, OH::BatteryConfig config, OH::IEventDispatcher* eventDispatcher, TaskConfig taskConfig = { "ADC Battery", 4096, BATTERY_TASK_PRIORITY, tskNO_AFFINITY }) : AbstractBattery(config, eventDispatcher, taskConfig), pin(pin) {}; ADCNaiveBattery(const uint8_t pin, OH::BatteryConfig config, OH::IEventDispatcher* eventDispatcher, const BaseType_t coreId = tskNO_AFFINITY) - : AbstractBattery(config, eventDispatcher, { "ADC Battery", 2048, BATTERY_TASK_PRIORITY, coreId }), pin(pin) {}; + : AbstractBattery(config, eventDispatcher, { "ADC Battery", 4096, BATTERY_TASK_PRIORITY, coreId }), pin(pin) {}; void setup() override; }; diff --git a/lib/arduino/components/serial_plotter.cpp b/lib/arduino/components/serial_plotter.cpp index 8d5a6cbc..6231d8d1 100644 --- a/lib/arduino/components/serial_plotter.cpp +++ b/lib/arduino/components/serial_plotter.cpp @@ -2,10 +2,10 @@ template void OH::SerialPlotter_OutputStates<_Tp>::run() { - while (1) { + while (true) { for (auto& _c : *output->getComponents()) { oh_output_path_t path = _c.first; - OH::OutputComponent* component = _c.second; + OH::HapticPlane* component = _c.second; for (auto& _s : *component->getOutputStates()) { oh_output_point_t point = _s.first; diff --git a/lib/arduino/components/serial_plotter.hpp b/lib/arduino/components/serial_plotter.hpp index 1ec93a53..77de15bd 100644 --- a/lib/arduino/components/serial_plotter.hpp +++ b/lib/arduino/components/serial_plotter.hpp @@ -1,10 +1,14 @@ #pragma once -#include -#include +#include +#include #include +#ifndef SERIAL_PLOTTER_BAUD +#define SERIAL_PLOTTER_BAUD 115200 +#endif // SERIAL_PLOTTER_BAUD + namespace OH { /** * Component, that prints the current state of the output to the serial port in Arduino's Serial Plotter format @@ -17,19 +21,19 @@ namespace OH { private: _Tp* serial; - Output* output; + HapticBody* output; uint32_t sampleRate; void setup(void) {}; void run(void); public: - SerialPlotter_OutputStates(_Tp& serial, Output* output, uint32_t sampleRate, TaskConfig taskConfig = { "Serial Plotter", 2048, 1, tskNO_AFFINITY }) + SerialPlotter_OutputStates(_Tp& serial, HapticBody* output, uint32_t sampleRate, TaskConfig taskConfig = { "Serial Plotter", 2048, 1, tskNO_AFFINITY }) : Task>(taskConfig), serial(&serial), output(output), sampleRate(sampleRate) {}; - SerialPlotter_OutputStates(_Tp& serial, Output* output) : SerialPlotter_OutputStates(serial, output, 100) {}; + SerialPlotter_OutputStates(_Tp& serial, HapticBody* output) : SerialPlotter_OutputStates(serial, output, 100) {}; void begin() override { this->setup(); @@ -42,7 +46,7 @@ namespace OH { */ template<> inline void SerialPlotter_OutputStates::setup() { - this->serial->begin(115200); + this->serial->begin(SERIAL_PLOTTER_BAUD); } template class SerialPlotter_OutputStates; diff --git a/lib/arduino/output_writers/pwm.cpp b/lib/arduino/output_writers/pwm.cpp index 83ba178d..693b03af 100644 --- a/lib/arduino/output_writers/pwm.cpp +++ b/lib/arduino/output_writers/pwm.cpp @@ -7,10 +7,18 @@ uint8_t PWMOutputWriter::CHANNELS = 0; void PWMOutputWriter::setup() { this->chan = PWMOutputWriter::CHANNELS++; +#if defined(ARDUINO_ARCH_ESP32) ledcSetup(this->chan, this->freq, this->resolution); ledcAttachPin(this->pin, this->chan); +#else + pinMode(this->pin, OUTPUT); +#endif }; void PWMOutputWriter::writeOutput(oh_output_intensity_t intensity) { +#if defined(ARDUINO_ARCH_ESP32) ledcWrite(chan, (uint16_t)map(intensity, 0, OH_OUTPUT_INTENSITY_MAX, 0, 4096)); +#else + analogWrite(this->pin, (uint16_t)map(intensity, 0, OH_OUTPUT_INTENSITY_MAX, 0, 255)); +#endif } diff --git a/lib/arduino/output_writers/pwm.hpp b/lib/arduino/output_writers/pwm.hpp index 324c8c5c..7c19ac4e 100644 --- a/lib/arduino/output_writers/pwm.hpp +++ b/lib/arduino/output_writers/pwm.hpp @@ -1,9 +1,8 @@ #pragma once -#include -#include +#include -class PWMOutputWriter : public OH::AbstractOutputWriter { +class PWMOutputWriter : public OH::AbstractActuator { private: static uint8_t CHANNELS; uint8_t pin, chan; diff --git a/lib/battery/abstract_battery.cpp b/lib/battery/abstract_battery.cpp new file mode 100644 index 00000000..76c6d31a --- /dev/null +++ b/lib/battery/abstract_battery.cpp @@ -0,0 +1,10 @@ +#include "abstract_battery.hpp" + +void OH::AbstractBattery::run() { + while (true) { + this->value = this->updateValue(); + this->eventDispatcher->postEvent(new BatteryLevelEvent(this->value)); + + delay(this->rate); + } +}; diff --git a/lib/core/abstract_battery.hpp b/lib/battery/abstract_battery.hpp similarity index 59% rename from lib/core/abstract_battery.hpp rename to lib/battery/abstract_battery.hpp index 43537e33..d70973c7 100644 --- a/lib/core/abstract_battery.hpp +++ b/lib/battery/abstract_battery.hpp @@ -1,6 +1,5 @@ #pragma once -#include "abstract_component.hpp" #include "sensor.hpp" #include "events.hpp" @@ -19,28 +18,26 @@ namespace OH { }; struct BatteryConfig { - int sampleRate; + uint sampleRate; }; - class AbstractBattery : public Task, public ISensor { - friend class Task; + class AbstractBattery : public ThrottledSensor { + friend class Task>; + friend class ThrottledSensor; private: - void run(void); + void run(void) override; protected: - BatteryConfig config; IEventDispatcher* eventDispatcher; - uint8_t level = 0; // 0 = min, 255 = max virtual void setup(void) {}; - virtual uint8_t updateLevel(void) = 0; + uint8_t updateValue() override; public: - AbstractBattery(BatteryConfig config, IEventDispatcher* eventDispatcher, TaskConfig taskConfig) : Task(taskConfig), config(config), eventDispatcher(eventDispatcher) {}; - uint8_t getValue() override { return this->level; }; + AbstractBattery(BatteryConfig config, IEventDispatcher* eventDispatcher, TaskConfig taskConfig) : ThrottledSensor(taskConfig, config.sampleRate), eventDispatcher(eventDispatcher) {}; void begin() override { this->setup(); - OH::Task::begin(); + ThrottledSensor::begin(); }; }; diff --git a/lib/bh/bh_utils.hpp b/lib/bh/bh_utils.hpp deleted file mode 100644 index f661475d..00000000 --- a/lib/bh/bh_utils.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include -#include - -namespace BH { - void plainOutputTransformer(OH::Output* output, std::string& value, const oh_output_point_t* layout[], const size_t layoutSize, const oh_output_path_t path); - void vestOutputTransformer(OH::Output* output, std::string& value, const oh_output_point_t* layout[], const size_t layoutSize); - void vestX16OutputTransformer(OH::Output* output, std::string& value, const oh_output_point_t* layout[], const size_t layoutSize, const uint8_t layoutGroups[], const size_t layoutGroupsSize); -} // namespace BH diff --git a/lib/bh/bh_constants.hpp b/lib/bhaptics/bh_constants.hpp similarity index 85% rename from lib/bh/bh_constants.hpp rename to lib/bhaptics/bh_constants.hpp index 3fc895c7..a93c5be2 100644 --- a/lib/bh/bh_constants.hpp +++ b/lib/bhaptics/bh_constants.hpp @@ -1,6 +1,8 @@ #pragma once -#include +#if defined(ARDUINO_ARCH_ESP32) + #include +#endif #define BH_SERIAL_NUMBER_LENGTH 10 @@ -11,11 +13,11 @@ #define NO_AUDIO_CABLE 0 #define AUDIO_CABLE 1 -#ifdef BH_DEVICE_TACTSUITX16 +#pragma region BH_DEVICE_TACTSUITX16 #define BH_LAYOUT_TACTSUITX16_SIZE_X 4 #define BH_LAYOUT_TACTSUITX16_SIZE_Y 2 -#define BH_LAYOUT_TACTSUITX16_MAKE_POINT(x, y) OH::mapPoint(x, y, (oh_output_coord_t) (BH_LAYOUT_TACTSUITX16_SIZE_X - 1), (oh_output_coord_t) (BH_LAYOUT_TACTSUITX16_SIZE_Y - 1)) +#define BH_LAYOUT_TACTSUITX16_MAKE_POINT(x, y) OH::PlaneMapper_Margin::mapPoint(x, y, (oh_output_coord_t) (BH_LAYOUT_TACTSUITX16_SIZE_X - 1), (oh_output_coord_t) (BH_LAYOUT_TACTSUITX16_SIZE_Y - 1)) // X16 suit uses the same packets structure as x40 suit and performs motor grouping in firmware #define BH_LAYOUT_TACTSUITX16_SIZE 40 @@ -76,13 +78,13 @@ #define BH_LAYOUT_TACTSUITX16_GROUPS { 0, 1, 4, 5, 10, 11, 14, 15, 20, 21, 24, 25, 30, 31, 34, 35 } #define BH_LAYOUT_TACTSUITX16_GROUPS_SIZE 16 -#endif +#pragma endregion BH_DEVICE_TACTSUITX16 -#ifdef BH_DEVICE_TACTSUITX40 +#pragma region BH_DEVICE_TACTSUITX40 #define BH_LAYOUT_TACTSUITX40_SIZE_X 4 #define BH_LAYOUT_TACTSUITX40_SIZE_Y 5 -#define BH_LAYOUT_TACTSUITX40_MAKE_POINT(x, y) OH::mapPoint(x, y, (oh_output_coord_t) (BH_LAYOUT_TACTSUITX40_SIZE_X - 1), (oh_output_coord_t) (BH_LAYOUT_TACTSUITX40_SIZE_Y - 1)) +#define BH_LAYOUT_TACTSUITX40_MAKE_POINT(x, y) OH::PlaneMapper_Margin::mapPoint(x, y, (oh_output_coord_t) (BH_LAYOUT_TACTSUITX40_SIZE_X - 1), (oh_output_coord_t) (BH_LAYOUT_TACTSUITX40_SIZE_Y - 1)) // X * Y for front and back #define BH_LAYOUT_TACTSUITX40_SIZE 40 @@ -135,13 +137,13 @@ /* 39 */ BH_LAYOUT_TACTSUITX40_MAKE_POINT(3, 4) \ } -#endif +#pragma endregion BH_DEVICE_TACTSUITX40 -#ifdef BH_DEVICE_TACTAL +#pragma region BH_DEVICE_TACTAL #define BH_LAYOUT_TACTAL_SIZE_X 6 #define BH_LAYOUT_TACTAL_SIZE_Y 1 -#define BH_LAYOUT_TACTAL_MAKE_POINT(x, y) OH::mapPoint(x, y, (oh_output_coord_t) (BH_LAYOUT_TACTAL_SIZE_X - 1), (oh_output_coord_t) (BH_LAYOUT_TACTAL_SIZE_Y - 1)) +#define BH_LAYOUT_TACTAL_MAKE_POINT(x, y) OH::PlaneMapper_Margin::mapPoint(x, y, (oh_output_coord_t) (BH_LAYOUT_TACTAL_SIZE_X - 1), (oh_output_coord_t) (BH_LAYOUT_TACTAL_SIZE_Y - 1)) #define BH_LAYOUT_TACTAL_SIZE (BH_LAYOUT_TACTAL_SIZE_X * BH_LAYOUT_TACTAL_SIZE_Y) #define BH_LAYOUT_TACTAL { \ @@ -153,13 +155,13 @@ BH_LAYOUT_TACTAL_MAKE_POINT(5, 0), \ } -#endif +#pragma endregion BH_DEVICE_TACTAL -#ifdef BH_DEVICE_TACTOSY2 +#pragma region BH_DEVICE_TACTOSY2 #define BH_LAYOUT_TACTOSY2_SIZE_X 3 #define BH_LAYOUT_TACTOSY2_SIZE_Y 2 -#define BH_LAYOUT_TACTOSY2_MAKE_POINT(x, y) OH::mapPoint(x, y, (oh_output_coord_t) (BH_LAYOUT_TACTOSY2_SIZE_X - 1), (oh_output_coord_t) (BH_LAYOUT_TACTOSY2_SIZE_Y - 1)) +#define BH_LAYOUT_TACTOSY2_MAKE_POINT(x, y) OH::PlaneMapper_Margin::mapPoint(x, y, (oh_output_coord_t) (BH_LAYOUT_TACTOSY2_SIZE_X - 1), (oh_output_coord_t) (BH_LAYOUT_TACTOSY2_SIZE_Y - 1)) #define BH_LAYOUT_TACTOSY2_SIZE (BH_LAYOUT_TACTOSY2_SIZE_X * BH_LAYOUT_TACTOSY2_SIZE_Y) #define BH_LAYOUT_TACTOSY2 { \ @@ -167,29 +169,29 @@ BH_LAYOUT_TACTOSY2_MAKE_POINT(0, 1), BH_LAYOUT_TACTOSY2_MAKE_POINT(1, 1), BH_LAYOUT_TACTOSY2_MAKE_POINT(2, 1), \ } -#endif +#pragma endregion BH_DEVICE_TACTOSY2 -#ifdef BH_DEVICE_TACTOSYH +#pragma region BH_DEVICE_TACTOSYH #define BH_LAYOUT_TACTOSYH_SIZE_X 1 #define BH_LAYOUT_TACTOSYH_SIZE_Y 3 -#define BH_LAYOUT_TACTOSYH_MAKE_POINT(x, y) OH::mapPoint(x, y, (oh_output_coord_t) (BH_LAYOUT_TACTOSYH_SIZE_X - 1), (oh_output_coord_t) (BH_LAYOUT_TACTOSYH_SIZE_Y - 1)) +#define BH_LAYOUT_TACTOSYH_MAKE_POINT(x, y) OH::PlaneMapper_Margin::mapPoint(x, y, (oh_output_coord_t) (BH_LAYOUT_TACTOSYH_SIZE_X - 1), (oh_output_coord_t) (BH_LAYOUT_TACTOSYH_SIZE_Y - 1)) #define BH_LAYOUT_TACTOSYH_SIZE (BH_LAYOUT_TACTOSYH_SIZE_X * BH_LAYOUT_TACTOSYH_SIZE_Y) #define BH_LAYOUT_TACTOSYH { BH_LAYOUT_TACTOSYH_MAKE_POINT(0, 0), BH_LAYOUT_TACTOSYH_MAKE_POINT(0, 1), BH_LAYOUT_TACTOSYH_MAKE_POINT(0, 2) } -#endif +#pragma endregion BH_DEVICE_TACTOSYH -#ifdef BH_DEVICE_TACTOSYF +#pragma region BH_DEVICE_TACTOSYF #define BH_LAYOUT_TACTOSYF_SIZE_X 1 #define BH_LAYOUT_TACTOSYF_SIZE_Y 3 -#define BH_LAYOUT_TACTOSYF_MAKE_POINT(x, y) OH::mapPoint(x, y, (oh_output_coord_t) (BH_LAYOUT_TACTOSYF_SIZE_X - 1), (oh_output_coord_t) (BH_LAYOUT_TACTOSYF_SIZE_Y - 1)) +#define BH_LAYOUT_TACTOSYF_MAKE_POINT(x, y) OH::PlaneMapper_Margin::mapPoint(x, y, (oh_output_coord_t) (BH_LAYOUT_TACTOSYF_SIZE_X - 1), (oh_output_coord_t) (BH_LAYOUT_TACTOSYF_SIZE_Y - 1)) #define BH_LAYOUT_TACTOSYF_SIZE (BH_LAYOUT_TACTOSYF_SIZE_X * BH_LAYOUT_TACTOSYF_SIZE_Y) #define BH_LAYOUT_TACTOSYF { BH_LAYOUT_TACTOSYF_MAKE_POINT(0, 0), BH_LAYOUT_TACTOSYF_MAKE_POINT(0, 1), BH_LAYOUT_TACTOSYF_MAKE_POINT(0, 2), } -#endif +#pragma endregion BH_DEVICE_TACTOSYF // All below are weird choices of bHaptics engineers... // Why to use unconventional UUIDs, that are reserved for other purposes? diff --git a/lib/bh/bh_types.hpp b/lib/bhaptics/bh_types.hpp similarity index 100% rename from lib/bh/bh_types.hpp rename to lib/bhaptics/bh_types.hpp diff --git a/lib/bh/bh_types_c.h b/lib/bhaptics/bh_types_c.h similarity index 100% rename from lib/bh/bh_types_c.h rename to lib/bhaptics/bh_types_c.h diff --git a/lib/bh/bh_utils.cpp b/lib/bhaptics/bh_utils.cpp similarity index 63% rename from lib/bh/bh_utils.cpp rename to lib/bhaptics/bh_utils.cpp index ada179e5..223ea4e0 100644 --- a/lib/bh/bh_utils.cpp +++ b/lib/bhaptics/bh_utils.cpp @@ -2,20 +2,21 @@ #include -void BH::plainOutputTransformer(OH::Output* output, std::string& value, const oh_output_point_t* layout[], const size_t layoutSize, const oh_output_path_t path) { +void BH::plainOutputTransformer(OH::HapticBody* output, std::string& value, const oh_output_point_t* layout[], const size_t layoutSize, const oh_output_path_t path) { for (size_t i = 0; i < layoutSize; i++) { uint8_t byte = value[i]; oh_output_data_t outputData{ .point = *layout[i], - .intensity = static_cast(map(byte, 0, 100, 0, OH_OUTPUT_INTENSITY_MAX)), + // TODO: optimize generic type + .intensity = static_cast(OH::map(byte, 0, 100, 0, OH_OUTPUT_INTENSITY_MAX)), }; output->writeOutput(path, outputData); } } -void BH::vestOutputTransformer(OH::Output* output, std::string& value, const oh_output_point_t* layout[], const size_t layoutSize) { +void BH::vestOutputTransformer(OH::HapticBody* output, std::string& value, const oh_output_point_t* layout[], const size_t layoutSize) { for (size_t i = 0; i < layoutSize / 2; i++) { uint8_t byte = value[i]; uint actIndex = i * 2; @@ -23,12 +24,14 @@ void BH::vestOutputTransformer(OH::Output* output, std::string& value, const oh_ const oh_output_data_t outputData0{ .point = *layout[actIndex], - .intensity = static_cast(map(((byte >> 4) & 0xf), 0, 15, 0, OH_OUTPUT_INTENSITY_MAX)), + // TODO: optimize generic type + .intensity = static_cast(OH::map(((byte >> 4) & 0xf), 0, 15, 0, OH_OUTPUT_INTENSITY_MAX)), }; const oh_output_data_t outputData1{ .point = *layout[actIndex + 1], - .intensity = static_cast(map((byte & 0xf), 0, 15, 0, OH_OUTPUT_INTENSITY_MAX)), + // TODO: optimize generic type + .intensity = static_cast(OH::map((byte & 0xf), 0, 15, 0, OH_OUTPUT_INTENSITY_MAX)), }; output->writeOutput(path, outputData0); @@ -36,7 +39,7 @@ void BH::vestOutputTransformer(OH::Output* output, std::string& value, const oh_ } } -void BH::vestX16OutputTransformer(OH::Output* output, std::string& value, const oh_output_point_t* layout[], const size_t layoutSize, const uint8_t layoutGroups[], const size_t layoutGroupsSize) { +void BH::vestX16OutputTransformer(OH::HapticBody* output, std::string& value, const oh_output_point_t* layout[], const size_t layoutSize, const uint8_t layoutGroups[], const size_t layoutGroupsSize) { uint8_t result[layoutSize]; // Unpack values @@ -77,7 +80,8 @@ void BH::vestX16OutputTransformer(OH::Output* output, std::string& value, const const auto path = (i < 10 || i >= 30) ? OUTPUT_PATH_CHEST_FRONT : OUTPUT_PATH_CHEST_BACK; const oh_output_data_t outputData{ .point = *layout[i], - .intensity = static_cast(map(result[i], 0, 15, 0, OH_OUTPUT_INTENSITY_MAX)), + // TODO: optimize generic type + .intensity = static_cast(OH::map(result[i], 0, 15, 0, OH_OUTPUT_INTENSITY_MAX)), }; output->writeOutput(path, outputData); diff --git a/lib/bhaptics/bh_utils.hpp b/lib/bhaptics/bh_utils.hpp new file mode 100644 index 00000000..f3ac91bd --- /dev/null +++ b/lib/bhaptics/bh_utils.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +namespace BH { + void plainOutputTransformer(OH::HapticBody* output, std::string& value, const oh_output_point_t* layout[], const size_t layoutSize, const oh_output_path_t path); + void vestOutputTransformer(OH::HapticBody* output, std::string& value, const oh_output_point_t* layout[], const size_t layoutSize); + void vestX16OutputTransformer(OH::HapticBody* output, std::string& value, const oh_output_point_t* layout[], const size_t layoutSize, const uint8_t layoutGroups[], const size_t layoutGroupsSize); +} // namespace BH diff --git a/lib/bh/connection_bhble.cpp b/lib/bhaptics_ble/connection_bhble.cpp similarity index 50% rename from lib/bh/connection_bhble.cpp rename to lib/bhaptics_ble/connection_bhble.cpp index 02d20d2a..ff573869 100644 --- a/lib/bh/connection_bhble.cpp +++ b/lib/bhaptics_ble/connection_bhble.cpp @@ -1,55 +1,67 @@ -#include +#include "connection_bhble.hpp" -#include +#include #include #include -#include -#include + +#if defined(BLUETOOTH_USE_NIMBLE) && BLUETOOTH_USE_NIMBLE == true + // BLE2902 not needed: https://github.com/h2zero/NimBLE-Arduino/blob/release/1.4/docs/Migration_guide.md#descriptors + + #define PROPERTY_READ NIMBLE_PROPERTY::READ + #define PROPERTY_WRITE NIMBLE_PROPERTY::WRITE + #define PROPERTY_WRITE_NR NIMBLE_PROPERTY::WRITE_NR + #define PROPERTY_BROADCAST NIMBLE_PROPERTY::BROADCAST + #define PROPERTY_NOTIFY NIMBLE_PROPERTY::NOTIFY + #define PROPERTY_INDICATE NIMBLE_PROPERTY::INDICATE +#else + #include + + #define PROPERTY_READ BLECharacteristic::PROPERTY_READ + #define PROPERTY_WRITE BLECharacteristic::PROPERTY_WRITE + #define PROPERTY_WRITE_NR BLECharacteristic::PROPERTY_WRITE_NR + #define PROPERTY_BROADCAST BLECharacteristic::PROPERTY_BROADCAST + #define PROPERTY_NOTIFY BLECharacteristic::PROPERTY_NOTIFY + #define PROPERTY_INDICATE BLECharacteristic::PROPERTY_INDICATE +#endif class BHServerCallbacks final : public BLEServerCallbacks { + private: + OH::IEventDispatcher* dispatcher; + public: - BHServerCallbacks() {} + BHServerCallbacks(OH::IEventDispatcher* eventDispatcher) : dispatcher(eventDispatcher) {} + + void onConnect(BLEServer* pServer) { + this->dispatcher->postEvent(new OH::IEvent(OH_EVENT_CONNECTED)); + } void onDisconnect(BLEServer* pServer) { + this->dispatcher->postEvent(new OH::IEvent(OH_EVENT_DISCONNECTED)); pServer->startAdvertising(); } }; class SerialOutputCharCallbacks : public BLECharacteristicCallbacks { void onWrite(BLECharacteristic* pCharacteristic) override { - Serial.printf(">>\tonWrite (UUID: %s) \n", - pCharacteristic->getUUID().toString().c_str()); - Serial.printf("\tvalue: `%s`, len: %u \n", - pCharacteristic->getValue().c_str(), - pCharacteristic->getValue().length()); + log_d(">>\tonWrite (UUID: %s)\n\tvalue: `%s`, len: %u", pCharacteristic->getUUID().toString().c_str(), pCharacteristic->getValue().c_str(), pCharacteristic->getValue().length()); }; void onRead(BLECharacteristic* pCharacteristic) override { - Serial.printf(">>\tonRead (UUID: %s) \n", - pCharacteristic->getUUID().toString().c_str()); - Serial.printf("\tvalue: `%s`, len: %u \n", - pCharacteristic->getValue().c_str(), - pCharacteristic->getValue().length()); + log_d(">>\tonRead (UUID: %s)\n\tvalue: `%s`, len: %u", pCharacteristic->getUUID().toString().c_str(), pCharacteristic->getValue().c_str(), pCharacteristic->getValue().length()); }; void onNotify(BLECharacteristic* pCharacteristic) override { - Serial.printf(">>\tonNotify (UUID: %s) \n", - pCharacteristic->getUUID().toString().c_str()); - Serial.printf("\tvalue: `%s`, len: %u \n", - pCharacteristic->getValue().c_str(), - pCharacteristic->getValue().length()); + log_d(">>\tonNotify (UUID: %s)\n\tvalue: `%s`, len: %u", pCharacteristic->getUUID().toString().c_str(), pCharacteristic->getValue().c_str(), pCharacteristic->getValue().length()); }; - void onStatus(BLECharacteristic* pCharacteristic, - Status s, - uint32_t code) override { - Serial.printf(">>\tonStatus (UUID: %s) \n", - pCharacteristic->getUUID().toString().c_str()); - Serial.printf("\tstatus: %d, code: %u \n", s, code); - Serial.printf("\tvalue: `%s`, len: %u \n", - pCharacteristic->getValue().c_str(), - pCharacteristic->getValue().length()); + #if defined(BLUETOOTH_USE_NIMBLE) && BLUETOOTH_USE_NIMBLE == true + void onStatus(BLECharacteristic* pCharacteristic, Status s, int code) override + #else + void onStatus(BLECharacteristic* pCharacteristic, Status s, uint32_t code) override + #endif + { + log_d(">>\tonNotify (UUID: %s)\n\tstatus: %d, code: %u \n\tvalue: `%s`, len: %u", pCharacteristic->getUUID().toString().c_str(), s, code, pCharacteristic->getValue().c_str(), pCharacteristic->getValue().length()); }; }; @@ -58,11 +70,10 @@ class MotorCharCallbacks : public BLECharacteristicCallbacks { bh_motor_handler_t motorTransformer; public: - MotorCharCallbacks(bh_motor_handler_t motorTransformer) - : motorTransformer(motorTransformer) {} + MotorCharCallbacks(bh_motor_handler_t motorTransformer) : motorTransformer(motorTransformer) {} void onWrite(BLECharacteristic* pCharacteristic) override { - auto value = pCharacteristic->getValue(); + std::string value = pCharacteristic->getValue(); this->motorTransformer(value); }; @@ -76,20 +87,22 @@ class ConfigCharCallbacks : public BLECharacteristicCallbacks { return; } - auto byte_0 = value[0], byte_1 = value[1], - byte_2 = value[2]; // this is the only byte, that ever changes + auto byte_0 = value[0], + byte_1 = value[1], + byte_2 = value[2]; - // Serial.printf(">>\tonWrite (Config Char): %3hhu %2hhu %2hhu \n", byte_0, - // byte_1, byte_2); + log_d(">>\tonWrite (Config Char): %3hhu %2hhu %2hhu", byte_0, byte_1, byte_2); }; }; void BH::ConnectionBHBLE::begin() { BLEDevice::init(this->config.deviceName); + this->callbacks->postInit(); + this->bleServer = BLEDevice::createServer(); - this->bleServer->setCallbacks(new BHServerCallbacks()); + this->bleServer->setCallbacks(new BHServerCallbacks(this->eventDispatcher)); auto scanResponseData = new BLEAdvertisementData(); scanResponseData->setAppearance(this->config.appearance); @@ -100,34 +113,37 @@ void BH::ConnectionBHBLE::begin() { // Each characteristic needs 2 handles and descriptor 1 handle. this->motorService = - this->bleServer->createService(BH_BLE_SERVICE_MOTOR_UUID, 25); + this->bleServer->createService(BH_BLE_SERVICE_MOTOR_UUID); { - MotorCharCallbacks* motorCallbacks = - new MotorCharCallbacks(this->motorHandler); + MotorCharCallbacks* motorCallbacks = new MotorCharCallbacks(this->motorHandler); auto* motorChar = this->motorService->createCharacteristic( BH_BLE_SERVICE_MOTOR_CHAR_MOTOR_UUID, - BLECharacteristic::PROPERTY_WRITE_NR); + PROPERTY_WRITE_NR + ); motorChar->setCallbacks(motorCallbacks); auto* motorCharStable = this->motorService->createCharacteristic( BH_BLE_SERVICE_MOTOR_CHAR_MOTOR_STABLE_UUID, - BLECharacteristic::PROPERTY_WRITE); + PROPERTY_WRITE + ); motorCharStable->setCallbacks(motorCallbacks); } { auto* configChar = this->motorService->createCharacteristic( BH_BLE_SERVICE_MOTOR_CHAR_CONFIG_UUID, - BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE); + PROPERTY_READ | PROPERTY_WRITE + ); configChar->setCallbacks(new ConfigCharCallbacks()); } { auto* serialNumberChar = this->motorService->createCharacteristic( BH_BLE_SERVICE_MOTOR_CHAR_SERIAL_KEY_UUID, - BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE); + PROPERTY_READ | PROPERTY_WRITE + ); serialNumberChar->setValue(this->config.serialNumber, BH_SERIAL_NUMBER_LENGTH); serialNumberChar->setCallbacks(new SerialOutputCharCallbacks()); } @@ -135,28 +151,29 @@ void BH::ConnectionBHBLE::begin() { { this->batteryChar = this->motorService->createCharacteristic( BH_BLE_SERVICE_MOTOR_CHAR_BATTERY_UUID, - BLECharacteristic::PROPERTY_READ | - BLECharacteristic:: - PROPERTY_WRITE_NR // for whatever reason, it have to be - // writable, otherwise Desktop app crashes + PROPERTY_READ | PROPERTY_WRITE_NR | PROPERTY_NOTIFY // for whatever reason, it have to bewritable, otherwise Desktop app crashes ); + +#if !defined(BLUETOOTH_USE_NIMBLE) || BLUETOOTH_USE_NIMBLE != true batteryChar->addDescriptor(new BLE2902()); +#endif // original bHaptics Player require non-null value for battery level, otherwise it crashes #if defined(BATTERY_ENABLED) && BATTERY_ENABLED == true - uint16_t defaultLevel = 0; + uint16_t defaultLevel = 0; #else - uint16_t defaultLevel = 100; + uint16_t defaultLevel = 100; #endif - this->batteryChar->setValue(defaultLevel); - // this->batteryChar->notify(); + this->batteryChar->setValue(defaultLevel); + // this->batteryChar->notify(); } { auto* versionChar = this->motorService->createCharacteristic( BH_BLE_SERVICE_MOTOR_CHAR_VERSION_UUID, - BLECharacteristic::PROPERTY_READ); + PROPERTY_READ + ); versionChar->setCallbacks(new SerialOutputCharCallbacks()); uint16_t firmwareVersion = BH_FIRMWARE_VERSION; versionChar->setValue(firmwareVersion); @@ -165,54 +182,39 @@ void BH::ConnectionBHBLE::begin() { { auto* monitorChar = this->motorService->createCharacteristic( BH_BLE_SERVICE_MOTOR_CHAR_TACTSUIT_MONITOR_UUID, - BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | - BLECharacteristic::PROPERTY_NOTIFY | - BLECharacteristic::PROPERTY_BROADCAST | - BLECharacteristic::PROPERTY_INDICATE | - BLECharacteristic::PROPERTY_WRITE_NR); + PROPERTY_READ | PROPERTY_WRITE | PROPERTY_NOTIFY | PROPERTY_BROADCAST | PROPERTY_INDICATE | PROPERTY_WRITE_NR + ); monitorChar->setCallbacks(new SerialOutputCharCallbacks()); + +#if !defined(BLUETOOTH_USE_NIMBLE) || BLUETOOTH_USE_NIMBLE != true monitorChar->addDescriptor(new BLE2902()); +#endif + uint16_t audioCableState = NO_AUDIO_CABLE; monitorChar->setValue(audioCableState); } // auto* athGlobalChar = this->motorService->createCharacteristic( // BH_BLE_SERVICE_MOTOR_CHAR_ATH_GLOBAL_CONF_UUID, - // BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | - // BLECharacteristic::PROPERTY_NOTIFY | - // BLECharacteristic::PROPERTY_BROADCAST| - // BLECharacteristic::PROPERTY_INDICATE| - // BLECharacteristic::PROPERTY_WRITE_NR + // PROPERTY_READ | PROPERTY_WRITE | PROPERTY_NOTIFY | PROPERTY_BROADCAST | PROPERTY_INDICATE | PROPERTY_WRITE_NR // ); // athGlobalChar->setCallbacks(new SerialOutputCharCallbacks()); // auto* athThemeChar = this->motorService->createCharacteristic( // BH_BLE_SERVICE_MOTOR_CHAR_ATH_THEME_UUID, - // BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | - // BLECharacteristic::PROPERTY_NOTIFY | - // BLECharacteristic::PROPERTY_BROADCAST| - // BLECharacteristic::PROPERTY_INDICATE| - // BLECharacteristic::PROPERTY_WRITE_NR + // PROPERTY_READ | PROPERTY_WRITE | PROPERTY_NOTIFY | PROPERTY_BROADCAST | PROPERTY_INDICATE | PROPERTY_WRITE_NR // ); // athThemeChar->setCallbacks(new SerialOutputCharCallbacks()); // auto* motorMappingChar = this->motorService->createCharacteristic( // BH_BLE_SERVICE_MOTOR_CHAR_MOTTOR_MAPPING_UUID, - // BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | - // BLECharacteristic::PROPERTY_NOTIFY | - // BLECharacteristic::PROPERTY_BROADCAST| - // BLECharacteristic::PROPERTY_INDICATE| - // BLECharacteristic::PROPERTY_WRITE_NR + // PROPERTY_READ | PROPERTY_WRITE | PROPERTY_NOTIFY | PROPERTY_BROADCAST | PROPERTY_INDICATE | PROPERTY_WRITE_NR // ); // motorMappingChar->setCallbacks(new SerialOutputCharCallbacks()); // auto* signatureMappingChar = this->motorService->createCharacteristic( // BH_BLE_SERVICE_MOTOR_CHAR_SIGNATURE_PATTERN_UUID, - // BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | - // BLECharacteristic::PROPERTY_NOTIFY | - // BLECharacteristic::PROPERTY_BROADCAST| - // BLECharacteristic::PROPERTY_INDICATE| - // BLECharacteristic::PROPERTY_WRITE_NR + // PROPERTY_READ | PROPERTY_WRITE | PROPERTY_NOTIFY | PROPERTY_BROADCAST | PROPERTY_INDICATE | PROPERTY_WRITE_NR // ); // signatureMappingChar->setCallbacks(new SerialOutputCharCallbacks()); @@ -223,7 +225,7 @@ void BH::ConnectionBHBLE::begin() { auto* dfuControlChar = dfuService->createCharacteristic( BH_BLE_SERVICE_MOTOR_CHAR_SIGNATURE_PATTERN_UUID, - BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE); + PROPERTY_READ | PROPERTY_WRITE); dfuService->start(); } diff --git a/lib/bh/connection_bhble.hpp b/lib/bhaptics_ble/connection_bhble.hpp similarity index 72% rename from lib/bh/connection_bhble.hpp rename to lib/bhaptics_ble/connection_bhble.hpp index b7070e15..7e9978e0 100644 --- a/lib/bh/connection_bhble.hpp +++ b/lib/bhaptics_ble/connection_bhble.hpp @@ -6,12 +6,16 @@ #include #include -#include #include +#if defined(BLUETOOTH_USE_NIMBLE) && BLUETOOTH_USE_NIMBLE == true + #include +#else + #include +#endif + #if defined(BATTERY_ENABLED) && BATTERY_ENABLED == true -#include "abstract_battery.hpp" -#include + #include #endif // typedef void (*bh_motor_handler_t)(std::string&); @@ -19,6 +23,15 @@ typedef std::function bh_motor_handler_t; namespace BH { + class BHBLEConnectionCallbacks { + public: + virtual void postInit() { + log_v("Default postInit"); + }; + }; + + static BHBLEConnectionCallbacks defaultCallback; + struct ConnectionBHBLE_Config { std::string deviceName; uint16_t appearance; @@ -35,6 +48,8 @@ namespace BH BLEService* motorService = nullptr; BLECharacteristic* batteryChar = nullptr; + BHBLEConnectionCallbacks* callbacks = &defaultCallback; + #if defined(BATTERY_ENABLED) && BATTERY_ENABLED == true void handleBatteryChange(const OH::BatteryLevelEvent* event) const; #endif @@ -59,5 +74,13 @@ namespace BH } #endif }; + + void setCallbacks(BHBLEConnectionCallbacks* pCallbacks) { + if (pCallbacks != nullptr) { + this->callbacks = pCallbacks; + } else { + this->callbacks = &defaultCallback; + } + }; }; } // namespace OH diff --git a/lib/core/abstract_battery.cpp b/lib/core/abstract_battery.cpp deleted file mode 100644 index 6bf5b9fa..00000000 --- a/lib/core/abstract_battery.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "abstract_battery.hpp" - -#ifdef ARDUINO -#include -#endif - -void OH::AbstractBattery::run() { - while (1) { - this->level = this->updateLevel(); - this->eventDispatcher->postEvent(new BatteryLevelEvent(this->level)); - - delay(this->config.sampleRate); - } -}; diff --git a/lib/core/abstract_component.cpp b/lib/core/abstract_component.cpp deleted file mode 100644 index ee0d59fc..00000000 --- a/lib/core/abstract_component.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "abstract_component.hpp" diff --git a/lib/core/abstract_component.hpp b/lib/core/abstract_component.hpp deleted file mode 100644 index 7610bc76..00000000 --- a/lib/core/abstract_component.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include -#include - -#include "task.hpp" - -#include - -namespace OH { - class IComponent { - public: - virtual void setup(void) {}; - }; - - class AbstractComponent : public IComponent { - }; - - template - class IComponentRegistry { - public: - virtual std::set<_Tp*> getComponents() = 0; - virtual void registerComponent(_Tp*) = 0; - }; -} // namespace OH diff --git a/lib/core/abstract_connection.hpp b/lib/core/abstract_connection.hpp index fd77b8de..75f899b6 100644 --- a/lib/core/abstract_connection.hpp +++ b/lib/core/abstract_connection.hpp @@ -1,6 +1,5 @@ #pragma once -#include "abstract_component.hpp" #include "events.hpp" namespace OH { class AbstractConnection { diff --git a/lib/core/logging.hpp b/lib/core/logging.hpp index f0ca9e33..1679cc2d 100644 --- a/lib/core/logging.hpp +++ b/lib/core/logging.hpp @@ -1,5 +1,17 @@ #pragma once #if defined(ARDUINO_ARCH_ESP32) -#include + #include +#elif defined(UNITY_INCLUDE_PRINT_FORMATTED) + #define log_e(...) TEST_PRINTF(__VA_ARGS__) + #define log_w(...) TEST_PRINTF(__VA_ARGS__) + #define log_i(...) TEST_PRINTF(__VA_ARGS__) + #define log_d(...) TEST_PRINTF(__VA_ARGS__) + #define log_t(...) TEST_PRINTF(__VA_ARGS__) +#else + #define log_e(...) + #define log_w(...) + #define log_i(...) + #define log_d(...) + #define log_t(...) #endif diff --git a/lib/core/sensor.hpp b/lib/core/sensor.hpp deleted file mode 100644 index 554c2307..00000000 --- a/lib/core/sensor.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -namespace OH -{ - template - class ISensor { - public: - virtual _Tp getValue() = 0; - }; -} // namespace OH diff --git a/lib/core/types.hpp b/lib/core/types.hpp index 4f029163..d5e7d8ba 100644 --- a/lib/core/types.hpp +++ b/lib/core/types.hpp @@ -1,7 +1,7 @@ #pragma once -#include "abstract_output_writer.hpp" -#include "point2.hpp" +#include +#include #include @@ -25,5 +25,4 @@ namespace OH { typedef OH::OutputData oh_output_data_t; typedef OH::OutputState oh_output_state_t; -typedef std::map - oh_output_writers_map_t; +typedef std::map oh_output_writers_map_t; diff --git a/lib/core/utility.cpp b/lib/core/utility.cpp deleted file mode 100644 index 6b851aaa..00000000 --- a/lib/core/utility.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "utility.hpp" diff --git a/lib/core/utility.hpp b/lib/core/utility.hpp index b60c3aa9..606375e4 100644 --- a/lib/core/utility.hpp +++ b/lib/core/utility.hpp @@ -24,4 +24,9 @@ namespace OH { inline bool contains(const _Tp* arr, const std::size_t size, const _Tp& val) { return std::find(arr, arr + size, val) != arr + size; }; + + template + inline _Tp map(_Tp x, _Tp in_min, _Tp in_max, _Tp out_min, _Tp out_max) { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; + } } // namespace OH diff --git a/lib/core/task.hpp b/lib/freertos/task.hpp similarity index 84% rename from lib/core/task.hpp rename to lib/freertos/task.hpp index 43b482b7..5804b5f5 100644 --- a/lib/core/task.hpp +++ b/lib/freertos/task.hpp @@ -2,10 +2,25 @@ #include "logging.hpp" -#include +extern "C" void delay(uint32_t ms); + +#if defined(ARDUINO_ARCH_ESP32) #include // Include the base FreeRTOS definitions. #include // Include the task definitions. +extern "C" { + BaseType_t xTaskCreateUniversal( + TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask, + const BaseType_t xCoreID + ); +} +#endif + namespace OH { struct TaskConfig { const char *name; @@ -14,8 +29,6 @@ namespace OH { const BaseType_t coreId = tskNO_AFFINITY; }; - class TaskComponent; - // Static polymorphic abstract base class for a FreeRTOS task using CRTP // pattern. Concrete implementations should implement a run() method. // @@ -23,7 +36,6 @@ namespace OH { template class Task { template friend class Task; - friend class TaskComponent; private: TaskConfig taskConfig; diff --git a/lib/haptics/haptic_body.cpp b/lib/haptics/haptic_body.cpp new file mode 100644 index 00000000..5da168c3 --- /dev/null +++ b/lib/haptics/haptic_body.cpp @@ -0,0 +1,22 @@ +#include "haptic_body.hpp" + +#include + +void OH::HapticBody::addComponent(const oh_output_path_t path, OH::HapticPlane* c) { + this->components[path] = c; +} + +std::map* OH::HapticBody::getComponents() { + return &this->components; +} + +void OH::HapticBody::writeOutput(const oh_output_path_t path, const oh_output_data_t& data) { + if (this->getComponents()->count(path) == 0) { + // if no requested component exists, skip + log_w("No component found for path %d", path); + return; + } + + auto componentSearch = this->getComponents()->find(path); + (*componentSearch).second->writeOutput(data); +} diff --git a/lib/haptics/haptic_body.hpp b/lib/haptics/haptic_body.hpp new file mode 100644 index 00000000..14cf0c70 --- /dev/null +++ b/lib/haptics/haptic_body.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "haptic_constants.h" +#include "haptic_plane.hpp" + +#include +#include + +#include + +namespace OH { + class HapticBody { + private: + typedef std::map oh_output_components_map_t; + std::map components{}; + + public: + HapticBody() {}; + + void addComponent(const oh_output_path_t, HapticPlane*); + oh_output_components_map_t* getComponents(); + + void writeOutput(const oh_output_path_t, const oh_output_data_t&); + + void setup() { + for (auto& component : this->components) { + component.second->setup(); + } + }; + }; +} // namespace OH diff --git a/lib/output/output_constants.h b/lib/haptics/haptic_constants.h similarity index 100% rename from lib/output/output_constants.h rename to lib/haptics/haptic_constants.h diff --git a/lib/output/output_component.cpp b/lib/haptics/haptic_plane.cpp similarity index 55% rename from lib/output/output_component.cpp rename to lib/haptics/haptic_plane.cpp index ed4b919f..c399872b 100644 --- a/lib/output/output_component.cpp +++ b/lib/haptics/haptic_plane.cpp @@ -1,8 +1,11 @@ -#include "output_component.hpp" +#include "haptic_plane.hpp" +#include +#include +#include #include -void OH::OutputComponent::setOutputs(oh_output_writers_map_t& outputs) { +void OH::HapticPlane::setOutputs(oh_output_writers_map_t& outputs) { this->writers.clear(); this->writers = outputs; @@ -17,31 +20,32 @@ void OH::OutputComponent::setOutputs(oh_output_writers_map_t& outputs) { } } -void OH::OutputComponent::setup() { +void OH::HapticPlane::setup() { for (const auto& kv : this->writers) { kv.second->setup(); } } -void OH::OutputComponent::writeOutput(const oh_output_data_t& data) { +void OH::HapticPlane::writeOutput(const oh_output_data_t& data) { if (this->writers.count(data.point) == 0) { log_w("No writer for point (%u, %u)", data.point.x, data.point.y); return; } - this->writers[data.point]->writeOutput(data.intensity); + auto state = &this->states[data.point]; + state->intensity = data.intensity; + + this->writers.at(data.point)->writeOutput(state->intensity); } -oh_output_point_t OH::ClosestOutputComponent::findClosestPoints( - std::list& pts, - const oh_output_point_t& target) { +oh_output_point_t OH::HapticPlane_Closest::findClosestPoints(std::list& pts, const oh_output_point_t& target) { + if (contains(pts, target)) { + return target; + } + std::multimap mp = {}; for (auto& _p : pts) { - if (target == _p) { - return _p; // if coord == target, no other needed - } - float dx = abs(((float)target.x / OH_OUTPUT_COORD_MAX) - ((float)_p.x / OH_OUTPUT_COORD_MAX)), dy = abs(((float)target.y / OH_OUTPUT_COORD_MAX) - ((float)_p.y / OH_OUTPUT_COORD_MAX)); @@ -51,16 +55,18 @@ oh_output_point_t OH::ClosestOutputComponent::findClosestPoints( } auto nearest = - std::min_element(mp.begin(), mp.end(), - [](const std::pair& a, - const std::pair& b) { - return a.first < b.first; - }); + std::min_element( + mp.begin(), + mp.end(), + [](const std::pair& a, const std::pair& b) { + return a.first < b.first; + } + ); return nearest->second; } -void OH::ClosestOutputComponent::writeOutput(const oh_output_data_t& data) { +void OH::HapticPlane_Closest::writeOutput(const oh_output_data_t& data) { auto closestPoint = this->findClosestPoints(this->points, data.point); auto state = &this->states[closestPoint]; diff --git a/lib/haptics/haptic_plane.hpp b/lib/haptics/haptic_plane.hpp new file mode 100644 index 00000000..8fffb099 --- /dev/null +++ b/lib/haptics/haptic_plane.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace OH { + /** + * Output "plane" (e.g. Chest, Palm, Finger, etc.) + */ + class HapticPlane { + protected: + std::list points{}; + oh_output_writers_map_t writers{}; + std::map states{}; + + void setOutputs(oh_output_writers_map_t&); + + public: + HapticPlane(oh_output_writers_map_t& outputs) { + this->setOutputs(outputs); + }; + std::list* getOutputPoints(void) { + return &this->points; + }; + std::map* getOutputStates(void) { + return &this->states; + }; + virtual void writeOutput(const oh_output_data_t&); + void setup(); + }; + + class HapticPlane_Closest : public HapticPlane { + protected: + oh_output_point_t findClosestPoints(std::list& pts, const oh_output_point_t& target); + void setOutputs(oh_output_writers_map_t&); + + public: + HapticPlane_Closest(oh_output_writers_map_t& outputs) : HapticPlane(outputs) {}; + void writeOutput(const oh_output_data_t&) override; + }; + + class PlaneMapper_Margin { + public: + + /** + * Re-maps a point index to output coordinate. + * @tparam _Tp The type of the point index. + */ + template + static inline oh_output_point_t* mapPoint(_Tp x, _Tp y, _Tp x_max, _Tp y_max) { + const oh_output_coord_t x_coord = map<_Tp>(x + 1, 0, x_max + 2, 0, OH_OUTPUT_COORD_MAX); + const oh_output_coord_t y_coord = map<_Tp>(y + 1, 0, y_max + 2, 0, OH_OUTPUT_COORD_MAX); + + return new oh_output_point_t(x_coord, y_coord); + } + + template + static inline std::map mapMatrixCoordinates(std::vector> map2d) { + std::map points{}; + + size_t y_size = map2d.size(); + size_t y_max = y_size - 1; + + for (size_t y = 0; y < y_size; ++y) { + auto row = map2d.at(y); + size_t x_size = row.size(); + size_t x_max = x_size - 1; + + for (size_t x = 0; x < x_size; ++x) { + AbstractActuator* wr = row.at(x); + oh_output_point_t* coord = mapPoint(x, y, x_max, y_max); + + points[*coord] = wr; + } + } + + return points; + } + }; +} // namespace OH diff --git a/lib/ina219/battery/ina219.cpp b/lib/ina219/battery/ina219.cpp index 02993f9f..ed882f00 100644 --- a/lib/ina219/battery/ina219.cpp +++ b/lib/ina219/battery/ina219.cpp @@ -4,7 +4,7 @@ void OH::INA219_Battery::setup() { this->active = this->sensor->begin(); } -uint8_t OH::INA219_Battery::updateLevel() { +uint8_t OH::INA219_Battery::updateValue() { if (!this->active) { return 0; } diff --git a/lib/ina219/battery/ina219.hpp b/lib/ina219/battery/ina219.hpp index 416b7b2d..d6d305cc 100644 --- a/lib/ina219/battery/ina219.hpp +++ b/lib/ina219/battery/ina219.hpp @@ -11,7 +11,7 @@ namespace OH { Adafruit_INA219* sensor; protected: - uint8_t updateLevel() override; + uint8_t updateValue() override; public: INA219_Battery(Adafruit_INA219* sensor, OH::BatteryConfig config, OH::IEventDispatcher* eventDispatcher, const BaseType_t coreId = tskNO_AFFINITY) diff --git a/lib/max17048/battery/max17048.cpp b/lib/max17048/battery/max17048.cpp index a32560c8..04216506 100644 --- a/lib/max17048/battery/max17048.cpp +++ b/lib/max17048/battery/max17048.cpp @@ -17,7 +17,7 @@ void OH::MAX1704_Battery::setup() { } } -uint8_t OH::MAX1704_Battery::updateLevel() { +uint8_t OH::MAX1704_Battery::updateValue() { if (!this->active) { return 0; } diff --git a/lib/max17048/battery/max17048.hpp b/lib/max17048/battery/max17048.hpp index cf5f7659..4558f6c3 100644 --- a/lib/max17048/battery/max17048.hpp +++ b/lib/max17048/battery/max17048.hpp @@ -11,7 +11,7 @@ namespace OH { SFE_MAX1704X* gauge; protected: - uint8_t updateLevel() override; + uint8_t updateValue() override; public: MAX1704_Battery(SFE_MAX1704X* gauge, OH::BatteryConfig config, OH::IEventDispatcher* eventDispatcher, const BaseType_t coreId) diff --git a/lib/output/abstract_output_writer.hpp b/lib/output/abstract_actuator.hpp similarity index 92% rename from lib/output/abstract_output_writer.hpp rename to lib/output/abstract_actuator.hpp index 6871550f..67d94dfe 100644 --- a/lib/output/abstract_output_writer.hpp +++ b/lib/output/abstract_actuator.hpp @@ -9,7 +9,7 @@ typedef OH_OUTPUT_INTENSITY_T oh_output_intensity_t; namespace OH { //! Singular output point (e.g. vibration motor) - class AbstractOutputWriter { + class AbstractActuator { public: virtual void setup(){}; virtual void writeOutput(oh_output_intensity_t intensity) = 0; diff --git a/lib/output/output.cpp b/lib/output/output.cpp deleted file mode 100644 index 03a0e874..00000000 --- a/lib/output/output.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "output.hpp" - -#include - -void OH::Output::addComponent(OH::OutputComponent* c) { - auto path = c->getPath(); - this->components[path] = c; -} - -std::map* OH::Output::getComponents() { - return &this->components; -} - -void OH::Output::writeOutput(const oh_output_path_t path, const oh_output_data_t& data) { - if (this->getComponents()->count(path) == 0) { - // if no requested component exists, skip - log_w("No component found for path %d", path); - return; - } - - auto componentSearch = this->getComponents()->find(path); - (*componentSearch).second->writeOutput(data); -} - -template -inline std::map OH::mapMatrixCoordinates(std::vector> map2d) { - std::map points{}; - - size_t y_size = map2d.size(); - size_t y_max = y_size - 1; - - for (size_t y = 0; y < y_size; ++y) { - auto row = map2d.at(y); - size_t x_size = row.size(); - size_t x_max = x_size - 1; - - for (size_t x = 0; x < x_size; ++x) { - AbstractOutputWriter* wr = row.at(x); - oh_output_point_t* coord = mapPoint(x, y, x_max, y_max); - - points[*coord] = wr; - } - } - - return points; -}; - -template oh_output_writers_map_t OH::mapMatrixCoordinates(std::vector>); diff --git a/lib/output/output.hpp b/lib/output/output.hpp deleted file mode 100644 index a798d07f..00000000 --- a/lib/output/output.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include "output_constants.h" -#include "output_component.hpp" - -#include -#include - -#include - -namespace OH { - class Output { - private: - typedef std::map oh_output_components_map_t; - std::map components{}; - - public: - Output() {}; - - void addComponent(OutputComponent*); - oh_output_components_map_t* getComponents(); - - void writeOutput(const oh_output_path_t, const oh_output_data_t&); - - void setup() { - for (auto& component : this->components) { - component.second->setup(); - } - }; - }; - - /** - * Re-maps a point index to output coordinate. - * @tparam _Tp The type of the point index. - */ - template - oh_output_point_t* mapPoint(_Tp x, _Tp y, _Tp x_max, _Tp y_max) { - const oh_output_coord_t x_coord = map(x, 0, x_max != 0 ? x_max : 1, 0, OH_OUTPUT_COORD_MAX); - const oh_output_coord_t y_coord = map(y, 0, y_max != 0 ? y_max : 1, 0, OH_OUTPUT_COORD_MAX); - - return new oh_output_point_t(x_coord, y_coord); - } - - template - std::map mapMatrixCoordinates(std::vector> map2d); -} // namespace OH diff --git a/lib/output/output_component.hpp b/lib/output/output_component.hpp deleted file mode 100644 index c4bfe643..00000000 --- a/lib/output/output_component.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include "abstract_output_writer.hpp" - -#include -#include - -#include -#include -#include - -namespace OH { - /** - * Output "plane" (e.g. Chest, Palm, Finger, etc.) - */ - class OutputComponent : public OH::AbstractComponent { - private: - oh_output_path_t path; - protected: - std::list points{}; - oh_output_writers_map_t writers{}; - std::map states{}; - - void setOutputs(oh_output_writers_map_t&); - - public: - OutputComponent(oh_output_path_t path, oh_output_writers_map_t& outputs) : path(path) { - this->setOutputs(outputs); - }; - oh_output_path_t getPath(void) { - return this->path; - }; - std::list* getOutputPoints(void) { - return &this->points; - }; - std::map* getOutputStates(void) { - return &this->states; - }; - virtual void writeOutput(const oh_output_data_t&); - void setup() override; - }; - - class ClosestOutputComponent : public OutputComponent { - protected: - oh_output_point_t findClosestPoints(std::list& pts, const oh_output_point_t& target); - void setOutputs(oh_output_writers_map_t&); - - public: - ClosestOutputComponent(oh_output_path_t path, oh_output_writers_map_t& outputs) - : OutputComponent(path, outputs) {}; - void writeOutput(const oh_output_data_t&) override; - }; -} // namespace OH diff --git a/lib/pca9685/output_writers/pca9685.hpp b/lib/pca9685/output_writers/pca9685.hpp index eded1981..be3d3f06 100644 --- a/lib/pca9685/output_writers/pca9685.hpp +++ b/lib/pca9685/output_writers/pca9685.hpp @@ -4,11 +4,10 @@ #include #include -#include -#include +#include namespace OH { - class PCA9685OutputWriter : public OH::AbstractOutputWriter { + class PCA9685OutputWriter : public OH::AbstractActuator { private: Adafruit_PWMServoDriver* driver; uint8_t num; diff --git a/lib/sensor/sensor.hpp b/lib/sensor/sensor.hpp new file mode 100644 index 00000000..fe70ed29 --- /dev/null +++ b/lib/sensor/sensor.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include "task.hpp" + +namespace OH +{ + template + class ISensor { + public: + virtual _Tp getValue() = 0; + }; + + template + class ThrottledSensor : public Task>, public ISensor<_Tp> { + template friend class RatePollingComponent; + friend class Task>; + + private: + virtual void run(void) { + while (true) { + this->value = this->updateValue(); + delay(this->rate); + } + }; + + protected: + _Tp value; + uint32_t rate; + virtual _Tp updateValue(void) = 0; + + public: + ThrottledSensor(TaskConfig taskConfig, uint32_t rate) : Task>(taskConfig), rate(rate) {}; + _Tp getValue() override { return this->value; }; + }; +} // namespace OH diff --git a/platformio.ini b/platformio.ini index 4115d612..61b31ea2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -16,6 +16,8 @@ extra_configs = ini/bhaptics.ini [common] +build_unflags = + -std=gnu++11 build_flags = -std=gnu++17 -D __OH_FIRMWARE__ @@ -23,12 +25,13 @@ build_flags = ; -D DEBUG_MODE=0 ; -D DEBUG_ESP_PORT=Serial ; -D SERIAL_PLOTTER=true - -D BATTERY_ENABLED=true -build_unflags = - -std=gnu++11 +; -D BATTERY_ENABLED=true +; -D BLUETOOTH_USE_NIMBLE=false + build_src_filter = +<*> - + lib_deps = Wire SPI @@ -36,23 +39,24 @@ lib_deps = adafruit/Adafruit PWM Servo Driver Library@^2.4.0 adafruit/Adafruit INA219@^1.2.1 sparkfun/SparkFun MAX1704x Fuel Gauge Arduino Library@^1.0.4 + h2zero/NimBLE-Arduino@^1.4.0 [env] -framework = arduino -platform = espressif32 -board = esp32doit-devkit-v1 - build_flags = ${common.build_flags} build_unflags = ${common.build_unflags} build_src_filter = ${common.build_src_filter} lib_deps = ${common.lib_deps} -upload_speed = 921600 -monitor_speed = 115200 -test_ignore = test_desktop +[env:native] +platform = native -[env:test] -build_flags = ${common.build_flags} build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} + -lgcov + --coverage build_src_filter = ${common.build_src_filter} + +lib_deps = ${common.lib_deps} + fabiobatsilva/ArduinoFake@^0.3.1 + +test_ignore = test_embedded diff --git a/scripts/test-cover.sh b/scripts/test-cover.sh new file mode 100755 index 00000000..d15330f7 --- /dev/null +++ b/scripts/test-cover.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -euxo pipefail + +build_dir=$1 +env=$2 +shift 2 + +# Run tests +$@ + +lcov -d $build_dir/$env/ -c -o lcov.info +lcov --remove lcov.info '/usr/include/*' '*.platformio/*' '*.pio/*' '*/tool-unity/*' '*/test/*' '*/MockArduino/*' -o lcov.info.cleaned +genhtml -p $PWD -o build/coverage/ --demangle-cpp lcov.info.cleaned diff --git a/test/test_bhaptics/main.cpp b/test/test_bhaptics/main.cpp new file mode 100644 index 00000000..a37628db --- /dev/null +++ b/test/test_bhaptics/main.cpp @@ -0,0 +1,357 @@ +#include +#include +#include +#include + +using namespace OH; +using namespace BH; + +class TestActuator : public AbstractActuator { + public: + bool isSetup = false; + oh_output_intensity_t intensity = 0; + + TestActuator() : AbstractActuator() {} + void setup() override { + this->isSetup = true; + } + void writeOutput(oh_output_intensity_t intensity) override { + this->intensity = intensity; + } +}; + +void test_layout_tactsuitx16(void) { + static const size_t bhLayoutSize = BH_LAYOUT_TACTSUITX16_SIZE; + static const oh_output_point_t* bhLayout[bhLayoutSize] = BH_LAYOUT_TACTSUITX16; + + static const size_t layoutGroupsSize = BH_LAYOUT_TACTSUITX16_GROUPS_SIZE; + static const uint8_t layoutGroups[layoutGroupsSize] = BH_LAYOUT_TACTSUITX16_GROUPS; + + auto body = new HapticBody(); + + TestActuator* actuator0 = new TestActuator(); + TestActuator* actuator1 = new TestActuator(); + TestActuator* actuator2 = new TestActuator(); + TestActuator* actuator3 = new TestActuator(); + TestActuator* actuator4 = new TestActuator(); + TestActuator* actuator5 = new TestActuator(); + TestActuator* actuator6 = new TestActuator(); + TestActuator* actuator7 = new TestActuator(); + TestActuator* actuator8 = new TestActuator(); + TestActuator* actuator9 = new TestActuator(); + TestActuator* actuator10 = new TestActuator(); + TestActuator* actuator11 = new TestActuator(); + TestActuator* actuator12 = new TestActuator(); + TestActuator* actuator13 = new TestActuator(); + TestActuator* actuator14 = new TestActuator(); + TestActuator* actuator15 = new TestActuator(); + + auto frontOutputs = PlaneMapper_Margin::mapMatrixCoordinates({ + {actuator0, actuator1, actuator2, actuator3}, + {actuator4, actuator5, actuator6, actuator7}, + }); + auto backOutputs = PlaneMapper_Margin::mapMatrixCoordinates({ + {actuator8, actuator9, actuator10, actuator11}, + {actuator12, actuator13, actuator14, actuator15}, + }); + + auto frontPlane = new HapticPlane(frontOutputs); + auto backPlane = new HapticPlane(backOutputs); + + body->addComponent(OUTPUT_PATH_CHEST_FRONT, frontPlane); + body->addComponent(OUTPUT_PATH_CHEST_BACK, backPlane); + body->setup(); + + uint8_t values[] = { + 0x01, 0x00, 0x23, 0x00, 0x00, 0x45, 0x00, 0x67, 0x00, 0x00, + 0x89, 0x00, 0xab, 0x00, 0x00, 0xcd, 0x00, 0xef, 0x00, 0x00, + }; + std::string value = std::string((char*)values, sizeof(values)); + + vestX16OutputTransformer(body, value, bhLayout, bhLayoutSize, layoutGroups, layoutGroupsSize); + TEST_ASSERT_EQUAL_INT(0, actuator0->intensity); + TEST_ASSERT_EQUAL_INT(17, actuator1->intensity); + TEST_ASSERT_EQUAL_INT(204, actuator2->intensity); + TEST_ASSERT_EQUAL_INT(221, actuator3->intensity); + TEST_ASSERT_EQUAL_INT(34, actuator4->intensity); + TEST_ASSERT_EQUAL_INT(51, actuator5->intensity); + TEST_ASSERT_EQUAL_INT(238, actuator6->intensity); + TEST_ASSERT_EQUAL_INT(255, actuator7->intensity); + + TEST_ASSERT_EQUAL_INT(68, actuator8->intensity); + TEST_ASSERT_EQUAL_INT(85, actuator9->intensity); + TEST_ASSERT_EQUAL_INT(136, actuator10->intensity); + TEST_ASSERT_EQUAL_INT(153, actuator11->intensity); + TEST_ASSERT_EQUAL_INT(102, actuator12->intensity); + TEST_ASSERT_EQUAL_INT(119, actuator13->intensity); + TEST_ASSERT_EQUAL_INT(170, actuator14->intensity); + TEST_ASSERT_EQUAL_INT(187, actuator15->intensity); +} + +void test_layout_tactsuitx40(void) { + static const size_t bhLayoutSize = BH_LAYOUT_TACTSUITX40_SIZE; + static const oh_output_point_t* bhLayout[bhLayoutSize] = BH_LAYOUT_TACTSUITX40; + + auto body = new HapticBody(); + + std::vector> frontMatrix = { + {new TestActuator(), new TestActuator(), new TestActuator(), new TestActuator()}, + {new TestActuator(), new TestActuator(), new TestActuator(), new TestActuator()}, + {new TestActuator(), new TestActuator(), new TestActuator(), new TestActuator()}, + {new TestActuator(), new TestActuator(), new TestActuator(), new TestActuator()}, + {new TestActuator(), new TestActuator(), new TestActuator(), new TestActuator()}, + }; + std::vector> backMatrix = { + {new TestActuator(), new TestActuator(), new TestActuator(), new TestActuator()}, + {new TestActuator(), new TestActuator(), new TestActuator(), new TestActuator()}, + {new TestActuator(), new TestActuator(), new TestActuator(), new TestActuator()}, + {new TestActuator(), new TestActuator(), new TestActuator(), new TestActuator()}, + {new TestActuator(), new TestActuator(), new TestActuator(), new TestActuator()}, + }; + + auto frontOutputs = PlaneMapper_Margin::mapMatrixCoordinates(frontMatrix); + auto backOutputs = PlaneMapper_Margin::mapMatrixCoordinates(backMatrix); + + auto frontPlane = new HapticPlane(frontOutputs); + auto backPlane = new HapticPlane(backOutputs); + + body->addComponent(OUTPUT_PATH_CHEST_FRONT, frontPlane); + body->addComponent(OUTPUT_PATH_CHEST_BACK, backPlane); + body->setup(); + + uint8_t values[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + std::string value = std::string((char*)values, sizeof(values)); + + vestOutputTransformer(body, value, bhLayout, bhLayoutSize); + TEST_ASSERT_EQUAL_INT(0, static_cast(frontMatrix[0][0])->intensity); + TEST_ASSERT_EQUAL_INT(17, static_cast(frontMatrix[0][1])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(frontMatrix[0][2])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(frontMatrix[0][3])->intensity); + TEST_ASSERT_EQUAL_INT(34, static_cast(frontMatrix[1][0])->intensity); + TEST_ASSERT_EQUAL_INT(51, static_cast(frontMatrix[1][1])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(frontMatrix[1][2])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(frontMatrix[1][3])->intensity); + TEST_ASSERT_EQUAL_INT(68, static_cast(frontMatrix[2][0])->intensity); + TEST_ASSERT_EQUAL_INT(85, static_cast(frontMatrix[2][1])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(frontMatrix[2][2])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(frontMatrix[2][3])->intensity); + TEST_ASSERT_EQUAL_INT(102, static_cast(frontMatrix[3][0])->intensity); + TEST_ASSERT_EQUAL_INT(119, static_cast(frontMatrix[3][1])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(frontMatrix[3][2])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(frontMatrix[3][3])->intensity); + TEST_ASSERT_EQUAL_INT(136, static_cast(frontMatrix[4][0])->intensity); + TEST_ASSERT_EQUAL_INT(153, static_cast(frontMatrix[4][1])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(frontMatrix[4][2])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(frontMatrix[4][3])->intensity); + + TEST_ASSERT_EQUAL_INT(170, static_cast(backMatrix[0][0])->intensity); + TEST_ASSERT_EQUAL_INT(187, static_cast(backMatrix[0][1])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(backMatrix[0][2])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(backMatrix[0][3])->intensity); + TEST_ASSERT_EQUAL_INT(204, static_cast(backMatrix[1][0])->intensity); + TEST_ASSERT_EQUAL_INT(221, static_cast(backMatrix[1][1])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(backMatrix[1][2])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(backMatrix[1][3])->intensity); + TEST_ASSERT_EQUAL_INT(238, static_cast(backMatrix[2][0])->intensity); + TEST_ASSERT_EQUAL_INT(255, static_cast(backMatrix[2][1])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(backMatrix[2][2])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(backMatrix[2][3])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(backMatrix[3][0])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(backMatrix[3][1])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(backMatrix[3][2])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(backMatrix[3][3])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(backMatrix[4][0])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(backMatrix[4][1])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(backMatrix[4][2])->intensity); + TEST_ASSERT_EQUAL_INT(0, static_cast(backMatrix[4][3])->intensity); +} + +void test_layout_tactal(void) { + static const size_t bhLayoutSize = BH_LAYOUT_TACTAL_SIZE; + static const oh_output_point_t* bhLayout[bhLayoutSize] = BH_LAYOUT_TACTAL; + + auto body = new HapticBody(); + + TestActuator* actuator0 = new TestActuator(); + TestActuator* actuator1 = new TestActuator(); + TestActuator* actuator2 = new TestActuator(); + TestActuator* actuator3 = new TestActuator(); + TestActuator* actuator4 = new TestActuator(); + TestActuator* actuator5 = new TestActuator(); + + auto outputs = PlaneMapper_Margin::mapMatrixCoordinates({ + { actuator0, actuator1, actuator2, actuator3, actuator4, actuator5 }, + }); + auto plane = new HapticPlane(outputs); + + body->addComponent(OUTPUT_PATH_ACCESSORY, plane); + body->setup(); + + uint8_t values[] = {0x64, 0x00, 0x00, 0x00, 0x00, 0x00}; + std::string value = std::string((char*)values, sizeof(values)); + + plainOutputTransformer(body, value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); + TEST_ASSERT_EQUAL_INT(255, actuator0->intensity); + TEST_ASSERT_EQUAL_INT(0, actuator1->intensity); + TEST_ASSERT_EQUAL_INT(0, actuator2->intensity); + TEST_ASSERT_EQUAL_INT(0, actuator3->intensity); + TEST_ASSERT_EQUAL_INT(0, actuator4->intensity); + TEST_ASSERT_EQUAL_INT(0, actuator5->intensity); + + value = "\x10\x20\x30\x40\x50\x60"; + + plainOutputTransformer(body, value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); + TEST_ASSERT_EQUAL_INT(40, actuator0->intensity); + TEST_ASSERT_EQUAL_INT(81, actuator1->intensity); + TEST_ASSERT_EQUAL_INT(122, actuator2->intensity); + TEST_ASSERT_EQUAL_INT(163, actuator3->intensity); + TEST_ASSERT_EQUAL_INT(204, actuator4->intensity); + TEST_ASSERT_EQUAL_INT(244, actuator5->intensity); +} + +void test_layout_tactosy2(void) { + static const size_t bhLayoutSize = BH_LAYOUT_TACTOSY2_SIZE; + static const oh_output_point_t* bhLayout[bhLayoutSize] = BH_LAYOUT_TACTOSY2; + + auto body = new HapticBody(); + + TestActuator* actuator0 = new TestActuator(); + TestActuator* actuator1 = new TestActuator(); + TestActuator* actuator2 = new TestActuator(); + TestActuator* actuator3 = new TestActuator(); + TestActuator* actuator4 = new TestActuator(); + TestActuator* actuator5 = new TestActuator(); + + auto outputs = PlaneMapper_Margin::mapMatrixCoordinates({ + { actuator0, actuator1, actuator2}, + { actuator3, actuator4, actuator5 }, + }); + auto plane = new HapticPlane(outputs); + + body->addComponent(OUTPUT_PATH_ACCESSORY, plane); + body->setup(); + + uint8_t values[] = {0x64, 0x00, 0x00, 0x00, 0x00, 0x00}; + std::string value = std::string((char*)values, sizeof(values)); + + plainOutputTransformer(body, value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); + TEST_ASSERT_EQUAL_INT(255, actuator0->intensity); + TEST_ASSERT_EQUAL_INT(0, actuator1->intensity); + TEST_ASSERT_EQUAL_INT(0, actuator2->intensity); + TEST_ASSERT_EQUAL_INT(0, actuator3->intensity); + TEST_ASSERT_EQUAL_INT(0, actuator4->intensity); + TEST_ASSERT_EQUAL_INT(0, actuator5->intensity); + + value = "\x10\x20\x30\x40\x50\x60"; + plainOutputTransformer(body, value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); + TEST_ASSERT_EQUAL_INT(40, actuator0->intensity); + TEST_ASSERT_EQUAL_INT(81, actuator1->intensity); + TEST_ASSERT_EQUAL_INT(122, actuator2->intensity); + TEST_ASSERT_EQUAL_INT(163, actuator3->intensity); + TEST_ASSERT_EQUAL_INT(204, actuator4->intensity); + TEST_ASSERT_EQUAL_INT(244, actuator5->intensity); +} + +void test_layout_tactosyh(void) { + static const size_t bhLayoutSize = BH_LAYOUT_TACTOSYH_SIZE; + static const oh_output_point_t* bhLayout[bhLayoutSize] = BH_LAYOUT_TACTOSYH; + + auto body = new HapticBody(); + + TestActuator* actuator0 = new TestActuator(); + TestActuator* actuator1 = new TestActuator(); + TestActuator* actuator2 = new TestActuator(); + + auto outputs = PlaneMapper_Margin::mapMatrixCoordinates({ + { actuator0 }, + { actuator1 }, + { actuator2 }, + }); + auto plane = new HapticPlane(outputs); + + body->addComponent(OUTPUT_PATH_ACCESSORY, plane); + body->setup(); + + uint8_t values[] = {0x64, 0x00, 0x00}; + std::string value = std::string((char*)values, sizeof(values)); + + plainOutputTransformer(body, value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); + TEST_ASSERT_EQUAL_INT(255, actuator0->intensity); + TEST_ASSERT_EQUAL_INT(0, actuator1->intensity); + TEST_ASSERT_EQUAL_INT(0, actuator2->intensity); + + value = "\x10\x20\x30"; + plainOutputTransformer(body, value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); + TEST_ASSERT_EQUAL_INT(40, actuator0->intensity); + TEST_ASSERT_EQUAL_INT(81, actuator1->intensity); + TEST_ASSERT_EQUAL_INT(122, actuator2->intensity); +} + +void test_layout_tactosyf(void) { + static const size_t bhLayoutSize = BH_LAYOUT_TACTOSYF_SIZE; + static const oh_output_point_t* bhLayout[bhLayoutSize] = BH_LAYOUT_TACTOSYF; + + auto body = new HapticBody(); + + TestActuator* actuator0 = new TestActuator(); + TestActuator* actuator1 = new TestActuator(); + TestActuator* actuator2 = new TestActuator(); + + auto outputs = PlaneMapper_Margin::mapMatrixCoordinates({ + { actuator0 }, + { actuator1 }, + { actuator2 }, + }); + auto plane = new HapticPlane(outputs); + + body->addComponent(OUTPUT_PATH_ACCESSORY, plane); + body->setup(); + + uint8_t values[] = {0x64, 0x00, 0x00}; + std::string value = std::string((char*)values, sizeof(values)); + + plainOutputTransformer(body, value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); + TEST_ASSERT_EQUAL_INT(255, actuator0->intensity); + TEST_ASSERT_EQUAL_INT(0, actuator1->intensity); + TEST_ASSERT_EQUAL_INT(0, actuator2->intensity); + + value = "\x10\x20\x30"; + plainOutputTransformer(body, value, bhLayout, bhLayoutSize, OUTPUT_PATH_ACCESSORY); + TEST_ASSERT_EQUAL_INT(40, actuator0->intensity); + TEST_ASSERT_EQUAL_INT(81, actuator1->intensity); + TEST_ASSERT_EQUAL_INT(122, actuator2->intensity); +} + +int process(void) { + UNITY_BEGIN(); + + RUN_TEST(test_layout_tactsuitx16); + RUN_TEST(test_layout_tactsuitx40); + RUN_TEST(test_layout_tactal); + RUN_TEST(test_layout_tactosy2); + RUN_TEST(test_layout_tactosyh); + RUN_TEST(test_layout_tactosyf); + + return UNITY_END(); +} + +#ifdef ARDUINO + +#include + +void setup(void) { + process(); +} + +void loop(void) {} + +#else + +int main(int argc, char** argv) { + return process(); +} + +#endif diff --git a/test/test_common/output/test_closest.cpp b/test/test_common/output/test_closest.cpp deleted file mode 100644 index 0f831eb2..00000000 --- a/test/test_common/output/test_closest.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "unity.h" - -#ifdef UNIT_TEST - -class TestWriter : public OutputWriter { - public: - void writeOutput(oh_output_intensity_t intensity) override{}; -}; - -void test_coordinates(void) { - oh_output_map_t testOutputs{ - {oh_output_point_t(10, 10), new TestWriter()}, - {oh_output_point_t(UINT16_MAX - 10, UINT16_MAX - 10), new TestWriter()}, - }; - - auto output = new ClosestOutputComponent(testOutputs); - - auto points = output->getOutputPoints(); -} - -int process(void) { - UNITY_BEGIN(); - - RUN_TEST(test_coordinates); - - return UNITY_END(); -} - -#ifdef ARDUINO - -#include -void setup() { - process(); -} - -void loop() {} - -#else - -int main(int argc, char** argv) { - return process(); -} - -#endif - -#endif diff --git a/test/test_core_utility/main.cpp b/test/test_core_utility/main.cpp new file mode 100644 index 00000000..4b4335fb --- /dev/null +++ b/test/test_core_utility/main.cpp @@ -0,0 +1,86 @@ +#include +#include + +using namespace OH; + +void test_contains_container(void) { + std::vector v = {1, 2, 3, 4, 5}; + TEST_ASSERT_TRUE(contains(v, 1)); + TEST_ASSERT_TRUE(contains(v, 2)); + TEST_ASSERT_TRUE(contains(v, 3)); + TEST_ASSERT_TRUE(contains(v, 4)); + TEST_ASSERT_TRUE(contains(v, 5)); + TEST_ASSERT_FALSE(contains(v, 6)); +} + +void test_contains_iterator(void) { + int arr[] = {1, 2, 3, 4, 5}; + TEST_ASSERT_TRUE(contains(arr, arr + 5, 1)); + TEST_ASSERT_TRUE(contains(arr, arr + 5, 2)); + TEST_ASSERT_TRUE(contains(arr, arr + 5, 3)); + TEST_ASSERT_TRUE(contains(arr, arr + 5, 4)); + TEST_ASSERT_TRUE(contains(arr, arr + 5, 5)); + TEST_ASSERT_FALSE(contains(arr, arr + 5, 6)); +} + +void test_contains_string(void) { + std::string s = "Hello, World!"; + TEST_ASSERT_TRUE(contains(s, 'H')); + TEST_ASSERT_TRUE(contains(s, 'e')); + TEST_ASSERT_TRUE(contains(s, 'l')); + TEST_ASSERT_TRUE(contains(s, 'o')); + TEST_ASSERT_TRUE(contains(s, ',')); + TEST_ASSERT_TRUE(contains(s, ' ')); + TEST_ASSERT_TRUE(contains(s, 'W')); + TEST_ASSERT_TRUE(contains(s, 'r')); + TEST_ASSERT_TRUE(contains(s, 'd')); + TEST_ASSERT_TRUE(contains(s, '!')); + TEST_ASSERT_FALSE(contains(s, 'h')); + TEST_ASSERT_FALSE(contains(s, 'w')); + TEST_ASSERT_FALSE(contains(s, 'x')); + TEST_ASSERT_FALSE(contains(s, 'y')); + TEST_ASSERT_FALSE(contains(s, 'z')); +} + +void test_map(void) { + TEST_ASSERT_EQUAL_UINT16(0, map(0, 0, 4095, 0, 255)); + TEST_ASSERT_EQUAL_UINT16(127, map(2047, 0, 4095, 0, 255)); + TEST_ASSERT_EQUAL_UINT16(255, map(4095, 0, 4095, 0, 255)); + + TEST_ASSERT_EQUAL_UINT16(127, map(0, 0, 4095, 127, 255)); + TEST_ASSERT_EQUAL_UINT16(190, map(2047, 0, 4095, 127, 255)); + TEST_ASSERT_EQUAL_UINT16(255, map(4095, 0, 4095, 127, 255)); + + TEST_ASSERT_EQUAL_UINT16(0, map(2048, 2048, 4095, 0, 255)); + TEST_ASSERT_EQUAL_UINT16(127, map(3071, 2048, 4095, 0, 255)); + TEST_ASSERT_EQUAL_UINT16(255, map(4095, 2048, 4095, 0, 255)); +} + +int process(void) { + UNITY_BEGIN(); + + RUN_TEST(test_contains_container); + RUN_TEST(test_contains_iterator); + RUN_TEST(test_contains_string); + RUN_TEST(test_map); + + return UNITY_END(); +} + +#ifdef ARDUINO + +#include + +void setup(void) { + process(); +} + +void loop(void) {} + +#else + +int main(int argc, char** argv) { + return process(); +} + +#endif diff --git a/test/test_haptic_body/main.cpp b/test/test_haptic_body/main.cpp new file mode 100644 index 00000000..cbad27b1 --- /dev/null +++ b/test/test_haptic_body/main.cpp @@ -0,0 +1,63 @@ +#include +#include + +using namespace OH; + +class TestActuator : public AbstractActuator { + public: + bool isSetup = false; + oh_output_intensity_t intensity = 0; + + TestActuator() : AbstractActuator() {} + void setup() override { + this->isSetup = true; + } + void writeOutput(oh_output_intensity_t intensity) override { + this->intensity = intensity; + } +}; + +void test_it_sets_up_planes(void) { + auto body = new HapticBody(); + + oh_output_writers_map_t outputs = { + {{0, 0}, new TestActuator()}, + {{0, 1}, new TestActuator()}, + {{1, 0}, new TestActuator()}, + {{1, 1}, new TestActuator()}, + }; + auto plane = new HapticPlane(outputs); + + body->addComponent(0, plane); + body->setup(); + + for (auto& kv : outputs) { + TEST_ASSERT_TRUE(static_cast(kv.second)->isSetup); + } +} + +int process(void) { + UNITY_BEGIN(); + + RUN_TEST(test_it_sets_up_planes); + + return UNITY_END(); +} + +#ifdef ARDUINO + +#include + +void setup(void) { + process(); +} + +void loop(void) {} + +#else + +int main(int argc, char** argv) { + return process(); +} + +#endif diff --git a/test/test_haptics_plane/main.cpp b/test/test_haptics_plane/main.cpp new file mode 100644 index 00000000..c8080e19 --- /dev/null +++ b/test/test_haptics_plane/main.cpp @@ -0,0 +1,214 @@ +#include +#include + +using namespace OH; + +class TestActuator : public AbstractActuator { + public: + bool isSetup = false; + oh_output_intensity_t intensity = 0; + + TestActuator() : AbstractActuator() {} + void setup() override { + this->isSetup = true; + } + void writeOutput(oh_output_intensity_t intensity) override { + this->intensity = intensity; + } +}; + +void test_it_sets_up_actuators(void) { + oh_output_writers_map_t outputs = { + {{0, 0}, new TestActuator()}, + {{0, 1}, new TestActuator()}, + {{1, 0}, new TestActuator()}, + {{1, 1}, new TestActuator()}, + }; + + auto plane = new HapticPlane(outputs); + plane->setup(); + + for (auto& kv : outputs) { + TEST_ASSERT_TRUE(static_cast(kv.second)->isSetup); + } +} + +void test_it_writes_to_correct_output(void) { + auto actuator = new TestActuator(), + actuator2 = new TestActuator(), + actuator3 = new TestActuator(), + actuator4 = new TestActuator(); + + oh_output_writers_map_t outputs = { + {{0, 0}, actuator}, + {{0, 1}, actuator2}, + {{1, 0}, actuator3}, + {{1, 1}, actuator4}, + }; + + auto plane = new HapticPlane(outputs); + plane->setup(); + + plane->writeOutput({{0, 0}, 64}); + plane->writeOutput({{0, 1}, 128}); + plane->writeOutput({{1, 0}, 192}); + plane->writeOutput({{1, 1}, 255}); + + TEST_ASSERT_EQUAL_UINT8(64, actuator->intensity); + TEST_ASSERT_EQUAL_UINT8(128, actuator2->intensity); + TEST_ASSERT_EQUAL_UINT8(192, actuator3->intensity); + TEST_ASSERT_EQUAL_UINT8(255, actuator4->intensity); +} + +void test_it_updates_state(void) { + auto actuator = new TestActuator(), + actuator2 = new TestActuator(), + actuator3 = new TestActuator(), + actuator4 = new TestActuator(); + + oh_output_writers_map_t outputs = { + {{0, 0}, actuator}, + {{0, 1}, actuator2}, + {{1, 0}, actuator3}, + {{1, 1}, actuator4}, + }; + + auto plane = new HapticPlane(outputs); + plane->setup(); + + plane->writeOutput({{0, 0}, 64}); + plane->writeOutput({{0, 1}, 128}); + plane->writeOutput({{1, 0}, 192}); + plane->writeOutput({{1, 1}, 255}); + + TEST_ASSERT_EQUAL_UINT8(64, plane->getOutputStates()->at({0, 0}).intensity); + TEST_ASSERT_EQUAL_UINT8(128, plane->getOutputStates()->at({0, 1}).intensity); + TEST_ASSERT_EQUAL_UINT8(192, plane->getOutputStates()->at({1, 0}).intensity); + TEST_ASSERT_EQUAL_UINT8(255, plane->getOutputStates()->at({1, 1}).intensity); +} + +void test_closest_it_writes_to_correct_if_exact(void) { + auto actuator = new TestActuator(), + actuator2 = new TestActuator(), + actuator3 = new TestActuator(), + actuator4 = new TestActuator(); + + oh_output_writers_map_t outputs = { + {{0, 0}, actuator}, + {{0, 1}, actuator2}, + {{1, 0}, actuator3}, + {{1, 1}, actuator4}, + }; + + auto plane = new HapticPlane_Closest(outputs); + plane->setup(); + + plane->writeOutput({{0, 0}, 1}); + plane->writeOutput({{0, 1}, 2}); + plane->writeOutput({{1, 0}, 3}); + plane->writeOutput({{1, 1}, 4}); + + TEST_ASSERT_EQUAL(1, actuator->intensity); + TEST_ASSERT_EQUAL(2, actuator2->intensity); + TEST_ASSERT_EQUAL(3, actuator3->intensity); + TEST_ASSERT_EQUAL(4, actuator4->intensity); +} + +void test_closest_it_correctly_finds_closest(void) { + auto actuator = new TestActuator(), + actuator2 = new TestActuator(), + actuator3 = new TestActuator(), + actuator4 = new TestActuator(); + + oh_output_writers_map_t outputs = { + {{0, 0}, actuator}, + {{0, 64}, actuator2}, + {{64, 0}, actuator3}, + {{64, 64}, actuator4}, + }; + + auto plane = new HapticPlane_Closest(outputs); + plane->setup(); + + plane->writeOutput({{16, 16}, 16}); + plane->writeOutput({{65, 65}, 65}); + + TEST_ASSERT_EQUAL(16, actuator->intensity); + TEST_ASSERT_EQUAL(0, actuator2->intensity); + TEST_ASSERT_EQUAL(0, actuator3->intensity); + TEST_ASSERT_EQUAL(65, actuator4->intensity); +} + +void test_closest_it_updates_state(void) { + auto actuator = new TestActuator(), + actuator2 = new TestActuator(), + actuator3 = new TestActuator(), + actuator4 = new TestActuator(); + + oh_output_writers_map_t outputs = { + {{0, 0}, actuator}, + {{0, 64}, actuator2}, + {{64, 0}, actuator3}, + {{64, 64}, actuator4}, + }; + + auto plane = new HapticPlane_Closest(outputs); + plane->setup(); + + plane->writeOutput({{16, 16}, 16}); + plane->writeOutput({{65, 65}, 65}); + + TEST_ASSERT_EQUAL(16, plane->getOutputStates()->at({0, 0}).intensity); + TEST_ASSERT_EQUAL(0, plane->getOutputStates()->at({0, 64}).intensity); + TEST_ASSERT_EQUAL(0, plane->getOutputStates()->at({64, 0}).intensity); + TEST_ASSERT_EQUAL(65, plane->getOutputStates()->at({64, 64}).intensity); +} + +void test_plain_mapper_margin_map_points(void) { + auto point = PlaneMapper_Margin::mapPoint(0, 0, 0, 0); + + TEST_ASSERT_EQUAL(127, point->x); + TEST_ASSERT_EQUAL(127, point->y); + + point = PlaneMapper_Margin::mapPoint(0, 0, 1, 1); + + TEST_ASSERT_EQUAL(85, point->x); + TEST_ASSERT_EQUAL(85, point->y); + + point = PlaneMapper_Margin::mapPoint(1, 1, 1, 1); + + TEST_ASSERT_EQUAL(170, point->x); + TEST_ASSERT_EQUAL(170, point->y); +} + +int process(void) { + UNITY_BEGIN(); + + RUN_TEST(test_it_sets_up_actuators); + RUN_TEST(test_it_writes_to_correct_output); + RUN_TEST(test_it_updates_state); + RUN_TEST(test_closest_it_writes_to_correct_if_exact); + RUN_TEST(test_closest_it_correctly_finds_closest); + RUN_TEST(test_closest_it_updates_state); + RUN_TEST(test_plain_mapper_margin_map_points); + + return UNITY_END(); +} + +#ifdef ARDUINO + +#include + +void setup(void) { + process(); +} + +void loop(void) {} + +#else + +int main(int argc, char** argv) { + return process(); +} + +#endif diff --git a/test/test_math_point2/main.cpp b/test/test_math_point2/main.cpp new file mode 100644 index 00000000..d568a635 --- /dev/null +++ b/test/test_math_point2/main.cpp @@ -0,0 +1,59 @@ +#include +#include + +using namespace OH; + +void test_operator_equal(void) { + Point2 p1 = {1, 2}; + Point2 p2 = {1, 2}; + Point2 p3 = {2, 1}; + + TEST_ASSERT_TRUE(p1 == p2); + TEST_ASSERT_FALSE(p1 == p3); +} + +void test_operator_not_equal(void) { + Point2 p1 = {1, 2}; + Point2 p2 = {1, 2}; + Point2 p3 = {2, 1}; + + TEST_ASSERT_FALSE(p1 != p2); + TEST_ASSERT_TRUE(p1 != p3); +} + +void test_operator_less_than(void) { + Point2 p1 = {1, 2}; + Point2 p2 = {1, 2}; + Point2 p3 = {2, 1}; + + TEST_ASSERT_FALSE(p1 < p2); + TEST_ASSERT_TRUE(p1 < p3); +} + +int process(void) { + UNITY_BEGIN(); + + RUN_TEST(test_operator_equal); + RUN_TEST(test_operator_not_equal); + RUN_TEST(test_operator_less_than); + + return UNITY_END(); +} + +#ifdef ARDUINO + +#include + +void setup(void) { + process(); +} + +void loop(void) {} + +#else + +int main(int argc, char** argv) { + return process(); +} + +#endif